Add util method BaseRenderer.getStreamOffsetUs
This simplifies the common pattern of saving this offset in onStreamChanged to use it at a later point. PiperOrigin-RevId: 666226263
This commit is contained in:
parent
4ba9f59492
commit
6f0cb539d0
@ -418,6 +418,15 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
|
|||||||
return lastResetPositionUs;
|
return lastResetPositionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the offset added to timestamps of buffers read from the {@link SampleStream}.
|
||||||
|
*
|
||||||
|
* <p>Must only be called if the renderer is at least {@link #STATE_ENABLED}.
|
||||||
|
*/
|
||||||
|
protected final long getStreamOffsetUs() {
|
||||||
|
return streamOffsetUs;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a clear {@link FormatHolder}. */
|
/** Returns a clear {@link FormatHolder}. */
|
||||||
protected final FormatHolder getFormatHolder() {
|
protected final FormatHolder getFormatHolder() {
|
||||||
formatHolder.clear();
|
formatHolder.clear();
|
||||||
|
@ -119,7 +119,6 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||||||
private boolean inputStreamEnded;
|
private boolean inputStreamEnded;
|
||||||
private boolean outputStreamEnded;
|
private boolean outputStreamEnded;
|
||||||
@Nullable private Format streamFormat;
|
@Nullable private Format streamFormat;
|
||||||
private long outputStreamOffsetUs;
|
|
||||||
private long lastRendererPositionUs;
|
private long lastRendererPositionUs;
|
||||||
private long finalStreamEndPositionUs;
|
private long finalStreamEndPositionUs;
|
||||||
private boolean legacyDecodingEnabled;
|
private boolean legacyDecodingEnabled;
|
||||||
@ -159,7 +158,6 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||||||
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
|
||||||
formatHolder = new FormatHolder();
|
formatHolder = new FormatHolder();
|
||||||
finalStreamEndPositionUs = C.TIME_UNSET;
|
finalStreamEndPositionUs = C.TIME_UNSET;
|
||||||
outputStreamOffsetUs = C.TIME_UNSET;
|
|
||||||
lastRendererPositionUs = C.TIME_UNSET;
|
lastRendererPositionUs = C.TIME_UNSET;
|
||||||
legacyDecodingEnabled = false;
|
legacyDecodingEnabled = false;
|
||||||
}
|
}
|
||||||
@ -206,7 +204,6 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||||||
long startPositionUs,
|
long startPositionUs,
|
||||||
long offsetUs,
|
long offsetUs,
|
||||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
MediaSource.MediaPeriodId mediaPeriodId) {
|
||||||
outputStreamOffsetUs = offsetUs;
|
|
||||||
streamFormat = formats[0];
|
streamFormat = formats[0];
|
||||||
if (!isCuesWithTiming(streamFormat)) {
|
if (!isCuesWithTiming(streamFormat)) {
|
||||||
assertLegacyDecodingEnabledIfRequired();
|
assertLegacyDecodingEnabledIfRequired();
|
||||||
@ -462,7 +459,6 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||||||
streamFormat = null;
|
streamFormat = null;
|
||||||
finalStreamEndPositionUs = C.TIME_UNSET;
|
finalStreamEndPositionUs = C.TIME_UNSET;
|
||||||
clearOutput();
|
clearOutput();
|
||||||
outputStreamOffsetUs = C.TIME_UNSET;
|
|
||||||
lastRendererPositionUs = C.TIME_UNSET;
|
lastRendererPositionUs = C.TIME_UNSET;
|
||||||
if (subtitleDecoder != null) {
|
if (subtitleDecoder != null) {
|
||||||
releaseSubtitleDecoder();
|
releaseSubtitleDecoder();
|
||||||
@ -579,9 +575,7 @@ public final class TextRenderer extends BaseRenderer implements Callback {
|
|||||||
@SideEffectFree
|
@SideEffectFree
|
||||||
private long getPresentationTimeUs(long positionUs) {
|
private long getPresentationTimeUs(long positionUs) {
|
||||||
checkState(positionUs != C.TIME_UNSET);
|
checkState(positionUs != C.TIME_UNSET);
|
||||||
checkState(outputStreamOffsetUs != C.TIME_UNSET);
|
return positionUs - getStreamOffsetUs();
|
||||||
|
|
||||||
return positionUs - outputStreamOffsetUs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresNonNull("streamFormat")
|
@RequiresNonNull("streamFormat")
|
||||||
|
@ -153,7 +153,6 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||||||
private int consecutiveDroppedFrameCount;
|
private int consecutiveDroppedFrameCount;
|
||||||
private int buffersInCodecCount;
|
private int buffersInCodecCount;
|
||||||
private long lastRenderTimeUs;
|
private long lastRenderTimeUs;
|
||||||
private long outputStreamOffsetUs;
|
|
||||||
|
|
||||||
/** Decoder event counters used for debugging purposes. */
|
/** Decoder event counters used for debugging purposes. */
|
||||||
protected DecoderCounters decoderCounters;
|
protected DecoderCounters decoderCounters;
|
||||||
@ -342,10 +341,8 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||||||
long offsetUs,
|
long offsetUs,
|
||||||
MediaSource.MediaPeriodId mediaPeriodId)
|
MediaSource.MediaPeriodId mediaPeriodId)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
// TODO: This shouldn't just update the output stream offset as long as there are still buffers
|
// TODO: This code should make sure to render the first frame of the next stream if the playback
|
||||||
// of the previous stream in the decoder. It should also make sure to render the first frame of
|
// position reached the new stream.
|
||||||
// the next stream if the playback position reached the new stream.
|
|
||||||
outputStreamOffsetUs = offsetUs;
|
|
||||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,7 +872,9 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
|
|||||||
outputFormat = formatQueue.pollFirst();
|
outputFormat = formatQueue.pollFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
long presentationTimeUs = bufferTimeUs - outputStreamOffsetUs;
|
// TODO: This shouldn't just use the input stream offset and we should correctly track the
|
||||||
|
// output stream offset after decoding instead.
|
||||||
|
long presentationTimeUs = bufferTimeUs - getStreamOffsetUs();
|
||||||
if (shouldForceRender(earlyUs)) {
|
if (shouldForceRender(earlyUs)) {
|
||||||
renderOutputBuffer(outputBuffer, presentationTimeUs, checkNotNull(outputFormat));
|
renderOutputBuffer(outputBuffer, presentationTimeUs, checkNotNull(outputFormat));
|
||||||
return true;
|
return true;
|
||||||
|
@ -28,7 +28,6 @@ import androidx.media3.exoplayer.ExoPlaybackException;
|
|||||||
import androidx.media3.exoplayer.FormatHolder;
|
import androidx.media3.exoplayer.FormatHolder;
|
||||||
import androidx.media3.exoplayer.Renderer;
|
import androidx.media3.exoplayer.Renderer;
|
||||||
import androidx.media3.exoplayer.RendererCapabilities;
|
import androidx.media3.exoplayer.RendererCapabilities;
|
||||||
import androidx.media3.exoplayer.source.MediaSource;
|
|
||||||
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
import androidx.media3.exoplayer.source.SampleStream.ReadDataResult;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
@ -43,7 +42,6 @@ public final class CameraMotionRenderer extends BaseRenderer {
|
|||||||
private final DecoderInputBuffer buffer;
|
private final DecoderInputBuffer buffer;
|
||||||
private final ParsableByteArray scratch;
|
private final ParsableByteArray scratch;
|
||||||
|
|
||||||
private long offsetUs;
|
|
||||||
@Nullable private CameraMotionListener listener;
|
@Nullable private CameraMotionListener listener;
|
||||||
private long lastTimestampUs;
|
private long lastTimestampUs;
|
||||||
|
|
||||||
@ -75,15 +73,6 @@ public final class CameraMotionRenderer extends BaseRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStreamChanged(
|
|
||||||
Format[] formats,
|
|
||||||
long startPositionUs,
|
|
||||||
long offsetUs,
|
|
||||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
|
||||||
this.offsetUs = offsetUs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPositionReset(long positionUs, boolean joining) {
|
protected void onPositionReset(long positionUs, boolean joining) {
|
||||||
lastTimestampUs = Long.MIN_VALUE;
|
lastTimestampUs = Long.MIN_VALUE;
|
||||||
@ -118,7 +107,7 @@ public final class CameraMotionRenderer extends BaseRenderer {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.castNonNull(listener).onCameraMotion(lastTimestampUs - offsetUs, rotation);
|
Util.castNonNull(listener).onCameraMotion(lastTimestampUs - getStreamOffsetUs(), rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,6 @@ public class FakeVideoRenderer extends FakeRenderer {
|
|||||||
private final AtomicReference<VideoSize> videoSizeRef = new AtomicReference<>();
|
private final AtomicReference<VideoSize> videoSizeRef = new AtomicReference<>();
|
||||||
private @MonotonicNonNull Format format;
|
private @MonotonicNonNull Format format;
|
||||||
@Nullable private Object output;
|
@Nullable private Object output;
|
||||||
private long streamOffsetUs;
|
|
||||||
private boolean renderedFirstFrameAfterReset;
|
private boolean renderedFirstFrameAfterReset;
|
||||||
private boolean mayRenderFirstFrameAfterEnableIfNotStarted;
|
private boolean mayRenderFirstFrameAfterEnableIfNotStarted;
|
||||||
private boolean renderedFirstFrameAfterEnable;
|
private boolean renderedFirstFrameAfterEnable;
|
||||||
@ -73,7 +72,6 @@ public class FakeVideoRenderer extends FakeRenderer {
|
|||||||
MediaSource.MediaPeriodId mediaPeriodId)
|
MediaSource.MediaPeriodId mediaPeriodId)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||||
streamOffsetUs = offsetUs;
|
|
||||||
renderedFirstFrameAfterReset = false;
|
renderedFirstFrameAfterReset = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +148,7 @@ public class FakeVideoRenderer extends FakeRenderer {
|
|||||||
? (getState() == Renderer.STATE_STARTED
|
? (getState() == Renderer.STATE_STARTED
|
||||||
|| mayRenderFirstFrameAfterEnableIfNotStarted)
|
|| mayRenderFirstFrameAfterEnableIfNotStarted)
|
||||||
: !renderedFirstFrameAfterReset);
|
: !renderedFirstFrameAfterReset);
|
||||||
shouldProcess |= shouldRenderFirstFrame && playbackPositionUs >= streamOffsetUs;
|
shouldProcess |= shouldRenderFirstFrame && playbackPositionUs >= getStreamOffsetUs();
|
||||||
@Nullable Object output = this.output;
|
@Nullable Object output = this.output;
|
||||||
if (shouldProcess && !renderedFirstFrameAfterReset && output != null) {
|
if (shouldProcess && !renderedFirstFrameAfterReset && output != null) {
|
||||||
@MonotonicNonNull Format format = Assertions.checkNotNull(this.format);
|
@MonotonicNonNull Format format = Assertions.checkNotNull(this.format);
|
||||||
|
@ -42,7 +42,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
/* package */ abstract class ExoAssetLoaderBaseRenderer extends BaseRenderer {
|
/* package */ abstract class ExoAssetLoaderBaseRenderer extends BaseRenderer {
|
||||||
|
|
||||||
protected long streamStartPositionUs;
|
protected long streamStartPositionUs;
|
||||||
protected long streamOffsetUs;
|
|
||||||
protected @MonotonicNonNull SampleConsumer sampleConsumer;
|
protected @MonotonicNonNull SampleConsumer sampleConsumer;
|
||||||
protected @MonotonicNonNull Codec decoder;
|
protected @MonotonicNonNull Codec decoder;
|
||||||
protected boolean isEnded;
|
protected boolean isEnded;
|
||||||
@ -131,7 +130,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
long offsetUs,
|
long offsetUs,
|
||||||
MediaSource.MediaPeriodId mediaPeriodId) {
|
MediaSource.MediaPeriodId mediaPeriodId) {
|
||||||
this.streamStartPositionUs = startPositionUs;
|
this.streamStartPositionUs = startPositionUs;
|
||||||
this.streamOffsetUs = offsetUs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,6 +130,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
|
|
||||||
ByteBuffer inputBytes = checkNotNull(inputBuffer.data);
|
ByteBuffer inputBytes = checkNotNull(inputBuffer.data);
|
||||||
if (sefVideoSlowMotionFlattener != null) {
|
if (sefVideoSlowMotionFlattener != null) {
|
||||||
|
long streamOffsetUs = getStreamOffsetUs();
|
||||||
long presentationTimeUs = inputBuffer.timeUs - streamOffsetUs;
|
long presentationTimeUs = inputBuffer.timeUs - streamOffsetUs;
|
||||||
boolean shouldDropInputBuffer =
|
boolean shouldDropInputBuffer =
|
||||||
sefVideoSlowMotionFlattener.dropOrTransformSample(inputBytes, presentationTimeUs);
|
sefVideoSlowMotionFlattener.dropOrTransformSample(inputBytes, presentationTimeUs);
|
||||||
|
@ -300,7 +300,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
@Nullable private ExoPlaybackException pendingExoPlaybackException;
|
@Nullable private ExoPlaybackException pendingExoPlaybackException;
|
||||||
private boolean inputStreamPending;
|
private boolean inputStreamPending;
|
||||||
private long streamStartPositionUs;
|
private long streamStartPositionUs;
|
||||||
private long streamOffsetUs;
|
|
||||||
private boolean mayRenderStartOfStream;
|
private boolean mayRenderStartOfStream;
|
||||||
private long offsetToCompositionTimeUs;
|
private long offsetToCompositionTimeUs;
|
||||||
|
|
||||||
@ -311,7 +310,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
videoSink = checkStateNotNull(sequencePlayerRenderersWrapper.videoSink);
|
videoSink = checkStateNotNull(sequencePlayerRenderersWrapper.videoSink);
|
||||||
videoEffects = ImmutableList.of();
|
videoEffects = ImmutableList.of();
|
||||||
streamStartPositionUs = C.TIME_UNSET;
|
streamStartPositionUs = C.TIME_UNSET;
|
||||||
streamOffsetUs = C.TIME_UNSET;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageRenderer methods
|
// ImageRenderer methods
|
||||||
@ -397,7 +395,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
checkState(getTimeline().getWindowCount() == 1);
|
checkState(getTimeline().getWindowCount() == 1);
|
||||||
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
super.onStreamChanged(formats, startPositionUs, offsetUs, mediaPeriodId);
|
||||||
streamStartPositionUs = startPositionUs;
|
streamStartPositionUs = startPositionUs;
|
||||||
streamOffsetUs = offsetUs;
|
|
||||||
int mediaItemIndex = getTimeline().getIndexOfPeriod(mediaPeriodId.periodUid);
|
int mediaItemIndex = getTimeline().getIndexOfPeriod(mediaPeriodId.periodUid);
|
||||||
editedMediaItem =
|
editedMediaItem =
|
||||||
sequencePlayerRenderersWrapper.sequence.editedMediaItems.get(mediaItemIndex);
|
sequencePlayerRenderersWrapper.sequence.editedMediaItems.get(mediaItemIndex);
|
||||||
@ -429,11 +426,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
long positionUs, long elapsedRealtimeUs, Bitmap outputImage, long timeUs) {
|
long positionUs, long elapsedRealtimeUs, Bitmap outputImage, long timeUs) {
|
||||||
if (inputStreamPending) {
|
if (inputStreamPending) {
|
||||||
checkState(streamStartPositionUs != C.TIME_UNSET);
|
checkState(streamStartPositionUs != C.TIME_UNSET);
|
||||||
checkState(streamOffsetUs != C.TIME_UNSET);
|
|
||||||
videoSink.setPendingVideoEffects(videoEffects);
|
videoSink.setPendingVideoEffects(videoEffects);
|
||||||
videoSink.setStreamTimestampInfo(
|
videoSink.setStreamTimestampInfo(
|
||||||
streamStartPositionUs,
|
streamStartPositionUs,
|
||||||
streamOffsetUs,
|
getStreamOffsetUs(),
|
||||||
/* bufferTimestampAdjustmentUs= */ offsetToCompositionTimeUs,
|
/* bufferTimestampAdjustmentUs= */ offsetToCompositionTimeUs,
|
||||||
getLastResetPositionUs());
|
getLastResetPositionUs());
|
||||||
videoSink.onInputStreamChanged(
|
videoSink.onInputStreamChanged(
|
||||||
@ -451,6 +447,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ConstantRateTimestampIterator createTimestampIterator(long positionUs) {
|
private ConstantRateTimestampIterator createTimestampIterator(long positionUs) {
|
||||||
|
long streamOffsetUs = getStreamOffsetUs();
|
||||||
long imageBaseTimestampUs = streamOffsetUs + offsetToCompositionTimeUs;
|
long imageBaseTimestampUs = streamOffsetUs + offsetToCompositionTimeUs;
|
||||||
long positionWithinImage = positionUs - streamOffsetUs;
|
long positionWithinImage = positionUs - streamOffsetUs;
|
||||||
long firstBitmapTimeUs = imageBaseTimestampUs + positionWithinImage;
|
long firstBitmapTimeUs = imageBaseTimestampUs + positionWithinImage;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user