Bug 1147689 - Pass the session ID(s) of an encrypted frame into EME CDMs - r=cpearce
authorEdwin Flores <eflores@mozilla.com>
Thu, 26 Mar 2015 22:57:36 +1300
changeset 266117 74ecd8227fe3ef41ec9cbb5bcca257397eb74d71
parent 266116 192e8bcb8b803d36a396ad72ae000abc06d5c132
child 266118 06330b23ca2ab1bf1bfdab615971e88d8a24a576
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1147689
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 1147689 - Pass the session ID(s) of an encrypted frame into EME CDMs - r=cpearce
dom/media/eme/CDMCaps.cpp
dom/media/eme/CDMCaps.h
dom/media/eme/CDMProxy.cpp
dom/media/eme/CDMProxy.h
dom/media/fmp4/MP4Reader.cpp
dom/media/gmp/GMPDecryptorParent.cpp
dom/media/gmp/GMPEncryptedBufferDataImpl.cpp
dom/media/gmp/GMPEncryptedBufferDataImpl.h
dom/media/gmp/GMPTypes.ipdlh
dom/media/gmp/gmp-api/gmp-decryption.h
media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -189,9 +189,20 @@ CDMCaps::AutoLock::GetKeyStatusesForSess
   for (size_t i = 0; i < mData.mKeyStatuses.Length(); i++) {
     const auto& key = mData.mKeyStatuses[i];
     if (key.mSessionId.Equals(aSessionId)) {
       aOutKeyStatuses.AppendElement(key);
     }
   }
 }
 
+void
+CDMCaps::AutoLock::GetSessionIdsForKeyId(const CencKeyId& aKeyId,
+                                         nsTArray<nsCString>& aOutSessionIds)
+{
+  for (const auto& keyStatus : mData.mKeyStatuses) {
+    if (keyStatus.mId == aKeyId) {
+      aOutSessionIds.AppendElement(NS_ConvertUTF16toUTF8(keyStatus.mSessionId));
+    }
+  }
+}
+
 } // namespace mozilla
--- a/dom/media/eme/CDMCaps.h
+++ b/dom/media/eme/CDMCaps.h
@@ -63,16 +63,19 @@ public:
 
     // Returns true if key status changed,
     // i.e. the key status changed from usable to expired.
     bool SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, GMPMediaKeyStatus aStatus);
 
     void GetKeyStatusesForSession(const nsAString& aSessionId,
                                   nsTArray<KeyStatus>& aOutKeyStatuses);
 
+    void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
+                               nsTArray<nsCString>& aOutSessionIds);
+
     // Sets the capabilities of the CDM. aCaps is the logical OR of the
     // GMP_EME_CAP_* flags from gmp-decryption.h.
     void SetCaps(uint64_t aCaps);
 
     bool CanDecryptAndDecodeAudio();
     bool CanDecryptAndDecodeVideo();
 
     bool CanDecryptAudio();
--- a/dom/media/eme/CDMProxy.cpp
+++ b/dom/media/eme/CDMProxy.cpp
@@ -587,16 +587,24 @@ CDMProxy::gmp_Decrypted(uint32_t aId,
       mDecryptionJobs.RemoveElementAt(i);
       return;
     }
   }
   NS_WARNING("GMPDecryptorChild returned incorrect job ID");
 }
 
 void
+CDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
+                                nsTArray<nsCString>& aSessionIds)
+{
+  CDMCaps::AutoLock caps(Capabilites());
+  caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
+}
+
+void
 CDMProxy::Terminated()
 {
   MOZ_ASSERT(NS_IsMainThread());
   NS_WARNING("CDM terminated");
   if (!mKeys.IsNull()) {
     mKeys->Terminated();
   }
 }
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -161,16 +161,19 @@ public:
                      GMPErr aResult,
                      const nsTArray<uint8_t>& aDecryptedData);
 
   CDMCaps& Capabilites();
 
   // Main thread only.
   void OnKeyStatusesChange(const nsAString& aSessionId);
 
