Bug 1302331 - [Part3] Create CryptoInfo from MediaRawData and deliver it to MediaCodecDataDecoder or remote codec decoder. draft
authorKilik Kuo <kikuo@mozilla.com>
Tue, 20 Sep 2016 16:44:30 +0800
changeset 416430 c2c325dbad0b40dcf24e6de0c083f759e0b5100c
parent 416429 49452673088a461cffc403426a18a0addbe44df5
child 531856 1f7edf850c49a3c16f4dad160709f972659fc38e
push id30145
push userkikuo@mozilla.com
push dateThu, 22 Sep 2016 06:16:41 +0000
bugs1302331
milestone52.0a1
Bug 1302331 - [Part3] Create CryptoInfo from MediaRawData and deliver it to MediaCodecDataDecoder or remote codec decoder. MozReview-Commit-ID: 9pHHrhQPs9m
dom/media/platforms/android/AndroidDecoderModule.cpp
dom/media/platforms/android/MediaCodecDataDecoder.cpp
dom/media/platforms/android/RemoteDataDecoder.cpp
--- a/dom/media/platforms/android/AndroidDecoderModule.cpp
+++ b/dom/media/platforms/android/AndroidDecoderModule.cpp
@@ -24,16 +24,43 @@
     mozilla::LogLevel::Debug, ("AndroidDecoderModule(%p)::%s: " arg, \
       this, __func__, ##__VA_ARGS__))
 
 using namespace mozilla;
 using namespace mozilla::gl;
 using namespace mozilla::java::sdk;
 using media::TimeUnit;
 
+namespace {
+  template<class T>
+  mozilla::jni::ByteArray::LocalRef
+  CreateAndInitJByteArray(const T& data, jsize length)
+  {
+    JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
+    jbyteArray result = jenv->NewByteArray(length);
+    MOZ_CATCH_JNI_EXCEPTION(jenv);
+    jenv->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte*>(const_cast<T>(data)));
+    MOZ_CATCH_JNI_EXCEPTION(jenv);
+    return mozilla::jni::ByteArray::LocalRef::Adopt(jenv, result);
+  }
+
+  template<class T>
+  mozilla::jni::IntArray::LocalRef
+  CreateAndInitJIntArray(const T& data, jsize length)
+  {
+    JNIEnv* const jenv = mozilla::jni::GetEnvForThread();
+    jintArray result = jenv->NewIntArray(length);
+    MOZ_CATCH_JNI_EXCEPTION(jenv);
+    jenv->SetIntArrayRegion(result, 0, length, reinterpret_cast<const jint*>(const_cast<T>(data)));
+    MOZ_CATCH_JNI_EXCEPTION(jenv);
+    return mozilla::jni::IntArray::LocalRef::Adopt(jenv, result);
+  }
+}
+
+
 namespace mozilla {
 
 mozilla::LazyLogModule sAndroidDecoderModuleLog("AndroidDecoderModule");
 
 static const char*
 TranslateMimeType(const nsACString& aMimeType)
 {
   if (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8)) {
@@ -51,16 +78,73 @@ GetFeatureStatus(int32_t aFeature)
   int32_t status = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
   nsCString discardFailureId;
   if (!gfxInfo || NS_FAILED(gfxInfo->GetFeatureStatus(aFeature, discardFailureId, &status))) {
     return false;
   }
   return status == nsIGfxInfo::FEATURE_STATUS_OK;
 };
 
+CryptoInfo::LocalRef
+GetCryptoInfoFromSample(const MediaRawData* aSample)
+{
+  auto& cryptoObj = aSample->mCrypto;
+
+  if (!cryptoObj.mValid) {
+    return nullptr;
+  }
+
+  CryptoInfo::LocalRef cryptoInfo;
+  nsresult rv = CryptoInfo::New(&cryptoInfo);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  uint32_t numSubSamples =
+    std::min<uint32_t>(cryptoObj.mPlainSizes.Length(), cryptoObj.mEncryptedSizes.Length());
+
+  uint32_t totalSubSamplesSize = 0;
+  for (auto& size : cryptoObj.mEncryptedSizes) {
+    totalSubSamplesSize += size;
+  }
+
+  // mPlainSizes is uint16_t, need to transform to uint32_t first.
+  nsTArray<uint32_t> plainSizes;
+  for (auto& size : cryptoObj.mPlainSizes) {
+    totalSubSamplesSize += size;
+    plainSizes.AppendElement(size);
+  }
+
+  uint32_t codecSpecificDataSize = aSample->Size() - totalSubSamplesSize;
+  // Size of codec specific data("CSD") for Android MediaCodec usage should be
+  // included in the 1st plain size.
+  plainSizes[0] += codecSpecificDataSize;
+
+  static const int kExpectedIVLength = 16;
+  auto tempIV(cryptoObj.mIV);
+  auto tempIVLength = tempIV.Length();
+  MOZ_ASSERT(tempIVLength <= kExpectedIVLength);
+  for (size_t i = tempIVLength; i < kExpectedIVLength; i++) {
+    // Padding with 0
+    tempIV.AppendElement(0);
+  }
+
+  auto numBytesOfPlainData = CreateAndInitJIntArray(&plainSizes[0], plainSizes.Length());
+  auto numBytesOfEncryptedData = CreateAndInitJIntArray(&cryptoObj.mEncryptedSizes[0],
+                                                        cryptoObj.mEncryptedSizes.Length());
+  auto iv = CreateAndInitJByteArray(&tempIV[0], tempIV.Length());
+  auto keyId = CreateAndInitJByteArray(&cryptoObj.mKeyId[0], cryptoObj.mKeyId.Length());
+  cryptoInfo->Set(numSubSamples,
+                  numBytesOfPlainData,
+                  numBytesOfEncryptedData,
+                  keyId,
+                  iv,
+                  MediaCodec::CRYPTO_MODE_AES_CTR);
+
+  return cryptoInfo;
+}
+
 bool
 AndroidDecoderModule::SupportsMimeType(const nsACString& aMimeType,
                                        DecoderDoctorDiagnostics* aDiagnostics) const
 {
   if (!AndroidBridge::Bridge() ||
       AndroidBridge::Bridge()->GetAPIVersion() < 16) {
     return false;
   }
--- a/dom/media/platforms/android/MediaCodecDataDecoder.cpp
+++ b/dom/media/platforms/android/MediaCodecDataDecoder.cpp
@@ -389,18 +389,25 @@ MediaCodecDataDecoder::QueueSample(const
   void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
 
   MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >=
              aSample->Size(),
              "Decoder buffer is not large enough for sample");
 
   PodCopy(static_cast<uint8_t*>(directBuffer), aSample->Data(), aSample->Size());
 
-  res = mDecoder->QueueInputBuffer(inputIndex, 0, aSample->Size(),
-                                   aSample->mTime, 0);
+  CryptoInfo::LocalRef cryptoInfo = GetCryptoInfoFromSample(aSample);
+  if (cryptoInfo) {
+    res = mDecoder->QueueSecureInputBuffer(inputIndex, 0, cryptoInfo,
+                                           aSample->mTime, 0);
+  } else {
+    res = mDecoder->QueueInputBuffer(inputIndex, 0, aSample->Size(),
+                                     aSample->mTime, 0);
+  }
+
   if (NS_FAILED(res)) {
     return res;
   }
 
   mDurations.push_back(TimeUnit::FromMicroseconds(aSample->mDuration));
   return NS_OK;
 }
 
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -436,17 +436,17 @@ RemoteDataDecoder::Flush()
 void
 RemoteDataDecoder::Drain()
 {
   BufferInfo::LocalRef bufferInfo;
   nsresult rv = BufferInfo::New(&bufferInfo);
   NS_ENSURE_SUCCESS_VOID(rv);
   bufferInfo->Set(0, 0, -1, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
 
-  mJavaDecoder->Input(nullptr, bufferInfo);
+  mJavaDecoder->Input(nullptr, bufferInfo, nullptr);
 }
 
 void
 RemoteDataDecoder::Shutdown()
 {
   LOG("");
   MOZ_ASSERT(mJavaDecoder && mJavaCallbacks);
 
@@ -477,12 +477,12 @@ RemoteDataDecoder::Input(MediaRawData* a
   BufferInfo::LocalRef bufferInfo;
   nsresult rv = BufferInfo::New(&bufferInfo);
   if (NS_FAILED(rv)) {
     mCallback->Error(MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__));
     return;
   }
   bufferInfo->Set(0, aSample->Size(), aSample->mTime, 0);
 
-  mJavaDecoder->Input(bytes, bufferInfo);
+  mJavaDecoder->Input(bytes, bufferInfo, GetCryptoInfoFromSample(aSample));
 }
 
 } // mozilla