Refactor MediaCodecVideoRenderer to use a Builder

MediaCodecVideoRenderer is becoming unwieldy with the numerous constructors and optional settings. This refactors MediaCodecVideoRenderer to use a builder pattern for simplicity.

PiperOrigin-RevId: 723022129
This commit is contained in:
michaelkatz 2025-02-04 04:05:58 -08:00 committed by Copybara-Service
parent 1431497e7f
commit decfb9b0a9
8 changed files with 333 additions and 248 deletions

View File

@ -367,15 +367,15 @@ public class DefaultRenderersFactory implements RenderersFactory {
long allowedVideoJoiningTimeMs, long allowedVideoJoiningTimeMs,
ArrayList<Renderer> out) { ArrayList<Renderer> out) {
MediaCodecVideoRenderer videoRenderer = MediaCodecVideoRenderer videoRenderer =
new MediaCodecVideoRenderer( new MediaCodecVideoRenderer.Builder(context)
context, .setCodecAdapterFactory(getCodecAdapterFactory())
getCodecAdapterFactory(), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(allowedVideoJoiningTimeMs)
allowedVideoJoiningTimeMs, .setEnableDecoderFallback(enableDecoderFallback)
enableDecoderFallback, .setEventHandler(eventHandler)
eventHandler, .setEventListener(eventListener)
eventListener, .setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); .build();
out.add(videoRenderer); out.add(videoRenderer);
if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) { if (extensionRendererMode == EXTENSION_RENDERER_MODE_OFF) {
@ -770,15 +770,15 @@ public class DefaultRenderersFactory implements RenderersFactory {
long allowedVideoJoiningTimeMs) { long allowedVideoJoiningTimeMs) {
if (enableMediaCodecVideoRendererPrewarming if (enableMediaCodecVideoRendererPrewarming
&& renderer.getClass() == MediaCodecVideoRenderer.class) { && renderer.getClass() == MediaCodecVideoRenderer.class) {
return new MediaCodecVideoRenderer( return new MediaCodecVideoRenderer.Builder(context)
context, .setCodecAdapterFactory(getCodecAdapterFactory())
getCodecAdapterFactory(), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(allowedVideoJoiningTimeMs)
allowedVideoJoiningTimeMs, .setEnableDecoderFallback(enableDecoderFallback)
enableDecoderFallback, .setEventHandler(eventHandler)
eventHandler, .setEventListener(eventListener)
eventListener, .setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY); .build();
} }
return null; return null;
} }

View File

@ -78,6 +78,7 @@ import androidx.media3.exoplayer.mediacodec.MediaCodecUtil.DecoderQueryException
import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.video.VideoRendererEventListener.EventDispatcher; import androidx.media3.exoplayer.video.VideoRendererEventListener.EventDispatcher;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.checkerframework.checker.initialization.qual.Initialized; import org.checkerframework.checker.initialization.qual.Initialized;
@ -187,42 +188,168 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private long periodDurationUs; private long periodDurationUs;
private boolean pendingVideoSinkInputStreamChange; private boolean pendingVideoSinkInputStreamChange;
/** A builder to create {@link MediaCodecVideoRenderer} instances. */
public static final class Builder {
private final Context context;
private boolean buildCalled;
private MediaCodecSelector mediaCodecSelector;
private MediaCodecAdapter.Factory codecAdapterFactory;
private long allowedJoiningTimeMs;
private boolean enableDecoderFallback;
@Nullable private Handler eventHandler;
@Nullable private VideoRendererEventListener eventListener;
private int maxDroppedFramesToNotify;
private float assumedMinimumCodecOperatingRate;
@Nullable private VideoSink videoSink;
/** /**
* Creates a new builder.
*
* @param context A context. * @param context A context.
* @param mediaCodecSelector A decoder selector.
*/ */
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) { public Builder(Context context) {
this(context, mediaCodecSelector, 0); this.context = context;
this.mediaCodecSelector = MediaCodecSelector.DEFAULT;
this.codecAdapterFactory = MediaCodecAdapter.Factory.getDefault(context);
this.assumedMinimumCodecOperatingRate = 30;
}
/** Sets the {@link MediaCodecSelector decoder selector}. */
@CanIgnoreReturnValue
public Builder setMediaCodecSelector(MediaCodecSelector mediaCodecSelector) {
this.mediaCodecSelector = mediaCodecSelector;
return this;
} }
/** /**
* @param context A context. * Sets the {@link MediaCodecAdapter.Factory} used to create {@link MediaCodecAdapter}
* @param mediaCodecSelector A decoder selector. * instances.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
*/ */
@CanIgnoreReturnValue
public Builder setCodecAdapterFactory(MediaCodecAdapter.Factory codecAdapterFactory) {
this.codecAdapterFactory = codecAdapterFactory;
return this;
}
/**
* Sets the maximum duration in milliseconds for which this video renderer can attempt to
* seamlessly join an ongoing playback.
*/
@CanIgnoreReturnValue
public Builder setAllowedJoiningTimeMs(long allowedJoiningTimeMs) {
this.allowedJoiningTimeMs = allowedJoiningTimeMs;
return this;
}
/**
* Sets whether to enable fallback to lower-priority decoders if decoder initialization fails.
* This may result in using a decoder that is slower/less efficient than the primary decoder.
*/
@CanIgnoreReturnValue
public Builder setEnableDecoderFallback(boolean enableDecoderFallback) {
this.enableDecoderFallback = enableDecoderFallback;
return this;
}
/**
* Sets a handler to use when delivering events to {@code eventListener}.
*
* <p>The {@link #setEventHandler event handler} and {@link #setEventListener event listener}
* are linked in that both should be set to either {@code null} or non-{@code null} values.
*/
@CanIgnoreReturnValue
public Builder setEventHandler(@Nullable Handler eventHandler) {
this.eventHandler = eventHandler;
return this;
}
/**
* Sets a listener for {@link VideoRendererEventListener} events.
*
* <p>The {@link #setEventHandler event handler} and {@link #setEventListener event listener}
* are linked in that both should be set to either {@code null} or non-{@code null} values.
*/
@CanIgnoreReturnValue
public Builder setEventListener(@Nullable VideoRendererEventListener eventListener) {
this.eventListener = eventListener;
return this;
}
/**
* Sets the maximum number of frames that can be dropped between invocations of {@link
* VideoRendererEventListener#onDroppedFrames(int, long)}.
*/
@CanIgnoreReturnValue
public Builder setMaxDroppedFramesToNotify(int maxDroppedFramesToNotify) {
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
return this;
}
/**
* Sets a codec operating rate that all codecs instantiated by this renderer are assumed to meet
* implicitly (i.e. without the operating rate being set explicitly using {@link
* MediaFormat#KEY_OPERATING_RATE}).
*/
@CanIgnoreReturnValue
public Builder setAssumedMinimumCodecOperatingRate(float assumedMinimumCodecOperatingRate) {
this.assumedMinimumCodecOperatingRate = assumedMinimumCodecOperatingRate;
return this;
}
/**
* Sets a {@link VideoSink} to consume the frames.
*
* <p>If a {@link VideoSink} is not set and effects are {@linkplain #MSG_SET_VIDEO_EFFECTS set},
* a {@link VideoSink} produced by a {@link PlaybackVideoGraphWrapper} with its default
* configuration will be used to apply effects and render the frames on the output.
*/
@CanIgnoreReturnValue
public Builder setVideoSink(@Nullable VideoSink videoSink) {
this.videoSink = videoSink;
return this;
}
/**
* Builds the {@link MediaCodecVideoRenderer}. Must only be called once per Builder instance.
*
* <p>Throws {@link IllegalStateException} if the {@link #setEventHandler event handler} and the
* {@link #setEventListener event listener} are neither both {@code null} nor both non-{@code
* null}.
*/
public MediaCodecVideoRenderer build() {
checkState(!buildCalled);
checkState(
(eventHandler == null && eventListener == null)
|| (eventHandler != null && eventListener != null));
buildCalled = true;
return new MediaCodecVideoRenderer(this);
}
}
/**
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
public MediaCodecVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) {
this(new Builder(context).setMediaCodecSelector(mediaCodecSelector));
}
/**
* @deprecated Use {@link Builder} instead.
*/
@Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, MediaCodecSelector mediaCodecSelector, long allowedJoiningTimeMs) { Context context, MediaCodecSelector mediaCodecSelector, long allowedJoiningTimeMs) {
this( this(
context, new Builder(context)
mediaCodecSelector, .setMediaCodecSelector(mediaCodecSelector)
allowedJoiningTimeMs, .setAllowedJoiningTimeMs(allowedJoiningTimeMs));
/* eventHandler= */ null,
/* eventListener= */ null,
/* maxDroppedFramesToNotify= */ 0);
} }
/** /**
* @param context A context. * @deprecated Use {@link Builder} instead.
* @param mediaCodecSelector A decoder selector.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
*/ */
@Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, Context context,
MediaCodecSelector mediaCodecSelector, MediaCodecSelector mediaCodecSelector,
@ -231,31 +358,18 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Nullable VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify) { int maxDroppedFramesToNotify) {
this( this(
context, new Builder(context)
MediaCodecAdapter.Factory.getDefault(context), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
allowedJoiningTimeMs, .setEventHandler(eventHandler)
/* enableDecoderFallback= */ false, .setEventListener(eventListener)
eventHandler, .setMaxDroppedFramesToNotify(maxDroppedFramesToNotify));
eventListener,
maxDroppedFramesToNotify,
/* assumedMinimumCodecOperatingRate= */ 30);
} }
/** /**
* @param context A context. * @deprecated Use {@link Builder} instead.
* @param mediaCodecSelector A decoder selector.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
* @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
* initialization fails. This may result in using a decoder that is slower/less efficient than
* the primary decoder.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
*/ */
@Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, Context context,
MediaCodecSelector mediaCodecSelector, MediaCodecSelector mediaCodecSelector,
@ -265,33 +379,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Nullable VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify) { int maxDroppedFramesToNotify) {
this( this(
context, new Builder(context)
MediaCodecAdapter.Factory.getDefault(context), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
allowedJoiningTimeMs, .setEnableDecoderFallback(enableDecoderFallback)
enableDecoderFallback, .setEventHandler(eventHandler)
eventHandler, .setEventListener(eventListener)
eventListener, .setMaxDroppedFramesToNotify(maxDroppedFramesToNotify));
maxDroppedFramesToNotify,
/* assumedMinimumCodecOperatingRate= */ 30);
} }
/** /**
* @param context A context. * @deprecated Use {@link Builder} instead.
* @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link
* MediaCodecAdapter} instances.
* @param mediaCodecSelector A decoder selector.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
* @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
* initialization fails. This may result in using a decoder that is slower/less efficient than
* the primary decoder.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
*/ */
@Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, Context context,
MediaCodecAdapter.Factory codecAdapterFactory, MediaCodecAdapter.Factory codecAdapterFactory,
@ -302,38 +402,20 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Nullable VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify) { int maxDroppedFramesToNotify) {
this( this(
context, new Builder(context)
codecAdapterFactory, .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setCodecAdapterFactory(codecAdapterFactory)
allowedJoiningTimeMs, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
enableDecoderFallback, .setEnableDecoderFallback(enableDecoderFallback)
eventHandler, .setEventHandler(eventHandler)
eventListener, .setEventListener(eventListener)
maxDroppedFramesToNotify, .setMaxDroppedFramesToNotify(maxDroppedFramesToNotify));
/* assumedMinimumCodecOperatingRate= */ 30);
} }
/** /**
* Creates a new instance. * @deprecated Use {@link Builder} instead.
*
* @param context A context.
* @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link
* MediaCodecAdapter} instances.
* @param mediaCodecSelector A decoder selector.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
* @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
* initialization fails. This may result in using a decoder that is slower/less efficient than
* the primary decoder.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
* @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by
* this renderer are assumed to meet implicitly (i.e. without the operating rate being set
* explicitly using {@link MediaFormat#KEY_OPERATING_RATE}).
*/ */
@Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, Context context,
MediaCodecAdapter.Factory codecAdapterFactory, MediaCodecAdapter.Factory codecAdapterFactory,
@ -345,22 +427,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
int maxDroppedFramesToNotify, int maxDroppedFramesToNotify,
float assumedMinimumCodecOperatingRate) { float assumedMinimumCodecOperatingRate) {
this( this(
context, new Builder(context)
codecAdapterFactory, .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setCodecAdapterFactory(codecAdapterFactory)
allowedJoiningTimeMs, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
enableDecoderFallback, .setEnableDecoderFallback(enableDecoderFallback)
eventHandler, .setEventHandler(eventHandler)
eventListener, .setEventListener(eventListener)
maxDroppedFramesToNotify, .setMaxDroppedFramesToNotify(maxDroppedFramesToNotify)
assumedMinimumCodecOperatingRate, .setAssumedMinimumCodecOperatingRate(assumedMinimumCodecOperatingRate));
/* videoSink= */ (VideoSink) null);
} }
/** /**
* @deprecated Use {@link #MediaCodecVideoRenderer(Context, MediaCodecAdapter.Factory, * @deprecated Use {@link Builder} instead.
* MediaCodecSelector, long, boolean, Handler, VideoRendererEventListener, int, float,
* VideoSink)} instead.
*/ */
@Deprecated @Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
@ -375,45 +454,23 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
float assumedMinimumCodecOperatingRate, float assumedMinimumCodecOperatingRate,
@Nullable VideoSinkProvider videoSinkProvider) { @Nullable VideoSinkProvider videoSinkProvider) {
this( this(
context, new Builder(context)
codecAdapterFactory, .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setCodecAdapterFactory(codecAdapterFactory)
allowedJoiningTimeMs, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
enableDecoderFallback, .setEnableDecoderFallback(enableDecoderFallback)
eventHandler, .setEventHandler(eventHandler)
eventListener, .setEventListener(eventListener)
maxDroppedFramesToNotify, .setMaxDroppedFramesToNotify(maxDroppedFramesToNotify)
assumedMinimumCodecOperatingRate, .setAssumedMinimumCodecOperatingRate(assumedMinimumCodecOperatingRate)
/* videoSink= */ videoSinkProvider == null .setVideoSink(
? null videoSinkProvider == null ? null : videoSinkProvider.getSink(/* inputIndex= */ 0)));
: videoSinkProvider.getSink(/* inputIndex= */ 0));
} }
/** /**
* Creates a new instance. * @deprecated Use {@link Builder} instead.
*
* @param context A context.
* @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link
* MediaCodecAdapter} instances.
* @param mediaCodecSelector A decoder selector.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback.
* @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder
* initialization fails. This may result in using a decoder that is slower/less efficient than
* the primary decoder.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between
* invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}.
* @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by
* this renderer are assumed to meet implicitly (i.e. without the operating rate being set
* explicitly using {@link MediaFormat#KEY_OPERATING_RATE}).
* @param videoSink The {@link VideoSink} consuming the frames. If {@code null} and effects are
* {@linkplain #MSG_SET_VIDEO_EFFECTS set}, a {@link VideoSink} produced by a {@link
* PlaybackVideoGraphWrapper} with its default configuration will be used to apply effects and
* render the frames on the output.
*/ */
@Deprecated
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, Context context,
MediaCodecAdapter.Factory codecAdapterFactory, MediaCodecAdapter.Factory codecAdapterFactory,
@ -425,22 +482,39 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
int maxDroppedFramesToNotify, int maxDroppedFramesToNotify,
float assumedMinimumCodecOperatingRate, float assumedMinimumCodecOperatingRate,
@Nullable VideoSink videoSink) { @Nullable VideoSink videoSink) {
this(
new Builder(context)
.setMediaCodecSelector(mediaCodecSelector)
.setCodecAdapterFactory(codecAdapterFactory)
.setAllowedJoiningTimeMs(allowedJoiningTimeMs)
.setEnableDecoderFallback(enableDecoderFallback)
.setEventHandler(eventHandler)
.setEventListener(eventListener)
.setMaxDroppedFramesToNotify(maxDroppedFramesToNotify)
.setAssumedMinimumCodecOperatingRate(assumedMinimumCodecOperatingRate)
.setVideoSink(videoSink));
}
/**
* @param builder The {@link Builder} containing construction parameters.
*/
protected MediaCodecVideoRenderer(Builder builder) {
super( super(
C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_VIDEO,
codecAdapterFactory, builder.codecAdapterFactory,
mediaCodecSelector, builder.mediaCodecSelector,
enableDecoderFallback, builder.enableDecoderFallback,
assumedMinimumCodecOperatingRate); builder.assumedMinimumCodecOperatingRate);
this.context = context.getApplicationContext(); this.context = builder.context.getApplicationContext();
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.maxDroppedFramesToNotify = builder.maxDroppedFramesToNotify;
this.videoSink = videoSink; this.videoSink = builder.videoSink;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(builder.eventHandler, builder.eventListener);
ownsVideoSink = videoSink == null; ownsVideoSink = videoSink == null;
@SuppressWarnings("nullness:assignment") @SuppressWarnings("nullness:assignment")
VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this; VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this;
videoFrameReleaseControl = videoFrameReleaseControl =
new VideoFrameReleaseControl( new VideoFrameReleaseControl(
this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs); this.context, /* frameTimingEvaluator= */ thisRef, builder.allowedJoiningTimeMs);
videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo(); videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo();
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround(); deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
outputResolution = Size.UNKNOWN; outputResolution = Size.UNKNOWN;

View File

@ -22,6 +22,7 @@ import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.f
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample; import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
@ -175,7 +176,8 @@ public class MediaCodecVideoRendererTest {
/* forceSecure= */ false)); /* forceSecure= */ false));
mediaCodecVideoRenderer = mediaCodecVideoRenderer =
new MediaCodecVideoRenderer( new MediaCodecVideoRenderer(
ApplicationProvider.getApplicationContext(), new MediaCodecVideoRenderer.Builder(ApplicationProvider.getApplicationContext())
.setCodecAdapterFactory(
new DefaultMediaCodecAdapterFactory( new DefaultMediaCodecAdapterFactory(
ApplicationProvider.getApplicationContext(), ApplicationProvider.getApplicationContext(),
() -> { () -> {
@ -185,13 +187,13 @@ public class MediaCodecVideoRendererTest {
() -> { () -> {
queueingThread = new HandlerThread("MCVRTest:MediaCodecQueueingThread"); queueingThread = new HandlerThread("MCVRTest:MediaCodecQueueingThread");
return queueingThread; return queueingThread;
}), }))
mediaCodecSelector, .setMediaCodecSelector(mediaCodecSelector)
/* allowedJoiningTimeMs= */ 0, .setAllowedJoiningTimeMs(0)
/* enableDecoderFallback= */ false, .setEnableDecoderFallback(false)
/* eventHandler= */ new Handler(testMainLooper), .setEventHandler(new Handler(testMainLooper))
/* eventListener= */ eventListener, .setEventListener(eventListener)
/* maxDroppedFramesToNotify= */ 1) { .setMaxDroppedFramesToNotify(1)) {
@Override @Override
protected @Capabilities int supportsFormat( protected @Capabilities int supportsFormat(
MediaCodecSelector mediaCodecSelector, Format format) { MediaCodecSelector mediaCodecSelector, Format format) {
@ -1336,13 +1338,13 @@ public class MediaCodecVideoRendererTest {
} }
}; };
MediaCodecVideoRenderer renderer = MediaCodecVideoRenderer renderer =
new MediaCodecVideoRenderer( new MediaCodecVideoRenderer.Builder(ApplicationProvider.getApplicationContext())
ApplicationProvider.getApplicationContext(), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(0)
/* allowedJoiningTimeMs= */ 0, .setEventHandler(new Handler(testMainLooper))
/* eventHandler= */ new Handler(testMainLooper), .setEventListener(eventListener)
/* eventListener= */ eventListener, .setMaxDroppedFramesToNotify(1)
/* maxDroppedFramesToNotify= */ 1); .build();
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
@Capabilities @Capabilities
@ -1421,13 +1423,13 @@ public class MediaCodecVideoRendererTest {
} }
}; };
MediaCodecVideoRenderer renderer = MediaCodecVideoRenderer renderer =
new MediaCodecVideoRenderer( new MediaCodecVideoRenderer.Builder(ApplicationProvider.getApplicationContext())
ApplicationProvider.getApplicationContext(), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(0)
/* allowedJoiningTimeMs= */ 0, .setEventHandler(new Handler(testMainLooper))
/* eventHandler= */ new Handler(testMainLooper), .setEventListener(eventListener)
/* eventListener= */ eventListener, .setMaxDroppedFramesToNotify(1)
/* maxDroppedFramesToNotify= */ 1); .build();
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
@Capabilities int capabilitiesDvheDtr = renderer.supportsFormat(formatDvheDtr); @Capabilities int capabilitiesDvheDtr = renderer.supportsFormat(formatDvheDtr);
@ -1481,13 +1483,13 @@ public class MediaCodecVideoRendererTest {
H264_PROFILE8_LEVEL4_HW_MEDIA_CODEC_INFO, H264_PROFILE8_LEVEL5_SW_MEDIA_CODEC_INFO); H264_PROFILE8_LEVEL4_HW_MEDIA_CODEC_INFO, H264_PROFILE8_LEVEL5_SW_MEDIA_CODEC_INFO);
}; };
MediaCodecVideoRenderer renderer = MediaCodecVideoRenderer renderer =
new MediaCodecVideoRenderer( new MediaCodecVideoRenderer.Builder(ApplicationProvider.getApplicationContext())
ApplicationProvider.getApplicationContext(), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(0)
/* allowedJoiningTimeMs= */ 0, .setEventHandler(new Handler(testMainLooper))
/* eventHandler= */ new Handler(testMainLooper), .setEventListener(eventListener)
/* eventListener= */ eventListener, .setMaxDroppedFramesToNotify(1)
/* maxDroppedFramesToNotify= */ 1); .build();
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
List<MediaCodecInfo> mediaCodecInfoList = List<MediaCodecInfo> mediaCodecInfoList =
@ -1524,13 +1526,13 @@ public class MediaCodecVideoRendererTest {
H264_PROFILE8_LEVEL5_SW_MEDIA_CODEC_INFO, H264_PROFILE8_LEVEL4_HW_MEDIA_CODEC_INFO); H264_PROFILE8_LEVEL5_SW_MEDIA_CODEC_INFO, H264_PROFILE8_LEVEL4_HW_MEDIA_CODEC_INFO);
}; };
MediaCodecVideoRenderer renderer = MediaCodecVideoRenderer renderer =
new MediaCodecVideoRenderer( new MediaCodecVideoRenderer.Builder(ApplicationProvider.getApplicationContext())
ApplicationProvider.getApplicationContext(), .setMediaCodecSelector(mediaCodecSelector)
mediaCodecSelector, .setAllowedJoiningTimeMs(0)
/* allowedJoiningTimeMs= */ 0, .setEventHandler(new Handler(testMainLooper))
/* eventHandler= */ new Handler(testMainLooper), .setEventListener(eventListener)
/* eventListener= */ eventListener, .setMaxDroppedFramesToNotify(1)
/* maxDroppedFramesToNotify= */ 1); .build();
renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT); renderer.init(/* index= */ 0, PlayerId.UNSET, Clock.DEFAULT);
List<MediaCodecInfo> mediaCodecInfoList = List<MediaCodecInfo> mediaCodecInfoList =
@ -1609,6 +1611,15 @@ public class MediaCodecVideoRendererTest {
assertThat(surfacesSet).containsExactly(newSurface); assertThat(surfacesSet).containsExactly(newSurface);
} }
@Test
public void build_calledTwice_throwsIllegalStateException() throws Exception {
MediaCodecVideoRenderer.Builder mediaCodecVideoRendererBuilder =
new MediaCodecVideoRenderer.Builder(ApplicationProvider.getApplicationContext());
mediaCodecVideoRendererBuilder.build();
assertThrows(IllegalStateException.class, mediaCodecVideoRendererBuilder::build);
}
private void maybeIdleAsynchronousMediaCodecAdapterThreads() { private void maybeIdleAsynchronousMediaCodecAdapterThreads() {
if (queueingThread != null) { if (queueingThread != null) {
shadowOf(queueingThread.getLooper()).idle(); shadowOf(queueingThread.getLooper()).idle();

View File

@ -104,12 +104,12 @@ import java.util.ArrayList;
VideoRendererEventListener eventListener, VideoRendererEventListener eventListener,
int maxDroppedFrameCountToNotify) { int maxDroppedFrameCountToNotify) {
super( super(
context, new Builder(context)
mediaCodecSelector, .setMediaCodecSelector(mediaCodecSelector)
allowedJoiningTimeMs, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
eventHandler, .setEventHandler(eventHandler)
eventListener, .setEventListener(eventListener)
maxDroppedFrameCountToNotify); .setMaxDroppedFramesToNotify(maxDroppedFrameCountToNotify));
timestampsList = new long[ARRAY_SIZE]; timestampsList = new long[ARRAY_SIZE];
inputFormatChangeTimesUs = new ArrayDeque<>(); inputFormatChangeTimesUs = new ArrayDeque<>();

View File

@ -205,14 +205,14 @@ public class CapturingRenderersFactory implements RenderersFactory, Dumper.Dumpa
@Nullable VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify) { int maxDroppedFramesToNotify) {
super( super(
context, new Builder(context)
codecAdapterFactory, .setCodecAdapterFactory(codecAdapterFactory)
mediaCodecSelector, .setMediaCodecSelector(mediaCodecSelector)
allowedJoiningTimeMs, .setAllowedJoiningTimeMs(allowedJoiningTimeMs)
enableDecoderFallback, .setEnableDecoderFallback(enableDecoderFallback)
eventHandler, .setEventHandler(eventHandler)
eventListener, .setEventListener(eventListener)
maxDroppedFramesToNotify); .setMaxDroppedFramesToNotify(maxDroppedFramesToNotify));
} }
@Override @Override

View File

@ -431,7 +431,7 @@ public class EffectPlaybackPixelTest {
private static class NoFrameDroppedVideoRenderer extends MediaCodecVideoRenderer { private static class NoFrameDroppedVideoRenderer extends MediaCodecVideoRenderer {
public NoFrameDroppedVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) { public NoFrameDroppedVideoRenderer(Context context, MediaCodecSelector mediaCodecSelector) {
super(context, mediaCodecSelector); super(new Builder(context).setMediaCodecSelector(mediaCodecSelector));
} }
@Override @Override

View File

@ -640,12 +640,12 @@ public final class ExperimentalFrameExtractor {
VideoRendererEventListener videoRendererEventListener, VideoRendererEventListener videoRendererEventListener,
boolean toneMapHdrToSdr) { boolean toneMapHdrToSdr) {
super( super(
context, new Builder(context)
mediaCodecSelector, .setMediaCodecSelector(mediaCodecSelector)
/* allowedJoiningTimeMs= */ 0, .setAllowedJoiningTimeMs(0)
Util.createHandlerForCurrentOrMainLooper(), .setEventHandler(Util.createHandlerForCurrentOrMainLooper())
videoRendererEventListener, .setEventListener(videoRendererEventListener)
/* maxDroppedFramesToNotify= */ 0); .setMaxDroppedFramesToNotify(0));
this.toneMapHdrToSdr = toneMapHdrToSdr; this.toneMapHdrToSdr = toneMapHdrToSdr;
effectsFromPlayer = ImmutableList.of(); effectsFromPlayer = ImmutableList.of();
} }

View File

@ -282,16 +282,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
VideoSink videoSink, VideoSink videoSink,
boolean requestToneMapping) { boolean requestToneMapping) {
super( super(
context, new Builder(context)
MediaCodecAdapter.Factory.getDefault(context), .setMediaCodecSelector(MediaCodecSelector.DEFAULT)
MediaCodecSelector.DEFAULT, .setCodecAdapterFactory(MediaCodecAdapter.Factory.getDefault(context))
DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS, .setAllowedJoiningTimeMs(DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS)
/* enableDecoderFallback= */ false, .setEnableDecoderFallback(false)
eventHandler, .setEventHandler(eventHandler)
videoRendererEventListener, .setEventListener(videoRendererEventListener)
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY, .setMaxDroppedFramesToNotify(MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY)
/* assumedMinimumCodecOperatingRate= */ DEFAULT_FRAME_RATE, .setAssumedMinimumCodecOperatingRate(DEFAULT_FRAME_RATE)
videoSink); .setVideoSink(videoSink));
this.sequence = sequence; this.sequence = sequence;
this.videoSink = videoSink; this.videoSink = videoSink;
this.requestToneMapping = requestToneMapping; this.requestToneMapping = requestToneMapping;