HLS: Fix incorrect handling of byte ranges for EXT-X-MAP tags

Issue: #8783
#minor-release
PiperOrigin-RevId: 366265419
This commit is contained in:
olly 2021-04-01 17:22:17 +01:00 committed by marcbaechinger
parent 106294158a
commit 4fd8e791f6
3 changed files with 56 additions and 2 deletions

View file

@ -39,6 +39,8 @@
codec input size
([#8705](https://github.com/google/ExoPlayer/issues/8705)).
* HLS:
* Fix incorrect application of byte ranges to `EXT-X-MAP` tags
([#8783](https://github.com/google/ExoPlayer/issues/8783)).
* Fix issue that could cause playback to become stuck if corresponding
`EXT-X-DISCONTINUITY` tags in different media playlists occur at
different positions in time

View file

@ -702,6 +702,10 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
segmentByteRangeOffset = Long.parseLong(splitByteRange[1]);
}
}
if (segmentByteRangeLength == C.LENGTH_UNSET) {
// The segment has no byte range defined.
segmentByteRangeOffset = 0;
}
if (fullSegmentEncryptionKeyUri != null && fullSegmentEncryptionIV == null) {
// See RFC 8216, Section 4.3.2.5.
throw new ParserException(
@ -715,7 +719,9 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
segmentByteRangeLength,
fullSegmentEncryptionKeyUri,
fullSegmentEncryptionIV);
segmentByteRangeOffset = 0;
if (segmentByteRangeLength != C.LENGTH_UNSET) {
segmentByteRangeOffset += segmentByteRangeLength;
}
segmentByteRangeLength = C.LENGTH_UNSET;
} else if (line.startsWith(TAG_TARGET_DURATION)) {
targetDurationUs = parseIntAttr(line, REGEX_TARGET_DURATION) * C.MICROS_PER_SECOND;
@ -948,7 +954,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
String segmentUri = replaceVariableReferences(line, variableDefinitions);
@Nullable Segment inferredInitSegment = urlToInferredInitSegment.get(segmentUri);
if (segmentByteRangeLength == C.LENGTH_UNSET) {
// The segment is not byte range defined.
// The segment has no byte range defined.
segmentByteRangeOffset = 0;
} else if (isIFrameOnly && initializationSegment == null && inferredInitSegment == null) {
// The segment is a resource byte range without an initialization segment.

View file

@ -154,6 +154,52 @@ public class HlsMediaPlaylistParserTest {
assertThat(segment.url).isEqualTo("https://priv.example.com/fileSequence2683.ts");
}
@Test
public void parseMediaPlaylist_withByteRanges() throws Exception {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
String playlistString =
"#EXTM3U\n"
+ "#EXT-X-VERSION:3\n"
+ "#EXT-X-TARGETDURATION:5\n"
+ "\n"
+ "#EXT-X-BYTERANGE:200@100\n"
+ "#EXT-X-MAP:URI=\"stream.mp4\"\n"
+ "#EXTINF:5,\n"
+ "#EXT-X-BYTERANGE:400\n"
+ "stream.mp4\n"
+ "#EXTINF:5,\n"
+ "#EXT-X-BYTERANGE:500\n"
+ "stream.mp4\n"
+ "#EXT-X-DISCONTINUITY\n"
+ "#EXT-X-MAP:URI=\"init.mp4\"\n"
+ "#EXTINF:5,\n"
+ "segment.mp4\n";
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
HlsPlaylist playlist = new HlsPlaylistParser().parse(playlistUri, inputStream);
HlsMediaPlaylist mediaPlaylist = (HlsMediaPlaylist) playlist;
List<Segment> segments = mediaPlaylist.segments;
assertThat(segments).isNotNull();
assertThat(segments).hasSize(3);
Segment segment = segments.get(0);
assertThat(segment.initializationSegment.byteRangeOffset).isEqualTo(100);
assertThat(segment.initializationSegment.byteRangeLength).isEqualTo(200);
assertThat(segment.byteRangeOffset).isEqualTo(300);
assertThat(segment.byteRangeLength).isEqualTo(400);
segment = segments.get(1);
assertThat(segment.byteRangeOffset).isEqualTo(700);
assertThat(segment.byteRangeLength).isEqualTo(500);
segment = segments.get(2);
assertThat(segment.initializationSegment.byteRangeOffset).isEqualTo(0);
assertThat(segment.initializationSegment.byteRangeLength).isEqualTo(C.LENGTH_UNSET);
assertThat(segment.byteRangeOffset).isEqualTo(0);
assertThat(segment.byteRangeLength).isEqualTo(C.LENGTH_UNSET);
}
@Test
public void parseSampleAesMethod() throws Exception {
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");