diff options
| -rw-r--r-- | media/java/android/media/MediaCodec.java | 38 | ||||
| -rw-r--r-- | media/jni/android_media_MediaCodec.cpp | 137 | ||||
| -rw-r--r-- | media/jni/android_media_MediaCodec.h | 12 |
3 files changed, 186 insertions, 1 deletions
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 66cea9d4..410383d 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -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 @@ -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 diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 217216a..01d3833 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -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); } @@ -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"); @@ -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 }, diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 6bb4071..570c33b 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -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> @@ -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( |
