Commit 629e1c51 by tonihei

Use ArrayDeque for pending output stream changes.

The current logic uses manual array operations to keep track of pending
changes. Modernize this code by using an ArrayDeque and a data class.
This also allows to extend the output stream information in the future.

This also fixes a bug where a position reset accidentally assigns a pending
stream offset instead of keeping the current one.

PiperOrigin-RevId: 511787571
(cherry picked from commit 4e0babdc)
parent d0c07691
...@@ -206,10 +206,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -206,10 +206,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/ */
private static final long MAX_CODEC_HOTSWAP_TIME_MS = 1000; private static final long MAX_CODEC_HOTSWAP_TIME_MS = 1000;
// Generally there is zero or one pending output stream offset. We track more offsets to allow for
// pending output streams that have fewer frames than the codec latency.
private static final int MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT = 10;
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE) @Target(TYPE_USE)
...@@ -304,9 +300,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -304,9 +300,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private final TimedValueQueue<Format> formatQueue; private final TimedValueQueue<Format> formatQueue;
private final ArrayList<Long> decodeOnlyPresentationTimestamps; private final ArrayList<Long> decodeOnlyPresentationTimestamps;
private final MediaCodec.BufferInfo outputBufferInfo; private final MediaCodec.BufferInfo outputBufferInfo;
private final long[] pendingOutputStreamStartPositionsUs; private final ArrayDeque<OutputStreamInfo> pendingOutputStreamChanges;
private final long[] pendingOutputStreamOffsetsUs;
private final long[] pendingOutputStreamSwitchTimesUs;
@Nullable private Format inputFormat; @Nullable private Format inputFormat;
@Nullable private Format outputFormat; @Nullable private Format outputFormat;
...@@ -361,9 +355,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -361,9 +355,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean pendingOutputEndOfStream; private boolean pendingOutputEndOfStream;
@Nullable private ExoPlaybackException pendingPlaybackException; @Nullable private ExoPlaybackException pendingPlaybackException;
protected DecoderCounters decoderCounters; protected DecoderCounters decoderCounters;
private long outputStreamStartPositionUs; private OutputStreamInfo outputStreamInfo;
private long outputStreamOffsetUs;
private int pendingOutputStreamOffsetCount;
/** /**
* @param trackType The {@link C.TrackType track type} that the renderer handles. * @param trackType The {@link C.TrackType track type} that the renderer handles.
...@@ -396,11 +388,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -396,11 +388,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
currentPlaybackSpeed = 1f; currentPlaybackSpeed = 1f;
targetPlaybackSpeed = 1f; targetPlaybackSpeed = 1f;
renderTimeLimitMs = C.TIME_UNSET; renderTimeLimitMs = C.TIME_UNSET;
pendingOutputStreamStartPositionsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; pendingOutputStreamChanges = new ArrayDeque<>();
pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT]; setOutputStreamInfo(OutputStreamInfo.UNSET);
pendingOutputStreamSwitchTimesUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
outputStreamStartPositionUs = C.TIME_UNSET;
setOutputStreamOffsetUs(C.TIME_UNSET);
// MediaCodec outputs audio buffers in native endian: // MediaCodec outputs audio buffers in native endian:
// https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers // https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers
// and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness. // and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness.
...@@ -646,23 +635,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -646,23 +635,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override @Override
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs)
throws ExoPlaybackException { throws ExoPlaybackException {
if (this.outputStreamOffsetUs == C.TIME_UNSET) { if (outputStreamInfo.streamOffsetUs == C.TIME_UNSET) {
checkState(this.outputStreamStartPositionUs == C.TIME_UNSET); checkState(outputStreamInfo.startPositionUs == C.TIME_UNSET);
this.outputStreamStartPositionUs = startPositionUs; setOutputStreamInfo(
setOutputStreamOffsetUs(offsetUs); new OutputStreamInfo(
} else { /* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs));
if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) {
Log.w(
TAG,
"Too many stream changes, so dropping offset: "
+ pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]);
} else { } else {
pendingOutputStreamOffsetCount++; pendingOutputStreamChanges.add(
} new OutputStreamInfo(largestQueuedPresentationTimeUs, startPositionUs, offsetUs));
pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1] = startPositionUs;
pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs;
pendingOutputStreamSwitchTimesUs[pendingOutputStreamOffsetCount - 1] =
largestQueuedPresentationTimeUs;
} }
} }
...@@ -685,12 +665,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -685,12 +665,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
waitingForFirstSampleInFormat = true; waitingForFirstSampleInFormat = true;
} }
formatQueue.clear(); formatQueue.clear();
if (pendingOutputStreamOffsetCount != 0) { pendingOutputStreamChanges.clear();
setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]);
outputStreamStartPositionUs =
pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1];
pendingOutputStreamOffsetCount = 0;
}
} }
@Override @Override
...@@ -704,9 +679,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -704,9 +679,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override @Override
protected void onDisabled() { protected void onDisabled() {
inputFormat = null; inputFormat = null;
outputStreamStartPositionUs = C.TIME_UNSET; setOutputStreamInfo(OutputStreamInfo.UNSET);
setOutputStreamOffsetUs(C.TIME_UNSET); pendingOutputStreamChanges.clear();
pendingOutputStreamOffsetCount = 0;
flushOrReleaseCodec(); flushOrReleaseCodec();
} }
...@@ -1591,29 +1565,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1591,29 +1565,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/ */
@CallSuper @CallSuper
protected void onProcessedOutputBuffer(long presentationTimeUs) { protected void onProcessedOutputBuffer(long presentationTimeUs) {
while (pendingOutputStreamOffsetCount != 0 if (!pendingOutputStreamChanges.isEmpty()
&& presentationTimeUs >= pendingOutputStreamSwitchTimesUs[0]) { && presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) {
outputStreamStartPositionUs = pendingOutputStreamStartPositionsUs[0]; setOutputStreamInfo(pendingOutputStreamChanges.poll());
setOutputStreamOffsetUs(pendingOutputStreamOffsetsUs[0]);
pendingOutputStreamOffsetCount--;
System.arraycopy(
pendingOutputStreamStartPositionsUs,
/* srcPos= */ 1,
pendingOutputStreamStartPositionsUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
System.arraycopy(
pendingOutputStreamOffsetsUs,
/* srcPos= */ 1,
pendingOutputStreamOffsetsUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
System.arraycopy(
pendingOutputStreamSwitchTimesUs,
/* srcPos= */ 1,
pendingOutputStreamSwitchTimesUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
onProcessedStreamChange(); onProcessedStreamChange();
} }
} }
...@@ -2060,13 +2014,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -2060,13 +2014,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* boolean, Format)} to get the playback position with respect to the media. * boolean, Format)} to get the playback position with respect to the media.
*/ */
protected final long getOutputStreamOffsetUs() { protected final long getOutputStreamOffsetUs() {
return outputStreamOffsetUs; return outputStreamInfo.streamOffsetUs;
} }
private void setOutputStreamOffsetUs(long outputStreamOffsetUs) { private void setOutputStreamInfo(OutputStreamInfo outputStreamInfo) {
this.outputStreamOffsetUs = outputStreamOffsetUs; this.outputStreamInfo = outputStreamInfo;
if (outputStreamOffsetUs != C.TIME_UNSET) { if (outputStreamInfo.streamOffsetUs != C.TIME_UNSET) {
onOutputStreamOffsetUsChanged(outputStreamOffsetUs); onOutputStreamOffsetUsChanged(outputStreamInfo.streamOffsetUs);
} }
} }
...@@ -2513,6 +2467,26 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -2513,6 +2467,26 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
&& "OMX.MTK.AUDIO.DECODER.MP3".equals(name); && "OMX.MTK.AUDIO.DECODER.MP3".equals(name);
} }
private static final class OutputStreamInfo {
public static final OutputStreamInfo UNSET =
new OutputStreamInfo(
/* previousStreamLastBufferTimeUs= */ C.TIME_UNSET,
/* startPositionUs= */ C.TIME_UNSET,
/* streamOffsetUs= */ C.TIME_UNSET);
public final long previousStreamLastBufferTimeUs;
public final long startPositionUs;
public final long streamOffsetUs;
public OutputStreamInfo(
long previousStreamLastBufferTimeUs, long startPositionUs, long streamOffsetUs) {
this.previousStreamLastBufferTimeUs = previousStreamLastBufferTimeUs;
this.startPositionUs = startPositionUs;
this.streamOffsetUs = streamOffsetUs;
}
}
@RequiresApi(31) @RequiresApi(31)
private static final class Api31 { private static final class Api31 {
private Api31() {} private Api31() {}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment