mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix IndexOutOfBoundsException
in LegacySubtitleUtil
This is caused when the requested "output start time" is equal to or larger than the last event time in a `Subtitle` object. This resolves the error in Issue: androidx/media#1516, but subtitles are still not renderered (probably because the timestamps aren't what we expect somewhere, but I need to investigate this part further). #cherrypick PiperOrigin-RevId: 660462720
This commit is contained in:
parent
0530d663bc
commit
3763e5bc1d
@ -61,6 +61,10 @@
|
|||||||
* TTML: Fix handling of percentage `tts:fontSize` values to ensure they
|
* TTML: Fix handling of percentage `tts:fontSize` values to ensure they
|
||||||
are correctly inherited from parent nodes with percentage `tts:fontSize`
|
are correctly inherited from parent nodes with percentage `tts:fontSize`
|
||||||
values.
|
values.
|
||||||
|
* Fix `IndexOutOfBoundsException` in `LegacySubtitleUtil` due to
|
||||||
|
incorrectly handling the case of the requested output start time being
|
||||||
|
greater than or equal to the final event time in the `Subtitle`
|
||||||
|
([#1516](https://github.com/androidx/media/issues/1516)).
|
||||||
* Metadata:
|
* Metadata:
|
||||||
* Image:
|
* Image:
|
||||||
* Add `ExternallyLoadedImageDecoder` for simplified integration with
|
* Add `ExternallyLoadedImageDecoder` for simplified integration with
|
||||||
|
@ -37,17 +37,12 @@ public class LegacySubtitleUtil {
|
|||||||
*/
|
*/
|
||||||
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) {
|
int startIndex = getStartIndex(subtitle, outputOptions.startTimeUs);
|
||||||
return;
|
|
||||||
}
|
|
||||||
int startIndex = getStartIndex(subtitle, outputOptions);
|
|
||||||
boolean startedInMiddleOfCue = false;
|
boolean startedInMiddleOfCue = false;
|
||||||
if (outputOptions.startTimeUs != C.TIME_UNSET) {
|
if (outputOptions.startTimeUs != C.TIME_UNSET && startIndex < subtitle.getEventTimeCount()) {
|
||||||
List<Cue> cuesAtStartTime = subtitle.getCues(outputOptions.startTimeUs);
|
List<Cue> cuesAtStartTime = subtitle.getCues(outputOptions.startTimeUs);
|
||||||
long firstEventTimeUs = subtitle.getEventTime(startIndex);
|
long firstEventTimeUs = subtitle.getEventTime(startIndex);
|
||||||
if (!cuesAtStartTime.isEmpty()
|
if (!cuesAtStartTime.isEmpty() && outputOptions.startTimeUs < firstEventTimeUs) {
|
||||||
&& startIndex < subtitle.getEventTimeCount()
|
|
||||||
&& outputOptions.startTimeUs < firstEventTimeUs) {
|
|
||||||
output.accept(
|
output.accept(
|
||||||
new CuesWithTiming(
|
new CuesWithTiming(
|
||||||
cuesAtStartTime,
|
cuesAtStartTime,
|
||||||
@ -74,16 +69,20 @@ public class LegacySubtitleUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getStartIndex(Subtitle subtitle, OutputOptions outputOptions) {
|
/**
|
||||||
if (outputOptions.startTimeUs == C.TIME_UNSET) {
|
* Returns the event index from {@code subtitle} that is equal to or after {@code startTimeUs}, or
|
||||||
|
* zero if {@code startTimeUs == C.TIME_UNSET}, or {@code subtitle.getEventTimeCount()} if {@code
|
||||||
|
* startTimeUs} is after all events in {@code subtitle}.
|
||||||
|
*/
|
||||||
|
private static int getStartIndex(Subtitle subtitle, long startTimeUs) {
|
||||||
|
if (startTimeUs == C.TIME_UNSET) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int nextEventTimeIndex = subtitle.getNextEventTimeIndex(outputOptions.startTimeUs);
|
int nextEventTimeIndex = subtitle.getNextEventTimeIndex(startTimeUs);
|
||||||
if (nextEventTimeIndex == C.INDEX_UNSET) {
|
if (nextEventTimeIndex == C.INDEX_UNSET) {
|
||||||
return subtitle.getEventTimeCount();
|
nextEventTimeIndex = subtitle.getEventTimeCount();
|
||||||
}
|
}
|
||||||
if (nextEventTimeIndex > 0
|
if (nextEventTimeIndex > 0 && subtitle.getEventTime(nextEventTimeIndex - 1) == startTimeUs) {
|
||||||
&& subtitle.getEventTime(nextEventTimeIndex - 1) == outputOptions.startTimeUs) {
|
|
||||||
nextEventTimeIndex--;
|
nextEventTimeIndex--;
|
||||||
}
|
}
|
||||||
return nextEventTimeIndex;
|
return nextEventTimeIndex;
|
||||||
|
@ -207,6 +207,24 @@ public class LegacySubtitleUtilWebvttTest {
|
|||||||
.containsExactly(SECOND_SUBTITLE_STRING);
|
.containsExactly(SECOND_SUBTITLE_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toCuesWithTiming_onlyEmitCuesAfterStartTime_startAtSubtitleEnd_simpleSubtitle() {
|
||||||
|
ImmutableList<CuesWithTiming> cuesWithTimingsList =
|
||||||
|
toCuesWithTimingList(
|
||||||
|
SIMPLE_SUBTITLE, SubtitleParser.OutputOptions.onlyCuesAfter(4_000_000));
|
||||||
|
|
||||||
|
assertThat(cuesWithTimingsList).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toCuesWithTiming_onlyEmitCuesAfterStartTime_startAfterSubtitleEnd_simpleSubtitle() {
|
||||||
|
ImmutableList<CuesWithTiming> cuesWithTimingsList =
|
||||||
|
toCuesWithTimingList(
|
||||||
|
SIMPLE_SUBTITLE, SubtitleParser.OutputOptions.onlyCuesAfter(4_500_000));
|
||||||
|
|
||||||
|
assertThat(cuesWithTimingsList).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void toCuesWithTiming_onlyEmitCuesAfterStartTime_startBetweenCues_consecutiveSubtitle() {
|
public void toCuesWithTiming_onlyEmitCuesAfterStartTime_startBetweenCues_consecutiveSubtitle() {
|
||||||
ImmutableList<CuesWithTiming> cuesWithTimingsList =
|
ImmutableList<CuesWithTiming> cuesWithTimingsList =
|
||||||
@ -340,6 +358,48 @@ public class LegacySubtitleUtilWebvttTest {
|
|||||||
.containsExactly(FIRST_SUBTITLE_STRING);
|
.containsExactly(FIRST_SUBTITLE_STRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_startAtSubtitleEnd_simpleSubtitle() {
|
||||||
|
ImmutableList<CuesWithTiming> cuesWithTimingsList =
|
||||||
|
toCuesWithTimingList(
|
||||||
|
SIMPLE_SUBTITLE,
|
||||||
|
SubtitleParser.OutputOptions.cuesAfterThenRemainingCuesBefore(4_000_000));
|
||||||
|
|
||||||
|
assertThat(cuesWithTimingsList).hasSize(2);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).startTimeUs).isEqualTo(1_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).durationUs).isEqualTo(1_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).endTimeUs).isEqualTo(2_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).cues.stream().map(c -> c.text))
|
||||||
|
.containsExactly(FIRST_SUBTITLE_STRING);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).startTimeUs).isEqualTo(3_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).durationUs).isEqualTo(1_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).endTimeUs).isEqualTo(4_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).cues.stream().map(c -> c.text))
|
||||||
|
.containsExactly(SECOND_SUBTITLE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_startAfterSubtitleEnd_simpleSubtitle() {
|
||||||
|
ImmutableList<CuesWithTiming> cuesWithTimingsList =
|
||||||
|
toCuesWithTimingList(
|
||||||
|
SIMPLE_SUBTITLE,
|
||||||
|
SubtitleParser.OutputOptions.cuesAfterThenRemainingCuesBefore(4_500_000));
|
||||||
|
|
||||||
|
assertThat(cuesWithTimingsList).hasSize(2);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).startTimeUs).isEqualTo(1_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).durationUs).isEqualTo(1_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).endTimeUs).isEqualTo(2_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(0).cues.stream().map(c -> c.text))
|
||||||
|
.containsExactly(FIRST_SUBTITLE_STRING);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).startTimeUs).isEqualTo(3_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).durationUs).isEqualTo(1_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).endTimeUs).isEqualTo(4_000_000);
|
||||||
|
assertThat(cuesWithTimingsList.get(1).cues.stream().map(c -> c.text))
|
||||||
|
.containsExactly(SECOND_SUBTITLE_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void
|
public void
|
||||||
toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_startBetweenCues_consecutiveSubtitle() {
|
toCuesWithTiming_emitCuesAfterStartTimeThenThoseBefore_startBetweenCues_consecutiveSubtitle() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user