Merge "media: add detachOutputSurface API for MediaCodec" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index ff7c3e6..4df7e3bd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -22552,6 +22552,7 @@
method @NonNull public static android.view.Surface createPersistentInputSurface();
method public int dequeueInputBuffer(long);
method public int dequeueOutputBuffer(@NonNull android.media.MediaCodec.BufferInfo, long);
+ method @FlaggedApi("android.media.codec.null_output_surface") public void detachOutputSurface();
method protected void finalize();
method public void flush();
method @NonNull public String getCanonicalName();
@@ -22600,6 +22601,7 @@
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
field public static final int BUFFER_FLAG_PARTIAL_FRAME = 8; // 0x8
field @Deprecated public static final int BUFFER_FLAG_SYNC_FRAME = 1; // 0x1
+ field @FlaggedApi("android.media.codec.null_output_surface") public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8; // 0x8
field public static final int CONFIGURE_FLAG_ENCODE = 1; // 0x1
field public static final int CONFIGURE_FLAG_USE_BLOCK_MODEL = 2; // 0x2
field public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4; // 0x4
@@ -22846,6 +22848,7 @@
field @Deprecated public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
field @Deprecated public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final String FEATURE_AdaptivePlayback = "adaptive-playback";
+ field @FlaggedApi("android.media.codec.null_output_surface") public static final String FEATURE_DetachedSurface = "detached-surface";
field @FlaggedApi("android.media.codec.dynamic_color_aspects") public static final String FEATURE_DynamicColorAspects = "dynamic-color-aspects";
field public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
field public static final String FEATURE_EncodingStatistics = "encoding-statistics";
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index add5999e..b9aee28 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,6 +16,7 @@
package android.media;
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
@@ -2213,6 +2214,18 @@
*/
public static final int CONFIGURE_FLAG_USE_CRYPTO_ASYNC = 4;
+ /**
+ * Configure the codec with a detached output surface.
+ * <p>
+ * This flag is only defined for a video decoder. MediaCodec
+ * configured with this flag will be in Surface mode even though
+ * the surface parameter is null.
+ *
+ * @see detachOutputSurface
+ */
+ @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+ public static final int CONFIGURE_FLAG_DETACHED_SURFACE = 8;
+
/** @hide */
@IntDef(
flag = true,
@@ -2395,6 +2408,31 @@
private native void native_setSurface(@NonNull Surface surface);
/**
+ * Detach the current output surface of a codec.
+ * <p>
+ * Detaches the currently associated output Surface from the
+ * MediaCodec decoder. This allows the SurfaceView or other
+ * component holding the Surface to be safely destroyed or
+ * modified without affecting the decoder's operation. After
+ * calling this method (and after it returns), the decoder will
+ * enter detached-Surface mode and will no longer render
+ * output.
+ *
+ * @throws IllegalStateException if the codec was not
+ * configured in surface mode.
+ * @see CONFIGURE_FLAG_DETACHED_SURFACE
+ */
+ @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+ public void detachOutputSurface() {
+ if (!mHasSurface) {
+ throw new IllegalStateException("codec was not configured for an output surface");
+ }
+ // note: we still have a surface in detached mode, so keep mHasSurface
+ // we also technically allow calling detachOutputSurface multiple times in a row
+ // native_detachSurface();
+ }
+
+ /**
* Create a persistent input surface that can be used with codecs that normally have an input
* surface, such as video encoders. A persistent input can be reused by subsequent
* {@link MediaCodec} or {@link MediaRecorder} instances, but can only be used by at
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 86f89ab..3174c37 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -20,6 +20,7 @@
import static android.media.Utils.sortDistinctRanges;
import static android.media.codec.Flags.FLAG_DYNAMIC_COLOR_ASPECTS;
import static android.media.codec.Flags.FLAG_HLG_EDITING;
+import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE;
import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST;
import android.annotation.FlaggedApi;
@@ -778,6 +779,17 @@
public static final String FEATURE_Roi = "region-of-interest";
/**
+ * <b>video decoder only</b>: codec supports detaching the
+ * output surface when in Surface mode.
+ * <p> If true, the codec can be configured in Surface mode
+ * without an actual surface (in detached surface mode).
+ * @see MediaCodec#CONFIGURE_FLAG_DETACHED_SURFACE
+ */
+ @SuppressLint("AllUpper")
+ @FlaggedApi(FLAG_NULL_OUTPUT_SURFACE)
+ public static final String FEATURE_DetachedSurface = "detached-surface";
+
+ /**
* Query codec feature capabilities.
* <p>
* These features are supported to be used by the codec. These
@@ -814,6 +826,9 @@
if (android.media.codec.Flags.dynamicColorAspects()) {
features.add(new Feature(FEATURE_DynamicColorAspects, (1 << 8), true));
}
+ if (android.media.codec.Flags.nullOutputSurface()) {
+ features.add(new Feature(FEATURE_DetachedSurface, (1 << 9), true));
+ }
// feature to exclude codec from REGULAR codec list
features.add(new Feature(FEATURE_SpecialCodec, (1 << 30), false, true));