Defer setting defaults for rendition reports until playlist is parsed
This makes sure that #EXT-X-RENDITION-REPORT tags can be placed before the list of segments/parts as well. We were previously assuming that these come at the end, which naturally would make sense and is done like this in all examples, but it is not explicitly defined by the spec. Issue: google/ExoPlayer#9592 PiperOrigin-RevId: 406329684
This commit is contained in:
parent
222db48298
commit
80c5e00b18
@ -647,7 +647,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
List<Segment> segments = new ArrayList<>();
|
||||
List<Part> trailingParts = new ArrayList<>();
|
||||
@Nullable Part preloadPart = null;
|
||||
Map<Uri, RenditionReport> renditionReports = new HashMap<>();
|
||||
List<RenditionReport> renditionReports = new ArrayList<>();
|
||||
List<String> tags = new ArrayList<>();
|
||||
|
||||
long segmentDurationUs = 0;
|
||||
@ -856,17 +856,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
} else if (line.equals(TAG_ENDLIST)) {
|
||||
hasEndTag = true;
|
||||
} else if (line.startsWith(TAG_RENDITION_REPORT)) {
|
||||
long defaultValue = mediaSequence + segments.size() - (trailingParts.isEmpty() ? 1 : 0);
|
||||
long lastMediaSequence = parseOptionalLongAttr(line, REGEX_LAST_MSN, defaultValue);
|
||||
List<Part> lastParts =
|
||||
trailingParts.isEmpty() ? Iterables.getLast(segments).parts : trailingParts;
|
||||
int defaultPartIndex =
|
||||
partTargetDurationUs != C.TIME_UNSET ? lastParts.size() - 1 : C.INDEX_UNSET;
|
||||
int lastPartIndex = parseOptionalIntAttr(line, REGEX_LAST_PART, defaultPartIndex);
|
||||
long lastMediaSequence = parseOptionalLongAttr(line, REGEX_LAST_MSN, C.INDEX_UNSET);
|
||||
int lastPartIndex = parseOptionalIntAttr(line, REGEX_LAST_PART, C.INDEX_UNSET);
|
||||
String uri = parseStringAttr(line, REGEX_URI, variableDefinitions);
|
||||
Uri playlistUri = Uri.parse(UriUtil.resolve(baseUri, uri));
|
||||
renditionReports.put(
|
||||
playlistUri, new RenditionReport(playlistUri, lastMediaSequence, lastPartIndex));
|
||||
renditionReports.add(new RenditionReport(playlistUri, lastMediaSequence, lastPartIndex));
|
||||
} else if (line.startsWith(TAG_PRELOAD_HINT)) {
|
||||
if (preloadPart != null) {
|
||||
continue;
|
||||
@ -1024,6 +1018,24 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
}
|
||||
}
|
||||
|
||||
Map<Uri, RenditionReport> renditionReportMap = new HashMap<>();
|
||||
for (int i = 0; i < renditionReports.size(); i++) {
|
||||
RenditionReport renditionReport = renditionReports.get(i);
|
||||
long lastMediaSequence = renditionReport.lastMediaSequence;
|
||||
if (lastMediaSequence == C.INDEX_UNSET) {
|
||||
lastMediaSequence = mediaSequence + segments.size() - (trailingParts.isEmpty() ? 1 : 0);
|
||||
}
|
||||
int lastPartIndex = renditionReport.lastPartIndex;
|
||||
if (lastPartIndex == C.INDEX_UNSET && partTargetDurationUs != C.TIME_UNSET) {
|
||||
List<Part> lastParts =
|
||||
trailingParts.isEmpty() ? Iterables.getLast(segments).parts : trailingParts;
|
||||
lastPartIndex = lastParts.size() - 1;
|
||||
}
|
||||
renditionReportMap.put(
|
||||
renditionReport.playlistUri,
|
||||
new RenditionReport(renditionReport.playlistUri, lastMediaSequence, lastPartIndex));
|
||||
}
|
||||
|
||||
if (preloadPart != null) {
|
||||
trailingParts.add(preloadPart);
|
||||
}
|
||||
@ -1048,7 +1060,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser<HlsPlayli
|
||||
segments,
|
||||
trailingParts,
|
||||
serverControl,
|
||||
renditionReports);
|
||||
renditionReportMap);
|
||||
}
|
||||
|
||||
private static DrmInitData getPlaylistProtectionSchemes(
|
||||
|
@ -903,6 +903,114 @@ public class HlsMediaPlaylistParserTest {
|
||||
assertThat(report0.lastPartIndex).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
parseMediaPlaylist_withRenditionReportBeforeSegmentsWithoutPartTargetDurationWithoutLastMsn_sameLastMsnAsCurrentPlaylist()
|
||||
throws IOException {
|
||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||
String playlistString =
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:4\n"
|
||||
+ "#EXT-X-VERSION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:266\n"
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\"\n"
|
||||
+ "#EXTINF:4.00000,\n"
|
||||
+ "fileSequence266.mp4\n";
|
||||
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
|
||||
|
||||
HlsMediaPlaylist playlist =
|
||||
(HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
|
||||
|
||||
assertThat(playlist.renditionReports).hasSize(1);
|
||||
HlsMediaPlaylist.RenditionReport report =
|
||||
playlist.renditionReports.get(Uri.parse("https://example.com/rendition0.m3u8"));
|
||||
assertThat(report.lastMediaSequence).isEqualTo(266);
|
||||
assertThat(report.lastPartIndex).isEqualTo(C.INDEX_UNSET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
parseMediaPlaylist_withRenditionReportBeforeSegementsDefaultMsn_sameMsnAsCurrentPlaylist()
|
||||
throws IOException {
|
||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||
String playlistString =
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:4\n"
|
||||
+ "#EXT-X-PART-INF:PART-TARGET=1\n"
|
||||
+ "#EXT-X-VERSION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:266\n"
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-PART=2\n"
|
||||
+ "#EXTINF:4.00000,\n"
|
||||
+ "fileSequence266.mp4\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n";
|
||||
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
|
||||
|
||||
HlsMediaPlaylist playlist =
|
||||
(HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
|
||||
|
||||
assertThat(playlist.renditionReports).hasSize(1);
|
||||
HlsMediaPlaylist.RenditionReport report =
|
||||
playlist.renditionReports.get(Uri.parse("https://example.com/rendition0.m3u8"));
|
||||
assertThat(report.lastMediaSequence).isEqualTo(267);
|
||||
assertThat(report.lastPartIndex).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
parseMediaPlaylist_withRenditionReportBeforeSegementsDefaultLastPart_sameLastPartIndexAsCurrentPlaylist()
|
||||
throws IOException {
|
||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||
String playlistString =
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:4\n"
|
||||
+ "#EXT-X-PART-INF:PART-TARGET=1\n"
|
||||
+ "#EXT-X-VERSION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:266\n"
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=267\n"
|
||||
+ "#EXTINF:4.00000,\n"
|
||||
+ "fileSequence266.mp4\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.1.ts\"\n";
|
||||
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
|
||||
|
||||
HlsMediaPlaylist playlist =
|
||||
(HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
|
||||
|
||||
assertThat(playlist.renditionReports).hasSize(1);
|
||||
HlsMediaPlaylist.RenditionReport report =
|
||||
playlist.renditionReports.get(Uri.parse("https://example.com/rendition0.m3u8"));
|
||||
assertThat(report.lastMediaSequence).isEqualTo(267);
|
||||
assertThat(report.lastPartIndex).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
parseMediaPlaylist_withRenditionReportBeforeSegements_sameMsnAndLastPartIndexAsCurrentPlaylist()
|
||||
throws IOException {
|
||||
Uri playlistUri = Uri.parse("https://example.com/test.m3u8");
|
||||
String playlistString =
|
||||
"#EXTM3U\n"
|
||||
+ "#EXT-X-TARGETDURATION:4\n"
|
||||
+ "#EXT-X-PART-INF:PART-TARGET=1\n"
|
||||
+ "#EXT-X-VERSION:6\n"
|
||||
+ "#EXT-X-MEDIA-SEQUENCE:266\n"
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\"\n"
|
||||
+ "#EXTINF:4.00000,\n"
|
||||
+ "fileSequence266.mp4\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.1.ts\"\n";
|
||||
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
|
||||
|
||||
HlsMediaPlaylist playlist =
|
||||
(HlsMediaPlaylist) new HlsPlaylistParser().parse(playlistUri, inputStream);
|
||||
|
||||
assertThat(playlist.renditionReports).hasSize(1);
|
||||
HlsMediaPlaylist.RenditionReport report =
|
||||
playlist.renditionReports.get(Uri.parse("https://example.com/rendition0.m3u8"));
|
||||
assertThat(report.lastMediaSequence).isEqualTo(267);
|
||||
assertThat(report.lastPartIndex).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
parseMediaPlaylist_withRenditionReportLowLatencyWithoutLastPartIndex_sameLastPartIndexAsCurrentPlaylist()
|
||||
@ -917,7 +1025,7 @@ public class HlsMediaPlaylistParserTest {
|
||||
+ "#EXTINF:4.00000,\n"
|
||||
+ "fileSequence266.mp4\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=100\n";
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=267\n";
|
||||
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
|
||||
|
||||
HlsMediaPlaylist playlist =
|
||||
@ -926,7 +1034,7 @@ public class HlsMediaPlaylistParserTest {
|
||||
assertThat(playlist.renditionReports).hasSize(1);
|
||||
HlsMediaPlaylist.RenditionReport report0 =
|
||||
playlist.renditionReports.get(Uri.parse("https://example.com/rendition0.m3u8"));
|
||||
assertThat(report0.lastMediaSequence).isEqualTo(100);
|
||||
assertThat(report0.lastMediaSequence).isEqualTo(267);
|
||||
assertThat(report0.lastPartIndex).isEqualTo(0);
|
||||
}
|
||||
|
||||
@ -945,7 +1053,7 @@ public class HlsMediaPlaylistParserTest {
|
||||
+ "fileSequence266.mp4\n"
|
||||
+ "#EXT-X-PART:DURATION=2.00000,URI=\"part267.0.ts\"\n"
|
||||
+ "#EXT-X-PRELOAD-HINT:TYPE=PART,URI=\"filePart267.1.ts\"\n"
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=100\n";
|
||||
+ "#EXT-X-RENDITION-REPORT:URI=\"/rendition0.m3u8\",LAST-MSN=267\n";
|
||||
InputStream inputStream = new ByteArrayInputStream(Util.getUtf8Bytes(playlistString));
|
||||
|
||||
HlsMediaPlaylist playlist =
|
||||
@ -955,7 +1063,7 @@ public class HlsMediaPlaylistParserTest {
|
||||
assertThat(playlist.renditionReports).hasSize(1);
|
||||
HlsMediaPlaylist.RenditionReport report0 =
|
||||
playlist.renditionReports.get(Uri.parse("https://example.com/rendition0.m3u8"));
|
||||
assertThat(report0.lastMediaSequence).isEqualTo(100);
|
||||
assertThat(report0.lastMediaSequence).isEqualTo(267);
|
||||
assertThat(report0.lastPartIndex).isEqualTo(0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user