Bug 1351953 - Send Data to CDM for decrypt and or decode in shmems. r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 27 Mar 2017 13:19:38 +1300
changeset 556489 04879d8c1639bf6f14cebc6031d8cc23e05e567a
parent 555725 b043233ec04f06768d59dcdfb9e928142280f3cc
child 556490 44dfbc465db14bb689a653e6c0b3cbc626c0a0d1
push id52568
push userbmo:cpearce@mozilla.com
push dateWed, 05 Apr 2017 23:29:31 +0000
reviewersgerald
bugs1351953
milestone55.0a1
Bug 1351953 - Send Data to CDM for decrypt and or decode in shmems. r=gerald MozReview-Commit-ID: 2UdGimoOLKr
dom/media/gmp/ChromiumCDMChild.cpp
dom/media/gmp/ChromiumCDMParent.cpp
dom/media/gmp/ChromiumCDMParent.h
dom/media/gmp/GMPTypes.ipdlh
dom/media/gmp/PChromiumCDM.ipdl
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -9,16 +9,17 @@
 #include "WidevineFileIO.h"
 #include "WidevineVideoFrame.h"
 #include "GMPLog.h"
 #include "GMPPlatform.h"
 #include "mozilla/Unused.h"
 #include "nsPrintfCString.h"
 #include "base/time.h"
 #include "GMPUtils.h"
