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