Use new MediaCodec APIs in MediaCodecRenderer.

In MediaCodecRenderer, we currently uses codec.getInput/OutputBuffers event
though these APIs are deprecated and are not recommended from API 21+. This
change makes sure that:
- On API 20 and below, we will keep using codec.getInput/OutputBuffers.
- On API 21+, we will use getInput/OutputBuffer(index) APIs instead.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=184112329
This commit is contained in:
hoangtc 2018-02-01 02:44:00 -08:00 committed by Oliver Woodman
parent a7d4d2d21c
commit 4f36ab203f

View File

@ -224,6 +224,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private long codecHotswapDeadlineMs; private long codecHotswapDeadlineMs;
private int inputIndex; private int inputIndex;
private int outputIndex; private int outputIndex;
private ByteBuffer outputBuffer;
private boolean shouldSkipOutputBuffer; private boolean shouldSkipOutputBuffer;
private boolean codecReconfigured; private boolean codecReconfigured;
private @ReconfigurationState int codecReconfigurationState; private @ReconfigurationState int codecReconfigurationState;
@ -322,7 +323,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
protected abstract void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format, protected abstract void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format,
MediaCrypto crypto) throws DecoderQueryException; MediaCrypto crypto) throws DecoderQueryException;
@SuppressWarnings("deprecation")
protected final void maybeInitCodec() throws ExoPlaybackException { protected final void maybeInitCodec() throws ExoPlaybackException {
if (codec != null || format == null) { if (codec != null || format == null) {
// We have a codec already, or we don't have a format with which to instantiate one. // We have a codec already, or we don't have a format with which to instantiate one.
@ -402,16 +402,15 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
long codecInitializedTimestamp = SystemClock.elapsedRealtime(); long codecInitializedTimestamp = SystemClock.elapsedRealtime();
onCodecInitialized(codecName, codecInitializedTimestamp, onCodecInitialized(codecName, codecInitializedTimestamp,
codecInitializedTimestamp - codecInitializingTimestamp); codecInitializedTimestamp - codecInitializingTimestamp);
inputBuffers = codec.getInputBuffers(); getCodecBuffers();
outputBuffers = codec.getOutputBuffers();
} catch (Exception e) { } catch (Exception e) {
throwDecoderInitError(new DecoderInitializationException(format, e, throwDecoderInitError(new DecoderInitializationException(format, e,
drmSessionRequiresSecureDecoder, codecName)); drmSessionRequiresSecureDecoder, codecName));
} }
codecHotswapDeadlineMs = getState() == STATE_STARTED codecHotswapDeadlineMs = getState() == STATE_STARTED
? (SystemClock.elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS) : C.TIME_UNSET; ? (SystemClock.elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS) : C.TIME_UNSET;
inputIndex = C.INDEX_UNSET; resetInputBuffer();
outputIndex = C.INDEX_UNSET; resetOutputBuffer();
waitingForFirstSyncFrame = true; waitingForFirstSyncFrame = true;
decoderCounters.decoderInitCount++; decoderCounters.decoderInitCount++;
} }
@ -487,13 +486,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
protected void releaseCodec() { protected void releaseCodec() {
codecHotswapDeadlineMs = C.TIME_UNSET; codecHotswapDeadlineMs = C.TIME_UNSET;
inputIndex = C.INDEX_UNSET; resetInputBuffer();
outputIndex = C.INDEX_UNSET; resetOutputBuffer();
waitingForKeys = false; waitingForKeys = false;
shouldSkipOutputBuffer = false; shouldSkipOutputBuffer = false;
decodeOnlyPresentationTimestamps.clear(); decodeOnlyPresentationTimestamps.clear();
inputBuffers = null; resetCodecBuffers();
outputBuffers = null;
codecInfo = null; codecInfo = null;
codecReconfigured = false; codecReconfigured = false;
codecReceivedBuffers = false; codecReceivedBuffers = false;
@ -508,7 +506,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecReceivedEos = false; codecReceivedEos = false;
codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReconfigurationState = RECONFIGURATION_STATE_NONE;
codecReinitializationState = REINITIALIZATION_STATE_NONE; codecReinitializationState = REINITIALIZATION_STATE_NONE;
buffer.data = null;
if (codec != null) { if (codec != null) {
decoderCounters.decoderReleaseCount++; decoderCounters.decoderReleaseCount++;
try { try {
@ -591,8 +588,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
protected void flushCodec() throws ExoPlaybackException { protected void flushCodec() throws ExoPlaybackException {
codecHotswapDeadlineMs = C.TIME_UNSET; codecHotswapDeadlineMs = C.TIME_UNSET;
inputIndex = C.INDEX_UNSET; resetInputBuffer();
outputIndex = C.INDEX_UNSET; resetOutputBuffer();
waitingForFirstSyncFrame = true; waitingForFirstSyncFrame = true;
waitingForKeys = false; waitingForKeys = false;
shouldSkipOutputBuffer = false; shouldSkipOutputBuffer = false;
@ -635,7 +632,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (inputIndex < 0) { if (inputIndex < 0) {
return false; return false;
} }
buffer.data = inputBuffers[inputIndex]; buffer.data = getInputBuffer(inputIndex);
buffer.clear(); buffer.clear();
} }
@ -647,7 +644,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} else { } else {
codecReceivedEos = true; codecReceivedEos = true;
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputIndex = C.INDEX_UNSET; resetInputBuffer();
} }
codecReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM; codecReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM;
return false; return false;
@ -657,7 +654,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecNeedsAdaptationWorkaroundBuffer = false; codecNeedsAdaptationWorkaroundBuffer = false;
buffer.data.put(ADAPTATION_WORKAROUND_BUFFER); buffer.data.put(ADAPTATION_WORKAROUND_BUFFER);
codec.queueInputBuffer(inputIndex, 0, ADAPTATION_WORKAROUND_BUFFER.length, 0, 0); codec.queueInputBuffer(inputIndex, 0, ADAPTATION_WORKAROUND_BUFFER.length, 0, 0);
inputIndex = C.INDEX_UNSET; resetInputBuffer();
codecReceivedBuffers = true; codecReceivedBuffers = true;
return true; return true;
} }
@ -715,7 +712,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} else { } else {
codecReceivedEos = true; codecReceivedEos = true;
codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); codec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
inputIndex = C.INDEX_UNSET; resetInputBuffer();
} }
} catch (CryptoException e) { } catch (CryptoException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw ExoPlaybackException.createForRenderer(e, getIndex());
@ -760,7 +757,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} else { } else {
codec.queueInputBuffer(inputIndex, 0, buffer.data.limit(), presentationTimeUs, 0); codec.queueInputBuffer(inputIndex, 0, buffer.data.limit(), presentationTimeUs, 0);
} }
inputIndex = C.INDEX_UNSET; resetInputBuffer();
codecReceivedBuffers = true; codecReceivedBuffers = true;
codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReconfigurationState = RECONFIGURATION_STATE_NONE;
decoderCounters.inputBufferCount++; decoderCounters.inputBufferCount++;
@ -770,6 +767,50 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return true; return true;
} }
private void getCodecBuffers() {
if (Util.SDK_INT < 21) {
inputBuffers = codec.getInputBuffers();
outputBuffers = codec.getOutputBuffers();
}
}
private void resetCodecBuffers() {
if (Util.SDK_INT < 21) {
inputBuffers = null;
outputBuffers = null;
}
}
private ByteBuffer getInputBuffer(int inputIndex) {
if (Util.SDK_INT >= 21) {
return codec.getInputBuffer(inputIndex);
} else {
return inputBuffers[inputIndex];
}
}
private ByteBuffer getOutputBuffer(int outputIndex) {
if (Util.SDK_INT >= 21) {
return codec.getOutputBuffer(outputIndex);
} else {
return outputBuffers[outputIndex];
}
}
private boolean hasOutputBuffer() {
return outputIndex >= 0;
}
private void resetInputBuffer() {
inputIndex = C.INDEX_UNSET;
buffer.data = null;
}
private void resetOutputBuffer() {
outputIndex = C.INDEX_UNSET;
outputBuffer = null;
}
private static MediaCodec.CryptoInfo getFrameworkCryptoInfo(DecoderInputBuffer buffer, private static MediaCodec.CryptoInfo getFrameworkCryptoInfo(DecoderInputBuffer buffer,
int adaptiveReconfigurationBytes) { int adaptiveReconfigurationBytes) {
MediaCodec.CryptoInfo cryptoInfo = buffer.cryptoInfo.getFrameworkCryptoInfoV16(); MediaCodec.CryptoInfo cryptoInfo = buffer.cryptoInfo.getFrameworkCryptoInfoV16();
@ -922,9 +963,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@Override @Override
public boolean isReady() { public boolean isReady() {
return format != null && !waitingForKeys && (isSourceReady() || outputIndex >= 0 return format != null
|| (codecHotswapDeadlineMs != C.TIME_UNSET && !waitingForKeys
&& SystemClock.elapsedRealtime() < codecHotswapDeadlineMs)); && (isSourceReady()
|| hasOutputBuffer()
|| (codecHotswapDeadlineMs != C.TIME_UNSET
&& SystemClock.elapsedRealtime() < codecHotswapDeadlineMs));
} }
/** /**
@ -940,14 +984,14 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @return Whether it may be possible to drain more output data. * @return Whether it may be possible to drain more output data.
* @throws ExoPlaybackException If an error occurs draining the output buffer. * @throws ExoPlaybackException If an error occurs draining the output buffer.
*/ */
@SuppressWarnings("deprecation")
private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs) private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs)
throws ExoPlaybackException { throws ExoPlaybackException {
if (outputIndex < 0) { if (!hasOutputBuffer()) {
int outputIndex;
if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) { if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) {
try { try {
outputIndex = codec.dequeueOutputBuffer(outputBufferInfo, outputIndex =
getDequeueOutputBufferTimeoutUs()); codec.dequeueOutputBuffer(outputBufferInfo, getDequeueOutputBufferTimeoutUs());
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
processEndOfStream(); processEndOfStream();
if (outputStreamEnded) { if (outputStreamEnded) {
@ -957,26 +1001,25 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return false; return false;
} }
} else { } else {
outputIndex = codec.dequeueOutputBuffer(outputBufferInfo, outputIndex =
getDequeueOutputBufferTimeoutUs()); codec.dequeueOutputBuffer(outputBufferInfo, getDequeueOutputBufferTimeoutUs());
} }
if (outputIndex >= 0) { if (outputIndex >= 0) {
// We've dequeued a buffer. // We've dequeued a buffer.
if (shouldSkipAdaptationWorkaroundOutputBuffer) { if (shouldSkipAdaptationWorkaroundOutputBuffer) {
shouldSkipAdaptationWorkaroundOutputBuffer = false; shouldSkipAdaptationWorkaroundOutputBuffer = false;
codec.releaseOutputBuffer(outputIndex, false); codec.releaseOutputBuffer(outputIndex, false);
outputIndex = C.INDEX_UNSET;
return true; return true;
} } else if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
if ((outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
// The dequeued buffer indicates the end of the stream. Process it immediately. // The dequeued buffer indicates the end of the stream. Process it immediately.
processEndOfStream(); processEndOfStream();
outputIndex = C.INDEX_UNSET;
return false; return false;
} else { } else {
// The dequeued buffer is a media buffer. Do some initial setup. The buffer will be this.outputIndex = outputIndex;
// processed by calling processOutputBuffer (possibly multiple times) below. outputBuffer = getOutputBuffer(outputIndex);
ByteBuffer outputBuffer = outputBuffers[outputIndex]; // The dequeued buffer is a media buffer. Do some initial setup.
// It will be processed by calling processOutputBuffer (possibly multiple times).
if (outputBuffer != null) { if (outputBuffer != null) {
outputBuffer.position(outputBufferInfo.offset); outputBuffer.position(outputBufferInfo.offset);
outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size); outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size);
@ -990,8 +1033,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
processOutputBuffersChanged(); processOutputBuffersChanged();
return true; return true;
} else /* MediaCodec.INFO_TRY_AGAIN_LATER (-1) or unknown negative return value */ { } else /* MediaCodec.INFO_TRY_AGAIN_LATER (-1) or unknown negative return value */ {
if (codecNeedsEosPropagationWorkaround && (inputStreamEnded if (codecNeedsEosPropagationWorkaround
|| codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM)) { && (inputStreamEnded
|| codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM)) {
processEndOfStream(); processEndOfStream();
} }
return false; return false;
@ -1001,9 +1045,16 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
boolean processedOutputBuffer; boolean processedOutputBuffer;
if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) { if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) {
try { try {
processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs, codec, processedOutputBuffer =
outputBuffers[outputIndex], outputIndex, outputBufferInfo.flags, processOutputBuffer(
outputBufferInfo.presentationTimeUs, shouldSkipOutputBuffer); positionUs,
elapsedRealtimeUs,
codec,
outputBuffer,
outputIndex,
outputBufferInfo.flags,
outputBufferInfo.presentationTimeUs,
shouldSkipOutputBuffer);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
processEndOfStream(); processEndOfStream();
if (outputStreamEnded) { if (outputStreamEnded) {
@ -1013,14 +1064,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
return false; return false;
} }
} else { } else {
processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs, codec, processedOutputBuffer =
outputBuffers[outputIndex], outputIndex, outputBufferInfo.flags, processOutputBuffer(
outputBufferInfo.presentationTimeUs, shouldSkipOutputBuffer); positionUs,
elapsedRealtimeUs,
codec,
outputBuffer,
outputIndex,
outputBufferInfo.flags,
outputBufferInfo.presentationTimeUs,
shouldSkipOutputBuffer);
} }
if (processedOutputBuffer) { if (processedOutputBuffer) {
onProcessedOutputBuffer(outputBufferInfo.presentationTimeUs); onProcessedOutputBuffer(outputBufferInfo.presentationTimeUs);
outputIndex = C.INDEX_UNSET; resetOutputBuffer();
return true; return true;
} }
@ -1048,9 +1106,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
/** /**
* Processes a change in the output buffers. * Processes a change in the output buffers.
*/ */
@SuppressWarnings("deprecation")
private void processOutputBuffersChanged() { private void processOutputBuffersChanged() {
outputBuffers = codec.getOutputBuffers(); if (Util.SDK_INT < 21) {
outputBuffers = codec.getOutputBuffers();
}
} }
/** /**