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

Commit 4ca49095 authored by Arun Johnson's avatar Arun Johnson
Browse files

Add API queueSecureInputBuffers for large audio frames

Bug: 298052174
API-Coverage-Bug: 309692716
Change-Id: I9c086d5bbb8fcaf79de211b8630ac0f49e6157cd
parent dbced385
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -22575,6 +22575,7 @@ package android.media {
    method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
    method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueSecureInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
    method public void release();
    method public void releaseOutputBuffer(int, boolean);
    method public void releaseOutputBuffer(int, long);
+50 −0
Original line number Diff line number Diff line
@@ -3210,6 +3210,51 @@ final public class MediaCodec {
        }
    }

    /**
     * Similar to {@link #queueInputBuffers queueInputBuffers} but submits multiple access units
     * in a buffer that is potentially encrypted.
     * <strong>Check out further notes at {@link #queueInputBuffers queueInputBuffers}.</strong>
     *
     * @param index The index of a client-owned input buffer previously returned
     *              in a call to {@link #dequeueInputBuffer}.
     * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
     *                    contents in the buffer. The ArrayDeque and the BufferInfo objects provided
     *                    can be recycled by the caller for re-use.
     * @param cryptoInfos ArrayDeque of {@link MediaCodec.CryptoInfo} objects to facilitate the
     *                    decryption of the contents. The ArrayDeque and the CryptoInfo objects
     *                    provided can be reused immediately after the call returns. These objects
     *                    should correspond to bufferInfo objects to ensure correct decryption.
     * @throws IllegalStateException if not in the Executing state or not in asynchronous mode.
     * @throws MediaCodec.CodecException upon codec error.
     * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
     *                    access units are not contiguous.
     * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
     *              An error code associated with the exception helps identify the
     *              reason for the failure.
     */
    @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
    public final void queueSecureInputBuffers(
            int index,
            @NonNull ArrayDeque<BufferInfo> bufferInfos,
            @NonNull ArrayDeque<CryptoInfo> cryptoInfos) {
        synchronized(mBufferLock) {
            if (mBufferMode == BUFFER_MODE_BLOCK) {
                throw new IncompatibleWithBlockModelException("queueSecureInputBuffers() "
                        + "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
                        + "Please use getQueueRequest() to queue buffers");
            }
            invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
            mDequeuedInputBuffers.remove(index);
        }
        try {
            native_queueSecureInputBuffers(
                    index, bufferInfos.toArray(), cryptoInfos.toArray());
        } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
            revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
            throw e;
        }
    }

    private native final void native_queueSecureInputBuffer(
            int index,
            int offset,
@@ -3217,6 +3262,11 @@ final public class MediaCodec {
            long presentationTimeUs,
            int flags) throws CryptoException;

    private native final void native_queueSecureInputBuffers(
            int index,
            @NonNull Object[] bufferInfos,
            @NonNull Object[] cryptoInfos) throws CryptoException, CodecException;

    /**
     * Returns the index of an input buffer to be filled with valid data
     * or -1 if no such buffer is currently available.
+171 −2
Original line number Diff line number Diff line
@@ -458,6 +458,24 @@ status_t JMediaCodec::queueSecureInputBuffer(
            presentationTimeUs, flags, errorDetailMsg);
}

status_t JMediaCodec::queueSecureInputBuffers(
        size_t index,
        size_t offset,
        size_t size,
        const sp<RefBase> &auInfos_,
        const sp<RefBase> &cryptoInfos_,
        AString *errorDetailMsg) {
    sp<BufferInfosWrapper> auInfos((BufferInfosWrapper *)auInfos_.get());
    sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
    return mCodec->queueSecureInputBuffers(
            index,
            offset,
            size,
            auInfos,
            cryptoInfos,
            errorDetailMsg);
}

status_t JMediaCodec::queueBuffer(
        size_t index, const std::shared_ptr<C2Buffer> &buffer,
        const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
@@ -2262,6 +2280,61 @@ struct NativeCryptoInfo {
    CryptoPlugin::Pattern mPattern;
};

// This class takes away all dependencies on java(env and jni) and
// could be used for taking cryptoInfo objects to MediaCodec.
struct MediaCodecCryptoInfo: public CodecCryptoInfo {
    explicit MediaCodecCryptoInfo(const NativeCryptoInfo &cryptoInfo) {
        if (cryptoInfo.mErr == OK) {
            mNumSubSamples = cryptoInfo.mNumSubSamples;
            mMode = cryptoInfo.mMode;
            mPattern = cryptoInfo.mPattern;
            if (cryptoInfo.mKey != nullptr) {
                mKeyBuffer = ABuffer::CreateAsCopy(cryptoInfo.mKey, 16);
                mKey = (uint8_t*)(mKeyBuffer.get() != nullptr ? mKeyBuffer.get()->data() : nullptr);
            }
            if (cryptoInfo.mIv != nullptr) {
               mIvBuffer = ABuffer::CreateAsCopy(cryptoInfo.mIv, 16);
               mIv = (uint8_t*)(mIvBuffer.get() != nullptr ? mIvBuffer.get()->data() : nullptr);
            }
            if (cryptoInfo.mSubSamples != nullptr) {
                mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * mNumSubSamples);
                if (mSubSamplesBuffer.get()) {
                    CryptoPlugin::SubSample * samples =
                            (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
                    for (int s = 0 ; s < mNumSubSamples ; s++) {
                        samples[s].mNumBytesOfClearData =
                                cryptoInfo.mSubSamples[s].mNumBytesOfClearData;
                        samples[s].mNumBytesOfEncryptedData =
                                cryptoInfo.mSubSamples[s].mNumBytesOfEncryptedData;
                    }
                    mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
                }
            }

        }
    }

    explicit MediaCodecCryptoInfo(jint size) {
        mSubSamplesBuffer = new ABuffer(sizeof(CryptoPlugin::SubSample) * 1);
        mNumSubSamples = 1;
        if (mSubSamplesBuffer.get()) {
            CryptoPlugin::SubSample * samples =
                    (CryptoPlugin::SubSample *)(mSubSamplesBuffer.get()->data());
            samples[0].mNumBytesOfClearData = size;
            samples[0].mNumBytesOfEncryptedData = 0;
            mSubSamples = (CryptoPlugin::SubSample *)mSubSamplesBuffer.get()->data();
        }
    }
    ~MediaCodecCryptoInfo() {}

protected:
    // all backup buffers for the base object.
    sp<ABuffer> mKeyBuffer;
    sp<ABuffer> mIvBuffer;
    sp<ABuffer> mSubSamplesBuffer;

};

static void android_media_MediaCodec_queueSecureInputBuffer(
        JNIEnv *env,
        jobject thiz,
@@ -2430,6 +2503,99 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
}

static status_t extractCryptoInfosFromObjectArray(JNIEnv * const env,
        jint * const totalSize,
        std::vector<std::unique_ptr<CodecCryptoInfo>> * const cryptoInfoObjs,
        const jobjectArray &objArray,
        AString * const errorDetailMsg) {
    if (env == nullptr
            || cryptoInfoObjs == nullptr
            || totalSize == nullptr) {
        if (errorDetailMsg) {
            *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
        }
        return BAD_VALUE;
    }
    const jsize numEntries = env->GetArrayLength(objArray);
    if (numEntries <= 0) {
        if (errorDetailMsg) {
            *errorDetailMsg = "Error: No CryptoInfo found while queuing for large frame input";
        }
        return BAD_VALUE;
    }
    cryptoInfoObjs->clear();
    *totalSize = 0;
    jint size = 0;
    for (jsize i = 0; i < numEntries ; i++) {
        jobject param = env->GetObjectArrayElement(objArray, i);
        if (param == NULL) {
            if (errorDetailMsg) {
                *errorDetailMsg = "Error: Null Parameters provided for extracting CryptoInfo";
            }
            return BAD_VALUE;
        }
        NativeCryptoInfo nativeInfo(env, param);
        std::unique_ptr<CodecCryptoInfo> info(new MediaCodecCryptoInfo(nativeInfo));
        for (int i = 0; i < info->mNumSubSamples; i++) {
            size += info->mSubSamples[i].mNumBytesOfClearData;
            size += info->mSubSamples[i].mNumBytesOfEncryptedData;
        }
        cryptoInfoObjs->push_back(std::move(info));
    }
    *totalSize = size;
    return OK;
}


static void android_media_MediaCodec_queueSecureInputBuffers(
        JNIEnv *env,
        jobject thiz,
        jint index,
        jobjectArray bufferInfosObjs,
        jobjectArray cryptoInfoObjs) {
    ALOGV("android_media_MediaCodec_queueSecureInputBuffers");

    sp<JMediaCodec> codec = getMediaCodec(env, thiz);

    if (codec == NULL || codec->initCheck() != OK) {
        throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
        return;
    }
    sp<BufferInfosWrapper> auInfos =
            new BufferInfosWrapper{decltype(auInfos->value)()};
    sp<CryptoInfosWrapper> cryptoInfos =
        new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
    AString errorDetailMsg;
    jint initialOffset = 0;
    jint totalSize = 0;
    status_t err = extractInfosFromObject(
            env,
            &initialOffset,
            &totalSize,
            &auInfos->value,
            bufferInfosObjs,
            &errorDetailMsg);
    if (err == OK) {
        err = extractCryptoInfosFromObjectArray(env,
            &totalSize,
            &cryptoInfos->value,
            cryptoInfoObjs,
            &errorDetailMsg);
    }
    if (err == OK) {
        err = codec->queueSecureInputBuffers(
                index,
                initialOffset,
                totalSize,
                auInfos,
                cryptoInfos,
                &errorDetailMsg);
    }
    throwExceptionAsNecessary(
            env, err, ACTION_CODE_FATAL,
            codec->getExceptionMessage(errorDetailMsg.c_str()).c_str(), codec->getCrypto());
}

static jobject android_media_MediaCodec_mapHardwareBuffer(JNIEnv *env, jclass, jobject bufferObj) {
    ALOGV("android_media_MediaCodec_mapHardwareBuffer");
    AHardwareBuffer *hardwareBuffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(
@@ -2780,8 +2946,8 @@ static void android_media_MediaCodec_native_queueLinearBlock(
                "error occurred while converting tunings from Java to native");
        return;
    }
    jint totalSize;
    jint initialOffset;
    jint totalSize = 0;
    jint initialOffset = 0;
    std::vector<AccessUnitInfo> infoVec;
    AString errorDetailMsg;
    err = extractInfosFromObject(env,
@@ -3950,6 +4116,9 @@ static const JNINativeMethod gMethods[] = {
    { "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
      (void *)android_media_MediaCodec_queueSecureInputBuffer },

    { "native_queueSecureInputBuffers", "(I[Ljava/lang/Object;[Ljava/lang/Object;)V",
      (void *)android_media_MediaCodec_queueSecureInputBuffers },

    { "native_mapHardwareBuffer",
      "(Landroid/hardware/HardwareBuffer;)Landroid/media/Image;",
      (void *)android_media_MediaCodec_mapHardwareBuffer },
+8 −0
Original line number Diff line number Diff line
@@ -114,6 +114,14 @@ struct JMediaCodec : public AHandler {
            uint32_t flags,
            AString *errorDetailMsg);

    status_t queueSecureInputBuffers(
            size_t index,
            size_t offset,
            size_t size,
            const sp<RefBase> &auInfos,
            const sp<RefBase> &cryptoInfos,
            AString *errorDetailMsg);

    status_t queueBuffer(
            size_t index, const std::shared_ptr<C2Buffer> &buffer,
            const sp<RefBase> &infos, const sp<AMessage> &tunings,