Bug 1144409 - Encrypted event should be fired once per initData; part 1: first initData. r=cpearce
☠☠ backed out by dd850ffd05bc ☠ ☠
authorGerald Squelart <from_mozilla@squelart.com>
Sun, 22 Mar 2015 23:26:00 -0400
changeset 263972 f3b3547c610ab0d7a923b8ac80730a8f33349b1e
parent 263939 84f7fa96af4fa19b0ce10f2d13f7f1b08f1abfe3
child 263973 6cb38e69721690ebbfc8dc7d43d43bd958060d3b
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1144409
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1144409 - Encrypted event should be fired once per initData; part 1: first initData. r=cpearce
dom/html/HTMLMediaElement.cpp
dom/media/MediaInfo.h
dom/media/fmp4/MP4Reader.cpp
dom/media/mediasource/MediaSourceReader.cpp
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3088,17 +3088,20 @@ void HTMLMediaElement::MetadataLoaded(co
   }
   if (mIsEncrypted) {
     if (!mMediaSource) {
       DecodeError();
       return;
     }
 
 #ifdef MOZ_EME
-    DispatchEncrypted(aInfo->mCrypto.mInitData, aInfo->mCrypto.mType);
+    // Dispatch a distinct 'encrypted' event for each initData we have.
+    for (const auto& initData : aInfo->mCrypto.mInitDatas) {
+      DispatchEncrypted(initData.mInitData, initData.mType);
+    }
 #endif
   }
 
   // Expose the tracks to JS directly.
   for (OutputMediaStream& out : mOutputStreams) {
     if (aInfo->HasAudio()) {
       TrackID audioTrackId = aInfo->mAudio.mTrackInfo.mOutputId;
       out.mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO);
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -100,43 +100,66 @@ public:
   // True if we have an active audio bitstream.
   bool mHasAudio;
 
   TrackInfo mTrackInfo;
 };
 
 class EncryptionInfo {
 public:
-  EncryptionInfo() : mIsEncrypted(false) {}
+  struct InitData {
+    InitData(const nsString& aType, nsTArray<uint8_t>&& aInitData)
+      : mType(aType)
+      , mInitData(Move(aInitData))
+    {
+    }
 
-  // Encryption type to be passed to JS. Usually `cenc'.
-  nsString mType;
+    // Encryption type to be passed to JS. Usually `cenc'.
+    nsString mType;
 
-  // Encryption data.
-  nsTArray<uint8_t> mInitData;
+    // Encryption data.
+    nsTArray<uint8_t> mInitData;
+  };
+  typedef nsTArray<InitData> InitDatas;
 
   // True if the stream has encryption metadata
-  bool mIsEncrypted;
+  bool IsEncrypted() const
+  {
+    return !mInitDatas.IsEmpty();
+  }
+
+  void AddInitData(const nsString& aType, nsTArray<uint8_t>&& aInitData)
+  {
+    mInitDatas.AppendElement(InitData(aType, Move(aInitData)));
+  }
+
+  void AddInitData(const EncryptionInfo& aInfo)
+  {
+    mInitDatas.AppendElements(aInfo.mInitDatas);
+  }
+
+  // One 'InitData' per encrypted buffer.
+  InitDatas mInitDatas;
 };
 
 class MediaInfo {
 public:
   bool HasVideo() const
   {
     return mVideo.mHasVideo;
   }
 
   bool HasAudio() const
   {
     return mAudio.mHasAudio;
   }
 
   bool IsEncrypted() const
   {
-    return mCrypto.mIsEncrypted;
+    return mCrypto.IsEncrypted();
   }
 
   bool HasValidMedia() const
   {
     return HasVideo() || HasAudio();
   }
 
   // TODO: Store VideoInfo and AudioIndo in arrays to support multi-tracks.
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -363,17 +363,17 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
     if (mAudio.mActive) {
       mAudio.mTrackDemuxer = new MP4AudioDemuxer(mDemuxer);
     }
     mCrypto = mDemuxer->Crypto();
 
     {
       MonitorAutoUnlock unlock(mDemuxerMonitor);
       ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-      mInfo.mCrypto.mIsEncrypted = mIsEncrypted = mCrypto.valid;
+      mIsEncrypted = mCrypto.valid;
     }
 
     // Remember that we've initialized the demuxer, so that if we're decoding
     // an encrypted stream and we need to wait for a CDM to be set, we don't
     // need to reinit the demuxer.
     mDemuxerInitialized = true;
   } else if (mPlatform && !IsWaitingMediaResources()) {
     *aInfo = mInfo;
@@ -395,25 +395,24 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
     mVideo.mCallback = new DecoderCallback(this, kVideo);
 
     // Collect telemetry from h264 AVCC SPS.
     if (!mFoundSPSForTelemetry) {
       mFoundSPSForTelemetry = AccumulateSPSTelemetry(video.extra_data);
     }
   }
 
