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

Commit 610f44db authored by Arun Johnson's avatar Arun Johnson Committed by Automerger Merge Worker
Browse files

Merge changes from topic "largeAudioBuffer" into main am: 5a20cf6f

parents 884340ec 5a20cf6f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -22573,6 +22573,7 @@ package android.media {
    method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters();
    method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
    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 public void release();
    method public void releaseOutputBuffer(int, boolean);
@@ -22634,6 +22635,7 @@ package android.media {
    method public abstract void onError(@NonNull android.media.MediaCodec, @NonNull android.media.MediaCodec.CodecException);
    method public abstract void onInputBufferAvailable(@NonNull android.media.MediaCodec, int);
    method public abstract void onOutputBufferAvailable(@NonNull android.media.MediaCodec, int, @NonNull android.media.MediaCodec.BufferInfo);
    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void onOutputBuffersAvailable(@NonNull android.media.MediaCodec, int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
    method public abstract void onOutputFormatChanged(@NonNull android.media.MediaCodec, @NonNull android.media.MediaFormat);
  }
@@ -22721,6 +22723,7 @@ package android.media {
  }
  public static final class MediaCodec.OutputFrame {
    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public java.util.ArrayDeque<android.media.MediaCodec.BufferInfo> getBufferInfos();
    method @NonNull public java.util.Set<java.lang.String> getChangedKeys();
    method public int getFlags();
    method @NonNull public android.media.MediaFormat getFormat();
@@ -22736,6 +22739,7 @@ package android.media {
  public final class MediaCodec.QueueRequest {
    method public void queue();
    method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setBufferInfos(@NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
    method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
    method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @NonNull android.media.MediaCodec.CryptoInfo);
    method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
+203 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media;

import android.Manifest;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -43,21 +44,25 @@ import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
/**
 MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
 It is part of the Android low-level multimedia support infrastructure (normally used together
@@ -1824,6 +1829,7 @@ final public class MediaCodec {
    private static final String EOS_AND_DECODE_ONLY_ERROR_MESSAGE = "An input buffer cannot have "
            + "both BUFFER_FLAG_END_OF_STREAM and BUFFER_FLAG_DECODE_ONLY flags";
    private static final int CB_CRYPTO_ERROR = 6;
    private static final int CB_LARGE_FRAME_OUTPUT_AVAILABLE = 7;

    private class EventHandler extends Handler {
        private MediaCodec mCodec;
@@ -1945,6 +1951,39 @@ final public class MediaCodec {
                    break;
                }

                case CB_LARGE_FRAME_OUTPUT_AVAILABLE:
                {
                    int index = msg.arg2;
                    ArrayDeque<BufferInfo> infos = (ArrayDeque<BufferInfo>)msg.obj;
                    synchronized(mBufferLock) {
                        switch (mBufferMode) {
                            case BUFFER_MODE_LEGACY:
                                validateOutputByteBuffersLocked(mCachedOutputBuffers,
                                        index, infos);
                                break;
                            case BUFFER_MODE_BLOCK:
                                while (mOutputFrames.size() <= index) {
                                    mOutputFrames.add(null);
                                }
                                OutputFrame frame = mOutputFrames.get(index);
                                if (frame == null) {
                                    frame = new OutputFrame(index);
                                    mOutputFrames.set(index, frame);
                                }
                                frame.setBufferInfos(infos);
                                frame.setAccessible(true);
                                break;
                            default:
                                throw new IllegalArgumentException(
                                        "Unrecognized buffer mode: for large frame output");
                        }
                    }
                    mCallback.onOutputBuffersAvailable(
                            mCodec, index, infos);

                    break;
                }

                case CB_ERROR:
                {
                    mCallback.onError(mCodec, (MediaCodec.CodecException) msg.obj);
@@ -2836,11 +2875,72 @@ final public class MediaCodec {
        }
    }

    /**
     * Submit multiple access units to the codec along with multiple
     * {@link MediaCodec.BufferInfo} describing the contents of the buffer. This method
     * is supported only in asynchronous mode. While this method can be used for all codecs,
     * it is meant for buffer batching, which is only supported by codecs that advertise
     * FEATURE_MultipleFrames. Other codecs will not output large output buffers via
     * onOutputBuffersAvailable, and instead will output single-access-unit output via
     * onOutputBufferAvailable.
     * <p>
     * Output buffer size can be configured using the following MediaFormat keys.
     * {@link MediaFormat#KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE} and
     * {@link MediaFormat#KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE}.
     * Details for each access unit present in the buffer should be described using
     * {@link MediaCodec.BufferInfo}. Access units must be laid out contiguously (without any gaps)
     * and in order. Multiple access units in the output if present, will be available in
     * {@link Callback#onOutputBuffersAvailable} or {@link Callback#onOutputBufferAvailable}
     * in case of single-access-unit output or when output does not contain any buffers,
     * such as flags.
     * <p>
     * All other details for populating {@link MediaCodec.BufferInfo} is the same as described in
     * {@link #queueInputBuffer}.
     *
     * @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.
     * @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 a crypto object has been specified in
     *         {@link #configure}
     */
    @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
    public final void queueInputBuffers(
            int index,
            @NonNull ArrayDeque<BufferInfo> bufferInfos) {
        synchronized(mBufferLock) {
            if (mBufferMode == BUFFER_MODE_BLOCK) {
                throw new IncompatibleWithBlockModelException("queueInputBuffers() "
                        + "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_queueInputBuffers(
                    index, bufferInfos.toArray());
        } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
            revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
            throw e;
        }
    }

    private native final void native_queueInputBuffer(
            int index,
            int offset, int size, long presentationTimeUs, int flags)
        throws CryptoException;

    private native final void native_queueInputBuffers(
            int index,
            @NonNull Object[] infos)
        throws CryptoException, CodecException;

    public static final int CRYPTO_MODE_UNENCRYPTED = 0;
    public static final int CRYPTO_MODE_AES_CTR     = 1;
    public static final int CRYPTO_MODE_AES_CBC     = 2;
@@ -3461,6 +3561,26 @@ final public class MediaCodec {
            return this;
        }

        /**
         * Sets MediaCodec.BufferInfo objects describing the access units
         * contained in this queue request. Access units must be laid out
         * contiguously without gaps and in order.
         *
         * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
         *              individual access-unit boundaries and the timestamps associated with it.
         *              The buffer is expected to contain the data in a continuous manner.
         * @return this object
         */
        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
        public @NonNull QueueRequest setBufferInfos(@NonNull ArrayDeque<BufferInfo> infos) {
            if (!isAccessible()) {
                throw new IllegalStateException("The request is stale");
            }
            mBufferInfos.clear();
            mBufferInfos.addAll(infos);
            return this;
        }

        /**
         * Add an integer parameter.
         * See {@link MediaFormat} for an exhaustive list of supported keys with
@@ -3577,10 +3697,18 @@ final public class MediaCodec {
                throw new IllegalStateException("No block is set");
            }
            setAccessible(false);
            if (mBufferInfos.isEmpty()) {
                BufferInfo info = new BufferInfo();
                info.size = mSize;
                info.offset = mOffset;
                info.presentationTimeUs = mPresentationTimeUs;
                info.flags = mFlags;
                mBufferInfos.add(info);
            }
            if (mLinearBlock != null) {
                mCodec.native_queueLinearBlock(
                        mIndex, mLinearBlock, mOffset, mSize, mCryptoInfo,
                        mPresentationTimeUs, mFlags,
                        mIndex, mLinearBlock, mCryptoInfo,
                        mBufferInfos.toArray(),
                        mTuningKeys, mTuningValues);
            } else if (mHardwareBuffer != null) {
                mCodec.native_queueHardwareBuffer(
@@ -3598,6 +3726,7 @@ final public class MediaCodec {
            mHardwareBuffer = null;
            mPresentationTimeUs = 0;
            mFlags = 0;
            mBufferInfos.clear();
            mTuningKeys.clear();
            mTuningValues.clear();
            return this;
@@ -3621,6 +3750,7 @@ final public class MediaCodec {
        private HardwareBuffer mHardwareBuffer = null;
        private long mPresentationTimeUs = 0;
        private @BufferFlag int mFlags = 0;
        private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
        private final ArrayList<String> mTuningKeys = new ArrayList<>();
        private final ArrayList<Object> mTuningValues = new ArrayList<>();

@@ -3630,11 +3760,8 @@ final public class MediaCodec {
    private native void native_queueLinearBlock(
            int index,
            @NonNull LinearBlock block,
            int offset,
            int size,
            @Nullable CryptoInfo cryptoInfo,
            long presentationTimeUs,
            int flags,
            @NonNull Object[] bufferInfos,
            @NonNull ArrayList<String> keys,
            @NonNull ArrayList<Object> values);

@@ -4048,6 +4175,27 @@ final public class MediaCodec {
        }
    }

    private void validateOutputByteBuffersLocked(
        @Nullable ByteBuffer[] buffers, int index, @NonNull ArrayDeque<BufferInfo> infoDeque) {
        Optional<BufferInfo> minInfo = infoDeque.stream().min(
                (info1, info2) -> Integer.compare(info1.offset, info2.offset));
        Optional<BufferInfo> maxInfo = infoDeque.stream().max(
                (info1, info2) -> Integer.compare(info1.offset, info2.offset));
        if (buffers == null) {
            if (index >= 0) {
                mValidOutputIndices.set(index);
            }
        } else if (index >= 0 && index < buffers.length) {
            ByteBuffer buffer = buffers[index];
            if (buffer != null && minInfo.isPresent() && maxInfo.isPresent()) {
                buffer.setAccessible(true);
                buffer.limit(maxInfo.get().offset + maxInfo.get().size);
                buffer.position(minInfo.get().offset);
            }
        }

    }

    private void validateOutputByteBufferLocked(
            @Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
        if (buffers == null) {
@@ -4405,6 +4553,22 @@ final public class MediaCodec {
            return mFlags;
        }

        /*
         * Returns the BufferInfos associated with this OutputFrame. These BufferInfos
         * describes the access units present in the OutputFrame. Access units are laid
         * out contiguously without gaps and in order.
         */
        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
        public @NonNull ArrayDeque<BufferInfo> getBufferInfos() {
            if (mBufferInfos.isEmpty()) {
                // single BufferInfo could be present.
                BufferInfo bufferInfo = new BufferInfo();
                bufferInfo.set(0, 0, mPresentationTimeUs, mFlags);
                mBufferInfos.add(bufferInfo);
            }
            return mBufferInfos;
        }

        /**
         * Returns a read-only {@link MediaFormat} for this frame. The returned
         * object is valid only until the client calls {@link MediaCodec#releaseOutputBuffer}.
@@ -4430,6 +4594,7 @@ final public class MediaCodec {
            mLinearBlock = null;
            mHardwareBuffer = null;
            mFormat = null;
            mBufferInfos.clear();
            mChangedKeys.clear();
            mKeySet.clear();
            mLoaded = false;
@@ -4448,6 +4613,11 @@ final public class MediaCodec {
            mFlags = info.flags;
        }

        void setBufferInfos(ArrayDeque<BufferInfo> infos) {
            mBufferInfos.clear();
            mBufferInfos.addAll(infos);
        }

        boolean isLoaded() {
            return mLoaded;
        }
@@ -4462,6 +4632,7 @@ final public class MediaCodec {
        private long mPresentationTimeUs = 0;
        private @BufferFlag int mFlags = 0;
        private MediaFormat mFormat = null;
        private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
        private final ArrayList<String> mChangedKeys = new ArrayList<>();
        private final Set<String> mKeySet = new HashSet<>();
        private boolean mAccessible = false;
@@ -5169,6 +5340,32 @@ final public class MediaCodec {
        public abstract void onOutputBufferAvailable(
                @NonNull MediaCodec codec, int index, @NonNull BufferInfo info);

        /**
         * Called when multiple access-units are available in the output.
         *
         * @param codec The MediaCodec object.
         * @param index The index of the available output buffer.
         * @param infos Infos describing the available output buffer {@link MediaCodec.BufferInfo}.
         *              Access units present in the output buffer are laid out contiguously
         *              without gaps and in order.
         */
        @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
        public void onOutputBuffersAvailable(
                @NonNull MediaCodec codec, int index, @NonNull ArrayDeque<BufferInfo> infos) {
            /*
             * This callback returns multiple BufferInfos when codecs are configured to operate on
             * large audio frame. Since at this point, we have a single large buffer, returning
             * each BufferInfo using
             * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable} may cause the
             * index to be released to the codec using {@link MediaCodec#releaseOutputBuffer}
             * before all BuffersInfos can be returned to the client.
             * Hence this callback is required to be implemented or else an exception is thrown.
             */
            throw new IllegalStateException(
                    "Client must override onOutputBuffersAvailable when codec is " +
                    "configured to operate with multiple access units");
        }

        /**
         * Called when the MediaCodec encountered an error
         *
+267 −21

File changed.

Preview size limit exceeded, changes collapsed.

+10 −3
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ class C2Buffer;
namespace android {

struct ABuffer;
struct AccessUnitInfo;
struct ALooper;
struct AMessage;
struct AString;
@@ -93,6 +94,13 @@ struct JMediaCodec : public AHandler {
            size_t offset, size_t size, int64_t timeUs, uint32_t flags,
            AString *errorDetailMsg);

    status_t queueInputBuffers(
            size_t index,
            size_t offset,
            size_t size,
            const sp<RefBase> &auInfo,
            AString *errorDetailMsg = NULL);

    status_t queueSecureInputBuffer(
            size_t index,
            size_t offset,
@@ -108,7 +116,7 @@ struct JMediaCodec : public AHandler {

    status_t queueBuffer(
            size_t index, const std::shared_ptr<C2Buffer> &buffer,
            int64_t timeUs, uint32_t flags, const sp<AMessage> &tunings,
            const sp<RefBase> &infos, const sp<AMessage> &tunings,
            AString *errorDetailMsg);

    status_t queueEncryptedLinearBlock(
@@ -121,8 +129,7 @@ struct JMediaCodec : public AHandler {
            const uint8_t iv[16],
            CryptoPlugin::Mode mode,
            const CryptoPlugin::Pattern &pattern,
            int64_t presentationTimeUs,
            uint32_t flags,
            const sp<RefBase> &infos,
            const sp<AMessage> &tunings,
            AString *errorDetailMsg);