Add workaround for codecs not propagating EOS signal.

If a codec received the EOS signal and already returned the last
output buffer, we should expect the output EOS very quickly. If
it doesn't arrive within 100ms, we can proceed to end the stream
manually without waiting any further to prevent cases where the
codec is completely stuck otherwise.

PiperOrigin-RevId: 679633116
This commit is contained in:
tonihei 2024-09-27 10:04:11 -07:00 committed by Copybara-Service
parent 287f353c87
commit 4481b3567e
2 changed files with 15 additions and 0 deletions

View File

@ -67,6 +67,8 @@
* Add workaround for a device issue on Galaxy Tab S7 FE that causes 60fps
secure H264 streams to be marked as unsupported
([#1619](https://github.com/androidx/media/issues/1619)).
* Add workaround for codecs that get stuck after the last sample without
returning an end-of-stream signal.
* Text:
* Metadata:
* Assign the `C.TRACK_TYPE_METADATA` type to tracks containing icy or

View File

@ -367,6 +367,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private boolean codecNeedsAdaptationWorkaroundBuffer;
private boolean shouldSkipAdaptationWorkaroundOutputBuffer;
private boolean codecNeedsEosPropagation;
private long lastOutputBufferProcessedRealtimeMs;
private boolean codecRegisteredOnBufferAvailableListener;
private long codecHotswapDeadlineMs;
private int inputIndex;
@ -447,6 +448,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
largestQueuedPresentationTimeUs = C.TIME_UNSET;
lastBufferInStreamPresentationTimeUs = C.TIME_UNSET;
lastProcessedOutputBufferTimeUs = C.TIME_UNSET;
lastOutputBufferProcessedRealtimeMs = C.TIME_UNSET;
codecDrainState = DRAIN_STATE_NONE;
codecDrainAction = DRAIN_ACTION_NONE;
decoderCounters = new DecoderCounters();
@ -973,6 +975,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
resetOutputBuffer();
codecHotswapDeadlineMs = C.TIME_UNSET;
codecReceivedEos = false;
lastOutputBufferProcessedRealtimeMs = C.TIME_UNSET;
codecReceivedBuffers = false;
codecNeedsAdaptationWorkaroundBuffer = false;
shouldSkipAdaptationWorkaroundOutputBuffer = false;
@ -1997,6 +2000,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
&& (inputStreamEnded || codecDrainState == DRAIN_STATE_WAIT_END_OF_STREAM)) {
processEndOfStream();
}
if (lastOutputBufferProcessedRealtimeMs != C.TIME_UNSET
&& lastOutputBufferProcessedRealtimeMs + 100 < getClock().currentTimeMillis()) {
// We processed the last output buffer more than 100ms ago without
// receiving an EOS buffer. This is likely a misbehaving codec, so
// process the end of stream manually. See b/359634542.
processEndOfStream();
}
return false;
}
@ -2071,6 +2081,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (processedOutputBuffer) {
onProcessedOutputBuffer(outputBufferInfo.presentationTimeUs);
boolean isEndOfStream = (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
if (!isEndOfStream && codecReceivedEos && isLastOutputBuffer) {
lastOutputBufferProcessedRealtimeMs = getClock().currentTimeMillis();
}
resetOutputBuffer();
if (!isEndOfStream) {
return true;