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

Commit bfc56f49 authored by Andreas Huber's avatar Andreas Huber
Browse files

DRM errors signaled by the CryptoPlugin are now visible to MediaCodec clients

through a custom exception "MediaCodec.CryptoException".

Change-Id: I30215e9e13bab68abad23e27dcead7c1accd07f1
related-to-bug: 6365261
parent 5cef554c
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -10972,8 +10972,8 @@ package android.media {
    method public java.nio.ByteBuffer[] getInputBuffers();
    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, android.media.MediaCodec.CryptoInfo, long, int);
    method public final void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
    method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
    method public final void release();
    method public final void releaseOutputBuffer(int, boolean);
    method public final void start();
@@ -10998,6 +10998,11 @@ package android.media {
    field public int size;
  }
  public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
    ctor public MediaCodec.CryptoException(int, java.lang.String);
    method public int getErrorCode();
  }
  public static final class MediaCodec.CryptoInfo {
    ctor public MediaCodec.CryptoInfo();
    method public void set(int, int[], int[], byte[], byte[], int);
+18 −2
Original line number Diff line number Diff line
@@ -280,6 +280,19 @@ final public class MediaCodec {
    */
    public native final void flush();

    public final static class CryptoException extends RuntimeException {
        public CryptoException(int errorCode, String detailMessage) {
            super(detailMessage);
            mErrorCode = errorCode;
        }

        public int getErrorCode() {
            return mErrorCode;
        }

        private int mErrorCode;
    }

    /** After filling a range of the input buffer at the specified index
     *  submit it to the component.
     *
@@ -304,10 +317,13 @@ final public class MediaCodec {
     *  @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}.
     *  @throws CryptoException if a crypto object has been specified in
     *          {@link #configure}
    */
    public native final void queueInputBuffer(
            int index,
            int offset, int size, long presentationTimeUs, int flags);
            int offset, int size, long presentationTimeUs, int flags)
        throws CryptoException;

    /** Metadata describing the structure of a (at least partially) encrypted
     *  input sample.
@@ -361,7 +377,7 @@ final public class MediaCodec {
            int offset,
            CryptoInfo info,
            long presentationTimeUs,
            int flags);
            int flags) throws CryptoException;

    /** Returns the index of an input buffer to be filled with valid data
     *  or -1 if no such buffer is currently available.
+45 −9
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/MediaErrors.h>

namespace android {
@@ -129,8 +130,10 @@ status_t JMediaCodec::flush() {

status_t JMediaCodec::queueInputBuffer(
        size_t index,
        size_t offset, size_t size, int64_t timeUs, uint32_t flags) {
    return mCodec->queueInputBuffer(index, offset, size, timeUs, flags);
        size_t offset, size_t size, int64_t timeUs, uint32_t flags,
        AString *errorDetailMsg) {
    return mCodec->queueInputBuffer(
            index, offset, size, timeUs, flags, errorDetailMsg);
}

status_t JMediaCodec::queueSecureInputBuffer(
@@ -142,10 +145,11 @@ status_t JMediaCodec::queueSecureInputBuffer(
        const uint8_t iv[16],
        CryptoPlugin::Mode mode,
        int64_t presentationTimeUs,
        uint32_t flags) {
        uint32_t flags,
        AString *errorDetailMsg) {
    return mCodec->queueSecureInputBuffer(
            index, offset, subSamples, numSubSamples, key, iv, mode,
            presentationTimeUs, flags);
            presentationTimeUs, flags, errorDetailMsg);
}

status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -251,7 +255,31 @@ static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
    setMediaCodec(env, thiz, NULL);
}

static jint throwExceptionAsNecessary(JNIEnv *env, status_t err) {
static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
    jclass clazz = env->FindClass("android/media/MediaCodec$CryptoException");
    CHECK(clazz != NULL);

    jmethodID constructID =
        env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;)V");
    CHECK(constructID != NULL);

    jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");

    jthrowable exception =
        (jthrowable)env->NewObject(clazz, constructID, err, msgObj);

    env->Throw(exception);
}

static jint throwExceptionAsNecessary(
        JNIEnv *env, status_t err, const char *msg = NULL) {
    if (err >= ERROR_DRM_WV_VENDOR_MIN && err <= ERROR_DRM_WV_VENDOR_MAX) {
        // We'll throw our custom MediaCodec.CryptoException

        throwCryptoException(env, err, msg);
        return 0;
    }

    switch (err) {
        case OK:
            return 0;
@@ -383,10 +411,13 @@ static void android_media_MediaCodec_queueInputBuffer(
        return;
    }

    AString errorDetailMsg;

    status_t err = codec->queueInputBuffer(
            index, offset, size, timestampUs, flags);
            index, offset, size, timestampUs, flags, &errorDetailMsg);

    throwExceptionAsNecessary(env, err);
    throwExceptionAsNecessary(
            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
}

static void android_media_MediaCodec_queueSecureInputBuffer(
@@ -497,13 +528,17 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
        }
    }

    AString errorDetailMsg;

    if (err == OK) {
        err = codec->queueSecureInputBuffer(
                index, offset,
                subSamples, numSubSamples,
                (const uint8_t *)key, (const uint8_t *)iv,
                (CryptoPlugin::Mode)mode,
                timestampUs, flags);
                timestampUs,
                flags,
                &errorDetailMsg);
    }

    if (iv != NULL) {
@@ -519,7 +554,8 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
    delete[] subSamples;
    subSamples = NULL;

    throwExceptionAsNecessary(env, err);
    throwExceptionAsNecessary(
            env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
}

static jint android_media_MediaCodec_dequeueInputBuffer(
+5 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ namespace android {

struct ALooper;
struct AMessage;
struct AString;
struct ICrypto;
struct ISurfaceTexture;
struct MediaCodec;
@@ -52,7 +53,8 @@ struct JMediaCodec : public RefBase {

    status_t queueInputBuffer(
            size_t index,
            size_t offset, size_t size, int64_t timeUs, uint32_t flags);
            size_t offset, size_t size, int64_t timeUs, uint32_t flags,
            AString *errorDetailMsg);

    status_t queueSecureInputBuffer(
            size_t index,
@@ -63,7 +65,8 @@ struct JMediaCodec : public RefBase {
            const uint8_t iv[16],
            CryptoPlugin::Mode mode,
            int64_t presentationTimeUs,
            uint32_t flags);
            uint32_t flags,
            AString *errorDetailMsg);

    status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs);