diff --git a/RELEASENOTES.md b/RELEASENOTES.md index f2305f89ec..d8d143e447 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -12,6 +12,11 @@ * Allow constant power upmixing/downmixing in DefaultAudioMixer. * Add support for float PCM to `ChannelMappingAudioProcessor`. * Video: + * Add experimental `ExoPlayer` API to include the + `MediaCodec.BUFFER_FLAG_DECODE_ONLY` flag when queuing decode-only input + buffers. This flag will signal the decoder to skip the decode-only + buffers thereby resulting in faster seeking. Enable it with + `DefaultRenderersFactory.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag`. * Text: * Metadata: * Image: diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java index af3bc5d0b4..37ceab5772 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/DefaultRenderersFactory.java @@ -24,10 +24,12 @@ import android.os.Handler; import android.os.Looper; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.media3.common.C; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.Log; import androidx.media3.common.util.UnstableApi; +import androidx.media3.common.util.Util; import androidx.media3.exoplayer.audio.AudioRendererEventListener; import androidx.media3.exoplayer.audio.AudioSink; import androidx.media3.exoplayer.audio.DefaultAudioSink; @@ -111,6 +113,7 @@ public class DefaultRenderersFactory implements RenderersFactory { private boolean enableMediaCodecVideoRendererPrewarming; private boolean parseAv1SampleDependencies; private long lateThresholdToDropDecoderInputUs; + private boolean enableMediaCodecBufferDecodeOnlyFlag; /** * @param context A {@link Context}. @@ -298,6 +301,26 @@ public class DefaultRenderersFactory implements RenderersFactory { return this; } + /** + * Sets whether the {@link MediaCodec#BUFFER_FLAG_DECODE_ONLY} flag will be included when queuing + * decode-only input buffers to the decoder. + * + *
If {@code false}, then only if the decoder is set up in tunneling mode will the decode-only + * input buffers be queued with the {@link MediaCodec#BUFFER_FLAG_DECODE_ONLY} flag. The default + * value is {@code false}. + * + *
Requires API 34. + * + *
This method is experimental and will be renamed or removed in a future release.
+ */
+ @RequiresApi(34)
+ @CanIgnoreReturnValue
+ public DefaultRenderersFactory experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
+ boolean enableMediaCodecBufferDecodeOnlyFlag) {
+ this.enableMediaCodecBufferDecodeOnlyFlag = enableMediaCodecBufferDecodeOnlyFlag;
+ return this;
+ }
+
/**
* Sets the maximum duration for which video renderers can attempt to seamlessly join an ongoing
* playback.
@@ -406,7 +429,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
VideoRendererEventListener eventListener,
long allowedVideoJoiningTimeMs,
ArrayList If {@code false}, then only if the decoder is set up in tunneling mode will decode-only
+ * input buffers be queued with the {@link MediaCodec#BUFFER_FLAG_DECODE_ONLY} flag. The default
+ * value is {@code false}.
+ *
+ * Requires API 34.
+ *
+ * This method is experimental and will be renamed or removed in a future release.
+ */
+ @RequiresApi(34)
+ @CanIgnoreReturnValue
+ public Builder experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
+ boolean enableMediaCodecBufferDecodeOnlyFlag) {
+ this.enableMediaCodecBufferDecodeOnlyFlag = enableMediaCodecBufferDecodeOnlyFlag;
+ return this;
+ }
+
/**
* Builds the {@link MediaCodecVideoRenderer}. Must only be called once per Builder instance.
*
@@ -597,6 +619,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
builder.lateThresholdToDropDecoderInputUs != C.TIME_UNSET
? -builder.lateThresholdToDropDecoderInputUs
: C.TIME_UNSET;
+ enableMediaCodecBufferDecodeOnlyFlag = builder.enableMediaCodecBufferDecodeOnlyFlag;
}
// FrameTimingEvaluator methods
@@ -1479,11 +1502,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
protected int getCodecBufferFlags(DecoderInputBuffer buffer) {
- if (Util.SDK_INT >= 34 && tunneling && isBufferBeforeStartTime(buffer)) {
+ if (Util.SDK_INT >= 34
+ && (enableMediaCodecBufferDecodeOnlyFlag || tunneling)
+ && isBufferBeforeStartTime(buffer)) {
// The buffer likely needs to be dropped because its timestamp is less than the start time.
- // We can't decide to do this after decoding because we won't get the buffer back from the
- // codec in tunneling mode. This may not work perfectly, e.g. when the codec is doing frame
- // rate conversion, but it's still better than not dropping the buffers at all.
+ // If tunneling, we can't decide to do this after decoding because we won't get the buffer
+ // back from the codec in tunneling mode. This may not work perfectly, e.g. when the codec is
+ // doing frame rate conversion, but it's still better than not dropping the buffers at all.
return MediaCodec.BUFFER_FLAG_DECODE_ONLY;
}
return 0;