Bug 1302331 - [Part3] Create CryptoInfo from MediaRawData and deliver it to MediaCodecDataDecoder or remote codec decoder.
MozReview-Commit-ID: 9pHHrhQPs9m
--- 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