Skip to content

Commit

Permalink
Allow missing hours in SubRip (.srt) subtitle timecodes
Browse files Browse the repository at this point in the history
Add a test for this case, and extend the existing tests to ensure the
hour is parsed when it's present.

issue:#7122
PiperOrigin-RevId: 302472213
  • Loading branch information
icbaker authored and ojw28 committed Mar 25, 2020
1 parent 92c4088 commit 0c20462
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 14 deletions.
2 changes: 2 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
([#6885](https://github.com/google/ExoPlayer/issues/6885)).
* Parse `tts:ruby` and `tts:rubyPosition` properties in TTML subtitles
(rendering is coming later).
* Allow missing hours in SubRip (.srt) timecodes
([#7122](https://github.com/google/ExoPlayer/issues/7122)).
* DRM:
* Add support for attaching DRM sessions to clear content in the demo app.
* Remove `DrmSessionManager` references from all renderers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {

private static final String TAG = "SubripDecoder";

// Some SRT files don't include hours in the timecode, so we use an optional group.
private static final String SUBRIP_TIMECODE = "(?:(\\d+):)?(\\d+):(\\d+),(\\d+)";
private static final Pattern SUBRIP_TIMING_LINE =
Pattern.compile("\\s*(" + SUBRIP_TIMECODE + ")\\s*-->\\s*(" + SUBRIP_TIMECODE + ")\\s*");

// NOTE: Android Studio's suggestion to simplify '\\}' is incorrect [internal: b/144480183].
private static final Pattern SUBRIP_TAG_PATTERN = Pattern.compile("\\{\\\\.*?\\}");
private static final String SUBRIP_ALIGNMENT_TAG = "\\{\\\\an[1-9]\\}";

Expand Down Expand Up @@ -229,7 +231,8 @@ private Cue buildCue(Spanned text, @Nullable String alignmentTag) {
}

private static long parseTimecode(Matcher matcher, int groupOffset) {
long timestampMs = Long.parseLong(matcher.group(groupOffset + 1)) * 60 * 60 * 1000;
@Nullable String hours = matcher.group(groupOffset + 1);
long timestampMs = hours != null ? Long.parseLong(hours) * 60 * 60 * 1000 : 0;
timestampMs += Long.parseLong(matcher.group(groupOffset + 2)) * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 3)) * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 4));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public final class SubripDecoderTest {
private static final String TYPICAL_NEGATIVE_TIMESTAMPS = "subrip/typical_negative_timestamps";
private static final String TYPICAL_UNEXPECTED_END = "subrip/typical_unexpected_end";
private static final String TYPICAL_WITH_TAGS = "subrip/typical_with_tags";
private static final String TYPICAL_NO_HOURS = "subrip/typical_no_hours";

@Test
public void decodeEmpty() throws IOException {
Expand Down Expand Up @@ -151,9 +152,14 @@ public void decodeCueWithTag() throws IOException {
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_WITH_TAGS);
Subtitle subtitle = decoder.decode(bytes, bytes.length, false);

assertTypicalCue1(subtitle, 0);
assertTypicalCue2(subtitle, 2);
assertTypicalCue3(subtitle, 4);
assertThat(subtitle.getCues(subtitle.getEventTime(0)).get(0).text.toString())
.isEqualTo("This is the first subtitle.");

assertThat(subtitle.getCues(subtitle.getEventTime(2)).get(0).text.toString())
.isEqualTo("This is the second subtitle.\nSecond subtitle with second line.");

assertThat(subtitle.getCues(subtitle.getEventTime(4)).get(0).text.toString())
.isEqualTo("This is the third subtitle.");

assertThat(subtitle.getCues(subtitle.getEventTime(6)).get(0).text.toString())
.isEqualTo("This { \\an2} is not a valid tag due to the space after the opening bracket.");
Expand All @@ -172,6 +178,19 @@ public void decodeCueWithTag() throws IOException {
assertAlignmentCue(subtitle, 26, Cue.ANCHOR_TYPE_START, Cue.ANCHOR_TYPE_END); // {/an9}
}

@Test
public void decodeTypicalNoHours() throws IOException {
SubripDecoder decoder = new SubripDecoder();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), TYPICAL_NO_HOURS);
Subtitle subtitle = decoder.decode(bytes, bytes.length, false);

assertThat(subtitle.getEventTimeCount()).isEqualTo(6);
assertTypicalCue1(subtitle, 0);
assertTypicalCue2(subtitle, 2);
assertTypicalCue3(subtitle, 4);
}

private static void assertTypicalCue1(Subtitle subtitle, int eventIndex) {
assertThat(subtitle.getEventTime(eventIndex)).isEqualTo(0);
assertThat(subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString())
Expand All @@ -187,10 +206,12 @@ private static void assertTypicalCue2(Subtitle subtitle, int eventIndex) {
}

private static void assertTypicalCue3(Subtitle subtitle, int eventIndex) {
assertThat(subtitle.getEventTime(eventIndex)).isEqualTo(4567000);
long expectedStartTimeUs = (((2L * 60L * 60L) + 4L) * 1000L + 567L) * 1000L;
assertThat(subtitle.getEventTime(eventIndex)).isEqualTo(expectedStartTimeUs);
assertThat(subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString())
.isEqualTo("This is the third subtitle.");
assertThat(subtitle.getEventTime(eventIndex + 1)).isEqualTo(8901000);
long expectedEndTimeUs = (((2L * 60L * 60L) + 8L) * 1000L + 901L) * 1000L;
assertThat(subtitle.getEventTime(eventIndex + 1)).isEqualTo(expectedEndTimeUs);
}

private static void assertAlignmentCue(
Expand Down
2 changes: 1 addition & 1 deletion testdata/src/test/assets/subrip/typical
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ This is the second subtitle.
Second subtitle with second line.

3
00:00:04,567 --> 00:00:08,901
02:00:04,567 --> 02:00:08,901
This is the third subtitle.
2 changes: 1 addition & 1 deletion testdata/src/test/assets/subrip/typical_extra_blank_line
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ This is the second subtitle.
Second subtitle with second line.

3
00:00:04,567 --> 00:00:08,901
02:00:04,567 --> 02:00:08,901
This is the third subtitle.
2 changes: 1 addition & 1 deletion testdata/src/test/assets/subrip/typical_missing_sequence
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ This is the second subtitle.
Second subtitle with second line.

3
00:00:04,567 --> 00:00:08,901
02:00:04,567 --> 02:00:08,901
This is the third subtitle.
6 changes: 3 additions & 3 deletions testdata/src/test/assets/subrip/typical_missing_timecode
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ This is the second subtitle.
Second subtitle with second line.

3
00:00:04,567 --> 00:00:08,901
02:00:04,567 --> 02:00:08,901
This is the third subtitle.

4
--> 00:00:10,901
--> 02:00:10,901
This is the fourth subtitle.

5
00:00:12,901 -->
02:00:12,901 -->
This is the fifth subtitle.
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ This is the second subtitle.
Second subtitle with second line.

3
00:00:04,567 --> 00:00:08,901
02:00:04,567 --> 02:00:08,901
This is the third subtitle.
12 changes: 12 additions & 0 deletions testdata/src/test/assets/subrip/typical_no_hours
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
1
00:00,000 --> 00:01,234
This is the first subtitle.

2
00:02,345 --> 00:03,456
This is the second subtitle.
Second subtitle with second line.

3
02:00:04,567 --> 02:00:08,901
This is the third subtitle.
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ This is the second subtitle.
Second subtitle with second line.

3
00:00:04,567 --> 00:00:08,901
02:00:04,567 --> 02:00:08,901
This is the third subtitle.

0 comments on commit 0c20462

Please sign in to comment.