mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
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:
parent
bdfd24290f
commit
29c43b5e24
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user