diff --git a/content/media/MediaDecoderReader.h b/content/media/MediaDecoderReader.h index eef53006019..08a3ba240dd 100644 --- a/content/media/MediaDecoderReader.h +++ b/content/media/MediaDecoderReader.h @@ -20,6 +20,7 @@ class TimeRanges; class RequestSampleCallback; class MediaDecoderReader; +class SharedDecoderManager; // Encapsulates the decoding and reading of media data. Reading can either // synchronous and done on the calling "decode" thread, or asynchronous and @@ -43,7 +44,8 @@ public: virtual bool IsDormantNeeded() { return false; } // Release media resources they should be released in dormant state // The reader can be made usable again by calling ReadMetadata(). - virtual void ReleaseMediaResources() {}; + virtual void ReleaseMediaResources() {} + virtual void SetSharedDecoderManager(SharedDecoderManager* aManager) {} // Breaks reference-counted cycles. Called during shutdown. // WARNING: If you override this, you must call the base implementation // in your override. diff --git a/content/media/fmp4/MP4Reader.cpp b/content/media/fmp4/MP4Reader.cpp index 3ca3e08d045..57f7a8e8cf7 100644 --- a/content/media/fmp4/MP4Reader.cpp +++ b/content/media/fmp4/MP4Reader.cpp @@ -14,6 +14,7 @@ #include "SharedThreadPool.h" #include "mozilla/Preferences.h" #include "mozilla/dom/TimeRanges.h" +#include "SharedDecoderManager.h" #ifdef MOZ_EME #include "mozilla/CDMProxy.h" @@ -403,12 +404,21 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo, const VideoDecoderConfig& video = mDemuxer->VideoConfig(); mInfo.mVideo.mDisplay = nsIntSize(video.display_width, video.display_height); - mVideo.mCallback = new DecoderCallback(this, kVideo); - mVideo.mDecoder = mPlatform->CreateH264Decoder(video, - mLayersBackendType, - mDecoder->GetImageContainer(), - mVideo.mTaskQueue, - mVideo.mCallback); + mVideo.mCallback = new DecoderCallback(this, kVideo); + if (mSharedDecoderManager) { + mVideo.mDecoder = + mSharedDecoderManager->CreateH264Decoder(video, + mLayersBackendType, + mDecoder->GetImageContainer(), + mVideo.mTaskQueue, + mVideo.mCallback); + } else { + mVideo.mDecoder = mPlatform->CreateH264Decoder(video, + mLayersBackendType, + mDecoder->GetImageContainer(), + mVideo.mTaskQueue, + mVideo.mCallback); + } NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, NS_ERROR_FAILURE); nsresult rv = mVideo.mDecoder->Init(); NS_ENSURE_SUCCESS(rv, rv); @@ -456,12 +466,6 @@ MP4Reader::GetDecoderData(TrackType aTrack) return (aTrack == kAudio) ? mAudio : mVideo; } -MediaDataDecoder* -MP4Reader::Decoder(TrackType aTrack) -{ - return GetDecoderData(aTrack).mDecoder; -} - MP4Sample* MP4Reader::PopSample(TrackType aTrack) { @@ -869,4 +873,21 @@ void MP4Reader::NotifyResourcesStatusChanged() #endif } +void +MP4Reader::SetIdle() +{ + if (mSharedDecoderManager && mVideo.mDecoder) { + mSharedDecoderManager->SetIdle(mVideo.mDecoder); + NotifyResourcesStatusChanged(); + } +} + +void +MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager) +{ +#ifdef MOZ_GONK_MEDIACODEC + mSharedDecoderManager = aManager; +#endif +} + } // namespace mozilla diff --git a/content/media/fmp4/MP4Reader.h b/content/media/fmp4/MP4Reader.h index 72d39cf21c9..526da0a1047 100644 --- a/content/media/fmp4/MP4Reader.h +++ b/content/media/fmp4/MP4Reader.h @@ -61,9 +61,12 @@ public: int64_t aStartTime) MOZ_OVERRIDE; // For Media Resource Management + virtual void SetIdle() MOZ_OVERRIDE; virtual bool IsWaitingMediaResources() MOZ_OVERRIDE; virtual bool IsDormantNeeded() MOZ_OVERRIDE; virtual void ReleaseMediaResources() MOZ_OVERRIDE; + virtual void SetSharedDecoderManager(SharedDecoderManager* aManager) + MOZ_OVERRIDE; virtual nsresult ResetDecode() MOZ_OVERRIDE; @@ -178,7 +181,6 @@ private: uint64_t mLastReportedNumDecodedFrames; DecoderData& GetDecoderData(mp4_demuxer::TrackType aTrack); - MediaDataDecoder* Decoder(mp4_demuxer::TrackType aTrack); layers::LayersBackend mLayersBackendType; @@ -192,6 +194,7 @@ private: bool mIndexReady; Monitor mIndexMonitor; + nsRefPtr mSharedDecoderManager; }; } // namespace mozilla diff --git a/content/media/fmp4/PlatformDecoderModule.h b/content/media/fmp4/PlatformDecoderModule.h index d8bf178eafd..1325b606fa1 100644 --- a/content/media/fmp4/PlatformDecoderModule.h +++ b/content/media/fmp4/PlatformDecoderModule.h @@ -228,8 +228,8 @@ public: virtual bool IsDormantNeeded() { return false; }; - virtual void ReleaseMediaResources() {}; - virtual void ReleaseDecoder() {}; + virtual void ReleaseMediaResources() {} + virtual void ReleaseDecoder() {} }; } // namespace mozilla diff --git a/content/media/fmp4/SharedDecoderManager.cpp b/content/media/fmp4/SharedDecoderManager.cpp new file mode 100644 index 00000000000..6818365289d --- /dev/null +++ b/content/media/fmp4/SharedDecoderManager.cpp @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SharedDecoderManager.h" +#include "mp4_demuxer/DecoderData.h" + +namespace mozilla { + +class SharedDecoderCallback : public MediaDataDecoderCallback +{ +public: + SharedDecoderCallback(SharedDecoderManager* aManager) : mManager(aManager) {} + + virtual void Output(MediaData* aData) MOZ_OVERRIDE + { + if (mManager->mActiveCallback) { + mManager->mActiveCallback->Output(aData); + } + } + virtual void Error() MOZ_OVERRIDE + { + if (mManager->mActiveCallback) { + mManager->mActiveCallback->Error(); + } + } + virtual void InputExhausted() MOZ_OVERRIDE + { + if (mManager->mActiveCallback) { + mManager->mActiveCallback->InputExhausted(); + } + } + virtual void DrainComplete() MOZ_OVERRIDE + { + if (mManager->mActiveCallback) { + mManager->DrainComplete(); + } + } + virtual void NotifyResourcesStatusChanged() MOZ_OVERRIDE + { + if (mManager->mActiveCallback) { + mManager->mActiveCallback->NotifyResourcesStatusChanged(); + } + } + virtual void ReleaseMediaResources() MOZ_OVERRIDE + { + if (mManager->mActiveCallback) { + mManager->mActiveCallback->ReleaseMediaResources(); + } + } + + nsRefPtr mManager; +}; + +SharedDecoderManager::SharedDecoderManager() + : mActiveProxy(nullptr) + , mActiveCallback(nullptr) + , mWaitForInternalDrain(false) + , mMonitor("SharedDecoderProxy") +{ + mCallback = new SharedDecoderCallback(this); +} + +SharedDecoderManager::~SharedDecoderManager() {} + +already_AddRefed +SharedDecoderManager::CreateH264Decoder( + const mp4_demuxer::VideoDecoderConfig& aConfig, + layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, + MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) +{ + if (!mDecoder) { + mConfig = aConfig; + nsAutoPtr platform(PlatformDecoderModule::Create()); + mDecoder = platform->CreateH264Decoder( + mConfig, aLayersBackend, aImageContainer, aVideoTaskQueue, mCallback); + if (!mDecoder) { + return nullptr; + } + nsresult rv = mDecoder->Init(); + NS_ENSURE_SUCCESS(rv, nullptr); + } + + nsRefPtr proxy( + new SharedDecoderProxy(this, aCallback, aConfig)); + return proxy.forget(); +} + +void +SharedDecoderManager::Select(SharedDecoderProxy* aProxy) +{ + if (mActiveProxy == aProxy) { + return; + } + SetIdle(mActiveProxy); + + mActiveProxy = aProxy; + mActiveCallback = aProxy->mCallback; + mConfig = aProxy->mConfig; +} + +void +SharedDecoderManager::SetIdle(MediaDataDecoder* aProxy) +{ + if (aProxy && mActiveProxy == aProxy) { + mWaitForInternalDrain = true; + mActiveProxy->Drain(); + MonitorAutoLock mon(mMonitor); + while (mWaitForInternalDrain) { + mon.Wait(); + } + mActiveProxy->Flush(); + mActiveProxy = nullptr; + } +} + +void +SharedDecoderManager::DrainComplete() +{ + if (mWaitForInternalDrain) { + MonitorAutoLock mon(mMonitor); + mWaitForInternalDrain = false; + mon.NotifyAll(); + } else { + mActiveCallback->DrainComplete(); + } +} + +SharedDecoderProxy::SharedDecoderProxy( + SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback, + const mp4_demuxer::VideoDecoderConfig& aConfig) + : mManager(aManager), mCallback(aCallback), mConfig(aConfig) +{ +} + +SharedDecoderProxy::~SharedDecoderProxy() { Shutdown(); } + +nsresult +SharedDecoderProxy::Init() +{ + return NS_OK; +} + +nsresult +SharedDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample) +{ + if (mManager->mActiveProxy != this) { + mManager->Select(this); + } + return mManager->mDecoder->Input(aSample); + return NS_OK; +} + +nsresult +SharedDecoderProxy::Flush() +{ + if (mManager->mActiveProxy == this) { + return mManager->mDecoder->Flush(); + } + return NS_OK; +} + +nsresult +SharedDecoderProxy::Drain() +{ + if (mManager->mActiveProxy == this) { + return mManager->mDecoder->Drain(); + } + return NS_OK; +} + +nsresult +SharedDecoderProxy::Shutdown() +{ + mManager->SetIdle(this); + return NS_OK; +} + +bool +SharedDecoderProxy::IsWaitingMediaResources() +{ + if (mManager->mActiveProxy == this) { + return mManager->mDecoder->IsWaitingMediaResources(); + } + return mManager->mActiveProxy != nullptr; +} + +bool +SharedDecoderProxy::IsDormantNeeded() +{ + return mManager->mDecoder->IsDormantNeeded(); +} + +void +SharedDecoderProxy::ReleaseMediaResources() +{ + if (mManager->mActiveProxy == this) { + mManager->mDecoder->ReleaseMediaResources(); + } +} + +void +SharedDecoderProxy::ReleaseDecoder() +{ + if (mManager->mActiveProxy == this) { + mManager->mDecoder->ReleaseMediaResources(); + } +} +} diff --git a/content/media/fmp4/SharedDecoderManager.h b/content/media/fmp4/SharedDecoderManager.h new file mode 100644 index 00000000000..3e30a56534d --- /dev/null +++ b/content/media/fmp4/SharedDecoderManager.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef SHARED_DECODER_MANAGER_H_ +#define SHARED_DECODER_MANAGER_H_ + +#include "PlatformDecoderModule.h" +#include "mozilla/Monitor.h" + +namespace mozilla +{ + +class MediaDataDecoder; +class SharedDecoderProxy; +class SharedDecoderCallback; + +class SharedDecoderManager +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedDecoderManager) + + SharedDecoderManager(); + + already_AddRefed CreateH264Decoder( + const mp4_demuxer::VideoDecoderConfig& aConfig, + layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer, MediaTaskQueue* aVideoTaskQueue, + MediaDataDecoderCallback* aCallback); + + void SetReader(MediaDecoderReader* aReader); + void Select(SharedDecoderProxy* aProxy); + void SetIdle(MediaDataDecoder* aProxy); + + friend class SharedDecoderProxy; + friend class SharedDecoderCallback; + +private: + virtual ~SharedDecoderManager(); + void DrainComplete(); + + mp4_demuxer::VideoDecoderConfig mConfig; + nsRefPtr mDecoder; + SharedDecoderProxy* mActiveProxy; + MediaDataDecoderCallback* mActiveCallback; + nsAutoPtr mCallback; + bool mWaitForInternalDrain; + Monitor mMonitor; +}; + +class SharedDecoderProxy : public MediaDataDecoder +{ +public: + SharedDecoderProxy(SharedDecoderManager* aManager, + MediaDataDecoderCallback* aCallback, + const mp4_demuxer::VideoDecoderConfig& aConfig); + virtual ~SharedDecoderProxy(); + + virtual nsresult Init() MOZ_OVERRIDE; + virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE; + virtual nsresult Flush() MOZ_OVERRIDE; + virtual nsresult Drain() MOZ_OVERRIDE; + virtual nsresult Shutdown() MOZ_OVERRIDE; + virtual bool IsWaitingMediaResources() MOZ_OVERRIDE; + virtual bool IsDormantNeeded() MOZ_OVERRIDE; + virtual void ReleaseMediaResources() MOZ_OVERRIDE; + virtual void ReleaseDecoder() MOZ_OVERRIDE; + + friend class SharedDecoderManager; + +private: + nsRefPtr mManager; + MediaDataDecoderCallback* mCallback; + const mp4_demuxer::VideoDecoderConfig& mConfig; +}; +} + +#endif diff --git a/content/media/fmp4/gonk/GonkVideoDecoderManager.cpp b/content/media/fmp4/gonk/GonkVideoDecoderManager.cpp index 6975f562ec1..7a83f4f2183 100644 --- a/content/media/fmp4/gonk/GonkVideoDecoderManager.cpp +++ b/content/media/fmp4/gonk/GonkVideoDecoderManager.cpp @@ -59,7 +59,7 @@ GonkVideoDecoderManager::GonkVideoDecoderManager( mVideoWidth = aConfig.display_width; mVideoHeight = aConfig.display_height; mDisplayWidth = aConfig.display_width; - mDisplayHeight = aConfig.display_width; + mDisplayHeight = aConfig.display_height; mInfo.mVideo.mHasVideo = true; nsIntSize displaySize(mDisplayWidth, mDisplayHeight); mInfo.mVideo.mDisplay = displaySize; diff --git a/content/media/fmp4/moz.build b/content/media/fmp4/moz.build index 1bb57e3899b..fc116d7f3ae 100644 --- a/content/media/fmp4/moz.build +++ b/content/media/fmp4/moz.build @@ -8,11 +8,13 @@ EXPORTS += [ 'MP4Decoder.h', 'MP4Reader.h', 'PlatformDecoderModule.h', + 'SharedDecoderManager.h', ] UNIFIED_SOURCES += [ 'BlankDecoderModule.cpp', 'PlatformDecoderModule.cpp', + 'SharedDecoderManager.cpp', ] SOURCES += [ diff --git a/content/media/mediasource/MediaSourceReader.cpp b/content/media/mediasource/MediaSourceReader.cpp index ba7aec16431..fa79a7e6321 100644 --- a/content/media/mediasource/MediaSourceReader.cpp +++ b/content/media/mediasource/MediaSourceReader.cpp @@ -14,6 +14,7 @@ #include "MediaSourceDecoder.h" #include "MediaSourceUtils.h" #include "SourceBufferDecoder.h" +#include "SharedDecoderManager.h" #ifdef MOZ_FMP4 #include "MP4Decoder.h" @@ -41,6 +42,7 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder) , mDropAudioBeforeThreshold(false) , mDropVideoBeforeThreshold(false) , mEnded(false) + , mSharedDecoderManager(new SharedDecoderManager()) { } @@ -354,6 +356,7 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType) // reader's callback. RefPtr> callback = new MediaDataDecodedListener(this, GetTaskQueue()); + reader->SetSharedDecoderManager(mSharedDecoderManager); reader->SetCallback(callback); reader->SetTaskQueue(GetTaskQueue()); reader->Init(nullptr); diff --git a/content/media/mediasource/MediaSourceReader.h b/content/media/mediasource/MediaSourceReader.h index ccaed724022..d7b0eba8671 100644 --- a/content/media/mediasource/MediaSourceReader.h +++ b/content/media/mediasource/MediaSourceReader.h @@ -116,6 +116,7 @@ private: nsRefPtr mVideoReader; bool mEnded; + nsRefPtr mSharedDecoderManager; }; } // namespace mozilla diff --git a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h index bca5c8a53bd..46c7b4177cd 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h +++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h @@ -113,6 +113,13 @@ class VideoDecoderConfig : public TrackConfig { public: VideoDecoderConfig() : display_width(0), display_height(0) {} + void operator=(const VideoDecoderConfig& aConfig) + { + display_width = aConfig.display_width; + display_height = aConfig.display_height; + extra_data.appendAll(aConfig.extra_data); + annex_b.appendAll(aConfig.annex_b); + } int32_t display_width; int32_t display_height;