Fix index out of bounds exception when a Subtitle is empty

Issue: androidx/media#1516

#cherrypick

PiperOrigin-RevId: 648416119
This commit is contained in:
ibaker 2024-07-01 10:37:20 -07:00 committed by Copybara-Service
parent 70c063905c
commit 711d18de03
3 changed files with 34 additions and 2 deletions

View File

@ -24,6 +24,9 @@
* Audio: * Audio:
* Video: * Video:
* Text: * Text:
* Fix an `IllegalArgumentException` from `LegacySubtitleUtil` when a
WebVTT subtitle sample contains no cues, e.g. as part of a DASH stream
([#1516](https://github.com/androidx/media/issues/1516)).
* Metadata: * Metadata:
* Image: * Image:
* DRM: * DRM:

View File

@ -32,11 +32,14 @@ public class LegacySubtitleUtil {
* Converts a {@link Subtitle} to a list of {@link CuesWithTiming} representing it, emitted to * Converts a {@link Subtitle} to a list of {@link CuesWithTiming} representing it, emitted to
* {@code output}. * {@code output}.
* *
* <p>This may only be called with {@link Subtitle} instances where the first event is non-empty * <p>This may only be called with empty {@link Subtitle} instances, or those where the first
* and the last event is an empty cue list. * event is non-empty and the last event is an empty cue list.
*/ */
public static void toCuesWithTiming( public static void toCuesWithTiming(
Subtitle subtitle, OutputOptions outputOptions, Consumer<CuesWithTiming> output) { Subtitle subtitle, OutputOptions outputOptions, Consumer<CuesWithTiming> output) {
if (subtitle.getEventTimeCount() == 0) {
return;
}
int startIndex = getStartIndex(subtitle, outputOptions); int startIndex = getStartIndex(subtitle, outputOptions);
boolean startedInMiddleOfCue = false; boolean startedInMiddleOfCue = false;
if (outputOptions.startTimeUs != C.TIME_UNSET) { if (outputOptions.startTimeUs != C.TIME_UNSET) {

View File

@ -39,6 +39,8 @@ public class LegacySubtitleUtilWebvttTest {
private static final String FIRST_SUBTITLE_STRING = "This is the first subtitle."; private static final String FIRST_SUBTITLE_STRING = "This is the first subtitle.";
private static final String SECOND_SUBTITLE_STRING = "This is the second subtitle."; private static final String SECOND_SUBTITLE_STRING = "This is the second subtitle.";
private static final WebvttSubtitle EMPTY_SUBTITLE = new WebvttSubtitle(ImmutableList.of());
private static final WebvttSubtitle SIMPLE_SUBTITLE = private static final WebvttSubtitle SIMPLE_SUBTITLE =
new WebvttSubtitle( new WebvttSubtitle(
Arrays.asList( Arrays.asList(
@ -135,6 +137,14 @@ public class LegacySubtitleUtilWebvttTest {
.containsExactly(SECOND_SUBTITLE_STRING); .containsExactly(SECOND_SUBTITLE_STRING);
} }
@Test
public void toCuesWithTiming_allCues_emptySubtitle() {
ImmutableList<CuesWithTiming> cuesWithTimingsList =
toCuesWithTimingList(EMPTY_SUBTITLE, SubtitleParser.OutputOptions.allCues());
assertThat(cuesWithTimingsList).isEmpty();
}
@Test @Test
public void toCuesWithTiming_onlyEmitCuesAfterStartTime_startBetweenCues_simpleSubtitle() { public void toCuesWithTiming_onlyEmitCuesAfterStartTime_startBetweenCues_simpleSubtitle() {
ImmutableList<CuesWithTiming> cuesWithTimingsList = ImmutableList<CuesWithTiming> cuesWithTimingsList =
@ -252,6 +262,14 @@ public class LegacySubtitleUtilWebvttTest {
.containsExactly(SECOND_SUBTITLE_STRING); .containsExactly(SECOND_SUBTITLE_STRING);
} }
@Test
public void toCuesWithTiming_onlyEmitCuesAfterStartTime_emptySubtitle() {
ImmutableList<CuesWithTiming> cuesWithTimingsList =
toCuesWithTimingList(EMPTY_SUBTITLE, SubtitleParser.OutputOptions.onlyCuesAfter(0));
assertThat(cuesWithTimingsList).isEmpty();
}
@Test @Test
public void public void
toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_startAtStartOfCue_simpleSubtitle() { toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_startAtStartOfCue_simpleSubtitle() {
@ -405,6 +423,14 @@ public class LegacySubtitleUtilWebvttTest {
.inOrder(); .inOrder();
} }
@Test
public void toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_emptySubtitle() {
ImmutableList<CuesWithTiming> cuesWithTimingsList =
toCuesWithTimingList(EMPTY_SUBTITLE, SubtitleParser.OutputOptions.onlyCuesAfter(0));
assertThat(cuesWithTimingsList).isEmpty();
}
private static ImmutableList<CuesWithTiming> toCuesWithTimingList( private static ImmutableList<CuesWithTiming> toCuesWithTimingList(
Subtitle subtitle, SubtitleParser.OutputOptions outputOptions) { Subtitle subtitle, SubtitleParser.OutputOptions outputOptions) {
ImmutableList.Builder<CuesWithTiming> result = ImmutableList.builder(); ImmutableList.Builder<CuesWithTiming> result = ImmutableList.builder();