Bug 1454630 - P2. Use new PDMFactory whenever encryption type change. r?bryce, r?cpearce draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sun, 27 May 2018 18:42:25 +0200
changeset 800554 3921cd4b0d05484247b19341b5eeb13e7a073e7f
parent 800368 232cc8ccc04486b2a8b9f0bbdb12b6719ac430e7
child 800555 4cf3d9f1f1a4e3213db50b0e8d6454d4783d0141
push id111396
push userbmo:jyavenard@mozilla.com
push dateMon, 28 May 2018 13:31:40 +0000
reviewersbryce, cpearce
bugs1454630
milestone62.0a1
Bug 1454630 - P2. Use new PDMFactory whenever encryption type change. r?bryce, r?cpearce If the content being played was first non-encrypted, the PDMFactory would have been set without a CDMProxy. As such, it is necessary to use a new PDMFactory when the encryption type changes (from clear to encrypted). Rather than attempting to detect if the encryption status has changed, simply use two PDMFactory, one with CDMProxy set and one without (for clear content) Also, never attempt to recycle a decoder if the encryption type changed (used only on Android) The TrackBuffersManager would have already handle the dispatching of the encrypted event when parsing the new init segment. As such, nothing more is necessary. MozReview-Commit-ID: Jn14P2F6N5V
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -796,49 +796,52 @@ MediaFormatReader::DecoderFactory::RunSt
     }
   }
 }
 
 MediaResult
 MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData)
 {
   auto& ownerData = aData.mOwnerData;
-
-  if (!mOwner->mPlatform) {
-    mOwner->mPlatform = new PDMFactory();
-    if (mOwner->IsEncrypted()) {
+  auto& decoder = mOwner->GetDecoderData(aData.mTrack);
+  auto& platform =
+    decoder.IsEncrypted() ? mOwner->mEncryptedPlatform : mOwner->mPlatform;
+
+  if (!platform) {
+    platform = new PDMFactory();
+    if (decoder.IsEncrypted()) {
       MOZ_ASSERT(mOwner->mCDMProxy);
-      mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy);
+      platform->SetCDMProxy(mOwner->mCDMProxy);
     }
   }
 
   // result may not be updated by PDMFactory::CreateDecoder, as such it must be
   // initialized to a fatal error by default.
   MediaResult result = MediaResult(
     NS_ERROR_DOM_MEDIA_FATAL_ERR,
     nsPrintfCString("error creating %s decoder", TrackTypeToStr(aData.mTrack)));
 
   switch (aData.mTrack) {
     case TrackInfo::kAudioTrack: {
-      aData.mDecoder = mOwner->mPlatform->CreateDecoder({
+      aData.mDecoder = platform->CreateDecoder({
         *ownerData.GetCurrentInfo()->GetAsAudioInfo(),
         ownerData.mTaskQueue,
         mOwner->mCrashHelper,
         CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
         &result,
         TrackInfo::kAudioTrack,
         &mOwner->OnTrackWaitingForKeyProducer()
       });
       break;
     }
 
     case TrackType::kVideoTrack: {
       // Decoders use the layers backend to decide if they can use hardware decoding,
       // so specify LAYERS_NONE if we want to forcibly disable it.
-      aData.mDecoder = mOwner->mPlatform->CreateDecoder(
+      aData.mDecoder = platform->CreateDecoder(
         { *ownerData.GetCurrentInfo()->GetAsVideoInfo(),
           ownerData.mTaskQueue,
           mOwner->mKnowsCompositor,
           mOwner->GetImageContainer(),
           mOwner->mCrashHelper,
           CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
           &result,
           TrackType::kVideoTrack,
@@ -1423,16 +1426,17 @@ MediaFormatReader::TearDownDecoders()
   if (mVideo.mTaskQueue) {
     mVideo.mTaskQueue->BeginShutdown();
     mVideo.mTaskQueue->AwaitShutdownAndIdle();
     mVideo.mTaskQueue = nullptr;
   }
 
   mDecoderFactory = nullptr;
   mPlatform = nullptr;
+  mEncryptedPlatform = nullptr;
   mVideoFrameContainer = nullptr;
 
   ReleaseResources();
   mBuffered.DisconnectAll();
   return mTaskQueue->BeginShutdown();
 }
 
 nsresult
@@ -1525,19 +1529,19 @@ MediaFormatReader::SetCDMProxy(CDMProxy*
     PrepareToSetCDMForTrack(TrackInfo::kAudioTrack);
   }
   if (HasVideo()) {
     PrepareToSetCDMForTrack(TrackInfo::kVideoTrack);
   }
 
   mCDMProxy = aProxy;
 
-  if (IsEncrypted() && !mCDMProxy) {
+  if (!mCDMProxy) {
     // Release old PDMFactory which contains an EMEDecoderModule.
-    mPlatform = nullptr;
+    mEncryptedPlatform = nullptr;
   }
 
   if (!mInitDone || mSetCDMForTracks.isEmpty() || !mCDMProxy) {
     // 1) MFR is not initialized yet or
     // 2) Demuxer is initialized without active audio and video or
     // 3) A null cdm proxy is set
     // the promise can be resolved directly.
     mSetCDMForTracks.clear();
@@ -1747,18 +1751,18 @@ MediaFormatReader::MaybeResolveMetadataP
   UpdateBuffered();
 
   mMetadataPromise.Resolve(Move(metadata), __func__);
 }
 
 bool
 MediaFormatReader::IsEncrypted() const
 {
-  return (HasAudio() && mInfo.mAudio.mCrypto.mValid) ||
-         (HasVideo() && mInfo.mVideo.mCrypto.mValid);
+  return (HasAudio() && mAudio.GetCurrentInfo()->mCrypto.mValid) ||
+         (HasVideo() && mVideo.GetCurrentInfo()->mCrypto.mValid);
 }
 
 void
 MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError)
 {
   mDemuxerInitRequest.Complete();
   mMetadataPromise.Reject(aError, __func__);
 }
@@ -2401,21 +2405,23 @@ MediaFormatReader::HandleDemuxedSamples(
   }
 
   RefPtr<MediaRawData> sample = decoder.mQueuedSamples[0];
   const RefPtr<TrackInfoSharedPtr> info = sample->mTrackInfo;
 
   if (info && decoder.mLastStreamSourceID != info->GetID()) {
     nsTArray<RefPtr<MediaRawData>> samples;
     if (decoder.mDecoder) {
-      bool recyclable = StaticPrefs::MediaDecoderRecycleEnabled() &&
-                        decoder.mDecoder->SupportDecoderRecycling();
+      bool recyclable =
+        StaticPrefs::MediaDecoderRecycleEnabled() &&
+        decoder.mDecoder->SupportDecoderRecycling() &&
+        (*info)->mCrypto.mValid == decoder.GetCurrentInfo()->mCrypto.mValid;
       if (!recyclable && decoder.mTimeThreshold.isNothing() &&
           (decoder.mNextStreamSourceID.isNothing() ||
-            decoder.mNextStreamSourceID.ref() != info->GetID())) {
+           decoder.mNextStreamSourceID.ref() != info->GetID())) {
         LOG("%s stream id has changed from:%d to:%d, draining decoder.",
             TrackTypeToStr(aTrack),
             decoder.mLastStreamSourceID,
             info->GetID());
         decoder.RequestDrain();
         decoder.mNextStreamSourceID = Some(info->GetID());
         ScheduleUpdate(aTrack);
         return;
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -334,16 +334,17 @@ private:
 
   bool ShouldSkip(media::TimeUnit aTimeThreshold);
 
   void SetVideoDecodeThreshold();
 
   size_t SizeOfQueue(TrackType aTrack);
 
   RefPtr<PDMFactory> mPlatform;
+  RefPtr<PDMFactory> mEncryptedPlatform;
 
   enum class DrainState
   {
     None,
     DrainRequested,
     Draining,
     PartialDrainPending,
     DrainCompleted,
@@ -582,16 +583,20 @@ private:
     // with MSE or the WebMDemuxer.
     const TrackInfo* GetCurrentInfo() const
     {
       if (mInfo) {
         return *mInfo;
       }
       return mOriginalInfo.get();
     }
+    bool IsEncrypted() const
+    {
+      return GetCurrentInfo()->mCrypto.mValid;
+    }
 
     // Used by the MDSM for logging purposes.
     Atomic<size_t> mSizeOfQueue;
     // Used by the MDSM to determine if video decoding is hardware accelerated.
     // This value is updated after a frame is successfully decoded.
     Atomic<bool> mIsHardwareAccelerated;
     // Sample format monitoring.
     uint32_t mLastStreamSourceID;