mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
VideoSink: merge setStreamStartPositionUs and onInputStreamChanged
setStreamStartPositionUs and onInputStreamChanged should both be called when the stream changes. PiperOrigin-RevId: 736121598
This commit is contained in:
parent
99767c6e25
commit
03892cc1b5
@ -177,15 +177,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamStartPositionUs(long streamStartPositionUs) {
|
||||
if (streamStartPositionUs != this.streamStartPositionUs) {
|
||||
videoFrameRenderControl.onStreamChanged(
|
||||
RELEASE_FIRST_FRAME_WHEN_PREVIOUS_STREAM_PROCESSED, streamStartPositionUs);
|
||||
this.streamStartPositionUs = streamStartPositionUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBufferTimestampAdjustmentUs(long bufferTimestampAdjustmentUs) {
|
||||
this.bufferTimestampAdjustmentUs = bufferTimestampAdjustmentUs;
|
||||
@ -220,7 +211,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
*/
|
||||
@Override
|
||||
public void onInputStreamChanged(
|
||||
@InputType int inputType, Format format, List<Effect> videoEffects) {
|
||||
@InputType int inputType, Format format, long startPositionUs, List<Effect> videoEffects) {
|
||||
checkState(videoEffects.isEmpty());
|
||||
if (format.width != inputFormat.width || format.height != inputFormat.height) {
|
||||
videoFrameRenderControl.onVideoSizeChanged(format.width, format.height);
|
||||
@ -229,6 +220,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
videoFrameReleaseControl.setFrameRate(format.frameRate);
|
||||
}
|
||||
inputFormat = format;
|
||||
if (startPositionUs != this.streamStartPositionUs) {
|
||||
videoFrameRenderControl.onStreamChanged(
|
||||
RELEASE_FIRST_FRAME_WHEN_PREVIOUS_STREAM_PROCESSED, startPositionUs);
|
||||
this.streamStartPositionUs = startPositionUs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1643,7 +1643,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when ready to {@linkplain VideoSink#onInputStreamChanged(int, Format, List<Effect>)
|
||||
* Called when ready to {@linkplain VideoSink#onInputStreamChanged(int, Format, long, List)
|
||||
* change} the input stream.
|
||||
*
|
||||
* <p>The default implementation applies this renderer's video effects.
|
||||
@ -1651,7 +1651,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
protected void changeVideoSinkInputStream(
|
||||
VideoSink videoSink, @VideoSink.InputType int inputType, Format format) {
|
||||
List<Effect> videoEffectsToApply = videoEffects != null ? videoEffects : ImmutableList.of();
|
||||
videoSink.onInputStreamChanged(inputType, format, videoEffectsToApply);
|
||||
videoSink.onInputStreamChanged(
|
||||
inputType, format, getOutputStreamStartPositionUs(), videoEffectsToApply);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1861,7 +1862,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
|
||||
if (videoSink != null) {
|
||||
// Signaling end of the previous stream.
|
||||
videoSink.signalEndOfCurrentInputStream();
|
||||
videoSink.setStreamStartPositionUs(getOutputStreamStartPositionUs());
|
||||
if (this.startPositionUs == C.TIME_UNSET) {
|
||||
this.startPositionUs = getOutputStreamStartPositionUs();
|
||||
}
|
||||
|
@ -407,15 +407,13 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
// We forward output size changes to the sink even if we are still flushing.
|
||||
videoGraphOutputFormat =
|
||||
videoGraphOutputFormat.buildUpon().setWidth(width).setHeight(height).build();
|
||||
defaultVideoSink.onInputStreamChanged(
|
||||
INPUT_TYPE_SURFACE, videoGraphOutputFormat, /* videoEffects= */ ImmutableList.of());
|
||||
onOutputStreamChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOutputFrameRateChanged(float frameRate) {
|
||||
videoGraphOutputFormat = videoGraphOutputFormat.buildUpon().setFrameRate(frameRate).build();
|
||||
defaultVideoSink.onInputStreamChanged(
|
||||
INPUT_TYPE_SURFACE, videoGraphOutputFormat, /* videoEffects= */ ImmutableList.of());
|
||||
onOutputStreamChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -436,8 +434,8 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
streamStartPositionsUs.pollFloor(bufferPresentationTimeUs);
|
||||
if (newOutputStreamStartPositionUs != null
|
||||
&& newOutputStreamStartPositionUs != outputStreamStartPositionUs) {
|
||||
defaultVideoSink.setStreamStartPositionUs(newOutputStreamStartPositionUs);
|
||||
outputStreamStartPositionUs = newOutputStreamStartPositionUs;
|
||||
onOutputStreamChanged();
|
||||
}
|
||||
boolean isLastFrame =
|
||||
finalBufferPresentationTimeUs != C.TIME_UNSET
|
||||
@ -580,9 +578,9 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
streamStartPositionsUs.pollFirst();
|
||||
}
|
||||
if (streamStartPositionsUs.size() == 1) {
|
||||
long lastStartPositionUs = checkNotNull(streamStartPositionsUs.pollFirst());
|
||||
// defaultVideoSink should use the latest startPositionUs if none is passed after flushing.
|
||||
defaultVideoSink.setStreamStartPositionUs(lastStartPositionUs);
|
||||
// Use the latest startPositionUs if none is passed after flushing.
|
||||
outputStreamStartPositionUs = checkNotNull(streamStartPositionsUs.pollFirst());
|
||||
onOutputStreamChanged();
|
||||
}
|
||||
lastOutputBufferPresentationTimeUs = C.TIME_UNSET;
|
||||
finalBufferPresentationTimeUs = C.TIME_UNSET;
|
||||
@ -619,6 +617,14 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
return inputColorInfo;
|
||||
}
|
||||
|
||||
private void onOutputStreamChanged() {
|
||||
defaultVideoSink.onInputStreamChanged(
|
||||
INPUT_TYPE_SURFACE,
|
||||
videoGraphOutputFormat,
|
||||
outputStreamStartPositionUs,
|
||||
/* videoEffects= */ ImmutableList.of());
|
||||
}
|
||||
|
||||
/** Receives input from an ExoPlayer renderer and forwards it to the video graph. */
|
||||
private final class InputVideoSink implements VideoSink, PlaybackVideoGraphWrapper.Listener {
|
||||
|
||||
@ -740,7 +746,7 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
|
||||
@Override
|
||||
public void onInputStreamChanged(
|
||||
@InputType int inputType, Format format, List<Effect> videoEffects) {
|
||||
@InputType int inputType, Format format, long startPositionUs, List<Effect> videoEffects) {
|
||||
checkState(isInitialized());
|
||||
switch (inputType) {
|
||||
case INPUT_TYPE_SURFACE:
|
||||
@ -755,6 +761,12 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
finalBufferPresentationTimeUs = C.TIME_UNSET;
|
||||
hasSignaledEndOfCurrentInputStream = false;
|
||||
registerInputStream(format);
|
||||
// Input timestamps should always be positive because they are offset by ExoPlayer. Adding a
|
||||
// position to the queue with timestamp 0 should therefore always apply it as long as it is
|
||||
// the only position in the queue.
|
||||
streamStartPositionsUs.add(
|
||||
lastBufferPresentationTimeUs == C.TIME_UNSET ? 0 : lastBufferPresentationTimeUs + 1,
|
||||
startPositionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -785,16 +797,6 @@ public final class PlaybackVideoGraphWrapper implements VideoSinkProvider, Video
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamStartPositionUs(long streamStartPositionUs) {
|
||||
// Input timestamps should always be positive because they are offset by ExoPlayer. Adding a
|
||||
// position to the queue with timestamp 0 should therefore always apply it as long as it is
|
||||
// the only position in the queue.
|
||||
streamStartPositionsUs.add(
|
||||
lastBufferPresentationTimeUs == C.TIME_UNSET ? 0 : lastBufferPresentationTimeUs + 1,
|
||||
streamStartPositionUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBufferTimestampAdjustmentUs(long bufferTimestampAdjustmentUs) {
|
||||
inputBufferTimestampAdjustmentUs = bufferTimestampAdjustmentUs;
|
||||
|
@ -188,7 +188,7 @@ public interface VideoSink {
|
||||
*
|
||||
* <p>This method returns {@code true} if the end of the last input stream has been {@linkplain
|
||||
* #signalEndOfCurrentInputStream() signaled} and all the input frames have been rendered. Note
|
||||
* that a new input stream can be {@linkplain #onInputStreamChanged(int, Format, List<Effect>)
|
||||
* that a new input stream can be {@linkplain #onInputStreamChanged(int, Format, long, List)
|
||||
* signaled} even when this method returns true (in which case the sink will not be ended
|
||||
* anymore).
|
||||
*/
|
||||
@ -210,14 +210,6 @@ public interface VideoSink {
|
||||
/** Sets {@linkplain Effect video effects} to apply immediately. */
|
||||
void setVideoEffects(List<Effect> videoEffects);
|
||||
|
||||
/**
|
||||
* Sets the current stream start position.
|
||||
*
|
||||
* @param streamStartPositionUs The start position of the buffer presentation timestamps of the
|
||||
* current stream, in microseconds.
|
||||
*/
|
||||
void setStreamStartPositionUs(long streamStartPositionUs);
|
||||
|
||||
/**
|
||||
* Sets the buffer timestamp adjustment.
|
||||
*
|
||||
@ -256,15 +248,18 @@ public interface VideoSink {
|
||||
*
|
||||
* @param inputType The {@link InputType} of the stream.
|
||||
* @param format The {@link Format} of the stream.
|
||||
* @param startPositionUs The start position of the buffer presentation timestamps of the stream,
|
||||
* in microseconds.
|
||||
* @param videoEffects The {@link List<Effect>} to apply to the new stream.
|
||||
*/
|
||||
void onInputStreamChanged(@InputType int inputType, Format format, List<Effect> videoEffects);
|
||||
void onInputStreamChanged(
|
||||
@InputType int inputType, Format format, long startPositionUs, List<Effect> videoEffects);
|
||||
|
||||
/**
|
||||
* Handles a video input frame.
|
||||
*
|
||||
* <p>Must be called after the corresponding stream is {@linkplain #onInputStreamChanged(int,
|
||||
* Format, List<Effect>) signaled}.
|
||||
* Format, long, List) signaled}.
|
||||
*
|
||||
* @param framePresentationTimeUs The frame's presentation time, in microseconds.
|
||||
* @param isLastFrame Whether this is the last frame of the video stream. This flag is set on a
|
||||
@ -281,7 +276,7 @@ public interface VideoSink {
|
||||
* Handles an input {@link Bitmap}.
|
||||
*
|
||||
* <p>Must be called after the corresponding stream is {@linkplain #onInputStreamChanged(int,
|
||||
* Format, List<Effect>) signaled}.
|
||||
* Format, long, List) signaled}.
|
||||
*
|
||||
* @param inputBitmap The {@link Bitmap} to queue to the video sink.
|
||||
* @param timestampIterator The times within the current stream that the bitmap should be shown
|
||||
|
@ -75,13 +75,15 @@ public final class PlaybackVideoGraphWrapperTest {
|
||||
PlaybackVideoGraphWrapper playbackVideoGraphWrapper =
|
||||
createPlaybackVideoGraphWrapper(testVideoGraphFactory);
|
||||
Format format = new Format.Builder().build();
|
||||
long startPositionUs = 0;
|
||||
VideoSink sink = playbackVideoGraphWrapper.getSink(/* inputIndex= */ 0);
|
||||
|
||||
sink.initialize(format);
|
||||
|
||||
sink.onInputStreamChanged(VideoSink.INPUT_TYPE_SURFACE, format, firstEffects);
|
||||
sink.onInputStreamChanged(VideoSink.INPUT_TYPE_SURFACE, format, secondEffects);
|
||||
sink.onInputStreamChanged(VideoSink.INPUT_TYPE_SURFACE, format, ImmutableList.of());
|
||||
sink.onInputStreamChanged(VideoSink.INPUT_TYPE_SURFACE, format, startPositionUs, firstEffects);
|
||||
sink.onInputStreamChanged(VideoSink.INPUT_TYPE_SURFACE, format, startPositionUs, secondEffects);
|
||||
sink.onInputStreamChanged(
|
||||
VideoSink.INPUT_TYPE_SURFACE, format, startPositionUs, ImmutableList.of());
|
||||
testVideoGraphFactory.verifyRegisteredEffectsMatches(/* invocationTimes= */ 3);
|
||||
assertThat(testVideoGraphFactory.getCapturedEffects())
|
||||
.isEqualTo(ImmutableList.of(firstEffects, secondEffects, ImmutableList.of()));
|
||||
|
@ -192,11 +192,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
executeOrDelay(videoSink -> videoSink.setVideoEffects(videoEffects));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStreamStartPositionUs(long streamStartPositionUs) {
|
||||
executeOrDelay(videoSink -> videoSink.setStreamStartPositionUs(streamStartPositionUs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBufferTimestampAdjustmentUs(long bufferTimestampAdjustmentUs) {
|
||||
executeOrDelay(
|
||||
@ -225,8 +220,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@Override
|
||||
public void onInputStreamChanged(
|
||||
@InputType int inputType, Format format, List<Effect> videoEffects) {
|
||||
executeOrDelay(videoSink -> videoSink.onInputStreamChanged(inputType, format, videoEffects));
|
||||
@InputType int inputType, Format format, long startPositionUs, List<Effect> videoEffects) {
|
||||
executeOrDelay(
|
||||
videoSink ->
|
||||
videoSink.onInputStreamChanged(inputType, format, startPositionUs, videoEffects));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -435,7 +435,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@Override
|
||||
protected void changeVideoSinkInputStream(
|
||||
VideoSink videoSink, @VideoSink.InputType int inputType, Format format) {
|
||||
videoSink.onInputStreamChanged(inputType, format, pendingEffects);
|
||||
videoSink.onInputStreamChanged(
|
||||
inputType, format, getOutputStreamStartPositionUs(), pendingEffects);
|
||||
}
|
||||
|
||||
private void activateBufferingVideoSink() {
|
||||
@ -614,7 +615,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
long positionUs, long elapsedRealtimeUs, Bitmap outputImage, long timeUs) {
|
||||
if (inputStreamPending) {
|
||||
checkState(streamStartPositionUs != C.TIME_UNSET);
|
||||
videoSink.setStreamStartPositionUs(streamStartPositionUs);
|
||||
videoSink.onInputStreamChanged(
|
||||
VideoSink.INPUT_TYPE_BITMAP,
|
||||
new Format.Builder()
|
||||
@ -624,6 +624,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
.setColorInfo(ColorInfo.SRGB_BT709_FULL)
|
||||
.setFrameRate(/* frameRate= */ DEFAULT_FRAME_RATE)
|
||||
.build(),
|
||||
streamStartPositionUs,
|
||||
videoEffects);
|
||||
inputStreamPending = false;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user