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

Commit 3a4be69c authored by Arun Johnson's avatar Arun Johnson Committed by Gerrit Code Review
Browse files

Merge changes from topic "largeAudioFrame" into main

* changes:
  Add API setMultiFrameEncryptedLinearBlock for BLOCK_MODEL
  Add API queueSecureInputBuffers for large audio frames
parents 7f0c8fef 677a881f
Loading
Loading
Loading
Loading
+2 −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);
@@ -22750,6 +22751,7 @@ package android.media {
    method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
    method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int);
    method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setMultiFrameEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>, @NonNull java.util.ArrayDeque<android.media.MediaCodec.CryptoInfo>);
    method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
    method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
  }
+95 −6
Original line number Diff line number Diff line
@@ -3212,6 +3212,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,
@@ -3219,6 +3264,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.
@@ -3464,7 +3514,7 @@ final public class MediaCodec {
            mLinearBlock = block;
            mOffset = offset;
            mSize = size;
            mCryptoInfo = null;
            mCryptoInfos.clear();
            return this;
        }

@@ -3498,7 +3548,44 @@ final public class MediaCodec {
            mLinearBlock = block;
            mOffset = offset;
            mSize = size;
            mCryptoInfo = cryptoInfo;
            mCryptoInfos.clear();
            mCryptoInfos.add(cryptoInfo);
            return this;
        }

        /**
         * Set an encrypted linear block to this queue request. Exactly one buffer must be
         * set for a queue request before calling {@link #queue}. The block can contain multiple
         * access units and if present should be laid out contiguously and without gaps.
         *
         * @param block The linear block object
         * @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} that describes the
         *                    structure of the encrypted input samples. The ArrayDeque and the
         *                    BufferInfo objects provided can be recycled by the caller for re-use.
         * @return this object
         * @throws IllegalStateException if a buffer is already set
         * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
         *                     access units are not contiguous.
         */
        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
        public @NonNull QueueRequest setMultiFrameEncryptedLinearBlock(
                @NonNull LinearBlock block,
                @NonNull ArrayDeque<MediaCodec.BufferInfo> bufferInfos,
                @NonNull ArrayDeque<MediaCodec.CryptoInfo> cryptoInfos) {
            if (!isAccessible()) {
                throw new IllegalStateException("The request is stale");
            }
            if (mLinearBlock != null || mHardwareBuffer != null) {
                throw new IllegalStateException("Cannot set block twice");
            }
            mLinearBlock = block;
            mBufferInfos.clear();
            mBufferInfos.addAll(bufferInfos);
            mCryptoInfos.clear();
            mCryptoInfos.addAll(cryptoInfos);
            return this;
        }

