mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-26 19:55:39 +00:00
Bug 1174721 - Use AudioCompactor for GonkAudioDecoderManager. r=sotaro
--HG-- extra : transplant_source : %29%E2H%CF%87k%D4%F4%5Dj%EE%00%CBD%BB%9Em%3C%3A%BC
This commit is contained in:
parent
a70edd2a83
commit
1bb190d317
@ -39,7 +39,7 @@ GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
|
||||
: mAudioChannels(aConfig.mChannels)
|
||||
, mAudioRate(aConfig.mRate)
|
||||
, mAudioProfile(aConfig.mProfile)
|
||||
, mAudioBuffer(nullptr)
|
||||
, mAudioCompactor(mAudioQueue)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
|
||||
MOZ_ASSERT(mAudioChannels);
|
||||
@ -107,77 +107,94 @@ GonkAudioDecoderManager::InitMediaCodecProxy()
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
||||
if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
|
||||
GonkAudioDecoderManager::CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset)
|
||||
{
|
||||
if (!(aBuffer != nullptr && aBuffer->data() != nullptr)) {
|
||||
GADM_LOG("Audio Buffer is not valid!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
int64_t timeUs;
|
||||
if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
|
||||
if (!aBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mAudioBuffer->range_length() == 0) {
|
||||
if (aBuffer->range_length() == 0) {
|
||||
// Some decoders may return spurious empty buffers that we just want to ignore
|
||||
// quoted from Android's AwesomePlayer.cpp
|
||||
ReleaseAudioBuffer();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (mLastTime > timeUs) {
|
||||
ReleaseAudioBuffer();
|
||||
GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastTime = timeUs;
|
||||
|
||||
const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
|
||||
size_t dataOffset = mAudioBuffer->range_offset();
|
||||
size_t size = mAudioBuffer->range_length();
|
||||
const uint8_t *data = static_cast<const uint8_t*>(aBuffer->data());
|
||||
size_t dataOffset = aBuffer->range_offset();
|
||||
size_t size = aBuffer->range_length();
|
||||
|
||||
nsAutoArrayPtr<AudioDataValue> buffer(new AudioDataValue[size/2]);
|
||||
memcpy(buffer.get(), data+dataOffset, size);
|
||||
uint32_t frames = size / (2 * mAudioChannels);
|
||||
|
||||
CheckedInt64 duration = FramesToUsecs(frames, mAudioRate);
|
||||
if (!duration.isValid()) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
RefPtr<AudioData> audioData = new AudioData(aStreamOffset,
|
||||
|
||||
typedef AudioCompactor::NativeCopy OmxCopy;
|
||||
mAudioCompactor.Push(aStreamOffset,
|
||||
timeUs,
|
||||
duration.value(),
|
||||
mAudioRate,
|
||||
frames,
|
||||
buffer.forget(),
|
||||
mAudioChannels,
|
||||
mAudioRate);
|
||||
ReleaseAudioBuffer();
|
||||
audioData.forget(v);
|
||||
OmxCopy(data+dataOffset,
|
||||
size,
|
||||
mAudioChannels));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class AutoReleaseAudioBuffer
|
||||
{
|
||||
public:
|
||||
AutoReleaseAudioBuffer(MediaBuffer* aBuffer, MediaCodecProxy* aCodecProxy)
|
||||
: mAudioBuffer(aBuffer)
|
||||
, mCodecProxy(aCodecProxy)
|
||||
{}
|
||||
|
||||
~AutoReleaseAudioBuffer()
|
||||
{
|
||||
if (mAudioBuffer) {
|
||||
mCodecProxy->ReleaseMediaBuffer(mAudioBuffer);
|
||||
}
|
||||
}
|
||||
private:
|
||||
MediaBuffer* mAudioBuffer;
|
||||
sp<MediaCodecProxy> mCodecProxy;
|
||||
};
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
RefPtr<MediaData>& aOutData)
|
||||
{
|
||||
aOutData = nullptr;
|
||||
if (mAudioQueue.GetSize() > 0) {
|
||||
aOutData = mAudioQueue.PopFront();
|
||||
return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK;
|
||||
}
|
||||
|
||||
status_t err;
|
||||
err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
|
||||
MediaBuffer* audioBuffer = nullptr;
|
||||
err = mDecoder->Output(&audioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US);
|
||||
AutoReleaseAudioBuffer a(audioBuffer, mDecoder.get());
|
||||
|
||||
switch (err) {
|
||||
case OK:
|
||||
{
|
||||
RefPtr<AudioData> data;
|
||||
nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
// Decoder outputs an empty video buffer, try again
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
} else if (rv != NS_OK || data == nullptr) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
aOutData = data;
|
||||
return NS_OK;
|
||||
nsresult rv = CreateAudioData(audioBuffer, aStreamOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
}
|
||||
case android::INFO_FORMAT_CHANGED:
|
||||
{
|
||||
@ -219,17 +236,11 @@ GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
case android::ERROR_END_OF_STREAM:
|
||||
{
|
||||
GADM_LOG("Got EOS frame!");
|
||||
RefPtr<AudioData> data;
|
||||
nsresult rv = CreateAudioData(aStreamOffset, getter_AddRefs(data));
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
// For EOS, no need to do any thing.
|
||||
return NS_ERROR_ABORT;
|
||||
} else if (rv != NS_OK || data == nullptr) {
|
||||
GADM_LOG("Failed to create audio data!");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
aOutData = data;
|
||||
return NS_ERROR_ABORT;
|
||||
nsresult rv = CreateAudioData(audioBuffer, aStreamOffset);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT);
|
||||
MOZ_ASSERT(mAudioQueue.GetSize() > 0);
|
||||
mAudioQueue.Finish();
|
||||
break;
|
||||
}
|
||||
case -ETIMEDOUT:
|
||||
{
|
||||
@ -243,14 +254,22 @@ GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
if (mAudioQueue.GetSize() > 0) {
|
||||
aOutData = mAudioQueue.PopFront();
|
||||
// Return NS_ERROR_ABORT at the last sample.
|
||||
return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
void GonkAudioDecoderManager::ReleaseAudioBuffer() {
|
||||
if (mAudioBuffer) {
|
||||
mDecoder->ReleaseMediaBuffer(mAudioBuffer);
|
||||
mAudioBuffer = nullptr;
|
||||
}
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Flush()
|
||||
{
|
||||
GADM_LOG("FLUSH<<<");
|
||||
mAudioQueue.Reset();
|
||||
GADM_LOG(">>>FLUSH");
|
||||
return GonkDecoderManager::Flush();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -7,6 +7,7 @@
|
||||
#if !defined(GonkAudioDecoderManager_h_)
|
||||
#define GonkAudioDecoderManager_h_
|
||||
|
||||
#include "AudioCompactor.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "GonkMediaDataDecoder.h"
|
||||
|
||||
@ -30,19 +31,21 @@ public:
|
||||
nsresult Output(int64_t aStreamOffset,
|
||||
RefPtr<MediaData>& aOutput) override;
|
||||
|
||||
virtual nsresult Flush() override;
|
||||
|
||||
private:
|
||||
bool InitMediaCodecProxy();
|
||||
|
||||
nsresult CreateAudioData(int64_t aStreamOffset,
|
||||
AudioData** aOutData);
|
||||
|
||||
void ReleaseAudioBuffer();
|
||||
nsresult CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset);
|
||||
|
||||
uint32_t mAudioChannels;
|
||||
uint32_t mAudioRate;
|
||||
const uint32_t mAudioProfile;
|
||||
|
||||
android::MediaBuffer* mAudioBuffer;
|
||||
MediaQueue<AudioData> mAudioQueue;
|
||||
|
||||
AudioCompactor mAudioCompactor;
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
nsresult Input(MediaRawData* aSample);
|
||||
|
||||
// Flush the queued sample.
|
||||
nsresult Flush();
|
||||
virtual nsresult Flush();
|
||||
|
||||
// Shutdown decoder and rejects the init promise.
|
||||
virtual nsresult Shutdown();
|
||||
|
Loading…
Reference in New Issue
Block a user