Merge "Information required to decrypt buffers is now packaged into MediaCodec.CryptoInfo"
This commit is contained in:
committed by
Android (Google) Code Review
commit
142095f75a
@@ -10960,7 +10960,7 @@ package android.media {
|
||||
method public java.nio.ByteBuffer[] getOutputBuffers();
|
||||
method public final java.util.Map<java.lang.String, java.lang.Object> getOutputFormat();
|
||||
method public final void queueInputBuffer(int, int, int, long, int);
|
||||
method public final void queueSecureInputBuffer(int, int, int[], int[], int, byte[], byte[], int, long, int);
|
||||
method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int);
|
||||
method public final void release();
|
||||
method public final void releaseOutputBuffer(int, boolean);
|
||||
method public final void start();
|
||||
@@ -10985,6 +10985,17 @@ package android.media {
|
||||
field public int size;
|
||||
}
|
||||
|
||||
public static final class MediaCodec.CryptoInfo {
|
||||
ctor public MediaCodec.CryptoInfo();
|
||||
method public void set(int, int[], int[], byte[], byte[], int);
|
||||
field public byte[] iv;
|
||||
field public byte[] key;
|
||||
field public int mode;
|
||||
field public int[] numBytesOfClearData;
|
||||
field public int[] numBytesOfEncryptedData;
|
||||
field public int numSubSamples;
|
||||
}
|
||||
|
||||
public final class MediaCodecList {
|
||||
method public static final int countCodecs();
|
||||
method public static final android.media.MediaCodecList.CodecCapabilities getCodecCapabilities(int, java.lang.String);
|
||||
@@ -11016,6 +11027,7 @@ package android.media {
|
||||
ctor public MediaExtractor();
|
||||
method public boolean advance();
|
||||
method public int countTracks();
|
||||
method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
|
||||
method public int getSampleFlags();
|
||||
method public long getSampleTime();
|
||||
method public int getSampleTrackIndex();
|
||||
|
||||
@@ -309,36 +309,57 @@ final public class MediaCodec {
|
||||
int index,
|
||||
int offset, int size, long presentationTimeUs, int flags);
|
||||
|
||||
/** Metadata describing the structure of a (at least partially) encrypted
|
||||
* input sample.
|
||||
* A buffer's data is considered to be partitioned into "subSamples",
|
||||
* each subSample starts with a (potentially empty) run of plain,
|
||||
* unencrypted bytes followed by a (also potentially empty) run of
|
||||
* encrypted bytes.
|
||||
* numBytesOfClearData can be null to indicate that all data is encrypted.
|
||||
*/
|
||||
public final static class CryptoInfo {
|
||||
public void set(
|
||||
int newNumSubSamples,
|
||||
int[] newNumBytesOfClearData,
|
||||
int[] newNumBytesOfEncryptedData,
|
||||
byte[] newKey,
|
||||
byte[] newIV,
|
||||
int newMode) {
|
||||
numSubSamples = newNumSubSamples;
|
||||
numBytesOfClearData = newNumBytesOfClearData;
|
||||
numBytesOfEncryptedData = newNumBytesOfEncryptedData;
|
||||
key = newKey;
|
||||
iv = newIV;
|
||||
mode = newMode;
|
||||
}
|
||||
|
||||
/** The number of subSamples that make up the buffer's contents. */
|
||||
public int numSubSamples;
|
||||
/** The number of leading unencrypted bytes in each subSample. */
|
||||
public int[] numBytesOfClearData;
|
||||
/** The number of trailing encrypted bytes in each subSample. */
|
||||
public int[] numBytesOfEncryptedData;
|
||||
/** A 16-byte opaque key */
|
||||
public byte[] key;
|
||||
/** A 16-byte initialization vector */
|
||||
public byte[] iv;
|
||||
/** The type of encryption that has been applied */
|
||||
public int mode;
|
||||
};
|
||||
|
||||
/** Similar to {@link #queueInputBuffer} but submits a buffer that is
|
||||
* potentially encrypted. The buffer's data is considered to be
|
||||
* partitioned into "subSamples", each subSample starts with a
|
||||
* (potentially empty) run of plain, unencrypted bytes followed
|
||||
* by a (also potentially empty) run of encrypted bytes.
|
||||
* potentially encrypted.
|
||||
* @param index The index of a client-owned input buffer previously returned
|
||||
* in a call to {@link #dequeueInputBuffer}.
|
||||
* @param offset The byte offset into the input buffer at which the data starts.
|
||||
* @param numBytesOfClearData The number of leading unencrypted bytes in
|
||||
* each subSample.
|
||||
* @param numBytesOfEncryptedData The number of trailing encrypted bytes
|
||||
* in each subSample.
|
||||
* @param numSubSamples The number of subSamples that make up the
|
||||
* buffer's contents.
|
||||
* @param key A 16-byte opaque key
|
||||
* @param iv A 16-byte initialization vector
|
||||
* @param mode The type of encryption that has been applied
|
||||
*
|
||||
* Either numBytesOfClearData or numBytesOfEncryptedData (but not both)
|
||||
* can be null to indicate that all respective sizes are 0.
|
||||
* @param presentationTimeUs The time at which this buffer should be rendered.
|
||||
* @param flags A bitmask of flags {@link #FLAG_SYNCFRAME},
|
||||
* {@link #FLAG_CODECCONFIG} or {@link #FLAG_EOS}.
|
||||
*/
|
||||
public native final void queueSecureInputBuffer(
|
||||
int index,
|
||||
int offset,
|
||||
int[] numBytesOfClearData,
|
||||
int[] numBytesOfEncryptedData,
|
||||
int numSubSamples,
|
||||
byte[] key,
|
||||
byte[] iv,
|
||||
int mode,
|
||||
CryptoInfo info,
|
||||
long presentationTimeUs,
|
||||
int flags);
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.media;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.media.MediaCodec;
|
||||
import android.net.Uri;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
@@ -235,6 +236,15 @@ final public class MediaExtractor {
|
||||
/** Returns the current sample's flags. */
|
||||
public native int getSampleFlags();
|
||||
|
||||
/** If the sample flags indicate that the current sample is at least
|
||||
* partially encrypted, this call returns relevant information about
|
||||
* the structure of the sample data required for decryption.
|
||||
* @param info The android.media.MediaCodec.CryptoInfo structure
|
||||
* to be filled in.
|
||||
* @return true iff the sample flags contain {@link #SAMPLE_FLAG_ENCRYPTED}
|
||||
*/
|
||||
public native boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info);
|
||||
|
||||
private static native final void native_init();
|
||||
private native final void native_setup();
|
||||
private native final void native_finalize();
|
||||
|
||||
@@ -49,6 +49,13 @@ enum {
|
||||
|
||||
struct fields_t {
|
||||
jfieldID context;
|
||||
|
||||
jfieldID cryptoInfoNumSubSamplesID;
|
||||
jfieldID cryptoInfoNumBytesOfClearDataID;
|
||||
jfieldID cryptoInfoNumBytesOfEncryptedDataID;
|
||||
jfieldID cryptoInfoKeyID;
|
||||
jfieldID cryptoInfoIVID;
|
||||
jfieldID cryptoInfoModeID;
|
||||
};
|
||||
|
||||
static fields_t gFields;
|
||||
@@ -387,12 +394,7 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
|
||||
jobject thiz,
|
||||
jint index,
|
||||
jint offset,
|
||||
jintArray numBytesOfClearDataObj,
|
||||
jintArray numBytesOfEncryptedDataObj,
|
||||
jint numSubSamples,
|
||||
jbyteArray keyObj,
|
||||
jbyteArray ivObj,
|
||||
jint mode,
|
||||
jobject cryptoInfoObj,
|
||||
jlong timestampUs,
|
||||
jint flags) {
|
||||
ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
|
||||
@@ -404,6 +406,25 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
|
||||
return;
|
||||
}
|
||||
|
||||
jint numSubSamples =
|
||||
env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
|
||||
|
||||
jintArray numBytesOfClearDataObj =
|
||||
(jintArray)env->GetObjectField(
|
||||
cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
|
||||
|
||||
jintArray numBytesOfEncryptedDataObj =
|
||||
(jintArray)env->GetObjectField(
|
||||
cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
|
||||
|
||||
jbyteArray keyObj =
|
||||
(jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
|
||||
|
||||
jbyteArray ivObj =
|
||||
(jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
|
||||
|
||||
jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
|
||||
|
||||
status_t err = OK;
|
||||
|
||||
CryptoPlugin::SubSample *subSamples = NULL;
|
||||
@@ -612,6 +633,30 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
|
||||
|
||||
gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
|
||||
CHECK(gFields.context != NULL);
|
||||
|
||||
clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
|
||||
CHECK(clazz != NULL);
|
||||
|
||||
gFields.cryptoInfoNumSubSamplesID =
|
||||
env->GetFieldID(clazz, "numSubSamples", "I");
|
||||
CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
|
||||
|
||||
gFields.cryptoInfoNumBytesOfClearDataID =
|
||||
env->GetFieldID(clazz, "numBytesOfClearData", "[I");
|
||||
CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
|
||||
|
||||
gFields.cryptoInfoNumBytesOfEncryptedDataID =
|
||||
env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I");
|
||||
CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
|
||||
|
||||
gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B");
|
||||
CHECK(gFields.cryptoInfoKeyID != NULL);
|
||||
|
||||
gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B");
|
||||
CHECK(gFields.cryptoInfoIVID != NULL);
|
||||
|
||||
gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I");
|
||||
CHECK(gFields.cryptoInfoModeID != NULL);
|
||||
}
|
||||
|
||||
static void android_media_MediaCodec_native_setup(
|
||||
@@ -666,7 +711,7 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "queueInputBuffer", "(IIIJI)V",
|
||||
(void *)android_media_MediaCodec_queueInputBuffer },
|
||||
|
||||
{ "queueSecureInputBuffer", "(II[I[II[B[BIJI)V",
|
||||
{ "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
|
||||
(void *)android_media_MediaCodec_queueSecureInputBuffer },
|
||||
|
||||
{ "dequeueInputBuffer", "(J)I",
|
||||
|
||||
@@ -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::getSampleTime(int64_t *sampleTimeUs) {
|
||||
}
|
||||
|
||||
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 @@ static jint android_media_MediaExtractor_getSampleFlags(
|
||||
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 @@ static void android_media_MediaExtractor_native_init(JNIEnv *env) {
|
||||
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 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "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",
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
struct MetaData;
|
||||
struct NuMediaExtractor;
|
||||
|
||||
struct JMediaExtractor : public RefBase {
|
||||
@@ -50,6 +51,7 @@ struct JMediaExtractor : public RefBase {
|
||||
status_t getSampleTrackIndex(size_t *trackIndex);
|
||||
status_t getSampleTime(int64_t *sampleTimeUs);
|
||||
status_t getSampleFlags(uint32_t *sampleFlags);
|
||||
status_t getSampleMeta(sp<MetaData> *sampleMeta);
|
||||
|
||||
protected:
|
||||
virtual ~JMediaExtractor();
|
||||
|
||||
Reference in New Issue
Block a user