Bug 1494178 - Add check to ChromiumCDMChild to mark samples with 0 encrypted bytes as unencrypted. r=cpearce
authorBryce Van Dyk <bvandyk@mozilla.com>
Wed, 26 Sep 2018 16:34:32 +0000
changeset 496769 e6f8e822851acb248df066141c3f2a6dcbad20d6
parent 496768 d86f6268d191ed31554a6b0b9d6d70e2891df83b
child 496770 14e7673d10f7f774ac2bd180a5fd54d2e5dc3acb
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1494178
milestone64.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 1494178 - Add check to ChromiumCDMChild to mark samples with 0 encrypted bytes as unencrypted. r=cpearce With the addition of an explicit encryption enum for CDM10 input data, if a sample has 0 encrypted bytes it must be marked as unencrypted. Historically we could let the CDM figure out based on the unencrypted + encrypted bytes. However, if we mark a sample as encrypted but it has 0 encrypted bytes, the CDM will fail to decrypt. This changeset adds a check to gracefully handle samples that are marked as encrypted but with no encrypted ranges. In such cases we mark the data as unencrypted and log that such data was encountered. This means we don't break playback of encrypted media should we overlook such cases, but have better detection via logging. Differential Revision: https://phabricator.services.mozilla.com/D6873
dom/media/gmp/ChromiumCDMChild.cpp
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -679,16 +679,42 @@ ConvertToCdmEncryptionScheme(const GMPEn
     case GMPEncryptionScheme::kGMPEncryptionCbcs:
       return cdm::EncryptionScheme::kCbcs;
     default:
       MOZ_ASSERT_UNREACHABLE("Cannot convert invalid encryption scheme!");
       return cdm::EncryptionScheme::kUnencrypted;
   }
 }
 
+static cdm::EncryptionScheme
+ConvertToCdmEncryptionScheme(const GMPEncryptionScheme& aEncryptionScheme,
+                             uint64_t aNumCipherBytes)
+{
+  if (aNumCipherBytes == 0) {
+    // Starting at CDM10, if fed a sample marked as encrypted that has no
+    // encrypted bytes, the CDM will give a decryption error. So we mark these
+    // as unencrypted to attempt to avoid such errors -- though ideally our
+    // demuxers should not emit such data, so log it.
+    if (aEncryptionScheme != GMPEncryptionScheme::kGMPEncryptionNone) {
+      GMP_LOG(
+        "ChromiumCDMChild::ConvertToCdmEncryptionScheme() got scheme marked "
+        "as encrypted, but with no cipher bytes! This should be caught "
+        "earlier, preferably by the demuxer! Returning "
+        "cdm::EncryptionScheme::kUnencrypted");
+    }
+    return cdm::EncryptionScheme::kUnencrypted;
+  }
+  if (aEncryptionScheme == GMPEncryptionScheme::kGMPEncryptionNone) {
+    GMP_LOG("ChromiumCDMChild::ConvertToCdmEncryptionScheme() got scheme "
+            "marked as unecrypted but with > 0 cipher bytes! Something is "
+            "buggy to emit such data -- likey a demuxer");
+  }
+  return ConvertToCdmEncryptionScheme(aEncryptionScheme);
+}
+
 static void
 InitInputBuffer(const CDMInputBuffer& aBuffer,
                 nsTArray<cdm::SubsampleEntry>& aSubSamples,
                 cdm::InputBuffer_2& aInputBuffer)
 {
   aInputBuffer.data = aBuffer.mData().get<uint8_t>();
   aInputBuffer.data_size = aBuffer.mData().Size<uint8_t>();
 
@@ -698,25 +724,27 @@ InitInputBuffer(const CDMInputBuffer& aB
     MOZ_ASSERT(aBuffer.mEncryptionScheme() ==
                GMPEncryptionScheme::kGMPEncryptionCenc);
     aInputBuffer.key_id = aBuffer.mKeyId().Elements();
     aInputBuffer.key_id_size = aBuffer.mKeyId().Length();
 
     aInputBuffer.iv = aBuffer.mIV().Elements();
     aInputBuffer.iv_size = aBuffer.mIV().Length();
 
+    uint64_t numCipherBytes = 0;
     aSubSamples.SetCapacity(aBuffer.mClearBytes().Length());
     for (size_t i = 0; i < aBuffer.mCipherBytes().Length(); i++) {
       aSubSamples.AppendElement(cdm::SubsampleEntry{
         aBuffer.mClearBytes()[i], aBuffer.mCipherBytes()[i] });
+      numCipherBytes += aBuffer.mCipherBytes()[i];
     }
     aInputBuffer.subsamples = aSubSamples.Elements();
     aInputBuffer.num_subsamples = aSubSamples.Length();
     aInputBuffer.encryption_scheme =
-      ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme());
+      ConvertToCdmEncryptionScheme(aBuffer.mEncryptionScheme(), numCipherBytes);
   }
   aInputBuffer.timestamp = aBuffer.mTimestamp();
 }
 
 bool
 ChromiumCDMChild::HasShmemOfSize(size_t aSize) const
 {
   for (const ipc::Shmem& shmem : mBuffers) {