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
This commit is contained in:
parent
d6e15b7953
commit
ec98bd9ea1
@ -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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
* <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 {
|
|||||||
* <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
|
||||||
@ -1091,6 +1129,21 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
|| "OMX.amlogic.avc.decoder.awesome.secure".equals(name)));
|
|| "OMX.amlogic.avc.decoder.awesome.secure".equals(name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user