diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp index 96be80667967..55f043a73816 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp @@ -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(mAudioBuffer->data()); - size_t dataOffset = mAudioBuffer->range_offset(); - size_t size = mAudioBuffer->range_length(); + const uint8_t *data = static_cast(aBuffer->data()); + size_t dataOffset = aBuffer->range_offset(); + size_t size = aBuffer->range_length(); - nsAutoArrayPtr 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 = new AudioData(aStreamOffset, - timeUs, - duration.value(), - frames, - buffer.forget(), - mAudioChannels, - mAudioRate); - ReleaseAudioBuffer(); - audioData.forget(v); + + typedef AudioCompactor::NativeCopy OmxCopy; + mAudioCompactor.Push(aStreamOffset, + timeUs, + mAudioRate, + frames, + mAudioChannels, + 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 mCodecProxy; +}; + nsresult GonkAudioDecoderManager::Output(int64_t aStreamOffset, RefPtr& 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 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 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 diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.h b/dom/media/platforms/gonk/GonkAudioDecoderManager.h index 49ee362ddda7..fc23cf133d90 100644 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.h +++ b/dom/media/platforms/gonk/GonkAudioDecoderManager.h @@ -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& 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 mAudioQueue; + + AudioCompactor mAudioCompactor; + }; } // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.h b/dom/media/platforms/gonk/GonkMediaDataDecoder.h index 3757ee319166..27cc9ca42d43 100644 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h +++ b/dom/media/platforms/gonk/GonkMediaDataDecoder.h @@ -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();