Handle C.TIME_END_OF_SOURCE buffer timestamps in CeaDecoder

The behaviour was changed in 1.4.0 with 0f42dd4752,
so that the buffer timestamp is compared to `outputStartTimeUs` when
deciding whether to discard a "decode only" buffer before decoding
(instead of the deprecated/removed `isDecodeOnly` property). This breaks
when the buffer timestamp is `TIME_END_OF_SOURCE` (which is
`Long.MIN_VALUE`), because `TIME_END_OF_SOURCE < outputStartTimeUs` is
always true, so the end-of-stream buffer is never passed to the decoder
and on to `TextRenderer` where it is used to
[set `inputStreamEnded = true`](40f187e4b4/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/text/TextRenderer.java (L434-L436))
and so playback hangs.

#cherrypick

Issue: androidx/media#1863
PiperOrigin-RevId: 695767247
This commit is contained in:
ibaker 2024-11-12 09:35:59 -08:00 committed by Copybara-Service
parent 40f187e4b4
commit 19b38c83b6
3 changed files with 25 additions and 1 deletions

View File

@ -43,6 +43,8 @@
* Text: * Text:
* Fix garbled CEA-608 subtitles in content with more than one SEI message * Fix garbled CEA-608 subtitles in content with more than one SEI message
per sample. per sample.
* Fix playback hanging on DASH multi-period streams when CEA-608 subtitles
are enabled ([#1863](https://github.com/androidx/media/issues/1863)).
* Metadata: * Metadata:
* Image: * Image:
* DRM: * DRM:

View File

@ -84,7 +84,9 @@ import java.util.ArrayDeque;
public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException { public void queueInputBuffer(SubtitleInputBuffer inputBuffer) throws SubtitleDecoderException {
Assertions.checkArgument(inputBuffer == dequeuedInputBuffer); Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
CeaInputBuffer ceaInputBuffer = (CeaInputBuffer) inputBuffer; CeaInputBuffer ceaInputBuffer = (CeaInputBuffer) inputBuffer;
if (outputStartTimeUs != C.TIME_UNSET && ceaInputBuffer.timeUs < outputStartTimeUs) { if (ceaInputBuffer.timeUs != C.TIME_END_OF_SOURCE
&& outputStartTimeUs != C.TIME_UNSET
&& ceaInputBuffer.timeUs < outputStartTimeUs) {
// We can start decoding anywhere in CEA formats, so discarding on the input side is fine. // We can start decoding anywhere in CEA formats, so discarding on the input side is fine.
releaseInputBuffer(ceaInputBuffer); releaseInputBuffer(ceaInputBuffer);
} else { } else {

View File

@ -328,6 +328,26 @@ public class Cea608DecoderTest {
assertThat(getOnlyCue(firstSubtitle).text.toString()).isEqualTo("test"); assertThat(getOnlyCue(firstSubtitle).text.toString()).isEqualTo("test");
} }
// https://github.com/androidx/media/issues/1863
@Test
public void endOfStreamBuffer_flagPassedThrough() throws Exception {
Cea608Decoder decoder =
new Cea608Decoder(
MimeTypes.APPLICATION_CEA608,
/* accessibilityChannel= */ 1,
Cea608Decoder.MIN_DATA_CHANNEL_TIMEOUT_MS);
SubtitleInputBuffer inputBuffer = checkNotNull(decoder.dequeueInputBuffer());
inputBuffer.timeUs = C.TIME_END_OF_SOURCE;
inputBuffer.addFlag(C.BUFFER_FLAG_END_OF_STREAM);
decoder.setOutputStartTimeUs(0);
decoder.queueInputBuffer(inputBuffer);
decoder.setPositionUs(123);
SubtitleOutputBuffer outputBuffer = decoder.dequeueOutputBuffer();
assertThat(outputBuffer.isEndOfStream()).isTrue();
}
private static byte[] createPacket(int header, int cc1, int cc2) { private static byte[] createPacket(int header, int cc1, int cc2) {
return new byte[] { return new byte[] {
UnsignedBytes.checkedCast(header), UnsignedBytes.checkedCast(header),