-  if (mIsEncrypted) {
+  if (mCrypto.valid) {
     nsTArray<uint8_t> initData;
     ExtractCryptoInitData(initData);
     if (initData.Length() == 0) {
       return NS_ERROR_FAILURE;
     }
 
-    mInfo.mCrypto.mInitData = initData;
-    mInfo.mCrypto.mType = NS_LITERAL_STRING("cenc");
+    mInfo.mCrypto.AddInitData(NS_LITERAL_STRING("cenc"), Move(initData));
   }
 
   // Get the duration, and report it to the decoder if we have it.
   Microseconds duration;
   {
     MonitorAutoLock lock(mDemuxerMonitor);
     duration = mDemuxer->Duration();
   }
--- a/dom/media/mediasource/MediaSourceReader.cpp
+++ b/dom/media/mediasource/MediaSourceReader.cpp
@@ -1049,32 +1049,16 @@ MediaSourceReader::MaybeNotifyHaveData()
     if (ended || haveVideo) {
       WaitPromise(MediaData::VIDEO_DATA).ResolveIfExists(MediaData::VIDEO_DATA, __func__);
     }
   }
   MSE_DEBUG("isSeeking=%d haveAudio=%d, haveVideo=%d ended=%d",
             IsSeeking(), haveAudio, haveVideo, ended);
 }
 
-static void
-CombineEncryptionData(EncryptionInfo& aTo, const EncryptionInfo& aFrom)
-{
-  if (!aFrom.mIsEncrypted) {
-    return;
-  }
-  aTo.mIsEncrypted = true;
-
-  if (!aTo.mType.IsEmpty() && !aTo.mType.Equals(aFrom.mType)) {
-    NS_WARNING("mismatched encryption types");
-  }
-
-  aTo.mType = aFrom.mType;
-  aTo.mInitData.AppendElements(aFrom.mInitData);
-}
-
 nsresult
 MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
 
   MSE_DEBUG("tracks=%u/%u audio=%p video=%p",
             mEssentialTrackBuffers.Length(), mTrackBuffers.Length(),
             mAudioTrack.get(), mVideoTrack.get());
@@ -1088,30 +1072,30 @@ MediaSourceReader::ReadMetadata(MediaInf
 
   if (mAudioTrack) {
     MOZ_ASSERT(mAudioTrack->IsReady());
     mAudioSourceDecoder = mAudioTrack->Decoders()[0];
 
     const MediaInfo& info = GetAudioReader()->GetMediaInfo();
     MOZ_ASSERT(info.HasAudio());
     mInfo.mAudio = info.mAudio;
-    CombineEncryptionData(mInfo.mCrypto, info.mCrypto);
+    mInfo.mCrypto.AddInitData(info.mCrypto);
     MSE_DEBUG("audio reader=%p duration=%lld",
               mAudioSourceDecoder.get(),
               mAudioSourceDecoder->GetReader()->GetDecoder()->GetMediaDuration());
   }
 
   if (mVideoTrack) {
     MOZ_ASSERT(mVideoTrack->IsReady());
     mVideoSourceDecoder = mVideoTrack->Decoders()[0];
 
     const MediaInfo& info = GetVideoReader()->GetMediaInfo();
     MOZ_ASSERT(info.HasVideo());
     mInfo.mVideo = info.mVideo;
-    CombineEncryptionData(mInfo.mCrypto, info.mCrypto);
+    mInfo.mCrypto.AddInitData(info.mCrypto);
     MSE_DEBUG("video reader=%p duration=%lld",
               GetVideoReader(),
               GetVideoReader()->GetDecoder()->GetMediaDuration());
   }
 
   *aInfo = mInfo;
   *aTags = nullptr; // TODO: Handle metadata.