Commit 8e9aadc5 by Oliver Woodman

Workaround for vorbis EOS flush bug (23361053).

I'm assuming this will be fixed in API level 24.
parent 879da812
...@@ -192,7 +192,9 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -192,7 +192,9 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
private DrmInitData drmInitData; private DrmInitData drmInitData;
private MediaCodec codec; private MediaCodec codec;
private boolean codecIsAdaptive; private boolean codecIsAdaptive;
private boolean codecNeedsEndOfStreamWorkaround; private boolean codecNeedsEosPropagationWorkaround;
private boolean codecNeedsEosFlushWorkaround;
private boolean codecReceivedEos;
private ByteBuffer[] inputBuffers; private ByteBuffer[] inputBuffers;
private ByteBuffer[] outputBuffers; private ByteBuffer[] outputBuffers;
private long codecHotswapTimeMs; private long codecHotswapTimeMs;
...@@ -319,7 +321,8 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -319,7 +321,8 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
String decoderName = decoderInfo.name; String decoderName = decoderInfo.name;
codecIsAdaptive = decoderInfo.adaptive; codecIsAdaptive = decoderInfo.adaptive;
codecNeedsEndOfStreamWorkaround = codecNeedsEndOfStreamWorkaround(decoderName); codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(decoderName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(decoderName);
try { try {
long codecInitializingTimestamp = SystemClock.elapsedRealtime(); long codecInitializingTimestamp = SystemClock.elapsedRealtime();
TraceUtil.beginSection("createByCodecName(" + decoderName + ")"); TraceUtil.beginSection("createByCodecName(" + decoderName + ")");
...@@ -395,7 +398,9 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -395,7 +398,9 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
codecReconfigured = false; codecReconfigured = false;
codecHasQueuedBuffers = false; codecHasQueuedBuffers = false;
codecIsAdaptive = false; codecIsAdaptive = false;
codecNeedsEndOfStreamWorkaround = false; codecNeedsEosPropagationWorkaround = false;
codecNeedsEosFlushWorkaround = false;
codecReceivedEos = false;
codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReconfigurationState = RECONFIGURATION_STATE_NONE;
codecReinitializationState = REINITIALIZATION_STATE_NONE; codecReinitializationState = REINITIALIZATION_STATE_NONE;
codecCounters.codecReleaseCount++; codecCounters.codecReleaseCount++;
...@@ -480,14 +485,19 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -480,14 +485,19 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
waitingForFirstSyncFrame = true; waitingForFirstSyncFrame = true;
waitingForKeys = false; waitingForKeys = false;
decodeOnlyPresentationTimestamps.clear(); decodeOnlyPresentationTimestamps.clear();
// Workaround for framework bugs. if (Util.SDK_INT < 18 || (codecNeedsEosFlushWorkaround && codecReceivedEos)) {
// See [Internal: b/8347958], [Internal: b/8578467], [Internal: b/8543366]. // Workaround framework bugs. See [Internal: b/8347958, b/8578467, b/8543366, b/23361053].
if (Util.SDK_INT >= 18 && codecReinitializationState == REINITIALIZATION_STATE_NONE) { releaseCodec();
codec.flush(); maybeInitCodec();
codecHasQueuedBuffers = false; } else if (codecReinitializationState != REINITIALIZATION_STATE_NONE) {
} else { // We're already waiting to release and re-initialize the codec. Since we're now flushing,
// there's no need to wait any longer.
releaseCodec(); releaseCodec();
maybeInitCodec(); maybeInitCodec();
} else {
// We can flush and re-use the existing decoder.
codec.flush();
codecHasQueuedBuffers = false;
} }
if (codecReconfigured && format != null) { if (codecReconfigured && format != null) {
// Any reconfiguration data that we send shortly before the flush may be discarded. We // Any reconfiguration data that we send shortly before the flush may be discarded. We
...@@ -524,9 +534,10 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -524,9 +534,10 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) { if (codecReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
// We need to re-initialize the codec. Send an end of stream signal to the existing codec so // We need to re-initialize the codec. Send an end of stream signal to the existing codec so
// that it outputs any remaining buffers before we release it. // that it outputs any remaining buffers before we release it.
if (codecNeedsEndOfStreamWorkaround) { if (codecNeedsEosPropagationWorkaround) {
// Do nothing. // Do nothing.
} else { } else {
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 = -1; inputIndex = -1;
} }
...@@ -581,9 +592,10 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -581,9 +592,10 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
} }
inputStreamEnded = true; inputStreamEnded = true;
try { try {
if (codecNeedsEndOfStreamWorkaround) { if (codecNeedsEosPropagationWorkaround) {
// Do nothing. // Do nothing.
} else { } else {
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 = -1; inputIndex = -1;
} }
...@@ -781,7 +793,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -781,7 +793,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
codecCounters.outputBuffersChangedCount++; codecCounters.outputBuffersChangedCount++;
return true; return true;
} else if (outputIndex < 0) { } else if (outputIndex < 0) {
if (codecNeedsEndOfStreamWorkaround && (inputStreamEnded if (codecNeedsEosPropagationWorkaround && (inputStreamEnded
|| codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM)) { || codecReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM)) {
processEndOfStream(); processEndOfStream();
return true; return true;
...@@ -879,17 +891,18 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -879,17 +891,18 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
} }
/** /**
* Returns whether the decoder is known to handle {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} * Returns whether the decoder is known to handle the propagation of the
* incorrectly on the host device. * {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} flag incorrectly on the host device.
* <p> * <p>
* If true is returned, the renderer will work around the issue by approximating end of stream * If true is returned, the renderer will work around the issue by approximating end of stream
* behavior without involvement of the underlying decoder. * behavior without relying on the flag being propagated through to an output buffer by the
* underlying decoder.
* *
* @param name The name of the decoder. * @param name The name of the decoder.
* @return True if the decoder is known to handle {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} * @return True if the decoder is known to handle {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM}
* incorrectly on the host device. False otherwise. * propagation incorrectly on the host device. False otherwise.
*/ */
private static boolean codecNeedsEndOfStreamWorkaround(String name) { private static boolean codecNeedsEosPropagationWorkaround(String name) {
return Util.SDK_INT <= 17 return Util.SDK_INT <= 17
&& "OMX.rk.video_decoder.avc".equals(name) && "OMX.rk.video_decoder.avc".equals(name)
&& ("ht7s3".equals(Util.DEVICE) // Tesco HUDL && ("ht7s3".equals(Util.DEVICE) // Tesco HUDL
...@@ -897,4 +910,19 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -897,4 +910,19 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|| "rk31sdk".equals(Util.DEVICE)); // Rockchip rk31 || "rk31sdk".equals(Util.DEVICE)); // Rockchip rk31
} }
/**
* Returns whether the decoder is known to behave incorrectly if flushed after receiving an input
* buffer with {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} set.
* <p>
* If true is returned, the renderer will work around the issue by instantiating a new decoder
* when this case occurs.
*
* @param name The name of the decoder.
* @return True if the decoder is known to behave incorrectly if flushed after receiving an input
* buffer with {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} set. False otherwise.
*/
private static boolean codecNeedsEosFlushWorkaround(String name) {
return Util.SDK_INT <= 23 && "OMX.google.vorbis.decoder".equals(name);
}
} }
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