diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java index 3cb5db30ec..6abb950254 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java @@ -104,10 +104,17 @@ public abstract class SegmentDownloader implements Downloader { * previous selection is cleared. If keys are null or empty, all representations are downloaded. */ public final void selectRepresentations(K[] keys) { - this.keys = keys != null ? keys.clone() : null; + this.keys = (keys != null && keys.length > 0) ? keys.clone() : null; resetCounters(); } + /** + * Returns keys for all representations. + * + * @see #selectRepresentations(Object[]) + */ + public abstract K[] getAllRepresentationKeys() throws IOException; + /** * Initializes the total segments, downloaded segments and downloaded bytes counters for the * selected representations. @@ -221,7 +228,7 @@ public abstract class SegmentDownloader implements Downloader { if (manifest != null) { List segments = null; try { - segments = getAllSegments(offlineDataSource, manifest, true); + segments = getSegments(offlineDataSource, manifest, getAllRepresentationKeys(), true); } catch (IOException e) { // Ignore exceptions. We do our best with what's available offline. } @@ -262,14 +269,6 @@ public abstract class SegmentDownloader implements Downloader { protected abstract List getSegments(DataSource dataSource, M manifest, K[] keys, boolean allowIncompleteIndex) throws InterruptedException, IOException; - /** - * Returns a list of all segments. - * - * @see #getSegments(DataSource, M, Object[], boolean) - */ - protected abstract List getAllSegments(DataSource dataSource, M manifest, - boolean allowPartialIndex) throws InterruptedException, IOException; - private void resetCounters() { totalSegments = C.LENGTH_UNSET; downloadedSegments = C.LENGTH_UNSET; @@ -295,9 +294,10 @@ public abstract class SegmentDownloader implements Downloader { private synchronized List initStatus(boolean offline) throws IOException, InterruptedException { DataSource dataSource = getDataSource(offline); - List segments = keys != null && keys.length > 0 - ? getSegments(dataSource, manifest, keys, offline) - : getAllSegments(dataSource, manifest, offline); + if (keys == null) { + keys = getAllRepresentationKeys(); + } + List segments = getSegments(dataSource, manifest, keys, offline); CachingCounters cachingCounters = new CachingCounters(); totalSegments = segments.size(); downloadedSegments = 0; diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java index 467f60fb0e..2b2c37be3d 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloader.java @@ -75,26 +75,24 @@ public final class DashDownloader extends SegmentDownloader getAllSegments(DataSource dataSource, DashManifest manifest, - boolean allowIndexLoadErrors) throws InterruptedException, IOException { - ArrayList segments = new ArrayList<>(); + public RepresentationKey[] getAllRepresentationKeys() throws IOException { + ArrayList keys = new ArrayList<>(); + DashManifest manifest = getManifest(); for (int periodIndex = 0; periodIndex < manifest.getPeriodCount(); periodIndex++) { List adaptationSets = manifest.getPeriod(periodIndex).adaptationSets; for (int adaptationIndex = 0; adaptationIndex < adaptationSets.size(); adaptationIndex++) { - AdaptationSet adaptationSet = adaptationSets.get(adaptationIndex); - RepresentationKey[] keys = new RepresentationKey[adaptationSet.representations.size()]; - for (int i = 0; i < keys.length; i++) { - keys[i] = new RepresentationKey(periodIndex, adaptationIndex, i); + int representationsCount = adaptationSets.get(adaptationIndex).representations.size(); + for (int i = 0; i < representationsCount; i++) { + keys.add(new RepresentationKey(periodIndex, adaptationIndex, i)); } - segments.addAll(getSegments(dataSource, manifest, keys, allowIndexLoadErrors)); } } - return segments; + return keys.toArray(new RepresentationKey[keys.size()]); + } + + @Override + protected DashManifest getManifest(DataSource dataSource, Uri uri) throws IOException { + return DashUtil.loadManifest(dataSource, uri); } @Override diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java index 5ac61294a4..a7bf35f2d1 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/offline/HlsDownloader.java @@ -36,7 +36,7 @@ import java.util.List; /** * Helper class to download HLS streams. * - * A subset of renditions can be downloaded by selecting them using {@link + *

A subset of renditions can be downloaded by selecting them using {@link * #selectRepresentations(Object[])}. As key, string form of the rendition's url is used. The urls * can be absolute or relative to the master playlist url. */ @@ -49,6 +49,16 @@ public final class HlsDownloader extends SegmentDownloader urls = new ArrayList<>(); + HlsMasterPlaylist manifest = getManifest(); + extractUrls(manifest.variants, urls); + extractUrls(manifest.audios, urls); + extractUrls(manifest.subtitles, urls); + return urls.toArray(new String[urls.size()]); + } + @Override protected HlsMasterPlaylist getManifest(DataSource dataSource, Uri uri) throws IOException { HlsPlaylist hlsPlaylist = loadManifest(dataSource, uri); @@ -59,17 +69,6 @@ public final class HlsDownloader extends SegmentDownloader getAllSegments(DataSource dataSource, HlsMasterPlaylist manifest, - boolean allowIndexLoadErrors) throws InterruptedException, IOException { - ArrayList urls = new ArrayList<>(); - extractUrls(manifest.variants, urls); - extractUrls(manifest.audios, urls); - extractUrls(manifest.subtitles, urls); - return getSegments(dataSource, manifest, urls.toArray(new String[urls.size()]), - allowIndexLoadErrors); - } - @Override protected List getSegments(DataSource dataSource, HlsMasterPlaylist manifest, String[] keys, boolean allowIndexLoadErrors) throws InterruptedException, IOException { @@ -104,7 +103,7 @@ public final class HlsDownloader extends SegmentDownloader loadable = new ParsingLoadable<>(dataSource, dataSpec, @@ -113,9 +112,11 @@ public final class HlsDownloader extends SegmentDownloader segments, HlsMediaPlaylist mediaPlaylist, - HlsMediaPlaylist.Segment hlsSegment, HashSet encryptionKeyUris) - throws IOException, InterruptedException { + private static void addSegment( + ArrayList segments, + HlsMediaPlaylist mediaPlaylist, + HlsMediaPlaylist.Segment hlsSegment, + HashSet encryptionKeyUris) { long startTimeUs = mediaPlaylist.startTimeUs + hlsSegment.relativeStartTimeUs; if (hlsSegment.fullSegmentEncryptionKeyUri != null) { Uri keyUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java index 5e9ae9a164..5b97101fc6 100644 --- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java +++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloader.java @@ -33,13 +33,12 @@ import java.util.List; /** * Helper class to download SmoothStreaming streams. * - *

Except {@link #getTotalSegments()}, {@link #getDownloadedSegments()} and - * {@link #getDownloadedBytes()}, this class isn't thread safe. + *

Except {@link #getTotalSegments()}, {@link #getDownloadedSegments()} and {@link + * #getDownloadedBytes()}, this class isn't thread safe. * *

Example usage: * - *

- * {@code
+ * 
{@code
  * SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor());
  * DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
  * DownloaderConstructorHelper constructorHelper =
@@ -56,8 +55,8 @@ import java.util.List;
  * });
  * // Access downloaded data using CacheDataSource
  * CacheDataSource cacheDataSource =
- *     new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);}
- * 
+ * new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE); + * }
*/ public final class SsDownloader extends SegmentDownloader { @@ -69,7 +68,20 @@ public final class SsDownloader extends SegmentDownloader } @Override - public SsManifest getManifest(DataSource dataSource, Uri uri) throws IOException { + public TrackKey[] getAllRepresentationKeys() throws IOException { + ArrayList keys = new ArrayList<>(); + SsManifest manifest = getManifest(); + for (int i = 0; i < manifest.streamElements.length; i++) { + StreamElement streamElement = manifest.streamElements[i]; + for (int j = 0; j < streamElement.formats.length; j++) { + keys.add(new TrackKey(i, j)); + } + } + return keys.toArray(new TrackKey[keys.size()]); + } + + @Override + protected SsManifest getManifest(DataSource dataSource, Uri uri) throws IOException { DataSpec dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH | DataSpec.FLAG_ALLOW_GZIP); ParsingLoadable loadable = new ParsingLoadable<>(dataSource, dataSpec, @@ -78,20 +90,6 @@ public final class SsDownloader extends SegmentDownloader return loadable.getResult(); } - @Override - protected List getAllSegments(DataSource dataSource, SsManifest manifest, - boolean allowIndexLoadErrors) throws InterruptedException, IOException { - ArrayList segments = new ArrayList<>(); - for (int i = 0; i < manifest.streamElements.length; i++) { - StreamElement streamElement = manifest.streamElements[i]; - for (int j = 0; j < streamElement.formats.length; j++) { - segments.addAll(getSegments(dataSource, manifest, new TrackKey[] {new TrackKey(i, j)}, - allowIndexLoadErrors)); - } - } - return segments; - } - @Override protected List getSegments(DataSource dataSource, SsManifest manifest, TrackKey[] keys, boolean allowIndexLoadErrors) throws InterruptedException, IOException {