author | Alfredo Yang <ayang> |
Mon, 04 May 2015 19:34:00 +0200 | |
changeset 242322 | b41ebad8dbe7290febcfff30d038cb2f5fc4e328 |
parent 242321 | c5d30567f41915f45a4864472b9ee030241ce1e8 |
child 242323 | 1163109f289589484509b584a58927141d98a173 |
push id | 59376 |
push user | cbook@mozilla.com |
push date | Tue, 05 May 2015 07:09:04 +0000 |
treeherder | mozilla-inbound@1163109f2895 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ajones |
bugs | 1127656 |
milestone | 40.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp +++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp @@ -33,25 +33,23 @@ PRLogModuleInfo* GetDemuxerLog(); #endif #define READ_OUTPUT_BUFFER_TIMEOUT_US 3000 using namespace android; typedef android::MediaCodecProxy MediaCodecProxy; namespace mozilla { -GonkAudioDecoderManager::GonkAudioDecoderManager( - MediaTaskQueue* aTaskQueue, - const AudioInfo& aConfig) - : GonkDecoderManager(aTaskQueue) - , mAudioChannels(aConfig.mChannels) +GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig) + : mAudioChannels(aConfig.mChannels) , mAudioRate(aConfig.mRate) , mAudioProfile(aConfig.mProfile) , mUseAdts(true) , mAudioBuffer(nullptr) + , mMonitor("GonkAudioDecoderManager") { MOZ_COUNT_CTOR(GonkAudioDecoderManager); MOZ_ASSERT(mAudioChannels); mCodecSpecificData = aConfig.mCodecSpecificConfig; mMimeType = aConfig.mMimeType; // Pass through mp3 without applying an ADTS header. if (!aConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) { @@ -106,23 +104,63 @@ GonkAudioDecoderManager::Init(MediaDataD if (rv == OK) { return mDecoder; } else { GADM_LOG("Failed to input codec specific data!"); return nullptr; } } -status_t -GonkAudioDecoderManager::SendSampleToOMX(MediaRawData* aSample) +bool +GonkAudioDecoderManager::HasQueuedSample() +{ + MonitorAutoLock mon(mMonitor); + return mQueueSample.Length(); +} + +nsresult +GonkAudioDecoderManager::Input(MediaRawData* aSample) { - return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData), - aSample->mSize, - aSample->mTime, - 0); + MonitorAutoLock mon(mMonitor); + nsRefPtr<MediaRawData> sample; + + if (aSample) { + sample = aSample; + if (!PerformFormatSpecificProcess(sample)) { + return NS_ERROR_FAILURE; + } + } else { + // It means EOS with empty sample. + sample = new MediaRawData(); + } + + mQueueSample.AppendElement(sample); + + status_t rv; + while (mQueueSample.Length()) { + nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0); + { + MonitorAutoUnlock mon_exit(mMonitor); + rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->mData), + data->mSize, + data->mTime, + 0); + } + if (rv == OK) { + mQueueSample.RemoveElementAt(0); + } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { + // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill + // buffer on time. + return NS_OK; + } else { + return NS_ERROR_UNEXPECTED; + } + } + + return NS_OK; } bool GonkAudioDecoderManager::PerformFormatSpecificProcess(MediaRawData* aSample) { if (aSample && mUseAdts) { int8_t frequency_index = mp4_demuxer::Adts::GetFrequencyIndex(mAudioRate); @@ -178,16 +216,31 @@ GonkAudioDecoderManager::CreateAudioData mAudioChannels, mAudioRate); ReleaseAudioBuffer(); audioData.forget(v); return NS_OK; } nsresult +GonkAudioDecoderManager::Flush() +{ + { + MonitorAutoLock mon(mMonitor); + mQueueSample.Clear(); + } + + if (mDecoder->flush() != OK) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult GonkAudioDecoderManager::Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutData) { aOutData = nullptr; status_t err; err = mDecoder->Output(&mAudioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US); switch (err) { @@ -253,20 +306,9 @@ GonkAudioDecoderManager::Output(int64_t } void GonkAudioDecoderManager::ReleaseAudioBuffer() { if (mAudioBuffer) { mDecoder->ReleaseMediaBuffer(mAudioBuffer); mAudioBuffer = nullptr; } } - -nsresult -GonkAudioDecoderManager::Flush() -{ - GonkDecoderManager::Flush(); - status_t err = mDecoder->flush(); - if (err != OK) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.h +++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.h @@ -18,46 +18,55 @@ struct MOZ_EXPORT ALooper; class MOZ_EXPORT MediaBuffer; } // namespace android namespace mozilla { class GonkAudioDecoderManager : public GonkDecoderManager { typedef android::MediaCodecProxy MediaCodecProxy; public: - GonkAudioDecoderManager(MediaTaskQueue* aTaskQueue, - const AudioInfo& aConfig); - ~GonkAudioDecoderManager(); + GonkAudioDecoderManager(const AudioInfo& aConfig); + + virtual ~GonkAudioDecoderManager() override; virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) override; + virtual nsresult Input(MediaRawData* aSample) override; + virtual nsresult Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutput) override; virtual nsresult Flush() override; -protected: - virtual bool PerformFormatSpecificProcess(MediaRawData* aSample) override; - - virtual status_t SendSampleToOMX(MediaRawData* aSample) override; + virtual bool HasQueuedSample() override; private: + bool PerformFormatSpecificProcess(MediaRawData* aSample); nsresult CreateAudioData(int64_t aStreamOffset, AudioData** aOutData); void ReleaseAudioBuffer(); - // MediaCodedc's wrapper that performs the decoding. - android::sp<MediaCodecProxy> mDecoder; const uint32_t mAudioChannels; const uint32_t mAudioRate; const uint32_t mAudioProfile; bool mUseAdts; MediaDataDecoderCallback* mReaderCallback; android::MediaBuffer* mAudioBuffer; android::sp<ALooper> mLooper; + + // MediaCodedc's wrapper that performs the decoding. + android::sp<android::MediaCodecProxy> mDecoder; + + // This monitor protects mQueueSample. + Monitor mMonitor; + + // An queue with the MP4 samples which are waiting to be sent into OMX. + // If an element is an empty MP4Sample, that menas EOS. There should not + // any sample be queued after EOS. + nsTArray<nsRefPtr<MediaRawData>> mQueueSample; }; } // namespace mozilla #endif // GonkAudioDecoderManager_h_
--- a/dom/media/fmp4/gonk/GonkDecoderModule.cpp +++ b/dom/media/fmp4/gonk/GonkDecoderModule.cpp @@ -29,29 +29,28 @@ GonkDecoderModule::Init() already_AddRefed<MediaDataDecoder> GonkDecoderModule::CreateVideoDecoder(const VideoInfo& aConfig, mozilla::layers::LayersBackend aLayersBackend, mozilla::layers::ImageContainer* aImageContainer, FlushableMediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { nsRefPtr<MediaDataDecoder> decoder = - new GonkMediaDataDecoder(new GonkVideoDecoderManager(aVideoTaskQueue, - aImageContainer, aConfig), + new GonkMediaDataDecoder(new GonkVideoDecoderManager(aImageContainer, aConfig), aVideoTaskQueue, aCallback); return decoder.forget(); } already_AddRefed<MediaDataDecoder> GonkDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig, FlushableMediaTaskQueue* aAudioTaskQueue, MediaDataDecoderCallback* aCallback) { nsRefPtr<MediaDataDecoder> decoder = - new GonkMediaDataDecoder(new GonkAudioDecoderManager(aAudioTaskQueue, aConfig), + new GonkMediaDataDecoder(new GonkAudioDecoderManager(aConfig), aAudioTaskQueue, aCallback); return decoder.forget(); } PlatformDecoderModule::ConversionRequired GonkDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const { if (aConfig.IsVideo()) {
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp +++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp @@ -20,68 +20,16 @@ PRLogModuleInfo* GetDemuxerLog(); #else #define LOG(...) #endif using namespace android; namespace mozilla { -GonkDecoderManager::GonkDecoderManager(MediaTaskQueue* aTaskQueue) - : mMonitor("GonkDecoderManager") -{ -} - -nsresult -GonkDecoderManager::Input(MediaRawData* aSample) -{ - ReentrantMonitorAutoEnter mon(mMonitor); - nsRefPtr<MediaRawData> sample; - - if (!aSample) { - // It means EOS with empty sample. - sample = new MediaRawData(); - } else { - sample = aSample; - if (!PerformFormatSpecificProcess(sample)) { - return NS_ERROR_FAILURE; - } - } - - mQueueSample.AppendElement(sample); - - status_t rv; - while (mQueueSample.Length()) { - nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0); - { - ReentrantMonitorAutoExit mon_exit(mMonitor); - rv = SendSampleToOMX(data); - } - if (rv == OK) { - mQueueSample.RemoveElementAt(0); - } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { - // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill - // buffer on time. - return NS_OK; - } else { - return NS_ERROR_UNEXPECTED; - } - } - - return NS_OK; -} - -nsresult -GonkDecoderManager::Flush() -{ - ReentrantMonitorAutoEnter mon(mMonitor); - mQueueSample.Clear(); - return NS_OK; -} - GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, FlushableMediaTaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mTaskQueue(aTaskQueue) , mCallback(aCallback) , mManager(aManager) , mSignaledEOS(false) , mDrainComplete(false)
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h +++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h @@ -14,63 +14,41 @@ class MediaCodecProxy; } // namespace android namespace mozilla { class MediaRawData; // Manage the data flow from inputting encoded data and outputting decode data. class GonkDecoderManager { public: - GonkDecoderManager(MediaTaskQueue* aTaskQueue); - virtual ~GonkDecoderManager() {} // Creates and initializs the GonkDecoder. // Returns nullptr on failure. virtual android::sp<android::MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) = 0; // Add samples into OMX decoder or queue them if decoder is out of input buffer. - virtual nsresult Input(MediaRawData* aSample); + virtual nsresult Input(MediaRawData* aSample) = 0; // Produces decoded output, it blocks until output can be produced or a timeout // is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE // if there's not enough data to produce more output. If this returns a failure // code other than NS_ERROR_NOT_AVAILABLE, an error will be reported to the // MP4Reader. // The overrided class should follow the same behaviour. virtual nsresult Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutput) = 0; // Flush the queued sample. - // It this function is overrided by subclass, this functino should be called - // in the overrided function. - virtual nsresult Flush(); + virtual nsresult Flush() = 0; - // It should be called in MediaTask thread. - bool HasQueuedSample() { - ReentrantMonitorAutoEnter mon(mMonitor); - return mQueueSample.Length(); - } + // True if sample is queued. + virtual bool HasQueuedSample() = 0; protected: - // It performs special operation to MP4 sample, the real action is depended on - // the codec type. - virtual bool PerformFormatSpecificProcess(MediaRawData* aSample) { return true; } - - // It sends MP4Sample to OMX layer. It must be overrided by subclass. - virtual android::status_t SendSampleToOMX(MediaRawData* aSample) = 0; - - // This monitor protects mQueueSample. - ReentrantMonitor mMonitor; - - // An queue with the MP4 samples which are waiting to be sent into OMX. - // If an element is an empty MP4Sample, that menas EOS. There should not - // any sample be queued after EOS. - nsTArray<nsRefPtr<MediaRawData>> mQueueSample; - nsRefPtr<MediaByteBuffer> mCodecSpecificData; nsAutoCString mMimeType; }; // Samples are decoded using the GonkDecoder (MediaCodec) // created by the GonkDecoderManager. This class implements // the higher-level logic that drives mapping the Gonk to the async
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp +++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp @@ -39,26 +39,25 @@ PRLogModuleInfo* GetDemuxerLog(); #endif using namespace mozilla::layers; using namespace android; typedef android::MediaCodecProxy MediaCodecProxy; namespace mozilla { GonkVideoDecoderManager::GonkVideoDecoderManager( - MediaTaskQueue* aTaskQueue, mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig) - : GonkDecoderManager(aTaskQueue) - , mImageContainer(aImageContainer) + : mImageContainer(aImageContainer) , mReaderCallback(nullptr) , mLastDecodedTime(0) , mColorConverterBufferSize(0) , mNativeWindow(nullptr) , mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock") + , mMonitor("GonkVideoDecoderManager") { MOZ_COUNT_CTOR(GonkVideoDecoderManager); mMimeType = aConfig.mMimeType; mVideoWidth = aConfig.mDisplay.width; mVideoHeight = aConfig.mDisplay.height; mDisplayWidth = aConfig.mDisplay.width; mDisplayHeight = aConfig.mDisplay.height; mInfo.mVideo = aConfig; @@ -113,16 +112,62 @@ GonkVideoDecoderManager::Init(MediaDataD MediaCodecProxy::kCanExposeGraphicBuffer)) { mNativeWindow = new GonkNativeWindow(); } return mDecoder; } nsresult +GonkVideoDecoderManager::Input(MediaRawData* aSample) +{ + MonitorAutoLock mon(mMonitor); + nsRefPtr<MediaRawData> sample; + + if (!aSample) { + // It means EOS with empty sample. + sample = new MediaRawData(); + } else { + sample = aSample; + } + + mQueueSample.AppendElement(sample); + + status_t rv; + while (mQueueSample.Length()) { + nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0); + { + MonitorAutoUnlock mon_unlock(mMonitor); + rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->mData), + data->mSize, + data->mTime, + 0); + } + if (rv == OK) { + mQueueSample.RemoveElementAt(0); + } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { + // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill + // buffer on time. + return NS_OK; + } else { + return NS_ERROR_UNEXPECTED; + } + } + + return NS_OK; +} + +bool +GonkVideoDecoderManager::HasQueuedSample() +{ + MonitorAutoLock mon(mMonitor); + return mQueueSample.Length(); +} + +nsresult GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v) { *v = nullptr; nsRefPtr<VideoData> data; int64_t timeUs; int32_t keyFrame; if (mVideoBuffer == nullptr) { @@ -300,16 +345,33 @@ GonkVideoDecoderManager::SetVideoFormat( return false; } return true; } GVDM_LOG("Fail to get output format"); return false; } +nsresult +GonkVideoDecoderManager::Flush() +{ + { + MonitorAutoLock mon(mMonitor); + mQueueSample.Clear(); + } + + mLastDecodedTime = 0; + + if (mDecoder->flush() != OK) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + // Blocks until decoded sample is produced by the deoder. nsresult GonkVideoDecoderManager::Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutData) { aOutData = nullptr; status_t err; if (mDecoder == nullptr) { @@ -388,37 +450,16 @@ GonkVideoDecoderManager::Output(int64_t void GonkVideoDecoderManager::ReleaseVideoBuffer() { if (mVideoBuffer) { mDecoder->ReleaseMediaBuffer(mVideoBuffer); mVideoBuffer = nullptr; } } -status_t -GonkVideoDecoderManager::SendSampleToOMX(MediaRawData* aSample) -{ - return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData), - aSample->mSize, - aSample->mTime, - 0); -} - -nsresult -GonkVideoDecoderManager::Flush() -{ - GonkDecoderManager::Flush(); - mLastDecodedTime = 0; - status_t err = mDecoder->flush(); - if (err != OK) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - void GonkVideoDecoderManager::codecReserved() { GVDM_LOG("codecReserved"); sp<AMessage> format = new AMessage; sp<Surface> surface; status_t rv = OK; // Fixed values @@ -569,17 +610,9 @@ void GonkVideoDecoderManager::ReleaseAll android::MediaBuffer *buffer; buffer = releasingVideoBuffers[i]; mDecoder->ReleaseMediaBuffer(buffer); buffer = nullptr; } releasingVideoBuffers.clear(); } -void GonkVideoDecoderManager::ReleaseMediaResources() { - GVDM_LOG("ReleseMediaResources"); - if (mDecoder == nullptr) { - return; - } - ReleaseAllPendingVideoBuffers(); - mDecoder->ReleaseMediaResources(); -} } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h +++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h @@ -33,36 +33,34 @@ namespace layers { class TextureClient; } // namespace mozilla::layers class GonkVideoDecoderManager : public GonkDecoderManager { typedef android::MediaCodecProxy MediaCodecProxy; typedef mozilla::layers::TextureClient TextureClient; public: - GonkVideoDecoderManager(MediaTaskQueue* aTaskQueue, - mozilla::layers::ImageContainer* aImageContainer, + GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer, const VideoInfo& aConfig); - ~GonkVideoDecoderManager(); + virtual ~GonkVideoDecoderManager() override; virtual android::sp<MediaCodecProxy> Init(MediaDataDecoderCallback* aCallback) override; + virtual nsresult Input(MediaRawData* aSample) override; + virtual nsresult Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutput) override; virtual nsresult Flush() override; - virtual void ReleaseMediaResources(); + virtual bool HasQueuedSample() override; static void RecycleCallback(TextureClient* aClient, void* aClosure); -protected: - virtual android::status_t SendSampleToOMX(MediaRawData* aSample) override; - private: struct FrameInfo { int32_t mWidth = 0; int32_t mHeight = 0; int32_t mStride = 0; int32_t mSliceHeight = 0; int32_t mColorFormat = 0; @@ -124,17 +122,16 @@ private: uint32_t mVideoWidth; uint32_t mVideoHeight; uint32_t mDisplayWidth; uint32_t mDisplayHeight; nsIntRect mPicture; nsIntSize mInitialFrame; - android::sp<MediaCodecProxy> mDecoder; nsRefPtr<layers::ImageContainer> mImageContainer; android::MediaBuffer* mVideoBuffer; MediaDataDecoderCallback* mReaderCallback; MediaInfo mInfo; android::sp<VideoResourceListener> mVideoListener; android::sp<MessageHandler> mHandler; @@ -155,13 +152,23 @@ private: }; // Hold video's MediaBuffers that are released. // The holded MediaBuffers are released soon after flush. Vector<android::MediaBuffer*> mPendingVideoBuffers; // The lock protects mPendingVideoBuffers. Mutex mPendingVideoBuffersLock; + // MediaCodedc's wrapper that performs the decoding. + android::sp<android::MediaCodecProxy> mDecoder; + + // This monitor protects mQueueSample. + Monitor mMonitor; + + // An queue with the MP4 samples which are waiting to be sent into OMX. + // If an element is an empty MP4Sample, that menas EOS. There should not + // any sample be queued after EOS. + nsTArray<nsRefPtr<MediaRawData>> mQueueSample; }; } // namespace mozilla #endif // GonkVideoDecoderManager_h_