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 0ddab5705a
commit 98295b4b3a
8 changed files with 122 additions and 17 deletions

View File

@ -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
}

View File

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

View File

@ -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<MediaDataDecoder>
SharedDecoderManager::CreateVideoDecoder(
PlatformDecoderModule* aPDM,
const mp4_demuxer::VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend, layers::ImageContainer* aImageContainer,
MediaTaskQueue* aVideoTaskQueue, MediaDataDecoderCallback* aCallback)
{
if (!mDecoder) {
nsRefPtr<PlatformDecoderModule> 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();
}
}

View File

@ -25,6 +25,7 @@ public:
SharedDecoderManager();
already_AddRefed<MediaDataDecoder> 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<MediaDataDecoder> mDecoder;
nsRefPtr<MediaTaskQueue> mTaskQueue;
SharedDecoderProxy* mActiveProxy;
MediaDataDecoderCallback* mActiveCallback;
nsAutoPtr<MediaDataDecoderCallback> mCallback;
bool mWaitForInternalDrain;
Monitor mMonitor;
bool mDecoderReleasedResources;
};
class SharedDecoderProxy : public MediaDataDecoder

View File

@ -48,7 +48,13 @@ WMFMediaDataDecoder::Init()
nsresult
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;
}
@ -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<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

View File

@ -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<MediaTaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;

View File

@ -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

View File

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