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.
|
* Allow constant power upmixing/downmixing in DefaultAudioMixer.
|
||||||
* Add support for float PCM to `ChannelMappingAudioProcessor`.
|
* Add support for float PCM to `ChannelMappingAudioProcessor`.
|
||||||
* Video:
|
* 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:
|
* Text:
|
||||||
* Metadata:
|
* Metadata:
|
||||||
* Image:
|
* Image:
|
||||||
|
@ -24,10 +24,12 @@ import android.os.Handler;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
|
||||||
import androidx.media3.exoplayer.audio.AudioSink;
|
import androidx.media3.exoplayer.audio.AudioSink;
|
||||||
import androidx.media3.exoplayer.audio.DefaultAudioSink;
|
import androidx.media3.exoplayer.audio.DefaultAudioSink;
|
||||||
@ -111,6 +113,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||||||
private boolean enableMediaCodecVideoRendererPrewarming;
|
private boolean enableMediaCodecVideoRendererPrewarming;
|
||||||
private boolean parseAv1SampleDependencies;
|
private boolean parseAv1SampleDependencies;
|
||||||
private long lateThresholdToDropDecoderInputUs;
|
private long lateThresholdToDropDecoderInputUs;
|
||||||
|
private boolean enableMediaCodecBufferDecodeOnlyFlag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context A {@link Context}.
|
* @param context A {@link Context}.
|
||||||
@ -298,6 +301,26 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||||||
return this;
|
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
|
* Sets the maximum duration for which video renderers can attempt to seamlessly join an ongoing
|
||||||
* playback.
|
* playback.
|
||||||
@ -406,7 +429,7 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||||||
VideoRendererEventListener eventListener,
|
VideoRendererEventListener eventListener,
|
||||||
long allowedVideoJoiningTimeMs,
|
long allowedVideoJoiningTimeMs,
|
||||||
ArrayList<Renderer> out) {
|
ArrayList<Renderer> out) {
|
||||||
MediaCodecVideoRenderer videoRenderer =
|
MediaCodecVideoRenderer.Builder videoRendererBuilder =
|
||||||
new MediaCodecVideoRenderer.Builder(context)
|
new MediaCodecVideoRenderer.Builder(context)
|
||||||
.setCodecAdapterFactory(getCodecAdapterFactory())
|
.setCodecAdapterFactory(getCodecAdapterFactory())
|
||||||
.setMediaCodecSelector(mediaCodecSelector)
|
.setMediaCodecSelector(mediaCodecSelector)
|
||||||
@ -416,9 +439,13 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||||||
.setEventListener(eventListener)
|
.setEventListener(eventListener)
|
||||||
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
||||||
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
||||||
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs)
|
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs);
|
||||||
.build();
|
if (Util.SDK_INT >= 34) {
|
||||||
out.add(videoRenderer);
|
videoRendererBuilder =
|
||||||
|
videoRendererBuilder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
|
||||||
|
enableMediaCodecBufferDecodeOnlyFlag);
|
||||||
|
}
|
||||||
|
out.add(videoRendererBuilder.build());
|
||||||
|
|
||||||
if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
|
if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
|
||||||
return;
|
return;
|
||||||
@ -851,17 +878,23 @@ public class DefaultRenderersFactory implements RenderersFactory {
|
|||||||
long allowedVideoJoiningTimeMs) {
|
long allowedVideoJoiningTimeMs) {
|
||||||
if (enableMediaCodecVideoRendererPrewarming
|
if (enableMediaCodecVideoRendererPrewarming
|
||||||
&& renderer.getClass() == MediaCodecVideoRenderer.class) {
|
&& renderer.getClass() == MediaCodecVideoRenderer.class) {
|
||||||
return new MediaCodecVideoRenderer.Builder(context)
|
MediaCodecVideoRenderer.Builder builder =
|
||||||
.setCodecAdapterFactory(getCodecAdapterFactory())
|
new MediaCodecVideoRenderer.Builder(context)
|
||||||
.setMediaCodecSelector(mediaCodecSelector)
|
.setCodecAdapterFactory(getCodecAdapterFactory())
|
||||||
.setAllowedJoiningTimeMs(allowedVideoJoiningTimeMs)
|
.setMediaCodecSelector(mediaCodecSelector)
|
||||||
.setEnableDecoderFallback(enableDecoderFallback)
|
.setAllowedJoiningTimeMs(allowedVideoJoiningTimeMs)
|
||||||
.setEventHandler(eventHandler)
|
.setEnableDecoderFallback(enableDecoderFallback)
|
||||||
.setEventListener(eventListener)
|
.setEventHandler(eventHandler)
|
||||||
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
.setEventListener(eventListener)
|
||||||
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
.setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
|
||||||
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs)
|
.experimentalSetParseAv1SampleDependencies(parseAv1SampleDependencies)
|
||||||
.build();
|
.experimentalSetLateThresholdToDropDecoderInputUs(lateThresholdToDropDecoderInputUs);
|
||||||
|
if (Util.SDK_INT >= 34) {
|
||||||
|
builder =
|
||||||
|
builder.experimentalSetEnableMediaCodecBufferDecodeOnlyFlag(
|
||||||
|
enableMediaCodecBufferDecodeOnlyFlag);
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
private final long minEarlyUsToDropDecoderInput;
|
private final long minEarlyUsToDropDecoderInput;
|
||||||
|
|
||||||
private final PriorityQueue<Long> droppedDecoderInputBufferTimestamps;
|
private final PriorityQueue<Long> droppedDecoderInputBufferTimestamps;
|
||||||
|
private final boolean enableMediaCodecBufferDecodeOnlyFlag;
|
||||||
|
|
||||||
private @MonotonicNonNull CodecMaxValues codecMaxValues;
|
private @MonotonicNonNull CodecMaxValues codecMaxValues;
|
||||||
private boolean codecNeedsSetOutputSurfaceWorkaround;
|
private boolean codecNeedsSetOutputSurfaceWorkaround;
|
||||||
@ -233,6 +234,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
@Nullable private VideoSink videoSink;
|
@Nullable private VideoSink videoSink;
|
||||||
private boolean parseAv1SampleDependencies;
|
private boolean parseAv1SampleDependencies;
|
||||||
private long lateThresholdToDropDecoderInputUs;
|
private long lateThresholdToDropDecoderInputUs;
|
||||||
|
private boolean enableMediaCodecBufferDecodeOnlyFlag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder.
|
* Creates a new builder.
|
||||||
@ -373,6 +375,26 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
return this;
|
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.
|
* 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
|
||||||
? -builder.lateThresholdToDropDecoderInputUs
|
? -builder.lateThresholdToDropDecoderInputUs
|
||||||
: C.TIME_UNSET;
|
: C.TIME_UNSET;
|
||||||
|
enableMediaCodecBufferDecodeOnlyFlag = builder.enableMediaCodecBufferDecodeOnlyFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrameTimingEvaluator methods
|
// FrameTimingEvaluator methods
|
||||||
@ -1479,11 +1502,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getCodecBufferFlags(DecoderInputBuffer buffer) {
|
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.
|
// 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
|
// If tunneling, we can't decide to do this after decoding because we won't get the buffer
|
||||||
// codec in tunneling mode. This may not work perfectly, e.g. when the codec is doing frame
|
// back from the codec in tunneling mode. This may not work perfectly, e.g. when the codec is
|
||||||
// rate conversion, but it's still better than not dropping the buffers at all.
|
// doing frame rate conversion, but it's still better than not dropping the buffers at all.
|
||||||
return MediaCodec.BUFFER_FLAG_DECODE_ONLY;
|
return MediaCodec.BUFFER_FLAG_DECODE_ONLY;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user