Remove VideoSinkProvider parameter from renderers

PiperOrigin-RevId: 655073481
This commit is contained in:
kimvde 2024-07-23 01:38:41 -07:00 committed by Copybara-Service
parent 6147050b90
commit 225d336713
5 changed files with 80 additions and 82 deletions

View File

@ -267,11 +267,6 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
// VideoSinkProvider methods // VideoSinkProvider methods
@Override
public VideoFrameReleaseControl getVideoFrameReleaseControl() {
return videoFrameReleaseControl;
}
@Override @Override
public VideoSink getSink() { public VideoSink getSink() {
return videoSinkImpl; return videoSinkImpl;
@ -347,31 +342,6 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
} }
} }
// Other public methods
/**
* Incrementally renders available video frames.
*
* @param positionUs The current playback position, in microseconds.
* @param elapsedRealtimeUs {@link android.os.SystemClock#elapsedRealtime()} in microseconds,
* taken approximately at the time the playback position was {@code positionUs}.
*/
public void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
if (pendingFlushCount == 0) {
videoFrameRenderControl.render(positionUs, elapsedRealtimeUs);
}
}
/**
* Returns the output surface that was {@linkplain #setOutputSurfaceInfo(Surface, Size) set}, or
* {@code null} if no surface is set or the surface is {@linkplain #clearOutputSurfaceInfo()
* cleared}.
*/
@Nullable
public Surface getOutputSurface() {
return currentSurfaceAndSize != null ? currentSurfaceAndSize.first : null;
}
// Internal methods // Internal methods
private VideoFrameProcessor initialize(Format sourceFormat) throws VideoSink.VideoSinkException { private VideoFrameProcessor initialize(Format sourceFormat) throws VideoSink.VideoSinkException {
@ -432,6 +402,19 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
return pendingFlushCount == 0 && videoFrameRenderControl.hasReleasedFrame(presentationTimeUs); return pendingFlushCount == 0 && videoFrameRenderControl.hasReleasedFrame(presentationTimeUs);
} }
/**
* Incrementally renders available video frames.
*
* @param positionUs The current playback position, in microseconds.
* @param elapsedRealtimeUs {@link android.os.SystemClock#elapsedRealtime()} in microseconds,
* taken approximately at the time the playback position was {@code positionUs}.
*/
private void render(long positionUs, long elapsedRealtimeUs) throws ExoPlaybackException {
if (pendingFlushCount == 0) {
videoFrameRenderControl.render(positionUs, elapsedRealtimeUs);
}
}
private void flush() { private void flush() {
if (!isInitialized()) { if (!isInitialized()) {
return; return;
@ -864,8 +847,7 @@ public final class CompositingVideoSinkProvider implements VideoSinkProvider, Vi
return; return;
} }
ArrayList<Effect> effects = new ArrayList<>(); ArrayList<Effect> effects = new ArrayList<>(videoEffects);
effects.addAll(videoEffects);
Format inputFormat = checkNotNull(this.inputFormat); Format inputFormat = checkNotNull(this.inputFormat);
checkStateNotNull(videoFrameProcessor) checkStateNotNull(videoFrameProcessor)
.registerInputStream( .registerInputStream(

View File

@ -150,7 +150,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
private static boolean deviceNeedsSetOutputSurfaceWorkaround; private static boolean deviceNeedsSetOutputSurfaceWorkaround;
private final Context context; private final Context context;
@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;
@ -356,7 +355,37 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
eventListener, eventListener,
maxDroppedFramesToNotify, maxDroppedFramesToNotify,
assumedMinimumCodecOperatingRate, assumedMinimumCodecOperatingRate,
/* videoSinkProvider= */ null); /* videoSink= */ (VideoSink) null);
}
/**
* @deprecated Use {@link #MediaCodecVideoRenderer(Context, MediaCodecAdapter.Factory,
* MediaCodecSelector, long, boolean, Handler, VideoRendererEventListener, int, float,
* VideoSink)} instead.
*/
@Deprecated
public MediaCodecVideoRenderer(
Context context,
MediaCodecAdapter.Factory codecAdapterFactory,
MediaCodecSelector mediaCodecSelector,
long allowedJoiningTimeMs,
boolean enableDecoderFallback,
@Nullable Handler eventHandler,
@Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify,
float assumedMinimumCodecOperatingRate,
@Nullable VideoSinkProvider videoSinkProvider) {
this(
context,
codecAdapterFactory,
mediaCodecSelector,
allowedJoiningTimeMs,
enableDecoderFallback,
eventHandler,
eventListener,
maxDroppedFramesToNotify,
assumedMinimumCodecOperatingRate,
videoSinkProvider == null ? null : videoSinkProvider.getSink());
} }
/** /**
@ -379,11 +408,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
* @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by * @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by
* this renderer are assumed to meet implicitly (i.e. without the operating rate being set * this renderer are assumed to meet implicitly (i.e. without the operating rate being set
* explicitly using {@link MediaFormat#KEY_OPERATING_RATE}). * explicitly using {@link MediaFormat#KEY_OPERATING_RATE}).
* @param videoSinkProvider The {@link VideoSinkProvider} that will be used for applying video * @param videoSink The {@link VideoSink} consuming the frames. If {@code null} and effects are
* effects also providing the {@linkplain VideoSinkProvider#getVideoFrameReleaseControl() * {@linkplain #MSG_SET_VIDEO_EFFECTS set}, a {@link VideoSink} produced by a {@link
* VideoFrameReleaseControl} for releasing video frames. If {@code null}, the {@link * CompositingVideoSinkProvider} with its default configuration will be used to apply effects
* CompositingVideoSinkProvider} with its default configuration will be used, and the renderer * and render the frames on the output.
* will drive releasing of video frames by itself.
*/ */
public MediaCodecVideoRenderer( public MediaCodecVideoRenderer(
Context context, Context context,
@ -395,7 +423,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
@Nullable VideoRendererEventListener eventListener, @Nullable VideoRendererEventListener eventListener,
int maxDroppedFramesToNotify, int maxDroppedFramesToNotify,
float assumedMinimumCodecOperatingRate, float assumedMinimumCodecOperatingRate,
@Nullable VideoSinkProvider videoSinkProvider) { @Nullable VideoSink videoSink) {
super( super(
C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_VIDEO,
codecAdapterFactory, codecAdapterFactory,
@ -404,18 +432,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
assumedMinimumCodecOperatingRate); assumedMinimumCodecOperatingRate);
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
this.videoSinkProvider = videoSinkProvider; this.videoSink = videoSink;
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
ownsVideoSink = videoSinkProvider == null; ownsVideoSink = videoSink == null;
if (videoSinkProvider == null) { @SuppressWarnings("nullness:assignment")
@SuppressWarnings("nullness:assignment") VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this;
VideoFrameReleaseControl.@Initialized FrameTimingEvaluator thisRef = this; videoFrameReleaseControl =
videoFrameReleaseControl = new VideoFrameReleaseControl(
new VideoFrameReleaseControl( this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs);
this.context, /* frameTimingEvaluator= */ thisRef, allowedJoiningTimeMs);
} else {
videoFrameReleaseControl = videoSinkProvider.getVideoFrameReleaseControl();
}
videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo(); videoFrameReleaseInfo = new VideoFrameReleaseControl.FrameReleaseInfo();
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround(); deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
outputResolution = Size.UNKNOWN; outputResolution = Size.UNKNOWN;
@ -651,14 +675,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
// 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 (!hasSetVideoSink) { if (!hasSetVideoSink) {
if ((videoEffects != null || !ownsVideoSink) && videoSink == null) { if (videoEffects != null && videoSink == null) {
VideoSinkProvider videoSinkProvider = videoSink =
this.videoSinkProvider != null new CompositingVideoSinkProvider.Builder(context, videoFrameReleaseControl)
? this.videoSinkProvider .setClock(getClock())
: new CompositingVideoSinkProvider.Builder(this.context, videoFrameReleaseControl) .build()
.setClock(getClock()) .getSink();
.build();
videoSink = videoSinkProvider.getSink();
} }
hasSetVideoSink = true; hasSetVideoSink = true;
} }

