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