diff --git a/library/core/src/androidTest/assets/subrip/typical_unexpected_end b/library/core/src/androidTest/assets/subrip/typical_unexpected_end new file mode 100644 index 0000000000..8e2949b8db --- /dev/null +++ b/library/core/src/androidTest/assets/subrip/typical_unexpected_end @@ -0,0 +1,10 @@ +1 +00:00:00,000 --> 00:00:01,234 +This is the first subtitle. + +2 +00:00:02,345 --> 00:00:03,456 +This is the second subtitle. +Second subtitle with second line. + +3 \ No newline at end of file diff --git a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/subrip/SubripDecoderTest.java b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/subrip/SubripDecoderTest.java index 167499fcdc..744634edda 100644 --- a/library/core/src/androidTest/java/com/google/android/exoplayer2/text/subrip/SubripDecoderTest.java +++ b/library/core/src/androidTest/java/com/google/android/exoplayer2/text/subrip/SubripDecoderTest.java @@ -31,6 +31,7 @@ public final class SubripDecoderTest extends InstrumentationTestCase { 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 TYPICAL_UNEXPECTED_END = "subrip/typical_unexpected_end"; private static final String NO_END_TIMECODES_FILE = "subrip/no_end_timecodes"; public void testDecodeEmpty() throws IOException { @@ -107,6 +108,17 @@ public final class SubripDecoderTest extends InstrumentationTestCase { assertTypicalCue3(subtitle, 0); } + public void testDecodeTypicalUnexpectedEnd() throws IOException { + // Parsing should succeed, parsing the first and second cues only. + SubripDecoder decoder = new SubripDecoder(); + byte[] bytes = TestUtil.getByteArray(getInstrumentation(), TYPICAL_UNEXPECTED_END); + SubripSubtitle subtitle = decoder.decode(bytes, bytes.length, false); + + assertEquals(4, subtitle.getEventTimeCount()); + assertTypicalCue1(subtitle, 0); + assertTypicalCue2(subtitle, 2); + } + public void testDecodeNoEndTimecodes() throws IOException { SubripDecoder decoder = new SubripDecoder(); byte[] bytes = TestUtil.getByteArray(getInstrumentation(), NO_END_TIMECODES_FILE); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java index b5927dcd95..cdeb1bd10b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java @@ -116,9 +116,32 @@ public final class OfflineLicenseHelper { optionalKeyRequestParameters, new Handler(handlerThread.getLooper()), eventListener); } - /** Releases the helper. Should be called when the helper is no longer required. */ - public void release() { - handlerThread.quit(); + /** + * @see DefaultDrmSessionManager#getPropertyByteArray + */ + public synchronized byte[] getPropertyByteArray(String key) { + return drmSessionManager.getPropertyByteArray(key); + } + + /** + * @see DefaultDrmSessionManager#setPropertyByteArray + */ + public synchronized void setPropertyByteArray(String key, byte[] value) { + drmSessionManager.setPropertyByteArray(key, value); + } + + /** + * @see DefaultDrmSessionManager#getPropertyString + */ + public synchronized String getPropertyString(String key) { + return drmSessionManager.getPropertyString(key); + } + + /** + * @see DefaultDrmSessionManager#setPropertyString + */ + public synchronized void setPropertyString(String key, String value) { + drmSessionManager.setPropertyString(key, value); } /** @@ -185,21 +208,12 @@ public final class OfflineLicenseHelper { } return licenseDurationRemainingSec; } - - public byte[] getPropertyByteArray(String key) { - return drmSessionManager.getPropertyByteArray(key); - } - public void setPropertyByteArray(String key, byte[] value) { - drmSessionManager.setPropertyByteArray(key, value); - } - - public String getPropertyString(String key) { - return drmSessionManager.getPropertyString(key); - } - - public void setPropertyString(String key, String value) { - drmSessionManager.setPropertyString(key, value); + /** + * Releases the helper. Should be called when the helper is no longer required. + */ + public void release() { + handlerThread.quit(); } private byte[] blockingKeyRequest(@Mode int licenseMode, byte[] offlineLicenseKeySetId, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java index 4645e45ae8..9a03311ccf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/AtomParsers.java @@ -995,9 +995,10 @@ import java.util.List; int objectTypeIndication = parent.readUnsignedByte(); String mimeType; switch (objectTypeIndication) { - case 0x6B: - mimeType = MimeTypes.AUDIO_MPEG; - return Pair.create(mimeType, null); + case 0x60: + case 0x61: + mimeType = MimeTypes.VIDEO_MPEG2; + break; case 0x20: mimeType = MimeTypes.VIDEO_MP4V; break; @@ -1007,6 +1008,9 @@ import java.util.List; case 0x23: mimeType = MimeTypes.VIDEO_H265; break; + case 0x6B: + mimeType = MimeTypes.AUDIO_MPEG; + return Pair.create(mimeType, null); case 0x40: case 0x66: case 0x67: @@ -1027,10 +1031,6 @@ import java.util.List; case 0xAB: mimeType = MimeTypes.AUDIO_DTS_HD; return Pair.create(mimeType, null); - case 0x60: /* Visual 13818-2 Simple Profile */ - case 0x61: /* Visual 13818-2 Main Profile */ - mimeType = MimeTypes.VIDEO_MPEG2; - break; default: mimeType = null; break; @@ -1038,8 +1038,8 @@ import java.util.List; parent.skipBytes(12); - // Start of the AudioSpecificConfig. - parent.skipBytes(1); // AudioSpecificConfig tag + // Start of the DecoderSpecificInfo. + parent.skipBytes(1); // DecoderSpecificInfo tag int initializationDataSize = parseExpandableClassSize(parent); byte[] initializationData = new byte[initializationDataSize]; parent.readBytes(initializationData, 0, initializationDataSize); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java index 49ebe84d67..6cce902e87 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/subrip/SubripDecoder.java @@ -69,8 +69,13 @@ public final class SubripDecoder extends SimpleSubtitleDecoder { // Read and parse the timing line. boolean haveEndTimecode = false; currentLine = subripData.readLine(); - Matcher matcher = currentLine == null ? null : SUBRIP_TIMING_LINE.matcher(currentLine); - if (matcher != null && matcher.matches()) { + if (currentLine == null) { + Log.w(TAG, "Unexpected end"); + break; + } + + Matcher matcher = SUBRIP_TIMING_LINE.matcher(currentLine); + if (matcher.matches()) { cueTimesUs.add(parseTimecode(matcher, 1)); if (!TextUtils.isEmpty(matcher.group(6))) { haveEndTimecode = true;