Skip negative SubRip timecodes

Issue: #2145

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=140868079
This commit is contained in:
olly 2016-12-02 10:49:26 -08:00 committed by Oliver Woodman
parent e0649db513
commit bbbd61e319
4 changed files with 36 additions and 20 deletions

View file

@ -0,0 +1,12 @@
1
-0:00:04,567 --> -0:00:03,456
This is the first subtitle.
2
-00:00:02,345 --> 00:00:01,234
This is the second subtitle.
Second subtitle with second line.
3
00:00:04,567 --> 00:00:08,901
This is the third subtitle.

View file

@ -30,6 +30,7 @@ public final class SubripDecoderTest extends InstrumentationTestCase {
private static final String TYPICAL_EXTRA_BLANK_LINE = "subrip/typical_extra_blank_line";
private static final String TYPICAL_MISSING_TIMECODE = "subrip/typical_missing_timecode";
private static final String TYPICAL_MISSING_SEQUENCE = "subrip/typical_missing_sequence";
private static final String TYPICAL_NEGATIVE_TIMESTAMPS = "subrip/typical_negative_timestamps";
private static final String NO_END_TIMECODES_FILE = "subrip/no_end_timecodes";
public void testDecodeEmpty() throws IOException {
@ -91,6 +92,15 @@ public final class SubripDecoderTest extends InstrumentationTestCase {
assertTypicalCue3(subtitle, 2);
}
public void testDecodeTypicalNegativeTimestamps() throws IOException {
// Parsing should succeed, parsing the third cue only.
SubripDecoder decoder = new SubripDecoder();
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_NEGATIVE_TIMESTAMPS);
SubripSubtitle subtitle = decoder.decode(bytes, bytes.length);
assertEquals(2, subtitle.getEventTimeCount());
assertTypicalCue3(subtitle, 0);
}
public void testDecodeNoEndTimecodes() throws IOException {
SubripDecoder decoder = new SubripDecoder();
byte[] bytes = TestUtil.getByteArray(getInstrumentation(), NO_END_TIMECODES_FILE);

View file

@ -548,7 +548,7 @@ public final class Cea608Decoder extends CeaDecoder {
private static boolean isPreambleAddressCode(byte cc1, byte cc2) {
// cc1 - 0|0|0|1|C|X|X|X
// cc2 - 0|1|X|X|X|X|X|X
return ((cc1 & 0xF0) == 0x10) && ((cc2 & 0xC0) == 0x80);
return ((cc1 & 0xF0) == 0x10) && ((cc2 & 0xC0) == 0x40);
}
private static boolean isTabCtrlCode(byte cc1, byte cc2) {

View file

@ -34,9 +34,9 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
private static final String TAG = "SubripDecoder";
private static final Pattern SUBRIP_TIMING_LINE = Pattern.compile("(\\S*)\\s*-->\\s*(\\S*)");
private static final Pattern SUBRIP_TIMESTAMP =
Pattern.compile("(?:(\\d+):)?(\\d+):(\\d+),(\\d+)");
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*");
private final StringBuilder textBuilder;
@ -50,7 +50,6 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
ArrayList<Cue> cues = new ArrayList<>();
LongArray cueTimesUs = new LongArray();
ParsableByteArray subripData = new ParsableByteArray(bytes, length);
boolean haveEndTimecode;
String currentLine;
while ((currentLine = subripData.readLine()) != null) {
@ -68,15 +67,14 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
}
// Read and parse the timing line.
haveEndTimecode = false;
boolean haveEndTimecode = false;
currentLine = subripData.readLine();
Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine);
if (matcher.find()) {
cueTimesUs.add(parseTimecode(matcher.group(1)));
String endTimecode = matcher.group(2);
if (!TextUtils.isEmpty(endTimecode)) {
if (matcher.matches()) {
cueTimesUs.add(parseTimecode(matcher, 1));
if (!TextUtils.isEmpty(matcher.group(6))) {
haveEndTimecode = true;
cueTimesUs.add(parseTimecode(matcher.group(2)));
cueTimesUs.add(parseTimecode(matcher, 6));
}
} else {
Log.w(TAG, "Skipping invalid timing: " + currentLine);
@ -105,15 +103,11 @@ public final class SubripDecoder extends SimpleSubtitleDecoder {
return new SubripSubtitle(cuesArray, cueTimesUsArray);
}
private static long parseTimecode(String s) throws NumberFormatException {
Matcher matcher = SUBRIP_TIMESTAMP.matcher(s);
if (!matcher.matches()) {
throw new NumberFormatException("has invalid format");
}
long timestampMs = Long.parseLong(matcher.group(1)) * 60 * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(2)) * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(3)) * 1000;
timestampMs += Long.parseLong(matcher.group(4));
private static long parseTimecode(Matcher matcher, int groupOffset) {
long timestampMs = Long.parseLong(matcher.group(groupOffset + 1)) * 60 * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 2)) * 60 * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 3)) * 1000;
timestampMs += Long.parseLong(matcher.group(groupOffset + 4));
return timestampMs * 1000;
}