View File

@ -24,12 +24,6 @@ import androidx.media3.common.util.UnstableApi;
@UnstableApi @UnstableApi
public interface VideoSinkProvider { public interface VideoSinkProvider {
/**
* Returns the {@link VideoFrameReleaseControl} that will be used for releasing of video frames
* during rendering.
*/
VideoFrameReleaseControl getVideoFrameReleaseControl();
/** Returns a {@link VideoSink} to forward video frames for processing. */ /** Returns a {@link VideoSink} to forward video frames for processing. */
VideoSink getSink(); VideoSink getSink();

View File

@ -647,7 +647,7 @@ public final class CompositionPlayer extends SimpleBasePlayer
context, context,
editedMediaItemSequence, editedMediaItemSequence,
previewAudioPipeline, previewAudioPipeline,
compositingVideoSinkProvider, compositingVideoSinkProvider.getSink(),
imageDecoderFactory) imageDecoderFactory)
: SequencePlayerRenderersWrapper.createForAudio( : SequencePlayerRenderersWrapper.createForAudio(
context, editedMediaItemSequence, previewAudioPipeline); context, editedMediaItemSequence, previewAudioPipeline);

View File

@ -46,7 +46,6 @@ import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
import androidx.media3.exoplayer.metadata.MetadataOutput; import androidx.media3.exoplayer.metadata.MetadataOutput;
import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.text.TextOutput; import androidx.media3.exoplayer.text.TextOutput;
import androidx.media3.exoplayer.video.CompositingVideoSinkProvider;
import androidx.media3.exoplayer.video.MediaCodecVideoRenderer; import androidx.media3.exoplayer.video.MediaCodecVideoRenderer;
import androidx.media3.exoplayer.video.VideoRendererEventListener; import androidx.media3.exoplayer.video.VideoRendererEventListener;
import androidx.media3.exoplayer.video.VideoSink; import androidx.media3.exoplayer.video.VideoSink;
@ -64,7 +63,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final Context context; private final Context context;
private final EditedMediaItemSequence sequence; private final EditedMediaItemSequence sequence;
private final PreviewAudioPipeline previewAudioPipeline; private final PreviewAudioPipeline previewAudioPipeline;
@Nullable private final CompositingVideoSinkProvider compositingVideoSinkProvider; @Nullable private final VideoSink videoSink;
@Nullable private final ImageDecoder.Factory imageDecoderFactory; @Nullable private final ImageDecoder.Factory imageDecoderFactory;
/** Creates a renderers wrapper for a player that will play video, image and audio. */ /** Creates a renderers wrapper for a player that will play video, image and audio. */
@ -72,10 +71,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Context context, Context context,
EditedMediaItemSequence sequence, EditedMediaItemSequence sequence,
PreviewAudioPipeline previewAudioPipeline, PreviewAudioPipeline previewAudioPipeline,
CompositingVideoSinkProvider compositingVideoSinkProvider, VideoSink videoSink,
ImageDecoder.Factory imageDecoderFactory) { ImageDecoder.Factory imageDecoderFactory) {
return new SequencePlayerRenderersWrapper( return new SequencePlayerRenderersWrapper(
context, sequence, previewAudioPipeline, compositingVideoSinkProvider, imageDecoderFactory); context, sequence, previewAudioPipeline, videoSink, imageDecoderFactory);
} }
/** Creates a renderers wrapper that for a player that will only play audio. */ /** Creates a renderers wrapper that for a player that will only play audio. */
@ -87,7 +86,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
context, context,
sequence, sequence,
previewAudioPipeline, previewAudioPipeline,
/* compositingVideoSinkProvider= */ null, /* videoSink= */ null,
/* imageDecoderFactory= */ null); /* imageDecoderFactory= */ null);
} }
@ -95,12 +94,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Context context, Context context,
EditedMediaItemSequence sequence, EditedMediaItemSequence sequence,
PreviewAudioPipeline previewAudioPipeline, PreviewAudioPipeline previewAudioPipeline,
@Nullable CompositingVideoSinkProvider compositingVideoSinkProvider, @Nullable VideoSink videoSink,
@Nullable ImageDecoder.Factory imageDecoderFactory) { @Nullable ImageDecoder.Factory imageDecoderFactory) {
this.context = context; this.context = context;
this.sequence = sequence; this.sequence = sequence;
this.previewAudioPipeline = previewAudioPipeline; this.previewAudioPipeline = previewAudioPipeline;
this.compositingVideoSinkProvider = compositingVideoSinkProvider; this.videoSink = videoSink;
this.imageDecoderFactory = imageDecoderFactory; this.imageDecoderFactory = imageDecoderFactory;
} }
@ -120,7 +119,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
audioRendererEventListener, audioRendererEventListener,
previewAudioPipeline.createInput())); previewAudioPipeline.createInput()));
if (compositingVideoSinkProvider != null) { if (videoSink != null) {
renderers.add( renderers.add(
new SequenceVideoRenderer( new SequenceVideoRenderer(
checkStateNotNull(context), checkStateNotNull(context),
@ -252,10 +251,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
videoRendererEventListener, videoRendererEventListener,
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY, MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY,
/* assumedMinimumCodecOperatingRate= */ DEFAULT_FRAME_RATE, /* assumedMinimumCodecOperatingRate= */ DEFAULT_FRAME_RATE,
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider)); checkStateNotNull(sequencePlayerRenderersWrapper.videoSink));
this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper; this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper;
videoSink = videoSink = checkStateNotNull(sequencePlayerRenderersWrapper.videoSink);
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider).getSink();
experimentalEnableProcessedStreamChangedAtStart(); experimentalEnableProcessedStreamChangedAtStart();
} }
@ -294,7 +292,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private static final class SequenceImageRenderer extends ImageRenderer { private static final class SequenceImageRenderer extends ImageRenderer {
private final SequencePlayerRenderersWrapper sequencePlayerRenderersWrapper; private final SequencePlayerRenderersWrapper sequencePlayerRenderersWrapper;
private final CompositingVideoSinkProvider compositingVideoSinkProvider;
private final VideoSink videoSink; private final VideoSink videoSink;
private ImmutableList<Effect> videoEffects; private ImmutableList<Effect> videoEffects;
@ -311,9 +308,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
super( super(
checkStateNotNull(sequencePlayerRenderersWrapper.imageDecoderFactory), ImageOutput.NO_OP); checkStateNotNull(sequencePlayerRenderersWrapper.imageDecoderFactory), ImageOutput.NO_OP);
this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper; this.sequencePlayerRenderersWrapper = sequencePlayerRenderersWrapper;
compositingVideoSinkProvider = videoSink = checkStateNotNull(sequencePlayerRenderersWrapper.videoSink);
checkStateNotNull(sequencePlayerRenderersWrapper.compositingVideoSinkProvider);
videoSink = compositingVideoSinkProvider.getSink();
videoEffects = ImmutableList.of(); videoEffects = ImmutableList.of();
streamStartPositionUs = C.TIME_UNSET; streamStartPositionUs = C.TIME_UNSET;
streamOffsetUs = C.TIME_UNSET; streamOffsetUs = C.TIME_UNSET;
@ -421,7 +416,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
throw exoPlaybackException; throw exoPlaybackException;
} }
super.render(positionUs, elapsedRealtimeUs); super.render(positionUs, elapsedRealtimeUs);
compositingVideoSinkProvider.render(positionUs, elapsedRealtimeUs); try {
videoSink.render(positionUs, elapsedRealtimeUs);
} catch (VideoSink.VideoSinkException e) {
throw createRendererException(
e, e.format, PlaybackException.ERROR_CODE_VIDEO_FRAME_PROCESSING_FAILED);
}
} }
@Override @Override