+  void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
+                             nsTArray<nsCString>& aSessionIds);
+
 #ifdef DEBUG
   bool IsOnGMPThread();
 #endif
 
 private:
 
   struct InitData {
     uint32_t mPromiseId;
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -744,16 +744,28 @@ MP4Reader::Update(TrackType aTrack)
     nsAutoPtr<MediaSample> sample(PopSample(aTrack));
 
     // Collect telemetry from h264 Annex B SPS.
     if (!mFoundSPSForTelemetry && sample && AnnexB::HasSPS(sample->mMp4Sample)) {
       nsRefPtr<ByteBuffer> extradata = AnnexB::ExtractExtraData(sample->mMp4Sample);
       mFoundSPSForTelemetry = AccumulateSPSTelemetry(extradata);
     }
 
+    if (sample && sample->mMp4Sample && sample->mMp4Sample->crypto.valid) {
+      CryptoSample& crypto = sample->mMp4Sample->crypto;
+      MOZ_ASSERT(crypto.session_ids.IsEmpty());
+
+      ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+
+      nsRefPtr<CDMProxy> proxy = mDecoder->GetCDMProxy();
+      MOZ_ASSERT(proxy);
+
+      proxy->GetSessionIdsForKeyId(crypto.key, crypto.session_ids);
+    }
+
     if (sample) {
       decoder.mDecoder->Input(sample->mMp4Sample.forget());
       if (aTrack == kVideo) {
         a.mParsed++;
       }
     } else {
       {
         MonitorAutoLock lock(decoder.mMonitor);
--- a/dom/media/gmp/GMPDecryptorParent.cpp
+++ b/dom/media/gmp/GMPDecryptorParent.cpp
@@ -142,17 +142,18 @@ GMPDecryptorParent::Decrypt(uint32_t aId
   }
 
   // Caller should ensure parameters passed in are valid.
   MOZ_ASSERT(!aBuffer.IsEmpty() && aCrypto.valid);
 
   GMPDecryptionData data(aCrypto.key,
                          aCrypto.iv,
                          aCrypto.plain_sizes,
-                         aCrypto.encrypted_sizes);
+                         aCrypto.encrypted_sizes,
+                         aCrypto.session_ids);
 
   unused << SendDecrypt(aId, aBuffer, data);
 }
 
 bool
 GMPDecryptorParent::RecvSetSessionId(const uint32_t& aCreateSessionId,
                                      const nsCString& aSessionId)
 {
--- a/dom/media/gmp/GMPEncryptedBufferDataImpl.cpp
+++ b/dom/media/gmp/GMPEncryptedBufferDataImpl.cpp
@@ -9,39 +9,42 @@
 namespace mozilla {
 namespace gmp {
 
 GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const CryptoSample& aCrypto)
   : mKeyId(aCrypto.key)
   , mIV(aCrypto.iv)
   , mClearBytes(aCrypto.plain_sizes)
   , mCipherBytes(aCrypto.encrypted_sizes)
+  , mSessionIdList(aCrypto.session_ids)
 {
 }
 
 GMPEncryptedBufferDataImpl::GMPEncryptedBufferDataImpl(const GMPDecryptionData& aData)
+  : mKeyId(aData.mKeyId())
+  , mIV(aData.mIV())
+  , mClearBytes(aData.mClearBytes())
+  , mCipherBytes(aData.mCipherBytes())
+  , mSessionIdList(aData.mSessionIds())
 {
-  mKeyId = aData.mKeyId();
-  mIV = aData.mIV();
-  mClearBytes = aData.mClearBytes();
-  mCipherBytes = aData.mCipherBytes();
   MOZ_ASSERT(mClearBytes.Length() == mCipherBytes.Length());
 }
 
 GMPEncryptedBufferDataImpl::~GMPEncryptedBufferDataImpl()
 {
 }
 
 void
 GMPEncryptedBufferDataImpl::RelinquishData(GMPDecryptionData& aData)
 {
   aData.mKeyId() = Move(mKeyId);
   aData.mIV() = Move(mIV);
   aData.mClearBytes() = Move(mClearBytes);
   aData.mCipherBytes() = Move(mCipherBytes);
+  mSessionIdList.RelinquishData(aData.mSessionIds());
 }
 
 const uint8_t*
 GMPEncryptedBufferDataImpl::KeyId() const
 {
   return mKeyId.Elements();
 }
 
@@ -70,19 +73,59 @@ GMPEncryptedBufferDataImpl::ClearBytes()
 }
 
 const uint32_t*
 GMPEncryptedBufferDataImpl::CipherBytes() const
 {
   return mCipherBytes.Elements();
 }
 
+const GMPStringList*
+GMPEncryptedBufferDataImpl::SessionIds() const
+{
+  return &mSessionIdList;
+}
+
 uint32_t
 GMPEncryptedBufferDataImpl::NumSubsamples() const
 {
   MOZ_ASSERT(mClearBytes.Length() == mCipherBytes.Length());
   // Return the min of the two, to ensure there's not chance of array index
   // out-of-bounds shenanigans.
   return std::min<uint32_t>(mClearBytes.Length(), mCipherBytes.Length());
 }
 
+GMPStringListImpl::GMPStringListImpl(const nsTArray<nsCString>& aStrings)
+  : mStrings(aStrings)
+{
+}
+
+const uint32_t
+GMPStringListImpl::Size() const
+{
+  return mStrings.Length();
+}
+
+void
+GMPStringListImpl::StringAt(uint32_t aIndex,
+                            const char** aOutString,
+                            uint32_t *aOutLength) const
+{
+  if (NS_WARN_IF(aIndex >= Size())) {
+    return;
+  }
+
+  *aOutString = mStrings[aIndex].BeginReading();
+  *aOutLength = mStrings[aIndex].Length();
+}
+
+void
+GMPStringListImpl::RelinquishData(nsTArray<nsCString>& aStrings)
+{
+  aStrings = Move(mStrings);
+}
+
+GMPStringListImpl::~GMPStringListImpl()
+{
+}
+
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPEncryptedBufferDataImpl.h
+++ b/dom/media/gmp/GMPEncryptedBufferDataImpl.h
@@ -9,16 +9,30 @@
 #include "gmp-decryption.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "nsTArray.h"
 #include "mozilla/gmp/GMPTypes.h"
 
 namespace mozilla {
 namespace gmp {
 
+class GMPStringListImpl : public GMPStringList
+{
+public:
+  GMPStringListImpl(const nsTArray<nsCString>& aStrings);
+  virtual const uint32_t Size() const override;
+  virtual void StringAt(uint32_t aIndex,
+                        const char** aOutString, uint32_t *aOutLength) const override;
+  virtual ~GMPStringListImpl() override;
+  void RelinquishData(nsTArray<nsCString>& aStrings);
+
+private:
+  nsTArray<nsCString> mStrings;
+};
+
 class GMPEncryptedBufferDataImpl : public GMPEncryptedBufferMetadata {
 private:
   typedef mp4_demuxer::CryptoSample CryptoSample;
 public:
   explicit GMPEncryptedBufferDataImpl(const CryptoSample& aCrypto);
   explicit GMPEncryptedBufferDataImpl(const GMPDecryptionData& aData);
   virtual ~GMPEncryptedBufferDataImpl();
 
@@ -26,22 +40,25 @@ public:
 
   virtual const uint8_t* KeyId() const override;
   virtual uint32_t KeyIdSize() const override;
   virtual const uint8_t* IV() const override;
   virtual uint32_t IVSize() const override;
   virtual uint32_t NumSubsamples() const override;
   virtual const uint16_t* ClearBytes() const override;
   virtual const uint32_t* CipherBytes() const override;
+  virtual const GMPStringList* SessionIds() const override;
 
 private:
   nsTArray<uint8_t> mKeyId;
   nsTArray<uint8_t> mIV;
   nsTArray<uint16_t> mClearBytes;
   nsTArray<uint32_t> mCipherBytes;
+
+  GMPStringListImpl mSessionIdList;
 };
 
 class GMPBufferImpl : public GMPBuffer {
 public:
   GMPBufferImpl(uint32_t aId, const nsTArray<uint8_t>& aData)
     : mId(aId)
     , mData(aData)
   {
--- a/dom/media/gmp/GMPTypes.ipdlh
+++ b/dom/media/gmp/GMPTypes.ipdlh
@@ -9,16 +9,17 @@ using GMPAudioCodecType from "gmp-audio-
 namespace mozilla {
 namespace gmp {
 
 struct GMPDecryptionData {
   uint8_t[] mKeyId;
   uint8_t[] mIV;
   uint16_t[] mClearBytes;
   uint32_t[] mCipherBytes;
+  nsCString[] mSessionIds;
 };
 
 struct GMPVideoEncodedFrameData
 {
   uint32_t mEncodedWidth;
   uint32_t mEncodedHeight;
   uint64_t mTimestamp; // microseconds
   uint64_t mDuration; // microseconds
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -14,16 +14,26 @@
 * limitations under the License.
 */
 
 #ifndef GMP_DECRYPTION_h_
 #define GMP_DECRYPTION_h_
 
 #include "gmp-platform.h"
 
+class GMPStringList {
+public:
+  virtual const uint32_t Size() const = 0;
+
+  virtual void StringAt(uint32_t aIndex,
+                        const char** aOutString, uint32_t* aOutLength) const = 0;
+
+  virtual ~GMPStringList() { }
+};
+
 class GMPEncryptedBufferMetadata {
 public:
   // Key ID to identify the decryption key.
   virtual const uint8_t* KeyId() const = 0;
 
   // Size (in bytes) of |KeyId()|.
   virtual uint32_t KeyIdSize() const = 0;
 
@@ -36,16 +46,20 @@ public:
   // Number of entries returned by ClearBytes() and CipherBytes().
   virtual uint32_t NumSubsamples() const = 0;
 
   virtual const uint16_t* ClearBytes() const = 0;
 
   virtual const uint32_t* CipherBytes() const = 0;
 
   virtual ~GMPEncryptedBufferMetadata() {}
+
+  // The set of MediaKeySession IDs associated with this decryption key in
+  // the current stream.
+  virtual const GMPStringList* SessionIds() const = 0;
 };
 
 class GMPBuffer {
 public:
   virtual uint32_t Id() const = 0;
   virtual uint8_t* Data() = 0;
   virtual uint32_t Size() const = 0;
   virtual void Resize(uint32_t aSize) = 0;
--- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h
@@ -6,16 +6,17 @@
 #define DECODER_DATA_H_
 
 #include "mozilla/Types.h"
 #include "mozilla/Vector.h"
 #include "nsAutoPtr.h"
 #include "nsRefPtr.h"
 #include "nsString.h"
 #include "nsTArray.h"
+#include "nsString.h"
 
 namespace stagefright
 {
 template <typename T> class sp;
 class MetaData;
 class MediaBuffer;
 }
 
@@ -78,16 +79,18 @@ public:
 class CryptoSample : public CryptoTrack
 {
 public:
   void Update(stagefright::sp<stagefright::MetaData>& aMetaData);
 
   nsTArray<uint16_t> plain_sizes;
   nsTArray<uint32_t> encrypted_sizes;
   nsTArray<uint8_t> iv;
+
+  nsTArray<nsCString> session_ids;
 };
 
 class TrackConfig
 {
 public:
   TrackConfig() : mTrackId(0), duration(0), media_time(0) {}
   nsAutoCString mime_type;
   uint32_t mTrackId;