Loading media/java/android/media/MediaCodec.java +37 −1 Original line number Diff line number Diff line Loading @@ -45,10 +45,16 @@ final public class MediaCodec { public int mFlags; }; // The follow flag constants MUST stay in sync with their equivalents // in MediaCodec.h ! public static int FLAG_SYNCFRAME = 1; public static int FLAG_CODECCONFIG = 2; public static int FLAG_EOS = 4; public static int FLAG_ENCRYPTED = 8; // The following mode constants MUST stay in sync with their equivalents // in media/hardware/CryptoAPI.h ! public static int MODE_UNENCRYPTED = 0; public static int MODE_AES_CTR = 1; /** Instantiate a codec component by mime type. For decoder components this is the mime type of media that this decoder should be able to Loading Loading @@ -176,6 +182,36 @@ final public class MediaCodec { int index, int offset, int size, long presentationTimeUs, int flags); /** 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. * @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. */ public native final void queueSecureInputBuffer( int index, int offset, int[] numBytesOfClearData, int[] numBytesOfEncryptedData, int numSubSamples, byte[] key, byte[] iv, int mode, long presentationTimeUs, int flags); // Returns the index of an input buffer to be filled with valid data // or -1 if no such buffer is currently available. // This method will return immediately if timeoutUs == 0, wait indefinitely Loading media/jni/android_media_MediaCodec.cpp +137 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,21 @@ status_t JMediaCodec::queueInputBuffer( return mCodec->queueInputBuffer(index, offset, size, timeUs, flags); } status_t JMediaCodec::queueSecureInputBuffer( size_t index, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, uint32_t flags) { return mCodec->queueSecureInputBuffer( index, offset, subSamples, numSubSamples, key, iv, mode, presentationTimeUs, flags); } status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { return mCodec->dequeueInputBuffer(index, timeoutUs); } Loading Loading @@ -367,6 +382,125 @@ static void android_media_MediaCodec_queueInputBuffer( throwExceptionAsNecessary(env, err); } static void android_media_MediaCodec_queueSecureInputBuffer( JNIEnv *env, jobject thiz, jint index, jint offset, jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj, jint numSubSamples, jbyteArray keyObj, jbyteArray ivObj, jint mode, jlong timestampUs, jint flags) { ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); sp<JMediaCodec> codec = getMediaCodec(env, thiz); if (codec == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } status_t err = OK; CryptoPlugin::SubSample *subSamples = NULL; jbyte *key = NULL; jbyte *iv = NULL; if (numSubSamples <= 0) { err = -EINVAL; } else if (numBytesOfClearDataObj == NULL && numBytesOfEncryptedDataObj == NULL) { err = -EINVAL; } else if (numBytesOfEncryptedDataObj != NULL && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { err = -ERANGE; } else if (numBytesOfClearDataObj != NULL && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { err = -ERANGE; } else { jboolean isCopy; jint *numBytesOfClearData = (numBytesOfClearDataObj == NULL) ? NULL : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); jint *numBytesOfEncryptedData = (numBytesOfEncryptedDataObj == NULL) ? NULL : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); subSamples = new CryptoPlugin::SubSample[numSubSamples]; for (jint i = 0; i < numSubSamples; ++i) { subSamples[i].mNumBytesOfClearData = (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; subSamples[i].mNumBytesOfEncryptedData = (numBytesOfEncryptedData == NULL) ? 0 : numBytesOfEncryptedData[i]; } if (numBytesOfEncryptedData != NULL) { env->ReleaseIntArrayElements( numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); numBytesOfEncryptedData = NULL; } if (numBytesOfClearData != NULL) { env->ReleaseIntArrayElements( numBytesOfClearDataObj, numBytesOfClearData, 0); numBytesOfClearData = NULL; } } if (err == OK && keyObj != NULL) { if (env->GetArrayLength(keyObj) != 16) { err = -EINVAL; } else { jboolean isCopy; key = env->GetByteArrayElements(keyObj, &isCopy); } } if (err == OK && ivObj != NULL) { if (env->GetArrayLength(ivObj) != 16) { err = -EINVAL; } else { jboolean isCopy; iv = env->GetByteArrayElements(ivObj, &isCopy); } } if (err == OK) { err = codec->queueSecureInputBuffer( index, offset, subSamples, numSubSamples, (const uint8_t *)key, (const uint8_t *)iv, (CryptoPlugin::Mode)mode, timestampUs, flags); } if (iv != NULL) { env->ReleaseByteArrayElements(ivObj, iv, 0); iv = NULL; } if (key != NULL) { env->ReleaseByteArrayElements(keyObj, key, 0); key = NULL; } delete[] subSamples; subSamples = NULL; throwExceptionAsNecessary(env, err); } static jint android_media_MediaCodec_dequeueInputBuffer( JNIEnv *env, jobject thiz, jlong timeoutUs) { ALOGV("android_media_MediaCodec_dequeueInputBuffer"); Loading Loading @@ -532,6 +666,9 @@ static JNINativeMethod gMethods[] = { { "queueInputBuffer", "(IIIJI)V", (void *)android_media_MediaCodec_queueInputBuffer }, { "queueSecureInputBuffer", "(II[I[II[B[BIJI)V", (void *)android_media_MediaCodec_queueSecureInputBuffer }, { "dequeueInputBuffer", "(J)I", (void *)android_media_MediaCodec_dequeueInputBuffer }, Loading media/jni/android_media_MediaCodec.h +12 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "jni.h" #include <media/hardware/CryptoAPI.h> #include <media/stagefright/foundation/ABase.h> #include <utils/Errors.h> #include <utils/RefBase.h> Loading Loading @@ -53,6 +54,17 @@ struct JMediaCodec : public RefBase { size_t index, size_t offset, size_t size, int64_t timeUs, uint32_t flags); status_t queueSecureInputBuffer( size_t index, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, uint32_t flags); status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs); status_t dequeueOutputBuffer( Loading Loading
media/java/android/media/MediaCodec.java +37 −1 Original line number Diff line number Diff line Loading @@ -45,10 +45,16 @@ final public class MediaCodec { public int mFlags; }; // The follow flag constants MUST stay in sync with their equivalents // in MediaCodec.h ! public static int FLAG_SYNCFRAME = 1; public static int FLAG_CODECCONFIG = 2; public static int FLAG_EOS = 4; public static int FLAG_ENCRYPTED = 8; // The following mode constants MUST stay in sync with their equivalents // in media/hardware/CryptoAPI.h ! public static int MODE_UNENCRYPTED = 0; public static int MODE_AES_CTR = 1; /** Instantiate a codec component by mime type. For decoder components this is the mime type of media that this decoder should be able to Loading Loading @@ -176,6 +182,36 @@ final public class MediaCodec { int index, int offset, int size, long presentationTimeUs, int flags); /** 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. * @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. */ public native final void queueSecureInputBuffer( int index, int offset, int[] numBytesOfClearData, int[] numBytesOfEncryptedData, int numSubSamples, byte[] key, byte[] iv, int mode, long presentationTimeUs, int flags); // Returns the index of an input buffer to be filled with valid data // or -1 if no such buffer is currently available. // This method will return immediately if timeoutUs == 0, wait indefinitely Loading
media/jni/android_media_MediaCodec.cpp +137 −0 Original line number Diff line number Diff line Loading @@ -126,6 +126,21 @@ status_t JMediaCodec::queueInputBuffer( return mCodec->queueInputBuffer(index, offset, size, timeUs, flags); } status_t JMediaCodec::queueSecureInputBuffer( size_t index, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, uint32_t flags) { return mCodec->queueSecureInputBuffer( index, offset, subSamples, numSubSamples, key, iv, mode, presentationTimeUs, flags); } status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) { return mCodec->dequeueInputBuffer(index, timeoutUs); } Loading Loading @@ -367,6 +382,125 @@ static void android_media_MediaCodec_queueInputBuffer( throwExceptionAsNecessary(env, err); } static void android_media_MediaCodec_queueSecureInputBuffer( JNIEnv *env, jobject thiz, jint index, jint offset, jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj, jint numSubSamples, jbyteArray keyObj, jbyteArray ivObj, jint mode, jlong timestampUs, jint flags) { ALOGV("android_media_MediaCodec_queueSecureInputBuffer"); sp<JMediaCodec> codec = getMediaCodec(env, thiz); if (codec == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return; } status_t err = OK; CryptoPlugin::SubSample *subSamples = NULL; jbyte *key = NULL; jbyte *iv = NULL; if (numSubSamples <= 0) { err = -EINVAL; } else if (numBytesOfClearDataObj == NULL && numBytesOfEncryptedDataObj == NULL) { err = -EINVAL; } else if (numBytesOfEncryptedDataObj != NULL && env->GetArrayLength(numBytesOfEncryptedDataObj) < numSubSamples) { err = -ERANGE; } else if (numBytesOfClearDataObj != NULL && env->GetArrayLength(numBytesOfClearDataObj) < numSubSamples) { err = -ERANGE; } else { jboolean isCopy; jint *numBytesOfClearData = (numBytesOfClearDataObj == NULL) ? NULL : env->GetIntArrayElements(numBytesOfClearDataObj, &isCopy); jint *numBytesOfEncryptedData = (numBytesOfEncryptedDataObj == NULL) ? NULL : env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy); subSamples = new CryptoPlugin::SubSample[numSubSamples]; for (jint i = 0; i < numSubSamples; ++i) { subSamples[i].mNumBytesOfClearData = (numBytesOfClearData == NULL) ? 0 : numBytesOfClearData[i]; subSamples[i].mNumBytesOfEncryptedData = (numBytesOfEncryptedData == NULL) ? 0 : numBytesOfEncryptedData[i]; } if (numBytesOfEncryptedData != NULL) { env->ReleaseIntArrayElements( numBytesOfEncryptedDataObj, numBytesOfEncryptedData, 0); numBytesOfEncryptedData = NULL; } if (numBytesOfClearData != NULL) { env->ReleaseIntArrayElements( numBytesOfClearDataObj, numBytesOfClearData, 0); numBytesOfClearData = NULL; } } if (err == OK && keyObj != NULL) { if (env->GetArrayLength(keyObj) != 16) { err = -EINVAL; } else { jboolean isCopy; key = env->GetByteArrayElements(keyObj, &isCopy); } } if (err == OK && ivObj != NULL) { if (env->GetArrayLength(ivObj) != 16) { err = -EINVAL; } else { jboolean isCopy; iv = env->GetByteArrayElements(ivObj, &isCopy); } } if (err == OK) { err = codec->queueSecureInputBuffer( index, offset, subSamples, numSubSamples, (const uint8_t *)key, (const uint8_t *)iv, (CryptoPlugin::Mode)mode, timestampUs, flags); } if (iv != NULL) { env->ReleaseByteArrayElements(ivObj, iv, 0); iv = NULL; } if (key != NULL) { env->ReleaseByteArrayElements(keyObj, key, 0); key = NULL; } delete[] subSamples; subSamples = NULL; throwExceptionAsNecessary(env, err); } static jint android_media_MediaCodec_dequeueInputBuffer( JNIEnv *env, jobject thiz, jlong timeoutUs) { ALOGV("android_media_MediaCodec_dequeueInputBuffer"); Loading Loading @@ -532,6 +666,9 @@ static JNINativeMethod gMethods[] = { { "queueInputBuffer", "(IIIJI)V", (void *)android_media_MediaCodec_queueInputBuffer }, { "queueSecureInputBuffer", "(II[I[II[B[BIJI)V", (void *)android_media_MediaCodec_queueSecureInputBuffer }, { "dequeueInputBuffer", "(J)I", (void *)android_media_MediaCodec_dequeueInputBuffer }, Loading
media/jni/android_media_MediaCodec.h +12 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include "jni.h" #include <media/hardware/CryptoAPI.h> #include <media/stagefright/foundation/ABase.h> #include <utils/Errors.h> #include <utils/RefBase.h> Loading Loading @@ -53,6 +54,17 @@ struct JMediaCodec : public RefBase { size_t index, size_t offset, size_t size, int64_t timeUs, uint32_t flags); status_t queueSecureInputBuffer( size_t index, size_t offset, const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode, int64_t presentationTimeUs, uint32_t flags); status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs); status_t dequeueOutputBuffer( Loading