Pass clock to release control from sink provider

In order to do that, make the VideoSink nullable in MCVR.

We want to avoid calling VideoFrameReleaseControl.setClock directly
from MCVR when the sink is enabled. The goal is to handle all the
communication with the release control from the sink/sink provider.

PiperOrigin-RevId: 642542063
This commit is contained in:
kimvde 2024-06-12 01:48:47 -07:00 committed by Copybara-Service
parent 859ef082d4
commit 5a24f40a66
6 changed files with 117 additions and 73 deletions

View File

@ -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.
*
* <p>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<CompositingVideoSinkProvider.Listener> 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<Effect> 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);
}

View File

@ -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<Effect> 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<Effect> 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();
}

View File

@ -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.
*
* <p>Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
* <p>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.
*
* <p>Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
* <p>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}.
*
* <p>Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
* <p>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.
*
* <p>Must be called after the sink is {@linkplain #initialize(Format, Clock) initialized}.
* <p>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

View File

@ -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() {

View File

@ -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++) {

View File

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