mirror of
https://github.com/androidx/media.git
synced 2025-05-17 12:39:52 +08:00
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. #minor-release PiperOrigin-RevId: 511787571
This commit is contained in:
parent
ecf168b359
commit
f042012495
@ -209,10 +209,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)
|
||||||
@ -307,9 +303,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;
|
|
||||||
private final OggOpusAudioPacketizer oggOpusAudioPacketizer;
|
private final OggOpusAudioPacketizer oggOpusAudioPacketizer;
|
||||||
|
|
||||||
@Nullable private Format inputFormat;
|
@Nullable private Format inputFormat;
|
||||||
@ -365,9 +359,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.
|
||||||
@ -400,11 +392,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.
|
||||||
@ -651,23 +640,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(
|
||||||
|
/* previousStreamLastBufferTimeUs= */ C.TIME_UNSET, startPositionUs, offsetUs));
|
||||||
} else {
|
} else {
|
||||||
if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) {
|
pendingOutputStreamChanges.add(
|
||||||
Log.w(
|
new OutputStreamInfo(largestQueuedPresentationTimeUs, startPositionUs, offsetUs));
|
||||||
TAG,
|
|
||||||
"Too many stream changes, so dropping offset: "
|
|
||||||
+ pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]);
|
|
||||||
} else {
|
|
||||||
pendingOutputStreamOffsetCount++;
|
|
||||||
}
|
|
||||||
pendingOutputStreamStartPositionsUs[pendingOutputStreamOffsetCount - 1] = startPositionUs;
|
|
||||||
pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs;
|
|
||||||
pendingOutputStreamSwitchTimesUs[pendingOutputStreamOffsetCount - 1] =
|
|
||||||
largestQueuedPresentationTimeUs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,12 +670,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
|
||||||
@ -709,9 +684,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1614,29 +1588,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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2083,13 +2037,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2543,6 +2497,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() {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user