Make VideoSink final in MCVR

This is to be able to set some values on the VideoSink before it's
initialized (for example, the effects)

PiperOrigin-RevId: 629966220
This commit is contained in:
kimvde 2024-05-02 00:04:10 -07:00 committed by Copybara-Service
parent d3850722d3
commit bdb8d8e329

View File

@ -144,6 +144,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private final Context context; private final Context context;
private final VideoSinkProvider videoSinkProvider; private final VideoSinkProvider videoSinkProvider;
private final boolean ownsVideoSinkProvider; private final boolean ownsVideoSinkProvider;
private final VideoSink videoSink;
private final EventDispatcher eventDispatcher; private final EventDispatcher eventDispatcher;
private final int maxDroppedFramesToNotify; private final int maxDroppedFramesToNotify;
private final boolean deviceNeedsNoPostProcessWorkaround; private final boolean deviceNeedsNoPostProcessWorkaround;
@ -175,7 +176,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private int tunnelingAudioSessionId; private int tunnelingAudioSessionId;
/* package */ @Nullable OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener; /* package */ @Nullable OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener;
@Nullable private VideoFrameMetadataListener frameMetadataListener; @Nullable private VideoFrameMetadataListener frameMetadataListener;
@Nullable private VideoSink videoSink;
/** /**
* @param context A context. * @param context A context.
@ -406,7 +406,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs)); this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs));
} }
this.videoSinkProvider = videoSinkProvider; this.videoSinkProvider = videoSinkProvider;
this.videoFrameReleaseControl = videoSink = videoSinkProvider.getSink();
videoFrameReleaseControl =
checkStateNotNull(this.videoSinkProvider.getVideoFrameReleaseControl()); checkStateNotNull(this.videoSinkProvider.getVideoFrameReleaseControl());
videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo(); videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo();
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround(); deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
@ -666,12 +667,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override @Override
public boolean isEnded() { public boolean isEnded() {
return super.isEnded() && (videoSink == null || videoSink.isEnded()); return super.isEnded() && (!videoSink.isInitialized() || videoSink.isEnded());
} }
@Override @Override
public boolean isReady() { public boolean isReady() {
boolean readyToReleaseFrames = super.isReady() && (videoSink == null || videoSink.isReady()); boolean readyToReleaseFrames =
super.isReady() && (!videoSink.isInitialized() || videoSink.isReady());
if (readyToReleaseFrames if (readyToReleaseFrames
&& ((placeholderSurface != null && displaySurface == placeholderSurface) && ((placeholderSurface != null && displaySurface == placeholderSurface)
|| getCodec() == null || getCodec() == null
@ -731,7 +733,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Override @Override
protected void onRelease() { protected void onRelease() {
super.onRelease(); super.onRelease();
if (ownsVideoSinkProvider && videoSink != null) { if (ownsVideoSinkProvider) {
videoSinkProvider.release(); videoSinkProvider.release();
} }
} }
@ -755,9 +757,7 @@ 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);
if (videoSink != null) {
videoSink.setVideoFrameMetadataListener(frameMetadataListener); 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);
@ -777,8 +777,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
outputResolution = (Size) checkNotNull(message); outputResolution = (Size) checkNotNull(message);
// TODO: b/292111083 Set the surface on the videoSinkProvider before it's initialized // TODO: b/292111083 Set the surface on the videoSinkProvider before it's initialized
// otherwise the first frames are missed until a new video output resolution arrives. // otherwise the first frames are missed until a new video output resolution arrives.
if (videoSink != null if (checkNotNull(outputResolution).getWidth() != 0
&& checkNotNull(outputResolution).getWidth() != 0
&& checkNotNull(outputResolution).getHeight() != 0 && checkNotNull(outputResolution).getHeight() != 0
&& displaySurface != null) { && displaySurface != null) {
videoSinkProvider.setOutputSurfaceInfo(displaySurface, checkNotNull(outputResolution)); videoSinkProvider.setOutputSurfaceInfo(displaySurface, checkNotNull(outputResolution));
@ -821,7 +820,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// The video sink is instantiated just before the first codec is ever created, so the sink can // The video sink is instantiated just before the first codec is ever created, so the sink can
// be non-null only when the codec is non-null. Therefore, we don't have to check if the sink // be non-null only when the codec is non-null. Therefore, we don't have to check if the sink
// is non-null but the codec is null. // is non-null but the codec is null.
if (codec != null && videoSink == null) { if (codec != null && !videoSink.isInitialized()) {
if (Util.SDK_INT >= 23 && displaySurface != null && !codecNeedsSetOutputSurfaceWorkaround) { if (Util.SDK_INT >= 23 && displaySurface != null && !codecNeedsSetOutputSurfaceWorkaround) {
setOutputSurfaceV23(codec, displaySurface); setOutputSurfaceV23(codec, displaySurface);
} else { } else {
@ -839,17 +838,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// next frame as soon as possible. // next frame as soon as possible.
videoFrameReleaseControl.join(/* renderNextFrameImmediately= */ true); videoFrameReleaseControl.join(/* renderNextFrameImmediately= */ true);
} }
// When effects previewing is enabled, set display surface and an unknown size.
if (videoSink != null) {
videoSinkProvider.setOutputSurfaceInfo(displaySurface, Size.UNKNOWN); videoSinkProvider.setOutputSurfaceInfo(displaySurface, Size.UNKNOWN);
}
} else { } else {
// The display surface has been removed. // The display surface has been removed.
reportedVideoSize = null; reportedVideoSize = null;
if (videoSink != null) {
videoSinkProvider.clearOutputSurfaceInfo(); videoSinkProvider.clearOutputSurfaceInfo();
} }
}
maybeSetupTunnelingForFirstFrame(); maybeSetupTunnelingForFirstFrame();
} else if (displaySurface != null && displaySurface != placeholderSurface) { } else if (displaySurface != null && displaySurface != placeholderSurface) {
// The display surface is set and unchanged. If we know the video size and/or have already // The display surface is set and unchanged. If we know the video size and/or have already
@ -904,13 +898,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
codecInfo, codecInfo,
mediaFormat, mediaFormat,
format, format,
videoSink != null ? videoSink.getInputSurface() : displaySurface, videoSink.isInitialized() ? 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 (videoSink != null && !videoSink.isFrameDropAllowedOnInput()) { if (videoSink.isInitialized() && !videoSink.isFrameDropAllowedOnInput()) {
mediaFormat.setInteger(MediaFormat.KEY_ALLOW_FRAME_DROP, 0); mediaFormat.setInteger(MediaFormat.KEY_ALLOW_FRAME_DROP, 0);
} }
} }
@ -941,7 +935,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 (videoSink != null) { if (videoSink.isInitialized()) {
try { try {
videoSink.render(positionUs, elapsedRealtimeUs); videoSink.render(positionUs, elapsedRealtimeUs);
} catch (VideoSink.VideoSinkException e) { } catch (VideoSink.VideoSinkException e) {
@ -963,7 +957,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
throws ExoPlaybackException { throws ExoPlaybackException {
super.setPlaybackSpeed(currentPlaybackSpeed, targetPlaybackSpeed); super.setPlaybackSpeed(currentPlaybackSpeed, targetPlaybackSpeed);
videoFrameReleaseControl.setPlaybackSpeed(currentPlaybackSpeed); videoFrameReleaseControl.setPlaybackSpeed(currentPlaybackSpeed);
if (videoSink != null) { if (videoSink.isInitialized()) {
videoSink.setPlaybackSpeed(currentPlaybackSpeed); videoSink.setPlaybackSpeed(currentPlaybackSpeed);
} }
} }
@ -1066,7 +1060,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// We always use the video sink if the video sink provider is passed to the renderer. // We always use the video sink if the video sink provider is passed to the renderer.
boolean useVideoSink = enableEffectsForOwnSinkProvider || !ownsVideoSinkProvider; boolean useVideoSink = enableEffectsForOwnSinkProvider || !ownsVideoSinkProvider;
if (useVideoSink) { if (useVideoSink) {
videoSink = videoSinkProvider.getSink();
if (!videoSink.isInitialized()) { if (!videoSink.isInitialized()) {
try { try {
videoSink.initialize(format, getClock()); videoSink.initialize(format, getClock());
@ -1109,9 +1102,6 @@ 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);
}
videoSink.setStreamOffsetUs(getOutputStreamOffsetUs()); videoSink.setStreamOffsetUs(getOutputStreamOffsetUs());
if (enableEffectsForOwnSinkProvider) { if (enableEffectsForOwnSinkProvider) {
if (displaySurface != null && outputResolution != null) { if (displaySurface != null && outputResolution != null) {
@ -1238,7 +1228,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
height = rotatedHeight; height = rotatedHeight;
pixelWidthHeightRatio = 1 / pixelWidthHeightRatio; pixelWidthHeightRatio = 1 / pixelWidthHeightRatio;
} }
} else if (videoSink == null) { } else if (!videoSink.isInitialized()) {
// 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;
} }
@ -1246,10 +1236,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
new VideoSize(width, height, unappliedRotationDegrees, pixelWidthHeightRatio); new VideoSize(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
videoFrameReleaseControl.setFrameRate(format.frameRate); videoFrameReleaseControl.setFrameRate(format.frameRate);
if (videoSink != null && mediaFormat != null) { if (videoSink.isInitialized() && mediaFormat != null) {
onReadyToRegisterVideoSinkInputStream(); onReadyToRegisterVideoSinkInputStream();
checkNotNull(videoSink) videoSink.registerInputStream(
.registerInputStream(
/* inputType= */ VideoSink.INPUT_TYPE_SURFACE, /* inputType= */ VideoSink.INPUT_TYPE_SURFACE,
format format
.buildUpon() .buildUpon()
@ -1342,7 +1331,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 VideoFrameProcessor if effects are enabled. // Opportunistically render to VideoFrameProcessor if effects are enabled.
if (displaySurface == placeholderSurface && videoSink == null) { if (displaySurface == placeholderSurface && !videoSink.isInitialized()) {
// 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);
@ -1352,7 +1341,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
return false; return false;
} }
if (videoSink != null) { if (videoSink.isInitialized()) {
try { try {
videoSink.render(positionUs, elapsedRealtimeUs); videoSink.render(positionUs, elapsedRealtimeUs);
} catch (VideoSink.VideoSinkException e) { } catch (VideoSink.VideoSinkException e) {
@ -1583,7 +1572,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
droppedSourceBufferCount, /* droppedDecoderBufferCount= */ buffersInCodecCount); droppedSourceBufferCount, /* droppedDecoderBufferCount= */ buffersInCodecCount);
} }
flushOrReinitializeCodec(); flushOrReinitializeCodec();
if (videoSink != null) { if (videoSink.isInitialized()) {
videoSink.flush(); videoSink.flush();
} }
return true; return true;
@ -1654,7 +1643,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
TraceUtil.endSection(); TraceUtil.endSection();
decoderCounters.renderedOutputBufferCount++; decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0; consecutiveDroppedFrameCount = 0;
if (videoSink == null) { if (!videoSink.isInitialized()) {
maybeNotifyVideoSizeChanged(decodedVideoSize); maybeNotifyVideoSizeChanged(decodedVideoSize);
maybeNotifyRenderedFirstFrame(); maybeNotifyRenderedFirstFrame();
} }
@ -1677,7 +1666,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
TraceUtil.endSection(); TraceUtil.endSection();
decoderCounters.renderedOutputBufferCount++; decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0; consecutiveDroppedFrameCount = 0;
if (videoSink == null) { if (!videoSink.isInitialized()) {
maybeNotifyVideoSizeChanged(decodedVideoSize); maybeNotifyVideoSizeChanged(decodedVideoSize);
maybeNotifyRenderedFirstFrame(); maybeNotifyRenderedFirstFrame();
} }