+#include "mozilla/ScopeExit.h"
 
 namespace mozilla {
 namespace gmp {
 
 ChromiumCDMChild::ChromiumCDMChild(GMPContentChild* aPlugin)
   : mPlugin(aPlugin)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
@@ -383,18 +384,18 @@ ChromiumCDMChild::DecryptFailed(uint32_t
   Unused << SendDecrypted(aId, aStatus, nsTArray<uint8_t>());
 }
 
 static void
 InitInputBuffer(const CDMInputBuffer& aBuffer,
                 nsTArray<cdm::SubsampleEntry>& aSubSamples,
                 cdm::InputBuffer& aInputBuffer)
 {
-  aInputBuffer.data = aBuffer.mData().Elements();
-  aInputBuffer.data_size = aBuffer.mData().Length();
+  aInputBuffer.data = aBuffer.mData().get<uint8_t>();
+  aInputBuffer.data_size = aBuffer.mData().Size<uint8_t>();
 
   if (aBuffer.mIsEncrypted()) {
     aInputBuffer.key_id = aBuffer.mKeyId().Elements();
     aInputBuffer.key_id_size = aBuffer.mKeyId().Length();
 
     aInputBuffer.iv = aBuffer.mIV().Elements();
     aInputBuffer.iv_size = aBuffer.mIV().Length();
 
@@ -410,16 +411,21 @@ InitInputBuffer(const CDMInputBuffer& aB
 }
 
 mozilla::ipc::IPCResult
 ChromiumCDMChild::RecvDecrypt(const uint32_t& aId,
                               const CDMInputBuffer& aBuffer)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::RecvDecrypt()");
+
+  auto autoDeallocateShmem = MakeScopeExit([&,this] {
+    this->DeallocShmem(aBuffer.mData());
+  });
+
   if (!mCDM) {
     GMP_LOG("ChromiumCDMChild::RecvDecrypt() no CDM");
     DecryptFailed(aId, cdm::kDecryptError);
     return IPC_OK();
   }
   if (aBuffer.mClearBytes().Length() != aBuffer.mCipherBytes().Length()) {
     GMP_LOG("ChromiumCDMChild::RecvDecrypt() clear/cipher bytes length doesn't "
             "match");
@@ -435,17 +441,17 @@ ChromiumCDMChild::RecvDecrypt(const uint
   cdm::Status status = mCDM->Decrypt(input, &output);
 
   if (status != cdm::kSuccess) {
     DecryptFailed(aId, status);
     return IPC_OK();
   }
 
   if (!output.DecryptedBuffer() ||
-      output.DecryptedBuffer()->Size() != aBuffer.mData().Length()) {
+      output.DecryptedBuffer()->Size() != aBuffer.mData().Size<uint8_t>()) {
     // The sizes of the input and output should exactly match.
     DecryptFailed(aId, cdm::kDecryptError);
     return IPC_OK();
   }
 
   nsTArray<uint8_t> buf =
     static_cast<WidevineBuffer*>(output.DecryptedBuffer())->ExtractBuffer();
   Unused << SendDecrypted(aId, cdm::kSuccess, buf);
@@ -505,16 +511,20 @@ ChromiumCDMChild::RecvResetVideoDecoder(
 mozilla::ipc::IPCResult
 ChromiumCDMChild::RecvDecryptAndDecodeFrame(const CDMInputBuffer& aBuffer)
 {
   MOZ_ASSERT(IsOnMessageLoopThread());
   GMP_LOG("ChromiumCDMChild::RecvDecryptAndDecodeFrame() t=%" PRId64 ")",
           aBuffer.mTimestamp());
   MOZ_ASSERT(mDecoderInitialized);
 
+  auto autoDeallocateShmem = MakeScopeExit([&, this] {
+    this->DeallocShmem(aBuffer.mData());
+  });
+
   // The output frame may not have the same timestamp as the frame we put in.
   // We may need to input a number of frames before we receive output. The
   // CDM's decoder reorders to ensure frames output are in presentation order.
   // So we need to store the durations of the frames input, and retrieve them
   // on output.
   mFrameDurations.Insert(aBuffer.mTimestamp(), aBuffer.mDuration());
 
   cdm::InputBuffer input;
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -164,29 +164,32 @@ ChromiumCDMParent::RemoveSession(const n
   if (!SendRemoveSession(aPromiseId, aSessionId)) {
     RejectPromise(
       aPromiseId,
       NS_ERROR_DOM_INVALID_STATE_ERR,
       NS_LITERAL_CSTRING("Failed to send removeSession to CDM process"));
   }
 }
 
-static bool
-InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, MediaRawData* aSample)
+bool
+ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, MediaRawData* aSample)
 {
   const CryptoSample& crypto = aSample->mCrypto;
   if (crypto.mEncryptedSizes.Length() != crypto.mPlainSizes.Length()) {
     GMP_LOG("InitCDMInputBuffer clear/cipher subsamples don't match");
     return false;
   }
 
-  nsTArray<uint8_t> data;
-  data.AppendElements(aSample->Data(), aSample->Size());
+  Shmem shmem;
+  if (!AllocShmem(aSample->Size(), Shmem::SharedMemory::TYPE_BASIC, &shmem)) {
+    return false;
+  }
+  memcpy(shmem.get<uint8_t>(), aSample->Data(), aSample->Size());
 
-  aBuffer = gmp::CDMInputBuffer(data,
+  aBuffer = gmp::CDMInputBuffer(shmem,
                                 crypto.mKeyId,
                                 crypto.mIV,
                                 aSample->mTime,
                                 aSample->mDuration,
                                 crypto.mPlainSizes,
                                 crypto.mEncryptedSizes,
                                 crypto.mValid);
   return true;
@@ -204,16 +207,17 @@ ChromiumCDMParent::Decrypt(MediaRawData*
     return DecryptPromise::CreateAndReject(DecryptResult(GenericErr, aSample),
                                            __func__);
   }
   RefPtr<DecryptJob> job = new DecryptJob(aSample);
   if (!SendDecrypt(job->mId, buffer)) {
     GMP_LOG(
       "ChromiumCDMParent::Decrypt(this=%p) failed to send decrypt message",
       this);
+    DeallocShmem(buffer.mData());
     return DecryptPromise::CreateAndReject(DecryptResult(GenericErr, aSample),
                                            __func__);
   }
   RefPtr<DecryptPromise> promise = job->Ensure();
   mDecrypts.AppendElement(job);
   return promise;
 }
 
@@ -716,16 +720,17 @@ ChromiumCDMParent::DecryptAndDecodeFrame
   }
 
   mLastStreamOffset = aSample->mOffset;
 
   if (!SendDecryptAndDecodeFrame(buffer)) {
     GMP_LOG(
       "ChromiumCDMParent::Decrypt(this=%p) failed to send decrypt message.",
       this);
+    DeallocShmem(buffer.mData());
     return MediaDataDecoder::DecodePromise::CreateAndReject(
       MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                   "Failed to send decrypt to CDM process."),
       __func__);
   }
 
   return mDecodePromise.Ensure(__func__);
 }
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -122,16 +122,18 @@ protected:
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   void RejectPromise(uint32_t aPromiseId,
                      nsresult aError,
                      const nsCString& aErrorMessage);
 
   void ResolvePromise(uint32_t aPromiseId);
 
+  bool InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer, MediaRawData* aSample);
+
   const uint32_t mPluginId;
   GMPContentParent* mContentParent;
   // Note: this pointer is a weak reference because otherwise it would cause
   // a cycle, as ChromiumCDMProxy has a strong reference to the
   // ChromiumCDMParent.
   ChromiumCDMProxy* mProxy = nullptr;
   nsDataHashtable<nsUint32HashKey, uint32_t> mPromiseToCreateSessionToken;
   nsTArray<RefPtr<DecryptJob>> mDecrypts;
--- a/dom/media/gmp/GMPTypes.ipdlh
+++ b/dom/media/gmp/GMPTypes.ipdlh
@@ -56,17 +56,17 @@ struct GMPVideoi420FrameData
 };
 
 struct GMPKeyInformation {
   uint8_t[] keyId;
   GMPMediaKeyStatus status;
 };
 
 struct CDMInputBuffer {
-  uint8_t[] mData;
+  Shmem mData;
   uint8_t[] mKeyId;
   uint8_t[] mIV;
   int64_t mTimestamp;
   int64_t mDuration;
   uint16_t[] mClearBytes;
   uint32_t[] mCipherBytes;
   bool mIsEncrypted;
 };
--- a/dom/media/gmp/PChromiumCDM.ipdl
+++ b/dom/media/gmp/PChromiumCDM.ipdl
@@ -82,17 +82,17 @@ parent:
   async OnLegacySessionError(nsCString aSessionId,
                              uint32_t aError,
                              uint32_t aSystemCode,
                              nsCString aMessage);
 
   async ResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccessful);
 
   // Return values of cdm::ContentDecryptionModule8::Decrypt
-  async Decrypted(uint32_t aId, uint32_t aStatus, uint8_t[] aData);
+  async Decrypted(uint32_t aId, uint32_t aStatus, Shmem aData);
 
   async OnDecoderInitDone(uint32_t aStatus);
 
   // Return values of cdm::ContentDecryptionModule8::DecryptAndDecodeFrame
   async Decoded(CDMVideoFrame aFrame);
   async DecodeFailed(uint32_t aStatus);
 
   async ResetVideoDecoderComplete();