Commit ec98bd9e by andrewlewis Committed by Oliver Woodman

Work around broken AAC decoder EoS handling on L.

SoftAAC2 would cause an exception to be thrown from
dequeueOutputBuffer/releaseOutputBuffer after queueing an end-of-stream buffer
for certain streams.

The bug was introduced in L and fixed in L MR1, so the workaround is targeted to
API 21.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=147613659
parent d6e15b79
...@@ -183,6 +183,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -183,6 +183,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean codecNeedsAdaptationWorkaround; private boolean codecNeedsAdaptationWorkaround;
private boolean codecNeedsEosPropagationWorkaround; private boolean codecNeedsEosPropagationWorkaround;
private boolean codecNeedsEosFlushWorkaround; private boolean codecNeedsEosFlushWorkaround;
private boolean codecNeedsEosOutputExceptionWorkaround;
private boolean codecNeedsMonoChannelCountWorkaround; private boolean codecNeedsMonoChannelCountWorkaround;
private boolean codecNeedsAdaptationWorkaroundBuffer; private boolean codecNeedsAdaptationWorkaroundBuffer;
private boolean shouldSkipAdaptationWorkaroundOutputBuffer; private boolean shouldSkipAdaptationWorkaroundOutputBuffer;
...@@ -342,6 +343,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -342,6 +343,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecNeedsAdaptationWorkaround = codecNeedsAdaptationWorkaround(codecName); codecNeedsAdaptationWorkaround = codecNeedsAdaptationWorkaround(codecName);
codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(codecName); codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(codecName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName); codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName);
codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName);
codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, format); codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, format);
try { try {
long codecInitializingTimestamp = SystemClock.elapsedRealtime(); long codecInitializingTimestamp = SystemClock.elapsedRealtime();
...@@ -513,7 +515,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -513,7 +515,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecNeedsAdaptationWorkaroundBuffer = false; codecNeedsAdaptationWorkaroundBuffer = false;
shouldSkipAdaptationWorkaroundOutputBuffer = false; shouldSkipAdaptationWorkaroundOutputBuffer = false;
if (codecNeedsFlushWorkaround || (codecNeedsEosFlushWorkaround && codecReceivedEos)) { if (codecNeedsFlushWorkaround || (codecNeedsEosFlushWorkaround && codecReceivedEos)) {
// Workaround framework bugs. See [Internal: b/8347958, b/8578467, b/8543366, b/23361053].
releaseCodec(); releaseCodec();
maybeInitCodec(); maybeInitCodec();
} else if (codecReinitializationState != REINITIALIZATION_STATE_NONE) { } else if (codecReinitializationState != REINITIALIZATION_STATE_NONE) {
...@@ -867,7 +868,22 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -867,7 +868,22 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs) private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs)
throws ExoPlaybackException { throws ExoPlaybackException {
if (outputIndex < 0) { if (outputIndex < 0) {
outputIndex = codec.dequeueOutputBuffer(outputBufferInfo, getDequeueOutputBufferTimeoutUs()); if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) {
try {
outputIndex = codec.dequeueOutputBuffer(outputBufferInfo,
getDequeueOutputBufferTimeoutUs());
} catch (IllegalStateException e) {
processEndOfStream();
if (outputStreamEnded) {
// Release the codec, as it's in an error state.
releaseCodec();
}
return false;
}
} else {
outputIndex = codec.dequeueOutputBuffer(outputBufferInfo,
getDequeueOutputBufferTimeoutUs());
}
if (outputIndex >= 0) { if (outputIndex >= 0) {
// We've dequeued a buffer. // We've dequeued a buffer.
if (shouldSkipAdaptationWorkaroundOutputBuffer) { if (shouldSkipAdaptationWorkaroundOutputBuffer) {
...@@ -906,9 +922,27 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -906,9 +922,27 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
} }
if (processOutputBuffer(positionUs, elapsedRealtimeUs, codec, outputBuffers[outputIndex], boolean processedOutputBuffer;
outputIndex, outputBufferInfo.flags, outputBufferInfo.presentationTimeUs, if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) {
shouldSkipOutputBuffer)) { try {
processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs, codec,
outputBuffers[outputIndex], outputIndex, outputBufferInfo.flags,
outputBufferInfo.presentationTimeUs, shouldSkipOutputBuffer);
} catch (IllegalStateException e) {
processEndOfStream();
if (outputStreamEnded) {
// Release the codec, as it's in an error state.
releaseCodec();
}
return false;
}
} else {
processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs, codec,
outputBuffers[outputIndex], outputIndex, outputBufferInfo.flags,
outputBufferInfo.presentationTimeUs, shouldSkipOutputBuffer);
}
if (processedOutputBuffer) {
onProcessedOutputBuffer(outputBufferInfo.presentationTimeUs); onProcessedOutputBuffer(outputBufferInfo.presentationTimeUs);
outputIndex = C.INDEX_UNSET; outputIndex = C.INDEX_UNSET;
return true; return true;
...@@ -1010,6 +1044,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1010,6 +1044,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* <p> * <p>
* If true is returned, the renderer will work around the issue by releasing the decoder and * If true is returned, the renderer will work around the issue by releasing the decoder and
* instantiating a new one rather than flushing the current instance. * instantiating a new one rather than flushing the current instance.
* <p>
* See [Internal: b/8347958, b/8543366].
* *
* @param name The name of the decoder. * @param name The name of the decoder.
* @return True if the decoder is known to fail when flushed. * @return True if the decoder is known to fail when flushed.
...@@ -1079,6 +1115,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1079,6 +1115,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* <p> * <p>
* If true is returned, the renderer will work around the issue by instantiating a new decoder * If true is returned, the renderer will work around the issue by instantiating a new decoder
* when this case occurs. * when this case occurs.
* <p>
* See [Internal: b/8578467, b/23361053].
* *
* @param name The name of the decoder. * @param name The name of the decoder.
* @return True if the decoder is known to behave incorrectly if flushed after receiving an input * @return True if the decoder is known to behave incorrectly if flushed after receiving an input
...@@ -1092,6 +1130,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer { ...@@ -1092,6 +1130,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
/** /**
* Returns whether the decoder may throw an {@link IllegalStateException} from
* {@link MediaCodec#dequeueOutputBuffer(MediaCodec.BufferInfo, long)} or
* {@link MediaCodec#releaseOutputBuffer(int, boolean)} after receiving an input
* buffer with {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} set.
* <p>
* See [Internal: b/17933838].
*
* @param name The name of the decoder.
* @return True if the decoder may throw an exception after receiving an end-of-stream buffer.
*/
private static boolean codecNeedsEosOutputExceptionWorkaround(String name) {
return Util.SDK_INT == 21 && "OMX.google.aac.decoder".equals(name);
}
/**
* Returns whether the decoder is known to set the number of audio channels in the output format * Returns whether the decoder is known to set the number of audio channels in the output format
* to 2 for the given input format, whilst only actually outputting a single channel. * to 2 for the given input format, whilst only actually outputting a single channel.
* <p> * <p>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment