Bug 1123535 - Make MP4Reader and WMFMediaDataDecoder support going dormant. r=kentuckyfriedtakahe

This commit is contained in:
Chris Pearce 2015-01-29 21:50:48 +13:00
parent 6a682696a6
commit df4bec5ff7
8 changed files with 122 additions and 17 deletions

View File

@ -117,6 +117,9 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
, mIsEncrypted(false) , mIsEncrypted(false)
, mIndexReady(false) , mIndexReady(false)
, mDemuxerMonitor("MP4 Demuxer") , 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_ASSERT(NS_IsMainThread(), "Must be on main thread.");
MOZ_COUNT_CTOR(MP4Reader); MOZ_COUNT_CTOR(MP4Reader);
@ -252,15 +255,15 @@ private:
#endif #endif
void MP4Reader::RequestCodecResource() { void MP4Reader::RequestCodecResource() {
#ifdef MOZ_GONK_MEDIACODEC #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
if(mVideo.mDecoder) { if (mVideo.mDecoder) {
mVideo.mDecoder->AllocateMediaResources(); mVideo.mDecoder->AllocateMediaResources();
} }
#endif #endif
} }
bool MP4Reader::IsWaitingOnCodecResource() { bool MP4Reader::IsWaitingOnCodecResource() {
#ifdef MOZ_GONK_MEDIACODEC #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources(); return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
#endif #endif
return false; return false;
@ -446,7 +449,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
mVideo.mCallback = new DecoderCallback(this, kVideo); mVideo.mCallback = new DecoderCallback(this, kVideo);
if (mSharedDecoderManager) { if (mSharedDecoderManager) {
mVideo.mDecoder = mVideo.mDecoder =
mSharedDecoderManager->CreateVideoDecoder(video, mSharedDecoderManager->CreateVideoDecoder(mPlatform,
video,
mLayersBackendType, mLayersBackendType,
mDecoder->GetImageContainer(), mDecoder->GetImageContainer(),
mVideo.mTaskQueue, mVideo.mTaskQueue,
@ -1001,15 +1005,20 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered)
bool MP4Reader::IsDormantNeeded() bool MP4Reader::IsDormantNeeded()
{ {
#ifdef MOZ_GONK_MEDIACODEC #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
return mVideo.mDecoder && mVideo.mDecoder->IsDormantNeeded(); return
#if defined(XP_WIN)
mDormantEnabled &&
#endif
mVideo.mDecoder &&
mVideo.mDecoder->IsDormantNeeded();
#endif #endif
return false; return false;
} }
void MP4Reader::ReleaseMediaResources() 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 // Before freeing a video codec, all video buffers needed to be released
// even from graphics pipeline. // even from graphics pipeline.
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
@ -1024,7 +1033,7 @@ void MP4Reader::ReleaseMediaResources()
void MP4Reader::NotifyResourcesStatusChanged() void MP4Reader::NotifyResourcesStatusChanged()
{ {
#ifdef MOZ_GONK_MEDIACODEC #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
if (mDecoder) { if (mDecoder) {
mDecoder->NotifyWaitingForResourcesStatusChanged(); mDecoder->NotifyWaitingForResourcesStatusChanged();
} }
@ -1043,7 +1052,7 @@ MP4Reader::SetIdle()
void void
MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager) MP4Reader::SetSharedDecoderManager(SharedDecoderManager* aManager)
{ {
#ifdef MOZ_GONK_MEDIACODEC #if defined(MOZ_GONK_MEDIACODEC) || defined(XP_WIN)
mSharedDecoderManager = aManager; mSharedDecoderManager = aManager;
#endif #endif
} }

View File

@ -267,6 +267,10 @@ private:
bool mIndexReady; bool mIndexReady;
Monitor mDemuxerMonitor; Monitor mDemuxerMonitor;
nsRefPtr<SharedDecoderManager> mSharedDecoderManager; nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
#if defined(XP_WIN)
const bool mDormantEnabled;
#endif
}; };
} // namespace mozilla } // namespace mozilla

View File

@ -55,11 +55,14 @@ public:
}; };
SharedDecoderManager::SharedDecoderManager() SharedDecoderManager::SharedDecoderManager()
: mActiveProxy(nullptr) : mTaskQueue(new MediaTaskQueue(GetMediaDecodeThreadPool()))
, mActiveProxy(nullptr)
, mActiveCallback(nullptr) , mActiveCallback(nullptr)
, mWaitForInternalDrain(false) , mWaitForInternalDrain(false)
, mMonitor("SharedDecoderProxy") , mMonitor("SharedDecoderProxy")
, mDecoderReleasedResources(false)
{ {
MOZ_ASSERT(NS_IsMainThread()); // taskqueue must be created on main thread.
mCallback = new SharedDecoderCallback(this); mCallback = new SharedDecoderCallback(this);
} }
@ -67,14 +70,18 @@ SharedDecoderManager::~SharedDecoderManager() {}
already_AddRefed<MediaDataDecoder> already_AddRefed<MediaDataDecoder>
SharedDecoderManager::CreateVideoDecoder( SharedDecoderManager::CreateVideoDecoder(
PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig, const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer, layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer,
MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback) MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
{ {
if (!mDecoder) { if (!mDecoder) {
nsRefPtr<PlatformDecoderModule> platform(PlatformDecoderModule::Create()); // We use the manager's task queue for the decoder, rather than the one
mDecoder = platform->CreateVideoDecoder( // passed in, so that none of the objects sharing the decoder can shutdown
aConfig, aLayersBackend, aImageContainer, aVideoTaskQueue, mCallback); // 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) { if (!mDecoder) {
return nullptr; return nullptr;
} }
@ -96,6 +103,11 @@ SharedDecoderManager::Select(SharedDecoderProxy* aProxy)
mActiveProxy = aProxy; mActiveProxy = aProxy;
mActiveCallback = aProxy->mCallback; mActiveCallback = aProxy->mCallback;
if (mDecoderReleasedResources) {
mDecoder->AllocateMediaResources();
mDecoderReleasedResources = false;
}
} }
void 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( SharedDecoderProxy::SharedDecoderProxy(
SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback) SharedDecoderManager* aManager, MediaDataDecoderCallback* aCallback)
: mManager(aManager), mCallback(aCallback) : mManager(aManager), mCallback(aCallback)
@ -146,7 +180,6 @@ SharedDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
mManager->Select(this); mManager->Select(this);
} }
return mManager->mDecoder->Input(aSample); return mManager->mDecoder->Input(aSample);
return NS_OK;
} }
nsresult nsresult
@ -193,7 +226,7 @@ void
SharedDecoderProxy::ReleaseMediaResources() SharedDecoderProxy::ReleaseMediaResources()
{ {
if (mManager->mActiveProxy == this) { if (mManager->mActiveProxy == this) {
mManager->mDecoder->ReleaseMediaResources(); mManager->ReleaseMediaResources();
} }
} }

View File

@ -25,6 +25,7 @@ public:
SharedDecoderManager(); SharedDecoderManager();
already_AddRefed<MediaDataDecoder> CreateVideoDecoder( already_AddRefed<MediaDataDecoder> CreateVideoDecoder(
PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig, const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer, MediaTaskQueue* aVideoTaskQueue, layers::ImageContainer* aImageContainer, MediaTaskQueue* aVideoTaskQueue,
@ -33,6 +34,8 @@ public:
void SetReader(MediaDecoderReader* aReader); void SetReader(MediaDecoderReader* aReader);
void Select(SharedDecoderProxy* aProxy); void Select(SharedDecoderProxy* aProxy);
void SetIdle(MediaDataDecoder* aProxy); void SetIdle(MediaDataDecoder* aProxy);
void ReleaseMediaResources();
void Shutdown();
friend class SharedDecoderProxy; friend class SharedDecoderProxy;
friend class SharedDecoderCallback; friend class SharedDecoderCallback;
@ -42,11 +45,13 @@ private:
void DrainComplete(); void DrainComplete();
nsRefPtr<MediaDataDecoder> mDecoder; nsRefPtr<MediaDataDecoder> mDecoder;
nsRefPtr<MediaTaskQueue> mTaskQueue;
SharedDecoderProxy* mActiveProxy; SharedDecoderProxy* mActiveProxy;
MediaDataDecoderCallback* mActiveCallback; MediaDataDecoderCallback* mActiveCallback;
nsAutoPtr<MediaDataDecoderCallback> mCallback; nsAutoPtr<MediaDataDecoderCallback> mCallback;
bool mWaitForInternalDrain; bool mWaitForInternalDrain;
Monitor mMonitor; Monitor mMonitor;
bool mDecoderReleasedResources;
}; };
class SharedDecoderProxy : public MediaDataDecoder class SharedDecoderProxy : public MediaDataDecoder

