mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Create API enabling use of MediaCodec.BUFFER_FLAG_DECODE_ONLY
If feature is enabled, MediaCodecVideoRenderer will 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. PiperOrigin-RevId: 734152464
This commit is contained in:
parent
c030e49dd6
commit
03a0fb4219
@ -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:
|
||||
|
@ -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.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>Requires API 34.
|
||||
*
|
||||
* <p>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<Renderer> out) {
|
||||
MediaCodecVideoRenderer videoRenderer =
|
||||
MediaCodecVideoRenderer.Builder videoRendererBuilder =
|
||||
new MediaCodecVideoRenderer.Builder(context)
|
||||
.setCodecAdapterFactory(getCodecAdapterFactory())
|
||||
.setMediaCodecSelector(mediaCodecSelector)
|
||||
@ -416,9 +439,13 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||
.setEventListener(eventListener)
|
||||
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
||||
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
||||
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs)
|
||||
.build();
|
||||
out.add(videoRenderer);
|
||||
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs);
|
||||
if (Util.SDK_INT >= 34) {
|
||||
videoRendererBuilder =
|
||||
videoRendererBuilder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
|
||||
enableMediaCodecBufferDecodeOnlyFlag);
|
||||
}
|
||||
out.add(videoRendererBuilder.build());
|
||||
|
||||
if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
|
||||
return;
|
||||
@ -851,17 +878,23 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
||||
long allowedVideoJoiningTimeMs) {
|
||||
if (enableMediaCodecVideoRendererPrewarming
|
||||
&& renderer.getClass() == MediaCodecVideoRenderer.class) {
|
||||
return new MediaCodecVideoRenderer.Builder(context)
|
||||
.setCodecAdapterFactory(getCodecAdapterFactory())
|
||||
.setMediaCodecSelector(mediaCodecSelector)
|
||||
.setAllowedJoiningTimeMs(allowedVideoJoiningTimeMs)
|
||||
.setEnableDecoderFallback(enableDecoderFallback)
|
||||
.setEventHandler(eventHandler)
|
||||
.setEventListener(eventListener)
|
||||
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
||||
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
||||
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs)
|
||||
.build();
|
||||
MediaCodecVideoRenderer.Builder builder =
|
||||
new MediaCodecVideoRenderer.Builder(context)
|
||||
.setCodecAdapterFactory(getCodecAdapterFactory())
|
||||
.setMediaCodecSelector(mediaCodecSelector)
|
||||
.setAllowedJoiningTimeMs(allowedVideoJoiningTimeMs)
|
||||
.setEnableDecoderFallback(enableDecoderFallback)
|
||||
.setEventHandler(eventHandler)
|
||||
.setEventListener(eventListener)
|
||||
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
||||
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
||||
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs);
|
||||
if (Util.SDK_INT >= 34) {
|
||||
builder =
|
||||
builder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
|
||||
enableMediaCodecBufferDecodeOnlyFlag);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -183,6 +183,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
private final long minEarlyUsToDropDecoderInput;
|
||||
|
||||
private final PriorityQueue<Long> droppedDecoderInputBufferTimestamps;
|
||||
private final boolean enableMediaCodecBufferDecodeOnlyFlag;
|
||||
|
||||
private @MonotonicNonNull CodecMaxValues codecMaxValues;
|
||||
private boolean codecNeedsSetOutputSurfaceWorkaround;
|
||||
@ -233,6 +234,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
@Nullable private VideoSink videoSink;
|
||||
private boolean parseAv1SampleDependencies;
|
||||
private long lateThresholdToDropDecoderInputUs;
|
||||
private boolean enableMediaCodecBufferDecodeOnlyFlag;
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
@ -373,6 +375,26 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the {@link MediaCodec#BUFFER_FLAG_DECODE_ONLY} flag will be included when
|
||||
* queuing decode-only input buffers to the decoder.
|
||||
*
|
||||
* <p>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}.
|
||||
*
|
||||
* <p>Requires API 34.
|
||||
*
|
||||
* <p>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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user