From 80c5e00b18e6675f206c4734811ae9c46f5389e0 Mon Sep 17 00:00:00 2001 From: bachinger Date: Fri, 29 Oct 2021 12:13:32 +0100 Subject: [PATCH] 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 --- .../hls/playlist/HlsPlaylistParser.java | 34 +++-- .../playlist/HlsMediaPlaylistParserTest.java | 116 +++++++++++++++++- 2 files changed, 135 insertions(+), 15 deletions(-) diff --git a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java index c740eac6cd..30cce581af 100644 --- a/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java +++ b/libraries/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java @@ -647,7 +647,7 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser segments = new ArrayList<>(); List trailingParts = new ArrayList<>(); @Nullable Part preloadPart = null; - Map renditionReports = new HashMap<>(); + List renditionReports = new ArrayList<>(); List tags = new ArrayList<>(); long segmentDurationUs = 0; @@ -856,17 +856,11 @@ public final class HlsPlaylistParser implements ParsingLoadable.Parser 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 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 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