View File

@ -48,7 +48,13 @@ WMFMediaDataDecoder::Init()
nsresult nsresult
WMFMediaDataDecoder::Shutdown() WMFMediaDataDecoder::Shutdown()
{ {
mTaskQueue->FlushAndDispatch(NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown)); DebugOnly<nsresult> 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; return NS_OK;
} }
@ -60,6 +66,13 @@ WMFMediaDataDecoder::ProcessShutdown()
mDecoder = nullptr; mDecoder = nullptr;
} }
void
WMFMediaDataDecoder::ProcessReleaseDecoder()
{
mMFTManager->Shutdown();
mDecoder = nullptr;
}
// Inserts data into the decoder's pipeline. // Inserts data into the decoder's pipeline.
nsresult nsresult
WMFMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample) WMFMediaDataDecoder::Input(mp4_demuxer::MP4Sample* aSample)
@ -142,4 +155,28 @@ WMFMediaDataDecoder::Drain()
return NS_OK; return NS_OK;
} }
void
WMFMediaDataDecoder::AllocateMediaResources()
{
mDecoder = mMFTManager->Init();
}
void
WMFMediaDataDecoder::ReleaseMediaResources()
{
DebugOnly<nsresult> 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 } // namespace mozilla

View File

@ -70,6 +70,12 @@ public:
virtual nsresult Shutdown() MOZ_OVERRIDE; 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: private:
// Called on the task queue. Inserts the sample into the decoder, and // Called on the task queue. Inserts the sample into the decoder, and
@ -85,6 +91,7 @@ private:
void ProcessDrain(); void ProcessDrain();
void ProcessShutdown(); void ProcessShutdown();
void ProcessReleaseDecoder();
RefPtr<MediaTaskQueue> mTaskQueue; RefPtr<MediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback; MediaDataDecoderCallback* mCallback;

View File

@ -100,7 +100,9 @@ WMFVideoMFTManager::~WMFVideoMFTManager()
{ {
MOZ_COUNT_DTOR(WMFVideoMFTManager); MOZ_COUNT_DTOR(WMFVideoMFTManager);
// Ensure DXVA/D3D9 related objects are released on the main thread. // Ensure DXVA/D3D9 related objects are released on the main thread.
DeleteOnMainThread(mDXVA2Manager); if (mDXVA2Manager) {
DeleteOnMainThread(mDXVA2Manager);
}
} }
const GUID& const GUID&
@ -140,6 +142,8 @@ public:
bool bool
WMFVideoMFTManager::InitializeDXVA() WMFVideoMFTManager::InitializeDXVA()
{ {
MOZ_ASSERT(!mDXVA2Manager);
// If we use DXVA but aren't running with a D3D layer manager then the // 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 // readback of decoded video frames from GPU to CPU memory grinds painting
// to a halt, and makes playback performance *worse*. // to a halt, and makes playback performance *worse*.
@ -488,6 +492,7 @@ void
WMFVideoMFTManager::Shutdown() WMFVideoMFTManager::Shutdown()
{ {
mDecoder = nullptr; mDecoder = nullptr;
DeleteOnMainThread(mDXVA2Manager);
} }
} // namespace mozilla } // namespace mozilla

View File

@ -411,6 +411,11 @@ MediaSourceReader::ContinueShutdown()
mVideoTrack = nullptr; mVideoTrack = nullptr;
mVideoReader = nullptr; mVideoReader = nullptr;
if (mSharedDecoderManager) {
mSharedDecoderManager->Shutdown();
mSharedDecoderManager = nullptr;
}
MOZ_ASSERT(mAudioPromise.IsEmpty()); MOZ_ASSERT(mAudioPromise.IsEmpty());
MOZ_ASSERT(mVideoPromise.IsEmpty()); MOZ_ASSERT(mVideoPromise.IsEmpty());