Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3bd2429 authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "New JAVA API to support submitting encrypted buffers of input data."

parents 85d9e020 9e6bcce1
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -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
+137 −0
Original line number Diff line number Diff line
@@ -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 },

+12 −0
Original line number Diff line number Diff line
@@ -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(