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

Commit 9e6bcce1 authored by Andreas Huber's avatar Andreas Huber
Browse files

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

Change-Id: Ib0df9a9427b4580946179860495b26f743558597
related-to-bug: 6275919
parent 335a6625
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(