Move common bookkeeping to MediaCodecRenderer.

This is a no-op change and just moves some duplicated logic into the
base class.

PiperOrigin-RevId: 294615218
This commit is contained in:
tonihei 2020-02-12 09:24:23 +00:00 committed by Oliver Woodman
parent bdfd24290f
commit 29c43b5e24
3 changed files with 86 additions and 122 deletions

View File

@ -22,7 +22,6 @@ import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.media.audiofx.Virtualizer;
import android.os.Handler;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
@ -43,7 +42,6 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.mediacodec.MediaFormatUtil;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MediaClock;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
@ -71,13 +69,6 @@ import java.util.List;
*/
public class MediaCodecAudioRenderer extends MediaCodecRenderer implements MediaClock {
/**
* Maximum number of tracked pending stream change times. Generally there is zero or one pending
* stream change. We track more to allow for pending changes that have fewer samples than the
* codec latency.
*/
private static final int MAX_PENDING_STREAM_CHANGE_COUNT = 10;
private static final String TAG = "MediaCodecAudioRenderer";
/**
* Custom key used to indicate bits per sample by some decoders on Vivo devices. For example
@ -88,7 +79,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private final Context context;
private final EventDispatcher eventDispatcher;
private final AudioSink audioSink;
private final long[] pendingStreamChangeTimesUs;
private int codecMaxInputSize;
private boolean passthroughEnabled;
@ -99,8 +89,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private long currentPositionUs;
private boolean allowFirstBufferPositionDiscontinuity;
private boolean allowPositionDiscontinuity;
private long lastInputTimeUs;
private int pendingStreamChangeCount;
/**
* @param context A context.
@ -354,8 +342,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
/* assumedMinimumCodecOperatingRate= */ 44100);
this.context = context.getApplicationContext();
this.audioSink = audioSink;
lastInputTimeUs = C.TIME_UNSET;
pendingStreamChangeTimesUs = new long[MAX_PENDING_STREAM_CHANGE_COUNT];
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
audioSink.setListener(new AudioSinkListener());
}
@ -666,22 +652,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
}
@Override
protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException {
super.onStreamChanged(formats, offsetUs);
if (lastInputTimeUs != C.TIME_UNSET) {
if (pendingStreamChangeCount == pendingStreamChangeTimesUs.length) {
Log.w(
TAG,
"Too many stream changes, so dropping change at "
+ pendingStreamChangeTimesUs[pendingStreamChangeCount - 1]);
} else {
pendingStreamChangeCount++;
}
pendingStreamChangeTimesUs[pendingStreamChangeCount - 1] = lastInputTimeUs;
}
}
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
super.onPositionReset(positionUs, joining);
@ -689,8 +659,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
currentPositionUs = positionUs;
allowFirstBufferPositionDiscontinuity = true;
allowPositionDiscontinuity = true;
lastInputTimeUs = C.TIME_UNSET;
pendingStreamChangeCount = 0;
}
@Override
@ -709,8 +677,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override
protected void onDisabled() {
try {
lastInputTimeUs = C.TIME_UNSET;
pendingStreamChangeCount = 0;
audioSink.flush();
} finally {
try {
@ -769,22 +735,12 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
allowFirstBufferPositionDiscontinuity = false;
}
lastInputTimeUs = Math.max(buffer.timeUs, lastInputTimeUs);
}
@CallSuper
@Override
protected void onProcessedOutputBuffer(long presentationTimeUs) {
while (pendingStreamChangeCount != 0 && presentationTimeUs >= pendingStreamChangeTimesUs[0]) {
audioSink.handleDiscontinuity();
pendingStreamChangeCount--;
System.arraycopy(
pendingStreamChangeTimesUs,
/* srcPos= */ 1,
pendingStreamChangeTimesUs,
/* destPos= */ 0,
pendingStreamChangeCount);
}
protected void onProcessedStreamChange() {
super.onProcessedStreamChange();
audioSink.handleDiscontinuity();
}
@Override
@ -803,8 +759,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
if (codecNeedsEosBufferTimestampWorkaround
&& bufferPresentationTimeUs == 0
&& (bufferFlags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0
&& lastInputTimeUs != C.TIME_UNSET) {
bufferPresentationTimeUs = lastInputTimeUs;
&& getLargestQueuedPresentationTimeUs() != C.TIME_UNSET) {
bufferPresentationTimeUs = getLargestQueuedPresentationTimeUs();
}
if (passthroughEnabled && (bufferFlags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {

View File

@ -262,6 +262,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/
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;
/**
* The possible return values for {@link #canKeepCodec(MediaCodec, MediaCodecInfo, Format,
* Format)}.
@ -384,6 +388,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private final TimedValueQueue<Format> formatQueue;
private final ArrayList<Long> decodeOnlyPresentationTimestamps;
private final MediaCodec.BufferInfo outputBufferInfo;
private final long[] pendingOutputStreamOffsetsUs;
private final long[] pendingOutputStreamSwitchTimesUs;
private boolean drmResourcesAcquired;
@Nullable private Format inputFormat;
@ -435,6 +441,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean pendingOutputEndOfStream;
@MediaCodecOperationMode private int mediaCodecOperationMode;
protected DecoderCounters decoderCounters;
private long outputStreamOffsetUs;
private int pendingOutputStreamOffsetCount;
/**
* @param trackType The track type that the renderer handles. One of the {@code C.TRACK_TYPE_*}
@ -475,6 +483,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
rendererOperatingRate = 1f;
renderTimeLimitMs = C.TIME_UNSET;
mediaCodecOperationMode = OPERATION_MODE_SYNCHRONOUS;
pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
pendingOutputStreamSwitchTimesUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
outputStreamOffsetUs = C.TIME_UNSET;
resetCodecStateForRelease();
}
@ -687,6 +698,25 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
decoderCounters = new DecoderCounters();
}
@Override
protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException {
if (outputStreamOffsetUs == C.TIME_UNSET) {
outputStreamOffsetUs = offsetUs;
} else {
if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) {
Log.w(
TAG,
"Too many stream changes, so dropping offset: "
+ pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]);
} else {
pendingOutputStreamOffsetCount++;
}
pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs;
pendingOutputStreamSwitchTimesUs[pendingOutputStreamOffsetCount - 1] =
largestQueuedPresentationTimeUs;
}
}
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
inputStreamEnded = false;
@ -700,6 +730,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
waitingForFirstSampleInFormat = true;
}
formatQueue.clear();
if (pendingOutputStreamOffsetCount != 0) {
outputStreamOffsetUs = pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1];
pendingOutputStreamOffsetCount = 0;
}
}
@Override
@ -715,6 +749,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override
protected void onDisabled() {
inputFormat = null;
outputStreamOffsetUs = C.TIME_UNSET;
pendingOutputStreamOffsetCount = 0;
if (sourceDrmSession != null || codecDrmSession != null) {
// TODO: Do something better with this case.
onReset();
@ -1473,12 +1509,33 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
/**
* Called when an output buffer is successfully processed.
* <p>
* The default implementation is a no-op.
*
* @param presentationTimeUs The timestamp associated with the output buffer.
*/
@CallSuper
protected void onProcessedOutputBuffer(long presentationTimeUs) {
while (pendingOutputStreamOffsetCount != 0
&& presentationTimeUs >= pendingOutputStreamSwitchTimesUs[0]) {
outputStreamOffsetUs = pendingOutputStreamOffsetsUs[0];
pendingOutputStreamOffsetCount--;
System.arraycopy(
pendingOutputStreamOffsetsUs,
/* srcPos= */ 1,
pendingOutputStreamOffsetsUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
System.arraycopy(
pendingOutputStreamSwitchTimesUs,
/* srcPos= */ 1,
pendingOutputStreamSwitchTimesUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
onProcessedStreamChange();
}
}
/** Called after the last output buffer before a stream change has been processed. */
protected void onProcessedStreamChange() {
// Do nothing.
}
@ -1833,6 +1890,20 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
pendingOutputEndOfStream = true;
}
/** Returns the largest queued input presentation time, in microseconds. */
protected final long getLargestQueuedPresentationTimeUs() {
return largestQueuedPresentationTimeUs;
}
/**
* Returns the offset that should be subtracted from {@code bufferPresentationTimeUs} in {@link
* #processOutputBuffer(long, long, MediaCodec, ByteBuffer, int, int, long, boolean, boolean,
* Format)} to get the playback position with respect to the media.
*/
protected final long getOutputStreamOffsetUs() {
return outputStreamOffsetUs;
}
private void reinitializeCodec() throws ExoPlaybackException {
releaseCodec();
maybeInitCodec();

View File

@ -87,9 +87,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private static final int[] STANDARD_LONG_EDGE_VIDEO_PX = new int[] {
1920, 1600, 1440, 1280, 960, 854, 640, 540, 480};
// 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;
/**
* Scale factor for the initial maximum input size used to configure the codec in non-adaptive
* playbacks. See {@link #getCodecMaxValues(MediaCodecInfo, Format, Format[])}.
@ -125,8 +122,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private final long allowedJoiningTimeMs;
private final int maxDroppedFramesToNotify;
private final boolean deviceNeedsNoPostProcessWorkaround;
private final long[] pendingOutputStreamOffsetsUs;
private final long[] pendingOutputStreamSwitchTimesUs;
private CodecMaxValues codecMaxValues;
private boolean codecNeedsSetOutputSurfaceWorkaround;
@ -159,10 +154,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private boolean tunneling;
private int tunnelingAudioSessionId;
/* package */ @Nullable OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener;
private long lastInputTimeUs;
private long outputStreamOffsetUs;
private int pendingOutputStreamOffsetCount;
@Nullable private VideoFrameMetadataListener frameMetadataListener;
/**
@ -347,10 +338,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(this.context);
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
deviceNeedsNoPostProcessWorkaround = deviceNeedsNoPostProcessWorkaround();
pendingOutputStreamOffsetsUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
pendingOutputStreamSwitchTimesUs = new long[MAX_PENDING_OUTPUT_STREAM_OFFSET_COUNT];
outputStreamOffsetUs = C.TIME_UNSET;
lastInputTimeUs = C.TIME_UNSET;
joiningDeadlineMs = C.TIME_UNSET;
currentWidth = Format.NO_VALUE;
currentHeight = Format.NO_VALUE;
@ -484,34 +471,12 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
frameReleaseTimeHelper.enable();
}
@Override
protected void onStreamChanged(Format[] formats, long offsetUs) throws ExoPlaybackException {
if (outputStreamOffsetUs == C.TIME_UNSET) {
outputStreamOffsetUs = offsetUs;
} else {
if (pendingOutputStreamOffsetCount == pendingOutputStreamOffsetsUs.length) {
Log.w(TAG, "Too many stream changes, so dropping offset: "
+ pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1]);
} else {
pendingOutputStreamOffsetCount++;
}
pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1] = offsetUs;
pendingOutputStreamSwitchTimesUs[pendingOutputStreamOffsetCount - 1] = lastInputTimeUs;
}
super.onStreamChanged(formats, offsetUs);
}
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
super.onPositionReset(positionUs, joining);
clearRenderedFirstFrame();
initialPositionUs = C.TIME_UNSET;
consecutiveDroppedFrameCount = 0;
lastInputTimeUs = C.TIME_UNSET;
if (pendingOutputStreamOffsetCount != 0) {
outputStreamOffsetUs = pendingOutputStreamOffsetsUs[pendingOutputStreamOffsetCount - 1];
pendingOutputStreamOffsetCount = 0;
}
if (joining) {
setJoiningDeadlineMs();
} else {
@ -556,9 +521,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@Override
protected void onDisabled() {
lastInputTimeUs = C.TIME_UNSET;
outputStreamOffsetUs = C.TIME_UNSET;
pendingOutputStreamOffsetCount = 0;
currentMediaFormat = null;
clearReportedVideoSize();
clearRenderedFirstFrame();
@ -759,7 +721,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
if (!tunneling) {
buffersInCodecCount++;
}
lastInputTimeUs = Math.max(buffer.timeUs, lastInputTimeUs);
if (Util.SDK_INT < 23 && tunneling) {
// In tunneled mode before API 23 we don't have a way to know when the buffer is output, so
// treat it as if it were output immediately.
@ -838,6 +799,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
initialPositionUs = positionUs;
}
long outputStreamOffsetUs = getOutputStreamOffsetUs();
long presentationTimeUs = bufferPresentationTimeUs - outputStreamOffsetUs;
if (isDecodeOnlyBuffer && !isLastBuffer) {
@ -970,15 +932,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
}
/**
* Returns the offset that should be subtracted from {@code bufferPresentationTimeUs} in {@link
* #processOutputBuffer(long, long, MediaCodec, ByteBuffer, int, int, long, boolean, boolean,
* Format)} to get the playback position with respect to the media.
*/
protected long getOutputStreamOffsetUs() {
return outputStreamOffsetUs;
}
/** Called when a buffer was processed in tunneling mode. */
protected void onProcessedTunneledBuffer(long presentationTimeUs) {
@Nullable Format format = updateOutputFormatForTime(presentationTimeUs);
@ -995,35 +948,19 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
setPendingOutputEndOfStream();
}
/**
* Called when an output buffer is successfully processed.
*
* @param presentationTimeUs The timestamp associated with the output buffer.
*/
@CallSuper
@Override
protected void onProcessedOutputBuffer(long presentationTimeUs) {
super.onProcessedOutputBuffer(presentationTimeUs);
if (!tunneling) {
buffersInCodecCount--;
}
while (pendingOutputStreamOffsetCount != 0
&& presentationTimeUs >= pendingOutputStreamSwitchTimesUs[0]) {
outputStreamOffsetUs = pendingOutputStreamOffsetsUs[0];
pendingOutputStreamOffsetCount--;
System.arraycopy(
pendingOutputStreamOffsetsUs,
/* srcPos= */ 1,
pendingOutputStreamOffsetsUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
System.arraycopy(
pendingOutputStreamSwitchTimesUs,
/* srcPos= */ 1,
pendingOutputStreamSwitchTimesUs,
/* destPos= */ 0,
pendingOutputStreamOffsetCount);
clearRenderedFirstFrame();
}
}
@Override
protected void onProcessedStreamChange() {
super.onProcessedStreamChange();
clearRenderedFirstFrame();
}
/**