From f99988363e020a57252feaf88f138173a9631749 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Mon, 23 Mar 2015 07:59:42 +1300 Subject: [PATCH] Bug 1145405 - Add shutdown checks to main thread dispatches in ClearKey CDM - r=cpearce --- media/gmp-clearkey/0.1/AudioDecoder.cpp | 52 ++++++++++++++++++++++-- media/gmp-clearkey/0.1/AudioDecoder.h | 8 ++++ media/gmp-clearkey/0.1/VideoDecoder.cpp | 54 ++++++++++++++++++++++--- media/gmp-clearkey/0.1/VideoDecoder.h | 8 ++++ 4 files changed, 113 insertions(+), 9 deletions(-) diff --git a/media/gmp-clearkey/0.1/AudioDecoder.cpp b/media/gmp-clearkey/0.1/AudioDecoder.cpp index 4967a12cb718..9d6d0865a273 100644 --- a/media/gmp-clearkey/0.1/AudioDecoder.cpp +++ b/media/gmp-clearkey/0.1/AudioDecoder.cpp @@ -30,6 +30,7 @@ AudioDecoder::AudioDecoder(GMPAudioHost *aHostAPI) , mWorkerThread(nullptr) , mMutex(nullptr) , mNumInputTasks(0) + , mHasShutdown(false) { } @@ -118,7 +119,7 @@ AudioDecoder::DecodeTask(GMPAudioSamples* aInput) if (GMP_FAILED(rv)) { CK_LOGE("Failed to decrypt with key id %08x...", *(uint32_t*)crypto->KeyId()); - GetPlatform()->runonmainthread(WrapTask(mCallback, &GMPAudioDecoderCallback::Error, rv)); + MaybeRunOnMainThread(WrapTask(mCallback, &GMPAudioDecoderCallback::Error, rv)); return; } } @@ -150,7 +151,7 @@ AudioDecoder::DecodeTask(GMPAudioSamples* aInput) if (mNumInputTasks == 0) { // We have run all input tasks. We *must* notify Gecko so that it will // send us more data. - GetPlatform()->runonmainthread(WrapTask(mCallback, &GMPAudioDecoderCallback::InputDataExhausted)); + MaybeRunOnMainThread(WrapTask(mCallback, &GMPAudioDecoderCallback::InputDataExhausted)); } } else if (FAILED(hr)) { LOG("AudioDecoder::DecodeTask() output failed hr=0x%x\n", hr); @@ -181,7 +182,7 @@ AudioDecoder::ReturnOutput(IMFSample* aSample) } ENSURE(SUCCEEDED(hr), /*void*/); - GetPlatform()->runonmainthread(WrapTask(mCallback, &GMPAudioDecoderCallback::Decoded, samples)); + MaybeRunOnMainThread(WrapTask(mCallback, &GMPAudioDecoderCallback::Decoded, samples)); } HRESULT @@ -241,7 +242,7 @@ AudioDecoder::DrainTask() ReturnOutput(output); } } - GetPlatform()->runonmainthread(WrapTask(mCallback, &GMPAudioDecoderCallback::DrainComplete)); + MaybeRunOnMainThread(WrapTask(mCallback, &GMPAudioDecoderCallback::DrainComplete)); } void @@ -258,5 +259,48 @@ AudioDecoder::DecodingComplete() if (mWorkerThread) { mWorkerThread->Join(); } + mHasShutdown = true; + + // Worker thread might have dispatched more tasks to the main thread that need this object. + // Append another task to delete |this|. + GetPlatform()->runonmainthread(WrapTask(this, &AudioDecoder::Destroy)); +} + +void +AudioDecoder::Destroy() +{ delete this; } + +void +AudioDecoder::MaybeRunOnMainThread(gmp_task_args_base* aTask) +{ + class MaybeRunTask : public GMPTask + { + public: + MaybeRunTask(AudioDecoder* aDecoder, gmp_task_args_base* aTask) + : mDecoder(aDecoder), mTask(aTask) + { } + + virtual void Run(void) { + if (mDecoder->HasShutdown()) { + CK_LOGD("Trying to dispatch to main thread after AudioDecoder has shut down"); + return; + } + + mTask->Run(); + } + + virtual void Destroy() + { + mTask->Destroy(); + delete this; + } + + private: + AudioDecoder* mDecoder; + gmp_task_args_base* mTask; + }; + + GetPlatform()->runonmainthread(new MaybeRunTask(this, aTask)); +} diff --git a/media/gmp-clearkey/0.1/AudioDecoder.h b/media/gmp-clearkey/0.1/AudioDecoder.h index 4750ddad9816..4182d50fd66d 100644 --- a/media/gmp-clearkey/0.1/AudioDecoder.h +++ b/media/gmp-clearkey/0.1/AudioDecoder.h @@ -19,6 +19,7 @@ #include "gmp-audio-decode.h" #include "gmp-audio-host.h" +#include "gmp-task-utils.h" #include "WMFAACDecoder.h" #include "mfobjects.h" @@ -41,6 +42,8 @@ public: virtual void DecodingComplete() override; + bool HasShutdown() { return mHasShutdown; } + private: void EnsureWorker(); @@ -53,6 +56,9 @@ private: HRESULT MFToGMPSample(IMFSample* aSample, GMPAudioSamples* aAudioFrame); + void MaybeRunOnMainThread(gmp_task_args_base* aTask); + void Destroy(); + GMPAudioHost *mHostAPI; // host-owned, invalid at DecodingComplete GMPAudioDecoderCallback* mCallback; // host-owned, invalid at DecodingComplete GMPThread* mWorkerThread; @@ -60,6 +66,8 @@ private: wmf::AutoPtr mDecoder; int32_t mNumInputTasks; + + bool mHasShutdown; }; #endif // __AudioDecoder_h__ diff --git a/media/gmp-clearkey/0.1/VideoDecoder.cpp b/media/gmp-clearkey/0.1/VideoDecoder.cpp index 26742e477f43..d1393a7aded8 100644 --- a/media/gmp-clearkey/0.1/VideoDecoder.cpp +++ b/media/gmp-clearkey/0.1/VideoDecoder.cpp @@ -34,6 +34,7 @@ VideoDecoder::VideoDecoder(GMPVideoHost *aHostAPI) , mMutex(nullptr) , mNumInputTasks(0) , mSentExtraData(false) + , mHasShutdown(false) { } @@ -160,7 +161,7 @@ VideoDecoder::DecodeTask(GMPVideoEncodedFrame* aInput) ClearKeyDecryptionManager::Get()->Decrypt(&buffer[0], buffer.size(), crypto); if (GMP_FAILED(rv)) { - GetPlatform()->runonmainthread(WrapTask(mCallback, &GMPVideoDecoderCallback::Error, rv)); + MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::Error, rv)); return; } } @@ -192,7 +193,7 @@ VideoDecoder::DecodeTask(GMPVideoEncodedFrame* aInput) hr = mDecoder->Output(&output); CK_LOGD("VideoDecoder::DecodeTask() output ret=0x%x\n", hr); if (hr == S_OK) { - GetPlatform()->runonmainthread( + MaybeRunOnMainThread( WrapTask(this, &VideoDecoder::ReturnOutput, CComPtr(mozilla::Move(output)), @@ -206,7 +207,7 @@ VideoDecoder::DecodeTask(GMPVideoEncodedFrame* aInput) if (mNumInputTasks == 0) { // We have run all input tasks. We *must* notify Gecko so that it will // send us more data. - GetPlatform()->runonmainthread( + MaybeRunOnMainThread( WrapTask(mCallback, &GMPVideoDecoderCallback::InputDataExhausted)); } @@ -347,7 +348,7 @@ VideoDecoder::DrainTask() hr = mDecoder->Output(&output); CK_LOGD("VideoDecoder::DrainTask() output ret=0x%x\n", hr); if (hr == S_OK) { - GetPlatform()->runonmainthread( + MaybeRunOnMainThread( WrapTask(this, &VideoDecoder::ReturnOutput, CComPtr(mozilla::Move(output)), @@ -357,7 +358,7 @@ VideoDecoder::DrainTask() assert(!output.Get()); } } - GetPlatform()->runonmainthread(WrapTask(mCallback, &GMPVideoDecoderCallback::DrainComplete)); + MaybeRunOnMainThread(WrapTask(mCallback, &GMPVideoDecoderCallback::DrainComplete)); } void @@ -374,5 +375,48 @@ VideoDecoder::DecodingComplete() if (mWorkerThread) { mWorkerThread->Join(); } + mHasShutdown = true; + + // Worker thread might have dispatched more tasks to the main thread that need this object. + // Append another task to delete |this|. + GetPlatform()->runonmainthread(WrapTask(this, &VideoDecoder::Destroy)); +} + +void +VideoDecoder::Destroy() +{ delete this; } + +void +VideoDecoder::MaybeRunOnMainThread(gmp_task_args_base* aTask) +{ + class MaybeRunTask : public GMPTask + { + public: + MaybeRunTask(VideoDecoder* aDecoder, gmp_task_args_base* aTask) + : mDecoder(aDecoder), mTask(aTask) + { } + + virtual void Run(void) { + if (mDecoder->HasShutdown()) { + CK_LOGD("Trying to dispatch to main thread after VideoDecoder has shut down"); + return; + } + + mTask->Run(); + } + + virtual void Destroy() + { + mTask->Destroy(); + delete this; + } + + private: + VideoDecoder* mDecoder; + gmp_task_args_base* mTask; + }; + + GetPlatform()->runonmainthread(new MaybeRunTask(this, aTask)); +} diff --git a/media/gmp-clearkey/0.1/VideoDecoder.h b/media/gmp-clearkey/0.1/VideoDecoder.h index 8baf66a91fb2..e96dca527758 100644 --- a/media/gmp-clearkey/0.1/VideoDecoder.h +++ b/media/gmp-clearkey/0.1/VideoDecoder.h @@ -17,6 +17,7 @@ #ifndef __VideoDecoder_h__ #define __VideoDecoder_h__ +#include "gmp-task-utils.h" #include "gmp-video-decode.h" #include "gmp-video-host.h" #include "WMFH264Decoder.h" @@ -48,6 +49,8 @@ public: virtual void DecodingComplete() override; + bool HasShutdown() { return mHasShutdown; } + private: void EnsureWorker(); @@ -67,6 +70,9 @@ private: int32_t aStride, GMPVideoi420Frame* aVideoFrame); + void MaybeRunOnMainThread(gmp_task_args_base* aTask); + void Destroy(); + GMPVideoHost *mHostAPI; // host-owned, invalid at DecodingComplete GMPVideoDecoderCallback* mCallback; // host-owned, invalid at DecodingComplete GMPThread* mWorkerThread; @@ -78,6 +84,8 @@ private: int32_t mNumInputTasks; bool mSentExtraData; + + bool mHasShutdown; }; #endif // __VideoDecoder_h__