Information required to decrypt buffers is now packaged into MediaCodec.CryptoInfo
New API on MediaExtractor to retrieve a CryptoInfo structure where applicable.
Change-Id: I18edfc9ac56a4544c8f17cba24401b96dacbff7d
related-to-bug: 6275919
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index e2cdbca..adf0e66 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -30,12 +30,15 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
#include <media/stagefright/NuMediaExtractor.h>
namespace android {
struct fields_t {
jfieldID context;
+
+ jmethodID cryptoInfoSetID;
};
static fields_t gFields;
@@ -166,7 +169,32 @@
}
status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
- return mImpl->getSampleFlags(sampleFlags);
+ *sampleFlags = 0;
+
+ sp<MetaData> meta;
+ status_t err = mImpl->getSampleMeta(&meta);
+
+ if (err != OK) {
+ return err;
+ }
+
+ int32_t val;
+ if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
+ (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC;
+ }
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED;
+ }
+
+ return OK;
+}
+
+status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
+ return mImpl->getSampleMeta(sampleMeta);
}
} // namespace android
@@ -369,6 +397,110 @@
return sampleFlags;
}
+static jboolean android_media_MediaExtractor_getSampleCryptoInfo(
+ JNIEnv *env, jobject thiz, jobject cryptoInfoObj) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return -1ll;
+ }
+
+ sp<MetaData> meta;
+ status_t err = extractor->getSampleMeta(&meta);
+
+ if (err != OK) {
+ return false;
+ }
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ return false;
+ }
+
+ size_t numSubSamples = size / sizeof(size_t);
+
+ if (numSubSamples == 0) {
+ return false;
+ }
+
+ jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples);
+ jboolean isCopy;
+ jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ dst[i] = ((const size_t *)data)[i];
+ }
+ env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0);
+ dst = NULL;
+
+ size_t encSize = size;
+ jintArray numBytesOfPlainDataObj = NULL;
+ if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ if (size != encSize) {
+ // The two must be of the same length.
+ return false;
+ }
+
+ numBytesOfPlainDataObj = env->NewIntArray(numSubSamples);
+ jboolean isCopy;
+ jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy);
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ dst[i] = ((const size_t *)data)[i];
+ }
+ env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0);
+ dst = NULL;
+ }
+
+ jbyteArray keyObj = NULL;
+ if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
+ if (size != 16) {
+ // Keys must be 16 bytes in length.
+ return false;
+ }
+
+ keyObj = env->NewByteArray(size);
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy);
+ memcpy(dst, data, size);
+ env->ReleaseByteArrayElements(keyObj, dst, 0);
+ dst = NULL;
+ }
+
+ jbyteArray ivObj = NULL;
+ if (meta->findData(kKeyCryptoIV, &type, &data, &size)) {
+ if (size != 16) {
+ // IVs must be 16 bytes in length.
+ return false;
+ }
+
+ ivObj = env->NewByteArray(size);
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy);
+ memcpy(dst, data, size);
+ env->ReleaseByteArrayElements(ivObj, dst, 0);
+ dst = NULL;
+ }
+
+ int32_t mode;
+ if (!meta->findInt32(kKeyCryptoMode, &mode)) {
+ mode = 0;
+ }
+
+ env->CallVoidMethod(
+ cryptoInfoObj,
+ gFields.cryptoInfoSetID,
+ numSubSamples,
+ numBytesOfPlainDataObj,
+ numBytesOfEncryptedDataObj,
+ keyObj,
+ ivObj,
+ mode);
+
+ return true;
+}
+
static void android_media_MediaExtractor_native_init(JNIEnv *env) {
jclass clazz = env->FindClass("android/media/MediaExtractor");
CHECK(clazz != NULL);
@@ -376,6 +508,12 @@
gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
CHECK(gFields.context != NULL);
+ clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
+ CHECK(clazz != NULL);
+
+ gFields.cryptoInfoSetID =
+ env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
+
DataSource::RegisterDefaultSniffers();
}
@@ -485,6 +623,9 @@
{ "getSampleFlags", "()I",
(void *)android_media_MediaExtractor_getSampleFlags },
+ { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z",
+ (void *)android_media_MediaExtractor_getSampleCryptoInfo },
+
{ "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
{ "native_setup", "()V",