From e2abc1a5235a2da3ae1abefface62ef09ec97108 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 27 Jan 2017 11:48:00 +0100 Subject: [PATCH] Bug 1319987: P7. Re-implement handling for WaitingForKey in MFR. r=cpearce,gerald MozReview-Commit-ID: FCiAO54oiH3 --HG-- extra : rebase_source : 898e175742ae4db13c48cf75463a9775968b0030 --- dom/media/MediaDecoderReader.h | 15 +++++++ dom/media/MediaFormatReader.cpp | 44 +++++++++++++++++-- dom/media/MediaFormatReader.h | 7 ++- dom/media/platforms/PlatformDecoderModule.h | 10 +++++ .../agnostic/eme/EMEDecoderModule.cpp | 39 +++++++++------- .../agnostic/eme/SamplesWaitingForKey.cpp | 10 ++++- .../agnostic/eme/SamplesWaitingForKey.h | 7 ++- .../platforms/wrappers/H264Converter.cpp | 6 ++- dom/media/platforms/wrappers/H264Converter.h | 2 + 9 files changed, 116 insertions(+), 24 deletions(-) diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index 6c4356e79c60..d224abb502d1 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -243,6 +243,18 @@ public: return mOnMediaNotSeekable; } + // Notified if the reader can't decode a sample due to a missing decryption + // key. + MediaEventSource& OnTrackWaitingForKey() + { + return mOnTrackWaitingForKey; + } + + MediaEventProducer& OnTrackWaitingForKeyProducer() + { + return mOnTrackWaitingForKey; + } + // Switch the video decoder to BlankDecoderModule. It might takes effective // since a few samples later depends on how much demuxed samples are already // queued in the original video decoder. @@ -306,6 +318,9 @@ protected: // Notify if this media is not seekable. MediaEventProducer mOnMediaNotSeekable; + // Notify if we are waiting for a decryption key. + MediaEventProducer mOnTrackWaitingForKey; + private: virtual nsresult InitInternal() { return NS_OK; } diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index ad0b2a5d5430..6528406bf41f 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -389,7 +389,9 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack) ownerData.mTaskQueue, mOwner->mCrashHelper, ownerData.mIsBlankDecode, - &result + &result, + aTrack, + &mOwner->OnTrackWaitingForKeyProducer() }); break; } @@ -406,7 +408,9 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack) mOwner->GetImageContainer(), mOwner->mCrashHelper, ownerData.mIsBlankDecode, - &result + &result, + aTrack, + &mOwner->OnTrackWaitingForKeyProducer() }); break; } @@ -847,6 +851,8 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, aDecoder->CompositorUpdatedEvent()->Connect( mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated); } + mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect( + mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey); } MediaFormatReader::~MediaFormatReader() @@ -895,6 +901,7 @@ MediaFormatReader::Shutdown() mDemuxer = nullptr; mCompositorUpdatedListener.DisconnectIfExists(); + mOnTrackWaitingForKeyListener.Disconnect(); RefPtr p = mShutdownPromise.Ensure(__func__); ShutdownPromise::All(OwnerThread(), promises) @@ -1523,6 +1530,21 @@ MediaFormatReader::NotifyWaitingForData(TrackType aTrack) ScheduleUpdate(aTrack); } +void +MediaFormatReader::NotifyWaitingForKey(TrackType aTrack) +{ + MOZ_ASSERT(OnTaskQueue()); + auto& decoder = GetDecoderData(aTrack); + if (mDecoder) { + mDecoder->NotifyWaitingForKey(); + } + if (!decoder.mDecodeRequest.Exists()) { + LOGV("WaitingForKey received while no pending decode. Ignoring"); + } + decoder.mWaitingForKey = true; + ScheduleUpdate(aTrack); +} + void MediaFormatReader::NotifyEndOfStream(TrackType aTrack) { @@ -2013,6 +2035,10 @@ MediaFormatReader::Update(TrackType aTrack) // EOS state. We can immediately reject the data promise. LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack)); decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); + } else if (decoder.mWaitingForKey) { + LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key", + TrackTypeToStr(aTrack)); + decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__); } } @@ -2054,13 +2080,23 @@ MediaFormatReader::Update(TrackType aTrack) decoder.mWaitingForData, decoder.HasPromise(), decoder.mLastStreamSourceID); - if ((decoder.mWaitingForData && - (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))) { + if ((decoder.mWaitingForData + && (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting)) + || (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) { // Nothing more we can do at present. LOGV("Still waiting for data or key."); return; } + if (decoder.mWaitingForKey) { + decoder.mWaitingForKey = false; + if (decoder.HasWaitingPromise() && !decoder.IsWaiting()) { + LOGV("No longer waiting for key. Resolving waiting promise"); + decoder.mWaitingPromise.Resolve(decoder.mType, __func__); + return; + } + } + if (!needInput) { LOGV("No need for additional input (pending:%u)", uint32_t(decoder.mOutput.Length())); diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index c85af13da692..b217edebb0ed 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -141,6 +141,7 @@ private: void NotifyDrainComplete(TrackType aTrack); void NotifyError(TrackType aTrack, const MediaResult& aError); void NotifyWaitingForData(TrackType aTrack); + void NotifyWaitingForKey(TrackType aTrack); void NotifyEndOfStream(TrackType aTrack); void ExtractCryptoInitData(nsTArray& aInitData); @@ -170,6 +171,7 @@ private: , mUpdateScheduled(false) , mDemuxEOS(false) , mWaitingForData(false) + , mWaitingForKey(false) , mReceivedNewData(false) , mNeedDraining(false) , mDraining(false) @@ -226,6 +228,7 @@ private: bool mUpdateScheduled; bool mDemuxEOS; bool mWaitingForData; + bool mWaitingForKey; bool mReceivedNewData; // Pending seek. @@ -245,7 +248,7 @@ private: bool IsWaiting() const { MOZ_ASSERT(mOwner->OnTaskQueue()); - return mWaitingForData; + return mWaitingForData || mWaitingForKey; } // MediaDataDecoder handler's variables. @@ -373,6 +376,7 @@ private: MOZ_ASSERT(mOwner->OnTaskQueue()); mDemuxEOS = false; mWaitingForData = false; + mWaitingForKey = false; mQueuedSamples.Clear(); mNeedDraining = false; mDecodeRequest.DisconnectIfExists(); @@ -560,6 +564,7 @@ private: UniquePtr mDecoderFactory; MediaEventListener mCompositorUpdatedListener; + MediaEventListener mOnTrackWaitingForKeyListener; void OnFirstDemuxCompleted(TrackInfo::TrackType aType, RefPtr aSamples); diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index e01e55088d81..ad5b5a1cb530 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -81,6 +81,8 @@ struct MOZ_STACK_CLASS CreateDecoderParams final RefPtr mKnowsCompositor; RefPtr mCrashHelper; bool mUseBlankDecoder = false; + TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack; + MediaEventProducer* mOnWaitingForKeyEvent = nullptr; private: void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; } @@ -99,6 +101,14 @@ private: { mKnowsCompositor = aKnowsCompositor; } + void Set(TrackInfo::TrackType aType) + { + mType = aType; + } + void Set(MediaEventProducer* aOnWaitingForKey) + { + mOnWaitingForKeyEvent = aOnWaitingForKey; + } template void Set(T1&& a1, T2&& a2, Ts&&... args) { diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp index 8fdb16685e95..36f0cf352eaa 100644 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp @@ -27,13 +27,14 @@ extern already_AddRefed CreateBlankDecoderModule(); class EMEDecryptor : public MediaDataDecoder { public: - EMEDecryptor(MediaDataDecoder* aDecoder, - CDMProxy* aProxy, - TaskQueue* aDecodeTaskQueue) + EMEDecryptor(MediaDataDecoder* aDecoder, CDMProxy* aProxy, + TaskQueue* aDecodeTaskQueue, TrackInfo::TrackType aType, + MediaEventProducer* aOnWaitingForKey) : mDecoder(aDecoder) , mTaskQueue(aDecodeTaskQueue) , mProxy(aProxy) - , mSamplesWaitingForKey(new SamplesWaitingForKey(mProxy)) + , mSamplesWaitingForKey( + new SamplesWaitingForKey(mProxy, aType, aOnWaitingForKey)) , mIsShutdown(false) { } @@ -204,12 +205,15 @@ private: class EMEMediaDataDecoderProxy : public MediaDataDecoderProxy { public: - EMEMediaDataDecoderProxy(already_AddRefed aProxyThread, - CDMProxy* aProxy) - : MediaDataDecoderProxy(Move(aProxyThread)) - , mTaskQueue(AbstractThread::GetCurrent()->AsTaskQueue()) - , mSamplesWaitingForKey(new SamplesWaitingForKey(aProxy)) - , mProxy(aProxy) + EMEMediaDataDecoderProxy( + already_AddRefed aProxyThread, CDMProxy* aProxy, + TrackInfo::TrackType aType, + MediaEventProducer* aOnWaitingForKey) + : MediaDataDecoderProxy(Move(aProxyThread)) + , mTaskQueue(AbstractThread::GetCurrent()->AsTaskQueue()) + , mSamplesWaitingForKey( + new SamplesWaitingForKey(aProxy, aType, aOnWaitingForKey)) + , mProxy(aProxy) { } @@ -289,7 +293,7 @@ EMEDecoderModule::~EMEDecoderModule() } static already_AddRefed -CreateDecoderWrapper(CDMProxy* aProxy) +CreateDecoderWrapper(CDMProxy* aProxy, const CreateDecoderParams& aParams) { RefPtr s(gmp::GeckoMediaPluginService::GetGeckoMediaPluginService()); if (!s) { @@ -299,8 +303,8 @@ CreateDecoderWrapper(CDMProxy* aProxy) if (!thread) { return nullptr; } - RefPtr decoder( - new EMEMediaDataDecoderProxy(thread.forget(), aProxy)); + RefPtr decoder(new EMEMediaDataDecoderProxy( + thread.forget(), aProxy, aParams.mType, aParams.mOnWaitingForKeyEvent)); return decoder.forget(); } @@ -317,7 +321,8 @@ EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) { // GMP decodes. Assume that means it can decrypt too. - RefPtr wrapper = CreateDecoderWrapper(mProxy); + RefPtr wrapper = + CreateDecoderWrapper(mProxy, aParams); auto params = GMPVideoDecoderParams(aParams); wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, params)); return wrapper.forget(); @@ -330,7 +335,8 @@ EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) } RefPtr emeDecoder(new EMEDecryptor( - decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue())); + decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue(), + aParams.mType, aParams.mOnWaitingForKeyEvent)); return emeDecoder.forget(); } @@ -355,7 +361,8 @@ EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams) } RefPtr emeDecoder(new EMEDecryptor( - decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue())); + decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue(), + aParams.mType, aParams.mOnWaitingForKeyEvent)); return emeDecoder.forget(); } diff --git a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp index c0fa9af954a4..e9dee73ea704 100644 --- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp +++ b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp @@ -8,13 +8,18 @@ #include "mozilla/CDMCaps.h" #include "mozilla/TaskQueue.h" #include "MediaData.h" +#include "MediaEventSource.h" #include "SamplesWaitingForKey.h" namespace mozilla { -SamplesWaitingForKey::SamplesWaitingForKey(CDMProxy* aProxy) +SamplesWaitingForKey::SamplesWaitingForKey( + CDMProxy* aProxy, TrackInfo::TrackType aType, + MediaEventProducer* aOnWaitingForKey) : mMutex("SamplesWaitingForKey") , mProxy(aProxy) + , mType(aType) + , mOnWaitingForKeyEvent(aOnWaitingForKey) { } @@ -41,6 +46,9 @@ SamplesWaitingForKey::WaitIfKeyNotUsable(MediaRawData* aSample) MutexAutoLock lock(mMutex); mSamples.AppendElement(Move(entry)); } + if (mOnWaitingForKeyEvent) { + mOnWaitingForKeyEvent->Notify(mType); + } caps.NotifyWhenKeyIdUsable(aSample->mCrypto.mKeyId, this); return p; } diff --git a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h index cc4a546b4b3d..accf7cf3d540 100644 --- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h +++ b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h @@ -10,12 +10,14 @@ #include "mozilla/MozPromise.h" #include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" +#include "MediaInfo.h" namespace mozilla { typedef nsTArray CencKeyId; class CDMProxy; +template class MediaEventProducer; class MediaRawData; // Encapsulates the task of waiting for the CDMProxy to have the necessary @@ -28,7 +30,8 @@ public: typedef MozPromise, bool, /* IsExclusive = */ true> WaitForKeyPromise; - explicit SamplesWaitingForKey(CDMProxy* aProxy); + SamplesWaitingForKey(CDMProxy* aProxy, TrackInfo::TrackType aType, + MediaEventProducer* aOnWaitingForKey); // Returns a promise that will be resolved if or when a key for decoding the // sample becomes usable. @@ -50,6 +53,8 @@ private: MozPromiseHolder mPromise; }; nsTArray mSamples; + const TrackInfo::TrackType mType; + MediaEventProducer* const mOnWaitingForKeyEvent; }; } // namespace mozilla diff --git a/dom/media/platforms/wrappers/H264Converter.cpp b/dom/media/platforms/wrappers/H264Converter.cpp index 06f534704074..d7c2ef569418 100644 --- a/dom/media/platforms/wrappers/H264Converter.cpp +++ b/dom/media/platforms/wrappers/H264Converter.cpp @@ -28,6 +28,8 @@ H264Converter::H264Converter(PlatformDecoderModule* aPDM, , mNeedAVCC(aPDM->DecoderNeedsConversion(aParams.mConfig) == PlatformDecoderModule::ConversionRequired::kNeedAVCC) , mLastError(NS_OK) + , mType(aParams.mType) + , mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent) { CreateDecoder(aParams.mDiagnostics); } @@ -194,7 +196,9 @@ H264Converter::CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics) aDiagnostics, mImageContainer, mKnowsCompositor, - mGMPCrashHelper + mGMPCrashHelper, + mType, + mOnWaitingForKeyEvent }); if (!mDecoder) { diff --git a/dom/media/platforms/wrappers/H264Converter.h b/dom/media/platforms/wrappers/H264Converter.h index 1d0a5f8f4534..2670ed046cb5 100644 --- a/dom/media/platforms/wrappers/H264Converter.h +++ b/dom/media/platforms/wrappers/H264Converter.h @@ -76,6 +76,8 @@ private: bool mNeedAVCC; nsresult mLastError; bool mNeedKeyframe = true; + const TrackInfo::TrackType mType; + MediaEventProducer* const mOnWaitingForKeyEvent; }; } // namespace mozilla