From cb46e875e4f037785002861302f90be96b5b3a48 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 15 Feb 2018 14:51:34 -0500 Subject: [PATCH] Added parsing of optional human-readable title #EXTINF:,[] --- .../hls/playlist/HlsMediaPlaylistParserTest.java | 11 ++++++++--- .../source/hls/playlist/HlsMediaPlaylist.java | 10 ++++++++-- .../source/hls/playlist/HlsPlaylistParser.java | 11 ++++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java index add631c39b..108c202fd1 100644 --- a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java +++ b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylistParserTest.java @@ -44,17 +44,17 @@ public class HlsMediaPlaylistParserTest extends TestCase { + "#EXT-X-DISCONTINUITY-SEQUENCE:4\n" + "#EXT-X-ALLOW-CACHE:YES\n" + "\n" - + "#EXTINF:7.975,\n" + + "#EXTINF:7.975,This is a human-readable title string.\n" + "#EXT-X-BYTERANGE:51370@0\n" + "https://priv.example.com/fileSequence2679.ts\n" + "\n" + "#EXT-X-KEY:METHOD=AES-128,URI=\"https://priv.example.com/key.php?r=2680\",IV=0x1566B\n" - + "#EXTINF:7.975,\n" + + "#EXTINF:7.975,Title with a url https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.1\n" + "#EXT-X-BYTERANGE:51501@2147483648\n" + "https://priv.example.com/fileSequence2680.ts\n" + "\n" + "#EXT-X-KEY:METHOD=NONE\n" - + "#EXTINF:7.941,\n" + + "#EXTINF:7.941,Title with a uuid 123e4567-e89b-12d3-a456-426655440000\n" + "#EXT-X-BYTERANGE:51501\n" // @2147535149 + "https://priv.example.com/fileSequence2681.ts\n" + "\n" @@ -88,6 +88,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { assertThat(mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence) .isEqualTo(4); assertThat(segment.durationUs).isEqualTo(7975000); + assertThat(segment.title).isEqualTo("This is a human-readable title string."); assertThat(segment.fullSegmentEncryptionKeyUri).isNull(); assertThat(segment.encryptionIV).isNull(); assertThat(segment.byterangeLength).isEqualTo(51370); @@ -97,6 +98,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { segment = segments.get(1); assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0); assertThat(segment.durationUs).isEqualTo(7975000); + assertThat(segment.title).isEqualTo("Title with a url https://tools.ietf.org/html/draft-pantos-http-live-streaming-23#section-4.3.2.1"); assertThat(segment.fullSegmentEncryptionKeyUri) .isEqualTo("https://priv.example.com/key.php?r=2680"); assertThat(segment.encryptionIV).isEqualTo("0x1566B"); @@ -107,6 +109,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { segment = segments.get(2); assertThat(segment.relativeDiscontinuitySequence).isEqualTo(0); assertThat(segment.durationUs).isEqualTo(7941000); + assertThat(segment.title).isEqualTo("Title with a uuid 123e4567-e89b-12d3-a456-426655440000"); assertThat(segment.fullSegmentEncryptionKeyUri).isNull(); assertThat(segment.encryptionIV).isEqualTo(null); assertThat(segment.byterangeLength).isEqualTo(51501); @@ -116,6 +119,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { segment = segments.get(3); assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1); assertThat(segment.durationUs).isEqualTo(7975000); + assertThat(segment.title).isNull(); assertThat(segment.fullSegmentEncryptionKeyUri) .isEqualTo("https://priv.example.com/key.php?r=2682"); // 0xA7A == 2682. @@ -128,6 +132,7 @@ public class HlsMediaPlaylistParserTest extends TestCase { segment = segments.get(4); assertThat(segment.relativeDiscontinuitySequence).isEqualTo(1); assertThat(segment.durationUs).isEqualTo(7975000); + assertThat(segment.title).isNull(); assertThat(segment.fullSegmentEncryptionKeyUri) .isEqualTo("https://priv.example.com/key.php?r=2682"); // 0xA7B == 2683. diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java index 77a4c9ed1d..52d3b80307 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMediaPlaylist.java @@ -41,6 +41,10 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * The duration of the segment in microseconds, as defined by #EXTINF. */ public final long durationUs; + /** + * The human-readable title of the segment as defined by #EXTINF. + */ + public final String title; /** * The number of #EXT-X-DISCONTINUITY tags in the playlist before the segment. */ @@ -70,12 +74,13 @@ public final class HlsMediaPlaylist extends HlsPlaylist { public final long byterangeLength; public Segment(String uri, long byterangeOffset, long byterangeLength) { - this(uri, 0, -1, C.TIME_UNSET, null, null, byterangeOffset, byterangeLength); + this(uri, 0, null, -1, C.TIME_UNSET, null, null, byterangeOffset, byterangeLength); } /** * @param url See {@link #url}. * @param durationUs See {@link #durationUs}. + * @param title See {@link #title}. * @param relativeDiscontinuitySequence See {@link #relativeDiscontinuitySequence}. * @param relativeStartTimeUs See {@link #relativeStartTimeUs}. * @param fullSegmentEncryptionKeyUri See {@link #fullSegmentEncryptionKeyUri}. @@ -83,11 +88,12 @@ public final class HlsMediaPlaylist extends HlsPlaylist { * @param byterangeOffset See {@link #byterangeOffset}. * @param byterangeLength See {@link #byterangeLength}. */ - public Segment(String url, long durationUs, int relativeDiscontinuitySequence, + public Segment(String url, long durationUs, String title, int relativeDiscontinuitySequence, long relativeStartTimeUs, String fullSegmentEncryptionKeyUri, String encryptionIV, long byterangeOffset, long byterangeLength) { this.url = url; this.durationUs = durationUs; + this.title = title; this.relativeDiscontinuitySequence = relativeDiscontinuitySequence; this.relativeStartTimeUs = relativeStartTimeUs; this.fullSegmentEncryptionKeyUri = fullSegmentEncryptionKeyUri; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java index 4deddc1869..60a2c3ec0c 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistParser.java @@ -104,7 +104,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli private static final Pattern REGEX_MEDIA_SEQUENCE = Pattern.compile(TAG_MEDIA_SEQUENCE + ":(\\d+)\\b"); private static final Pattern REGEX_MEDIA_DURATION = Pattern.compile(TAG_MEDIA_DURATION - + ":([\\d\\.]+)\\b"); + + ":([\\d\\.]+)\\b"); + private static final Pattern REGEX_MEDIA_TITLE = Pattern.compile(TAG_MEDIA_DURATION + + ":[\\d\\.]+\\b,(.+)?"); private static final Pattern REGEX_TIME_OFFSET = Pattern.compile("TIME-OFFSET=(-?[\\d\\.]+)\\b"); private static final Pattern REGEX_BYTERANGE = Pattern.compile(TAG_BYTERANGE + ":(\\d+(?:@\\d+)?)\\b"); @@ -349,6 +351,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli List<String> tags = new ArrayList<>(); long segmentDurationUs = 0; + String segmentTitle = null; boolean hasDiscontinuitySequence = false; int playlistDiscontinuitySequence = 0; int relativeDiscontinuitySequence = 0; @@ -402,7 +405,8 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli version = parseIntAttr(line, REGEX_VERSION); } else if (line.startsWith(TAG_MEDIA_DURATION)) { segmentDurationUs = - (long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND); + (long) (parseDoubleAttr(line, REGEX_MEDIA_DURATION) * C.MICROS_PER_SECOND); + segmentTitle = parseOptionalStringAttr(line, REGEX_MEDIA_TITLE); } else if (line.startsWith(TAG_KEY)) { String method = parseOptionalStringAttr(line, REGEX_METHOD); String keyFormat = parseOptionalStringAttr(line, REGEX_KEYFORMAT); @@ -462,11 +466,12 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli if (segmentByteRangeLength == C.LENGTH_UNSET) { segmentByteRangeOffset = 0; } - segments.add(new Segment(line, segmentDurationUs, relativeDiscontinuitySequence, + segments.add(new Segment(line, segmentDurationUs, segmentTitle, relativeDiscontinuitySequence, segmentStartTimeUs, encryptionKeyUri, segmentEncryptionIV, segmentByteRangeOffset, segmentByteRangeLength)); segmentStartTimeUs += segmentDurationUs; segmentDurationUs = 0; + segmentTitle = null; if (segmentByteRangeLength != C.LENGTH_UNSET) { segmentByteRangeOffset += segmentByteRangeLength; }