diff --git a/dom/media/fmp4/MP4Reader.cpp b/dom/media/fmp4/MP4Reader.cpp index a197f0a6ef6..c7237498303 100644 --- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -117,6 +117,9 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder) , mIsEncrypted(false) , mIndexReady(false) , mDemuxerMonitor("MP4 Demuxer") +#if defined(XP_WIN) + , mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)) +#endif { MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); MOZ_COUNT_CTOR(MP4Reader); @@ -252,15 +255,15 @@ private: #endif void MP4Reader::RequestCodecResource() { -#ifdef MOZ_GONK_MEDIACODEC - if(mVideo.mDecoder) { +#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) + if (mVideo.mDecoder) { mVideo.mDecoder->AllocateMediaResources(); } #endif } bool MP4Reader::IsWaitingOnCodecResource() { -#ifdef MOZ_GONK_MEDIACODEC +#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources(); #endif return false; @@ -446,7 +449,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo, mVideo.mCallback = new DecoderCallback(this, kVideo); if (mSharedDecoderManager) { mVideo.mDecoder = - mSharedDecoderManager->CreateVideoDecoder(video, + mSharedDecoderManager->CreateVideoDecoder(mPlatform, + video, mLayersBackendType, mDecoder->GetImageContainer(), mVideo.mTaskQueue, @@ -1001,15 +1005,20 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered) bool MP4Reader::IsDormantNeeded() { -#ifdef MOZ_GONK_MEDIACODEC - return mVideo.mDecoder && mVideo.mDecoder->IsDormantNeeded(); +#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) + return +#if defined(XP_WIN) + mDormantEnabled && +#endif + mVideo.mDecoder && + mVideo.mDecoder->IsDormantNeeded(); #endif return false; } void MP4Reader::ReleaseMediaResources() { -#ifdef MOZ_GONK_MEDIACODEC +#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) // Before freeing a video codec, all video buffers needed to be released // even from graphics pipeline. VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); @@ -1024,7 +1033,7 @@ void MP4Reader::ReleaseMediaResources() void MP4Reader::NotifyResourcesStatusChanged() { -#ifdef MOZ_GONK_MEDIACODEC +#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) if (mDecoder) { mDecoder->NotifyWaitingForResourcesStatusChanged(); } @@ -1043,7 +1052,7 @@ MP4Reader::SetIdle() void MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager) { -#ifdef MOZ_GONK_MEDIACODEC +#if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN) mSharedDecoderManager = aManager; #endif } diff --git a/dom/media/fmp4/MP4Reader.h b/dom/media/fmp4/MP4Reader.h index 626988aaa77..d1890f264c0 100644 --- a/dom/media/fmp4/MP4Reader.h +++ b/dom/media/fmp4/MP4Reader.h @@ -267,6 +267,10 @@ private: bool mIndexReady; Monitor mDemuxerMonitor; nsRefPtr mSharedDecoderManager; + +#if defined(XP_WIN) + const bool mDormantEnabled; +#endif }; } // namespace mozilla diff --git a/dom/media/fmp4/SharedDecoderManager.cpp b/dom/media/fmp4/SharedDecoderManager.cpp index 0891dd7747e..915fb11ff32 100644 --- a/dom/media/fmp4/SharedDecoderManager.cpp +++ b/dom/media/fmp4/SharedDecoderManager.cpp @@ -55,11 +55,14 @@ public: }; SharedDecoderManager::SharedDecoderManager() - : mActiveProxy(nullptr) + : mTaskQueue(new MediaTaskQueue(GetMediaDecodeThreadPool())) + , mActiveProxy(nullptr) , mActiveCallback(nullptr) , mWaitForInternalDrain(false) , mMonitor("SharedDecoderProxy") + , mDecoderReleasedResources(false) { + MOZ_ASSERT(NS_IsMainThread()); // taskqueue must be created on main thread. mCallback = new SharedDecoderCallback(this); } @@ -67,14 +70,18 @@ SharedDecoderManager::~SharedDecoderManager() {} already_AddRefed SharedDecoderManager::CreateVideoDecoder( + PlatformDecoderModule* aPDM, const mp4_demuxer::VideoDecoderConfig& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) { if (!mDecoder) { - nsRefPtr platform(PlatformDecoderModule::Create()); - mDecoder = platform->CreateVideoDecoder( - aConfig, aLayersBackend, aImageContainer, aVideoTaskQueue, mCallback); + // We use the manager's task queue for the decoder, rather than the one + // passed in, so that none of the objects sharing the decoder can shutdown + // the task queue while we're potentially still using it for a *different* + // object also sharing the decoder. + mDecoder = aPDM->CreateVideoDecoder( + aConfig, aLayersBackend, aImageContainer, mTaskQueue, mCallback); if (!mDecoder) { return nullptr; } @@ -96,6 +103,11 @@ SharedDecoderManager::Select(SharedDecoderProxy* aProxy) mActiveProxy = aProxy; mActiveCallback = aProxy->mCallback; + + if (mDecoderReleasedResources) { + mDecoder->AllocateMediaResources(); + mDecoderReleasedResources = false; + } } void @@ -125,6 +137,28 @@ SharedDecoderManager::DrainComplete() } } +void +SharedDecoderManager::ReleaseMediaResources() +{ + mDecoderReleasedResources = true; + mDecoder->ReleaseMediaResources(); + mActiveProxy = nullptr; +} + +void +SharedDecoderManager::Shutdown() +{ + if (mDecoder) { + mDecoder->Shutdown(); + mDecoder = nullptr; + } + if (mTaskQueue) { + mTaskQueue->BeginShutdown(); + mTaskQueue->AwaitShutdownAndIdle(); + mTaskQueue = nullptr; + } +} + SharedDecoderProxy::SharedDecoderProxy( SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback) : mManager(aManager), mCallback(aCallback) @@ -146,7 +180,6 @@ SharedDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample) mManager->Select(this); } return mManager->mDecoder->Input(aSample); - return NS_OK; } nsresult @@ -193,7 +226,7 @@ void SharedDecoderProxy::ReleaseMediaResources() { if (mManager->mActiveProxy == this) { - mManager->mDecoder->ReleaseMediaResources(); + mManager->ReleaseMediaResources(); } } diff --git a/dom/media/fmp4/SharedDecoderManager.h b/dom/media/fmp4/SharedDecoderManager.h index 0835cc41fbe..0acd7ee8fff 100644 --- a/dom/media/fmp4/SharedDecoderManager.h +++ b/dom/media/fmp4/SharedDecoderManager.h @@ -25,6 +25,7 @@ public: SharedDecoderManager(); already_AddRefed CreateVideoDecoder( + PlatformDecoderModule* aPDM, const mp4_demuxer::VideoDecoderConfig& aConfig, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, MediaTaskQueue* aVideoTaskQueue, @@ -33,6 +34,8 @@ public: void SetReader(MediaDecoderReader* aReader); void Select(SharedDecoderProxy* aProxy); void SetIdle(MediaDataDecoder* aProxy); + void ReleaseMediaResources(); + void Shutdown(); friend class SharedDecoderProxy; friend class SharedDecoderCallback; @@ -42,11 +45,13 @@ private: void DrainComplete(); nsRefPtr mDecoder; + nsRefPtr mTaskQueue; SharedDecoderProxy* mActiveProxy; MediaDataDecoderCallback* mActiveCallback; nsAutoPtr mCallback; bool mWaitForInternalDrain; Monitor mMonitor; + bool mDecoderReleasedResources; }; class SharedDecoderProxy : public MediaDataDecoder diff --git a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp index 2f6bb23ebc0..eb0dcafdd95 100644 --- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp +++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.cpp @@ -48,7 +48,13 @@ WMFMediaDataDecoder::Init() nsresult WMFMediaDataDecoder::Shutdown() { - mTaskQueue->FlushAndDispatch(NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown)); + DebugOnly rv = mTaskQueue->FlushAndDispatch( + NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown)); +#ifdef DEBUG + if (NS_FAILED(rv)) { + NS_WARNING("WMFMediaDataDecoder::Shutdown() dispatch of task failed!"); + } +#endif return NS_OK; } @@ -60,6 +66,13 @@ WMFMediaDataDecoder::ProcessShutdown() mDecoder = nullptr; } +void +WMFMediaDataDecoder::ProcessReleaseDecoder() +{ + mMFTManager->Shutdown(); + mDecoder = nullptr; +} + // Inserts data into the decoder's pipeline. nsresult WMFMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) @@ -142,4 +155,28 @@ WMFMediaDataDecoder::Drain() return NS_OK; } +void +WMFMediaDataDecoder::AllocateMediaResources() +{ + mDecoder = mMFTManager->Init(); +} + +void +WMFMediaDataDecoder::ReleaseMediaResources() +{ + DebugOnly rv = mTaskQueue->FlushAndDispatch( + NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessReleaseDecoder)); +#ifdef DEBUG + if (NS_FAILED(rv)) { + NS_WARNING("WMFMediaDataDecoder::ReleaseMediaResources() dispatch of task failed!"); + } +#endif +} + +void +WMFMediaDataDecoder::ReleaseDecoder() +{ + ReleaseMediaResources(); +} + } // namespace mozilla diff --git a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h index 16f4ee857d2..351ce144685 100644 --- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h +++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h @@ -70,6 +70,12 @@ public: virtual nsresult Shutdown() MOZ_OVERRIDE; + virtual bool IsWaitingMediaResources() { return false; }; + virtual bool IsDormantNeeded() { return true; }; + virtual void AllocateMediaResources() MOZ_OVERRIDE; + virtual void ReleaseMediaResources() MOZ_OVERRIDE; + virtual void ReleaseDecoder() MOZ_OVERRIDE; + private: // Called on the task queue. Inserts the sample into the decoder, and @@ -85,6 +91,7 @@ private: void ProcessDrain(); void ProcessShutdown(); + void ProcessReleaseDecoder(); RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; diff --git a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp index e8aef60b5f4..dbd07f2bbe3 100644 --- a/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/fmp4/wmf/WMFVideoMFTManager.cpp @@ -100,7 +100,9 @@ WMFVideoMFTManager::~WMFVideoMFTManager() { MOZ_COUNT_DTOR(WMFVideoMFTManager); // Ensure DXVA/D3D9 related objects are released on the main thread. - DeleteOnMainThread(mDXVA2Manager); + if (mDXVA2Manager) { + DeleteOnMainThread(mDXVA2Manager); + } } const GUID& @@ -140,6 +142,8 @@ public: bool WMFVideoMFTManager::InitializeDXVA() { + MOZ_ASSERT(!mDXVA2Manager); + // If we use DXVA but aren't running with a D3D layer manager then the // readback of decoded video frames from GPU to CPU memory grinds painting // to a halt, and makes playback performance *worse*. @@ -488,6 +492,7 @@ void WMFVideoMFTManager::Shutdown() { mDecoder = nullptr; + DeleteOnMainThread(mDXVA2Manager); } } // namespace mozilla diff --git a/dom/media/mediasource/MediaSourceReader.cpp b/dom/media/mediasource/MediaSourceReader.cpp index fb889b581a3..9b6cff6e8fe 100644 --- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -411,6 +411,11 @@ MediaSourceReader::ContinueShutdown() mVideoTrack = nullptr; mVideoReader = nullptr; + if (mSharedDecoderManager) { + mSharedDecoderManager->Shutdown(); + mSharedDecoderManager = nullptr; + } + MOZ_ASSERT(mAudioPromise.IsEmpty()); MOZ_ASSERT(mVideoPromise.IsEmpty());