From f6d26e59ae5e7b03c5a8ffe00e6b8946a5ae5c47 Mon Sep 17 00:00:00 2001 From: Marc Kassis Date: Thu, 24 Nov 2022 11:20:39 +0100 Subject: [PATCH] Add BUFFER_FLAG_DECODE_ONLY to MediaCodec. Disallow a frame to be queued with both DECODE_ONLY and EOS flags. Bug: 234708299 Test: atest DecodeOnlyTest CodecUnitTest Change-Id: I9fc8ccf8ef9b9d28d1e6f282b0256c33dbb18161 --- core/api/current.txt | 4 ++ media/java/android/media/MediaCodec.java | 48 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/core/api/current.txt b/core/api/current.txt index 787370abf2b7b..368940b294a46 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -21690,6 +21690,7 @@ package android.media { method public void subscribeToVendorParameters(@NonNull java.util.List); method public void unsubscribeFromVendorParameters(@NonNull java.util.List); field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2 + field public static final int BUFFER_FLAG_DECODE_ONLY = 32; // 0x20 field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4 field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1 field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8 @@ -21777,6 +21778,9 @@ package android.media { public class MediaCodec.IncompatibleWithBlockModelException extends java.lang.RuntimeException { } + public class MediaCodec.InvalidBufferFlagsException extends java.lang.RuntimeException { + } + public static final class MediaCodec.LinearBlock { method protected void finalize(); method public static boolean isCodecCopyFreeCompatible(@NonNull String[]); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index da2795f6dcfc1..80e115a4e530b 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -1709,6 +1709,33 @@ final public class MediaCodec { */ public static final int BUFFER_FLAG_MUXER_DATA = 16; + /** + * This indicates that the buffer is decoded and updates the internal state of the decoder, + * but does not produce any output buffer. + * + * When a buffer has this flag set, + * {@link OnFrameRenderedListener#onFrameRendered(MediaCodec, long, long)} and + * {@link Callback#onOutputBufferAvailable(MediaCodec, int, BufferInfo)} will not be called for + * that given buffer. + * + * For example, when seeking to a certain frame, that frame may need to reference previous + * frames in order for it to produce output. The preceding frames can be marked with this flag + * so that they are only decoded and their data is used when decoding the latter frame that + * should be initially displayed post-seek. + * Another example would be trick play, trick play is when a video is fast-forwarded and only a + * subset of the frames is to be rendered on the screen. The frames not to be rendered can be + * marked with this flag for the same reason as the above one. + * Marking frames with this flag improves the overall performance of playing a video stream as + * fewer frames need to be passed back to the app. + * + * In {@link CodecCapabilities#FEATURE_TunneledPlayback}, buffers marked with this flag + * are not rendered on the output surface. + * + * A frame should not be marked with this flag and {@link #BUFFER_FLAG_END_OF_STREAM} + * simultaneously, doing so will produce a {@link InvalidBufferFlagsException} + */ + public static final int BUFFER_FLAG_DECODE_ONLY = 32; + /** @hide */ @IntDef( flag = true, @@ -1719,6 +1746,7 @@ final public class MediaCodec { BUFFER_FLAG_END_OF_STREAM, BUFFER_FLAG_PARTIAL_FRAME, BUFFER_FLAG_MUXER_DATA, + BUFFER_FLAG_DECODE_ONLY, }) @Retention(RetentionPolicy.SOURCE) public @interface BufferFlag {} @@ -1744,6 +1772,8 @@ final public class MediaCodec { private static final int CB_OUTPUT_AVAILABLE = 2; private static final int CB_ERROR = 3; private static final int CB_OUTPUT_FORMAT_CHANGE = 4; + 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 class EventHandler extends Handler { private MediaCodec mCodec; @@ -2103,6 +2133,16 @@ final public class MediaCodec { } } + /** + * Thrown when a buffer is marked with an invalid combination of flags + * (e.g. both {@link #BUFFER_FLAG_END_OF_STREAM} and {@link #BUFFER_FLAG_DECODE_ONLY}) + */ + public class InvalidBufferFlagsException extends RuntimeException { + InvalidBufferFlagsException(String message) { + super(message); + } + } + /** * Configures a component. * @@ -2666,6 +2706,10 @@ final public class MediaCodec { int index, int offset, int size, long presentationTimeUs, int flags) throws CryptoException { + if ((flags & BUFFER_FLAG_DECODE_ONLY) != 0 + && (flags & BUFFER_FLAG_END_OF_STREAM) != 0) { + throw new InvalidBufferFlagsException(EOS_AND_DECODE_ONLY_ERROR_MESSAGE); + } synchronized(mBufferLock) { if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException("queueInputBuffer() " @@ -2936,6 +2980,10 @@ final public class MediaCodec { @NonNull CryptoInfo info, long presentationTimeUs, int flags) throws CryptoException { + if ((flags & BUFFER_FLAG_DECODE_ONLY) != 0 + && (flags & BUFFER_FLAG_END_OF_STREAM) != 0) { + throw new InvalidBufferFlagsException(EOS_AND_DECODE_ONLY_ERROR_MESSAGE); + } synchronized(mBufferLock) { if (mBufferMode == BUFFER_MODE_BLOCK) { throw new IncompatibleWithBlockModelException("queueSecureInputBuffer() "