@@ -3708,8 +3795,10 @@ final public class MediaCodec {
                mBufferInfos.add(info);
            }
            if (mLinearBlock != null) {

                mCodec.native_queueLinearBlock(
                        mIndex, mLinearBlock, mCryptoInfo,
                        mIndex, mLinearBlock,
                        mCryptoInfos.isEmpty() ? null : mCryptoInfos.toArray(),
                        mBufferInfos.toArray(),
                        mTuningKeys, mTuningValues);
            } else if (mHardwareBuffer != null) {
@@ -3724,11 +3813,11 @@ final public class MediaCodec {
            mLinearBlock = null;
            mOffset = 0;
            mSize = 0;
            mCryptoInfo = null;
            mHardwareBuffer = null;
            mPresentationTimeUs = 0;
            mFlags = 0;
            mBufferInfos.clear();
            mCryptoInfos.clear();
            mTuningKeys.clear();
            mTuningValues.clear();
            return this;
@@ -3748,11 +3837,11 @@ final public class MediaCodec {
        private LinearBlock mLinearBlock = null;
        private int mOffset = 0;
        private int mSize = 0;
        private MediaCodec.CryptoInfo mCryptoInfo = null;
        private HardwareBuffer mHardwareBuffer = null;
        private long mPresentationTimeUs = 0;
        private @BufferFlag int mFlags = 0;
        private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
        private final ArrayDeque<CryptoInfo> mCryptoInfos = new ArrayDeque<>();
        private final ArrayList<String> mTuningKeys = new ArrayList<>();
        private final ArrayList<Object> mTuningValues = new ArrayList<>();

@@ -3762,7 +3851,7 @@ final public class MediaCodec {
    private native void native_queueLinearBlock(
            int index,
            @NonNull LinearBlock block,
            @Nullable CryptoInfo cryptoInfo,
            @Nullable Object[] cryptoInfos,
            @NonNull Object[] bufferInfos,
            @NonNull ArrayList<String> keys,
            @NonNull ArrayList<Object> values);
+193 −18
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) {
@@ -470,19 +488,16 @@ status_t JMediaCodec::queueEncryptedLinearBlock(
        size_t index,
        const sp<hardware::HidlMemory> &buffer,
        size_t offset,
        const CryptoPlugin::SubSample *subSamples,
        size_t numSubSamples,
        const uint8_t key[16],
        const uint8_t iv[16],
        CryptoPlugin::Mode mode,
        const CryptoPlugin::Pattern &pattern,
        size_t size,
        const sp<RefBase> &infos,
        const sp<RefBase> &cryptoInfos_,
        const sp<AMessage> &tunings,
        AString *errorDetailMsg) {
    sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
    sp<CryptoInfosWrapper> cryptoInfos((CryptoInfosWrapper *)cryptoInfos_.get());
    return mCodec->queueEncryptedBuffer(
            index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
            auInfo, tunings, errorDetailMsg);
            index, buffer, offset, size, auInfo, cryptoInfos,
            tunings, errorDetailMsg);
}

status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -2262,6 +2277,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 +2500,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(
@@ -2762,7 +2925,7 @@ static void extractBufferFromContext(

static void android_media_MediaCodec_native_queueLinearBlock(
        JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
        jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
        jobjectArray cryptoInfoArray, jobjectArray objArray, jobject keys, jobject values) {
    ALOGV("android_media_MediaCodec_native_queueLinearBlock");

    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2780,8 +2943,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,
@@ -2832,8 +2995,19 @@ static void android_media_MediaCodec_native_queueLinearBlock(
                    "MediaCodec.LinearBlock#obtain method to obtain a compatible buffer.");
            return;
        }
        auto cryptoInfo =
                cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
        sp<CryptoInfosWrapper> cryptoInfos = new CryptoInfosWrapper{decltype(cryptoInfos->value)()};
        jint sampleSize = 0;
        if (cryptoInfoArray != nullptr) {
            extractCryptoInfosFromObjectArray(env,
                    &sampleSize,
                    &cryptoInfos->value,
                    cryptoInfoArray,
                    &errorDetailMsg);
        } else {
            sampleSize = totalSize;
            std::unique_ptr<CodecCryptoInfo> cryptoInfo{new MediaCodecCryptoInfo(totalSize)};
            cryptoInfos->value.push_back(std::move(cryptoInfo));
        }
        if (env->ExceptionCheck()) {
            // Creation of cryptoInfo failed. Let the exception bubble up.
            return;
@@ -2842,11 +3016,9 @@ static void android_media_MediaCodec_native_queueLinearBlock(
                index,
                memory,
                initialOffset,
                cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
                (const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
                cryptoInfo.mMode,
                cryptoInfo.mPattern,
                sampleSize,
                infos,
                cryptoInfos,
                tunings,
                &errorDetailMsg);
        ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
@@ -3950,6 +4122,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 },
@@ -3957,7 +4132,7 @@ static const JNINativeMethod gMethods[] = {
    { "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },

    { "native_queueLinearBlock",
      "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
      "(ILandroid/media/MediaCodec$LinearBlock;[Ljava/lang/Object;"
      "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
      (void *)android_media_MediaCodec_native_queueLinearBlock },

+10 −6
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,
@@ -123,13 +131,9 @@ struct JMediaCodec : public AHandler {
            size_t index,
            const sp<hardware::HidlMemory> &buffer,
            size_t offset,
            const CryptoPlugin::SubSample *subSamples,
            size_t numSubSamples,
            const uint8_t key[16],
            const uint8_t iv[16],
            CryptoPlugin::Mode mode,
            const CryptoPlugin::Pattern &pattern,
            size_t size,
            const sp<RefBase> &infos,
            const sp<RefBase> &cryptoInfos,
            const sp<AMessage> &tunings,
            AString *errorDetailMsg);