diff --git a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java index 35cd7f03d8..4dedc9526f 100644 --- a/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java +++ b/library/hls/src/androidTest/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylistParserTest.java @@ -16,16 +16,20 @@ package com.google.android.exoplayer2.source.hls.playlist; import android.net.Uri; + import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ParserException; import com.google.android.exoplayer2.util.MimeTypes; + +import junit.framework.TestCase; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.charset.Charset; import java.util.Collections; +import java.util.Comparator; import java.util.List; -import junit.framework.TestCase; /** * Test for {@link HlsMasterPlaylistParserTest} @@ -147,6 +151,44 @@ public class HlsMasterPlaylistParserTest extends TestCase { assertEquals(Collections.emptyList(), playlist.muxedCaptionFormats); } + public void testReorderedVariantCopy() throws IOException { + HlsMasterPlaylist playlist = parseMasterPlaylist(PLAYLIST_URI, MASTER_PLAYLIST); + HlsMasterPlaylist nonReorderedPlaylist = + playlist.copyWithReorderedVariants(new Comparator() { + @Override + public int compare(HlsMasterPlaylist.HlsUrl url1, HlsMasterPlaylist.HlsUrl url2) { + return 0; + } + }); + assertEquals(playlist.variants, nonReorderedPlaylist.variants); + HlsMasterPlaylist.HlsUrl preferred = null; + for (HlsMasterPlaylist.HlsUrl url : playlist.variants) { + if (preferred == null || url.format.bitrate > preferred.format.bitrate) { + preferred = url; + } + } + + assertNotNull(preferred); + + final Comparator comparator = Collections.reverseOrder(new Comparator() { + @Override + public int compare(HlsMasterPlaylist.HlsUrl url1, HlsMasterPlaylist.HlsUrl url2) { + if (url1.format.bitrate > url2.format.bitrate) { + return 1; + } + + if (url2.format.bitrate > url1.format.bitrate) { + return -1; + } + + return 0; + } + }); + HlsMasterPlaylist reorderedPlaylist = playlist.copyWithReorderedVariants(comparator); + + assertEquals(reorderedPlaylist.variants.get(0), preferred); + } + private static HlsMasterPlaylist parseMasterPlaylist(String uri, String playlistString) throws IOException { Uri playlistUri = Uri.parse(uri); diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index fd3d533337..b7f7124e44 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -26,9 +26,12 @@ import com.google.android.exoplayer2.source.MediaPeriod; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.SinglePeriodTimeline; import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; +import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.ParsingLoadable; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; import java.util.List; @@ -52,6 +55,7 @@ public final class HlsMediaSource implements MediaSource, private final HlsDataSourceFactory dataSourceFactory; private final int minLoadableRetryCount; private final EventDispatcher eventDispatcher; + private final ParsingLoadable.Parser playlistParser; private HlsPlaylistTracker playlistTracker; private Listener sourceListener; @@ -72,9 +76,17 @@ public final class HlsMediaSource implements MediaSource, public HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory, int minLoadableRetryCount, Handler eventHandler, AdaptiveMediaSourceEventListener eventListener) { + this(manifestUri, dataSourceFactory, minLoadableRetryCount, eventHandler, eventListener, new HlsPlaylistParser()); + } + + public HlsMediaSource(Uri manifestUri, HlsDataSourceFactory dataSourceFactory, + int minLoadableRetryCount, Handler eventHandler, + AdaptiveMediaSourceEventListener eventListener, + ParsingLoadable.Parser playlistParser) { this.manifestUri = manifestUri; this.dataSourceFactory = dataSourceFactory; this.minLoadableRetryCount = minLoadableRetryCount; + this.playlistParser = playlistParser; eventDispatcher = new EventDispatcher(eventHandler, eventListener); } @@ -82,7 +94,7 @@ public final class HlsMediaSource implements MediaSource, public void prepareSource(ExoPlayer player, boolean isTopLevelSource, Listener listener) { Assertions.checkState(playlistTracker == null); playlistTracker = new HlsPlaylistTracker(manifestUri, dataSourceFactory, eventDispatcher, - minLoadableRetryCount, this); + minLoadableRetryCount, this, playlistParser); sourceListener = listener; playlistTracker.start(); } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java index 04192def9d..5ded975f88 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsMasterPlaylist.java @@ -19,6 +19,7 @@ import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.util.MimeTypes; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; /** @@ -123,6 +124,25 @@ public final class HlsMasterPlaylist extends HlsPlaylist { muxedAudioFormat, muxedCaptionFormats); } + /** + * Returns a copy of this playlist which includes the variants sorted using the passed comparator. NOTE: the variants + * will be sorted in ascending order by default. If you wish to use descending order, you can wrap your comparator in + * {@link Collections#reverseOrder(Comparator)}. + * + * @param variantComparator the comparator to use to sort the variant list. + * @return a copy of this playlist which includes the variants sorted using the passed comparator. + */ + public HlsMasterPlaylist copyWithReorderedVariants(Comparator variantComparator) { + return new HlsMasterPlaylist(baseUri, tags, filterVariants(variants, variantComparator), audios, + subtitles, muxedAudioFormat, muxedCaptionFormats); + } + + private List filterVariants(List variants, Comparator variantComparator) { + List reorderedList = new ArrayList<>(variants); + Collections.sort(reorderedList, variantComparator); + return reorderedList; + } + /** * Creates a playlist with a single variant. * diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java index d3682217d8..52d5a4b5bc 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/playlist/HlsPlaylistTracker.java @@ -115,7 +115,7 @@ public final class HlsPlaylistTracker implements Loader.Callback playlistParser; private final int minRetryCount; private final IdentityHashMap playlistBundles; private final Handler playlistRefreshHandler; @@ -140,7 +140,7 @@ public final class HlsPlaylistTracker implements Loader.Callback playlistParser) { this.initialPlaylistUri = initialPlaylistUri; this.dataSourceFactory = dataSourceFactory; this.eventDispatcher = eventDispatcher; @@ -148,7 +148,7 @@ public final class HlsPlaylistTracker implements Loader.Callback(); initialPlaylistLoader = new Loader("HlsPlaylistTracker:MasterPlaylist"); - playlistParser = new HlsPlaylistParser(); + this.playlistParser = playlistParser; playlistBundles = new IdentityHashMap<>(); playlistRefreshHandler = new Handler(); }