Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); } media/java/android/media/MediaCodec.java +95 −6 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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. Loading Loading @@ -3464,7 +3514,7 @@ final public class MediaCodec { mLinearBlock = block; mOffset = offset; mSize = size; mCryptoInfo = null; mCryptoInfos.clear(); return this; } Loading Loading @@ -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; } Loading Loading @@ -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) { Loading @@ -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; Loading @@ -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<>(); Loading @@ -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); Loading media/jni/android_media_MediaCodec.cpp +193 −18 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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, Loading Loading @@ -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( Loading Loading @@ -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); Loading @@ -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, Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 }, Loading @@ -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 }, Loading media/jni/android_media_MediaCodec.h +10 −6 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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); }
media/java/android/media/MediaCodec.java +95 −6 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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. Loading Loading @@ -3464,7 +3514,7 @@ final public class MediaCodec { mLinearBlock = block; mOffset = offset; mSize = size; mCryptoInfo = null; mCryptoInfos.clear(); return this; } Loading Loading @@ -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; } Loading Loading @@ -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) { Loading @@ -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; Loading @@ -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<>(); Loading @@ -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); Loading
media/jni/android_media_MediaCodec.cpp +193 −18 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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, Loading Loading @@ -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( Loading Loading @@ -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); Loading @@ -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, Loading Loading @@ -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; Loading @@ -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); Loading Loading @@ -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 }, Loading @@ -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 }, Loading
media/jni/android_media_MediaCodec.h +10 −6 Original line number Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading