diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java
index 9539639813..6985ca5967 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/CompositingVideoSinkProvider.java
@@ -121,12 +121,14 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
private VideoFrameProcessor.@MonotonicNonNull Factory videoFrameProcessorFactory;
private PreviewingVideoGraph.@MonotonicNonNull Factory previewingVideoGraphFactory;
+ private Clock clock;
private boolean built;
/** Creates a builder. */
public Builder(Context context, VideoFrameReleaseControl videoFrameReleaseControl) {
this.context = context.getApplicationContext();
this.videoFrameReleaseControl = videoFrameReleaseControl;
+ clock = Clock.DEFAULT;
}
/**
@@ -162,6 +164,20 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
return this;
}
+ /**
+ * Sets the {@link Clock} that will be used.
+ *
+ *
By default, {@link Clock#DEFAULT} will be used.
+ *
+ * @param clock The {@link Clock}.
+ * @return This builder, for convenience.
+ */
+ @CanIgnoreReturnValue
+ public Builder setClock(Clock clock) {
+ this.clock = clock;
+ return this;
+ }
+
/**
* Builds the {@link CompositingVideoSinkProvider}.
*
@@ -202,9 +218,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
private final VideoFrameReleaseControl videoFrameReleaseControl;
private final VideoFrameRenderControl videoFrameRenderControl;
private final PreviewingVideoGraph.Factory previewingVideoGraphFactory;
+ private final Clock clock;
private final CopyOnWriteArraySet listeners;
- private @MonotonicNonNull Clock clock;
private @MonotonicNonNull Format outputFormat;
private @MonotonicNonNull VideoFrameMetadataListener videoFrameMetadataListener;
private @MonotonicNonNull HandlerWrapper handler;
@@ -223,7 +239,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
private CompositingVideoSinkProvider(Builder builder) {
context = builder.context;
videoSinkImpl = new VideoSinkImpl(context);
+ clock = builder.clock;
videoFrameReleaseControl = builder.videoFrameReleaseControl;
+ videoFrameReleaseControl.setClock(clock);
videoFrameRenderControl =
new VideoFrameRenderControl(new FrameRendererImpl(), videoFrameReleaseControl);
previewingVideoGraphFactory = checkStateNotNull(builder.previewingVideoGraphFactory);
@@ -359,13 +377,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
// Internal methods
- private VideoFrameProcessor initialize(Format sourceFormat, Clock clock)
- throws VideoSink.VideoSinkException {
+ private VideoFrameProcessor initialize(Format sourceFormat) throws VideoSink.VideoSinkException {
checkState(state == STATE_CREATED);
- this.clock = clock;
- handler = clock.createHandler(checkStateNotNull(Looper.myLooper()), /* callback= */ null);
-
ColorInfo inputColorInfo = getAdjustedInputColorInfo(sourceFormat.colorInfo);
ColorInfo outputColorInfo = inputColorInfo;
if (inputColorInfo.colorTransfer == C.COLOR_TRANSFER_HLG && Util.SDK_INT < 34) {
@@ -375,6 +389,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
outputColorInfo =
inputColorInfo.buildUpon().setColorTransfer(C.COLOR_TRANSFER_ST2084).build();
}
+ handler = clock.createHandler(checkStateNotNull(Looper.myLooper()), /* callback= */ null);
try {
videoGraph =
previewingVideoGraphFactory.create(
@@ -540,9 +555,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
}
@Override
- public void initialize(Format sourceFormat, Clock clock) throws VideoSinkException {
+ public void initialize(Format sourceFormat) throws VideoSinkException {
checkState(!isInitialized());
- videoFrameProcessor = CompositingVideoSinkProvider.this.initialize(sourceFormat, clock);
+ videoFrameProcessor = CompositingVideoSinkProvider.this.initialize(sourceFormat);
}
@Override
@@ -646,6 +661,9 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
@Override
public void setVideoEffects(List videoEffects) {
+ if (this.videoEffects.equals(videoEffects)) {
+ return;
+ }
setPendingVideoEffects(videoEffects);
maybeRegisterInputStream();
}
@@ -885,7 +903,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
Format format = outputFormat == null ? new Format.Builder().build() : outputFormat;
videoFrameMetadataListener.onVideoFrameAboutToBeRendered(
/* presentationTimeUs= */ bufferPresentationTimeUs,
- checkStateNotNull(clock).nanoTime(),
+ clock.nanoTime(),
format,
/* mediaFormat= */ null);
}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
index 7f1dbfc7ea..6227127b5d 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
@@ -142,7 +142,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private static boolean deviceNeedsSetOutputSurfaceWorkaround;
private final Context context;
- private final VideoSink videoSink;
+ @Nullable private final VideoSinkProvider videoSinkProvider;
private final boolean ownsVideoSink;
private final EventDispatcher eventDispatcher;
private final int maxDroppedFramesToNotify;
@@ -150,13 +150,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private final VideoFrameReleaseControl videoFrameReleaseControl;
private final VideoFrameReleaseControl.FrameReleaseInfo videoFrameReleaseInfo;
- private boolean shouldUseVideoSink;
- private boolean hasSetShouldUseVideoSink;
private @MonotonicNonNull CodecMaxValues codecMaxValues;
private boolean codecNeedsSetOutputSurfaceWorkaround;
private boolean codecHandlesHdr10PlusOutOfBandMetadata;
+ private @MonotonicNonNull VideoSink videoSink;
+ private boolean hasSetVideoSink;
+ private @MonotonicNonNull List videoEffects;
@Nullable private Surface displaySurface;
@Nullable private PlaceholderSurface placeholderSurface;
+ private Size outputResolution;
private boolean haveReportedFirstFrameRenderedForCurrentSurface;
private @C.VideoScalingMode int scalingMode;
private long droppedFrameAccumulationStartTimeMs;
@@ -168,7 +170,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private long lastFrameReleaseTimeNs;
private VideoSize decodedVideoSize;
@Nullable private VideoSize reportedVideoSize;
- private boolean hasEffects;
private int rendererPriority;
private boolean tunneling;
@@ -389,23 +390,23 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
mediaCodecSelector,
enableDecoderFallback,
assumedMinimumCodecOperatingRate);
- this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
this.context = context.getApplicationContext();
+ this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
+ this.videoSinkProvider = videoSinkProvider;
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
ownsVideoSink = videoSinkProvider == null;
if (videoSinkProvider == null) {
@SuppressWarnings("nullness:assignment")
VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this;
- VideoFrameReleaseControl videoFrameReleaseControl =
+ videoFrameReleaseControl =
new VideoFrameReleaseControl(
this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs);
- videoSinkProvider =
- new CompositingVideoSinkProvider.Builder(this.context, videoFrameReleaseControl).build();
+ } else {
+ videoFrameReleaseControl = videoSinkProvider.getVideoFrameReleaseControl();
}
- videoSink = videoSinkProvider.getSink();
- videoFrameReleaseControl = checkStateNotNull(videoSinkProvider.getVideoFrameReleaseControl());
videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo();
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
+ outputResolution = Size.UNKNOWN;
scalingMode = C.VIDEO_SCALING_MODE_DEFAULT;
decodedVideoSize = VideoSize.UNKNOWN;
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
@@ -619,7 +620,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
protected void onInit() {
super.onInit();
- videoFrameReleaseControl.setClock(getClock());
}
@Override
@@ -635,11 +635,22 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
eventDispatcher.enabled(decoderCounters);
// The video sink can only be enabled the first time the renderer is enabled, or after it has
// been reset.
- if (!hasSetShouldUseVideoSink) {
- shouldUseVideoSink = hasEffects || !ownsVideoSink;
- hasSetShouldUseVideoSink = true;
+ if (!hasSetVideoSink) {
+ if ((videoEffects != null || !ownsVideoSink) && videoSink == null) {
+ VideoSinkProvider videoSinkProvider =
+ this.videoSinkProvider != null
+ ? this.videoSinkProvider
+ : new CompositingVideoSinkProvider.Builder(this.context, videoFrameReleaseControl)
+ .setClock(getClock())
+ .build();
+ videoSink = videoSinkProvider.getSink();
+ }
+ hasSetVideoSink = true;
}
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
+ // Configure the VideoSink every time the renderer is enabled, in case the parameters have
+ // been overridden by another renderer. Also configure the VideoSink with the parameters that
+ // have been set on the renderer before creating the VideoSink.
videoSink.setListener(
new VideoSink.Listener() {
@Override
@@ -674,9 +685,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// Pass a direct executor since the callback handling involves posting on the app looper
// again, so there's no need to do two hops.
directExecutor());
+ if (frameMetadataListener != null) {
+ videoSink.setVideoFrameMetadataListener(frameMetadataListener);
+ }
+ if (displaySurface != null && !outputResolution.equals(Size.UNKNOWN)) {
+ videoSink.setOutputSurfaceInfo(displaySurface, outputResolution);
+ }
videoSink.setPlaybackSpeed(getPlaybackSpeed());
+ if (videoEffects != null) {
+ videoSink.setVideoEffects(videoEffects);
+ }
videoSink.onRendererEnabled(mayRenderStartOfStream);
} else {
+ videoFrameReleaseControl.setClock(getClock());
videoFrameReleaseControl.onEnabled(mayRenderStartOfStream);
}
}
@@ -688,13 +709,15 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
- // When this renderer doesn't own the VideoSink, it's possible that the VideoSink is already
- // initialized by another renderer, before this renderer is enabled.
- // Flush the video sink first to ensure it stops reading textures that will be owned by
- // MediaCodec once the codec is flushed.
- videoSink.flush();
- videoSink.setStreamOffsetAndAdjustmentUs(
- getOutputStreamOffsetUs(), getBufferTimestampAdjustmentUs());
+ if (videoSink != null) {
+ // When this renderer doesn't own the VideoSink, it's possible that the VideoSink is already
+ // initialized by another renderer, before this renderer is enabled.
+ // Flush the video sink first to ensure it stops reading textures that will be owned by
+ // MediaCodec once the codec is flushed.
+ videoSink.flush();
+ videoSink.setStreamOffsetAndAdjustmentUs(
+ getOutputStreamOffsetUs(), getBufferTimestampAdjustmentUs());
+ }
super.onPositionReset(positionUs, joining);
videoFrameReleaseControl.reset();
if (joining) {
@@ -709,12 +732,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
public boolean isEnded() {
- return super.isEnded() && (!shouldUseVideoSink || videoSink.isEnded());
+ return super.isEnded() && (videoSink == null || videoSink.isEnded());
}
@Override
public boolean isReady() {
- boolean readyToReleaseFrames = super.isReady() && (!shouldUseVideoSink || videoSink.isReady());
+ boolean readyToReleaseFrames = super.isReady() && (videoSink == null || videoSink.isReady());
if (readyToReleaseFrames
&& ((placeholderSurface != null && displaySurface == placeholderSurface)
|| getCodec() == null
@@ -733,7 +756,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
droppedFrameAccumulationStartTimeMs = elapsedRealtimeMs;
totalVideoFrameProcessingOffsetUs = 0;
videoFrameProcessingOffsetCount = 0;
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.onRendererStarted();
} else {
videoFrameReleaseControl.onStarted();
@@ -744,7 +767,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
protected void onStopped() {
maybeNotifyDroppedFrames();
maybeNotifyVideoFrameProcessingOffset();
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.onRendererStopped();
} else {
videoFrameReleaseControl.onStopped();
@@ -755,7 +778,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
protected void onDisabled() {
reportedVideoSize = null;
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.onRendererDisabled();
} else {
videoFrameReleaseControl.onDisabled();
@@ -776,7 +799,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
try {
super.onReset();
} finally {
- hasSetShouldUseVideoSink = false;
+ hasSetVideoSink = false;
if (placeholderSurface != null) {
releasePlaceholderSurface();
}
@@ -786,7 +809,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
protected void onRelease() {
super.onRelease();
- if (ownsVideoSink) {
+ if (videoSink != null && ownsVideoSink) {
videoSink.release();
}
}
@@ -810,7 +833,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
break;
case MSG_SET_VIDEO_FRAME_METADATA_LISTENER:
frameMetadataListener = (VideoFrameMetadataListener) checkNotNull(message);
- videoSink.setVideoFrameMetadataListener(frameMetadataListener);
+ if (videoSink != null) {
+ videoSink.setVideoFrameMetadataListener(frameMetadataListener);
+ }
break;
case MSG_SET_AUDIO_SESSION_ID:
int tunnelingAudioSessionId = (int) checkNotNull(message);
@@ -829,7 +854,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
case MSG_SET_VIDEO_OUTPUT_RESOLUTION:
Size outputResolution = (Size) checkNotNull(message);
if (outputResolution.getWidth() != 0 && outputResolution.getHeight() != 0) {
- videoSink.setOutputSurfaceInfo(checkStateNotNull(displaySurface), outputResolution);
+ this.outputResolution = outputResolution;
+ if (videoSink != null) {
+ videoSink.setOutputSurfaceInfo(checkStateNotNull(displaySurface), outputResolution);
+ }
}
break;
case MSG_SET_PRIORITY:
@@ -861,14 +889,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// We only need to update the codec if the display surface has changed.
if (this.displaySurface != displaySurface) {
this.displaySurface = displaySurface;
- if (!shouldUseVideoSink) {
+ if (videoSink == null) {
videoFrameReleaseControl.setOutputSurface(displaySurface);
}
haveReportedFirstFrameRenderedForCurrentSurface = false;
@State int state = getState();
@Nullable MediaCodecAdapter codec = getCodec();
- if (codec != null && !shouldUseVideoSink) {
+ if (codec != null && videoSink == null) {
if (Util.SDK_INT >= 23 && displaySurface != null && !codecNeedsSetOutputSurfaceWorkaround) {
setOutputSurfaceV23(codec, displaySurface);
} else {
@@ -889,7 +917,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
} else {
// The display surface has been removed.
reportedVideoSize = null;
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.clearOutputSurfaceInfo();
}
}
@@ -947,13 +975,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
codecInfo,
mediaFormat,
format,
- shouldUseVideoSink ? videoSink.getInputSurface() : displaySurface,
+ videoSink != null ? videoSink.getInputSurface() : displaySurface,
crypto);
}
@SuppressWarnings("InlinedApi") // VideoSink will check the API level
private void maybeSetKeyAllowFrameDrop(MediaFormat mediaFormat) {
- if (shouldUseVideoSink && !videoSink.isFrameDropAllowedOnInput()) {
+ if (videoSink != null && !videoSink.isFrameDropAllowedOnInput()) {
mediaFormat.setInteger(MediaFormat.KEY_ALLOW_FRAME_DROP, 0);
}
}
@@ -984,7 +1012,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
super.render(positionUs, elapsedRealtimeUs);
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
try {
videoSink.render(positionUs, elapsedRealtimeUs);
} catch (VideoSink.VideoSinkException e) {
@@ -1005,7 +1033,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
public void setPlaybackSpeed(float currentPlaybackSpeed, float targetPlaybackSpeed)
throws ExoPlaybackException {
super.setPlaybackSpeed(currentPlaybackSpeed, targetPlaybackSpeed);
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.setPlaybackSpeed(currentPlaybackSpeed);
} else {
videoFrameReleaseControl.setPlaybackSpeed(currentPlaybackSpeed);
@@ -1101,9 +1129,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@CallSuper
@Override
protected void onReadyToInitializeCodec(Format format) throws ExoPlaybackException {
- if (shouldUseVideoSink && !videoSink.isInitialized()) {
+ if (videoSink != null && !videoSink.isInitialized()) {
try {
- videoSink.initialize(format, getClock());
+ videoSink.initialize(format);
} catch (VideoSink.VideoSinkException e) {
throw createRendererException(
e, format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSOR_INIT_FAILED);
@@ -1113,8 +1141,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
/** Sets the {@linkplain Effect video effects} to apply. */
public void setVideoEffects(List effects) {
- videoSink.setVideoEffects(effects);
- hasEffects = true;
+ videoEffects = effects;
+ if (videoSink != null) {
+ videoSink.setVideoEffects(effects);
+ }
}
@Override
@@ -1227,14 +1257,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
height = rotatedHeight;
pixelWidthHeightRatio = 1 / pixelWidthHeightRatio;
}
- } else if (!shouldUseVideoSink) {
+ } else if (videoSink == null) {
// Neither the codec nor the video sink applies the rotation.
unappliedRotationDegrees = format.rotationDegrees;
}
decodedVideoSize =
new VideoSize(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
onReadyToRegisterVideoSinkInputStream();
videoSink.registerInputStream(
/* inputType= */ VideoSink.INPUT_TYPE_SURFACE,
@@ -1336,7 +1366,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// We are not rendering on a surface, the renderer will wait until a surface is set.
// Opportunistically render to VideoSink if it is enabled.
- if (displaySurface == placeholderSurface && !shouldUseVideoSink) {
+ if (displaySurface == placeholderSurface && videoSink == null) {
// Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
if (videoFrameReleaseInfo.getEarlyUs() < 30_000) {
skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
@@ -1346,7 +1376,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
return false;
}
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
try {
videoSink.render(positionUs, elapsedRealtimeUs);
} catch (VideoSink.VideoSinkException e) {
@@ -1473,7 +1503,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override
protected void onProcessedStreamChange() {
super.onProcessedStreamChange();
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.setStreamOffsetAndAdjustmentUs(
getOutputStreamOffsetUs(), getBufferTimestampAdjustmentUs());
} else {
@@ -1589,7 +1619,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
droppedSourceBufferCount, /* droppedDecoderBufferCount= */ buffersInCodecCount);
}
flushOrReinitializeCodec();
- if (shouldUseVideoSink) {
+ if (videoSink != null) {
videoSink.flush();
}
return true;
@@ -1660,7 +1690,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
TraceUtil.endSection();
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
- if (!shouldUseVideoSink) {
+ if (videoSink == null) {
maybeNotifyVideoSizeChanged(decodedVideoSize);
maybeNotifyRenderedFirstFrame();
}
@@ -1683,7 +1713,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
TraceUtil.endSection();
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
- if (!shouldUseVideoSink) {
+ if (videoSink == null) {
maybeNotifyVideoSizeChanged(decodedVideoSize);
maybeNotifyRenderedFirstFrame();
}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoSink.java
index c7beeff649..d84c9c548c 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoSink.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/VideoSink.java
@@ -25,7 +25,6 @@ import androidx.media3.common.C;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
import androidx.media3.common.VideoSize;
-import androidx.media3.common.util.Clock;
import androidx.media3.common.util.Size;
import androidx.media3.common.util.TimestampIterator;
import androidx.media3.common.util.UnstableApi;
@@ -131,12 +130,11 @@ public interface VideoSink {
* Initializes the video sink.
*
* @param sourceFormat The format of the compressed video.
- * @param clock The {@link Clock} that should be used.
* @throws VideoSink.VideoSinkException If initializing the sink failed.
*/
- void initialize(Format sourceFormat, Clock clock) throws VideoSinkException;
+ void initialize(Format sourceFormat) throws VideoSinkException;
- /** Returns whether the video sink is {@linkplain #initialize(Format, Clock) initialized}. */
+ /** Returns whether the video sink is {@linkplain #initialize(Format) initialized}. */
boolean isInitialized();
/**
@@ -166,7 +164,7 @@ public interface VideoSink {
/**
* Returns the input {@link Surface} where the video sink consumes input frames from.
*
- * Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
+ *
Must be called after the sink is {@linkplain #initialize(Format) initialized}.
*/
Surface getInputSurface();
@@ -204,7 +202,7 @@ public interface VideoSink {
/**
* Informs the video sink that a new input stream will be queued.
*
- *
Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
+ *
Must be called after the sink is {@linkplain #initialize(Format) initialized}.
*
* @param inputType The {@link InputType} of the stream.
* @param format The {@link Format} of the stream.
@@ -215,7 +213,7 @@ public interface VideoSink {
* Informs the video sink that a frame will be queued to its {@linkplain #getInputSurface() input
* surface}.
*
- *
Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
+ *
Must be called after the sink is {@linkplain #initialize(Format) initialized}.
*
* @param framePresentationTimeUs The frame's presentation time, in microseconds.
* @param isLastFrame Whether this is the last frame of the video stream.
@@ -228,7 +226,7 @@ public interface VideoSink {
/**
* Provides an input {@link Bitmap} to the video sink.
*
- *
Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
+ *
Must be called after the sink is {@linkplain #initialize(Format) initialized}.
*
* @param inputBitmap The {@link Bitmap} queued to the video sink.
* @param timestampIterator The times within the current stream that the bitmap should be shown
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/CompositingVideoSinkProviderTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/CompositingVideoSinkProviderTest.java
index 2bfedb41fb..f630c49af8 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/CompositingVideoSinkProviderTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/CompositingVideoSinkProviderTest.java
@@ -27,7 +27,6 @@ import androidx.media3.common.Format;
import androidx.media3.common.PreviewingVideoGraph;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.VideoGraph;
-import androidx.media3.common.util.Clock;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.List;
@@ -54,11 +53,9 @@ public final class CompositingVideoSinkProviderTest {
public void initializeSink_calledTwice_throws() throws VideoSink.VideoSinkException {
CompositingVideoSinkProvider provider = createCompositingVideoSinkProvider();
VideoSink sink = provider.getSink();
- sink.initialize(new Format.Builder().build(), Clock.DEFAULT);
+ sink.initialize(new Format.Builder().build());
- assertThrows(
- IllegalStateException.class,
- () -> sink.initialize(new Format.Builder().build(), Clock.DEFAULT));
+ assertThrows(IllegalStateException.class, () -> sink.initialize(new Format.Builder().build()));
}
private static CompositingVideoSinkProvider createCompositingVideoSinkProvider() {
diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java
index 7f1e547591..fbad74191a 100644
--- a/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java
+++ b/libraries/transformer/src/main/java/androidx/media3/transformer/CompositionPlayer.java
@@ -610,6 +610,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
CompositingVideoSinkProvider compositingVideoSinkProvider =
new CompositingVideoSinkProvider.Builder(context, videoFrameReleaseControl)
.setPreviewingVideoGraphFactory(checkNotNull(previewingVideoGraphFactory))
+ .setClock(clock)
.build();
compositingVideoSinkProvider.addListener(this);
for (int i = 0; i < composition.sequences.size(); i++) {
diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/SequencePlayerRenderersWrapper.java b/libraries/transformer/src/main/java/androidx/media3/transformer/SequencePlayerRenderersWrapper.java
index 82bdb84bfc..520d877db1 100644
--- a/libraries/transformer/src/main/java/androidx/media3/transformer/SequencePlayerRenderersWrapper.java
+++ b/libraries/transformer/src/main/java/androidx/media3/transformer/SequencePlayerRenderersWrapper.java
@@ -334,7 +334,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (!videoSink.isInitialized()) {
Format format = new Format.Builder().build();
try {
- videoSink.initialize(format, getClock());
+ videoSink.initialize(format);
} catch (VideoSink.VideoSinkException e) {
throw createRendererException(
e, format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSOR_INIT_FAILED);