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);