Make all segment downloader use the media item

PiperOrigin-RevId: 311527440
This commit is contained in:
bachinger 2020-05-14 15:24:40 +01:00 committed by Oliver Woodman
parent c1aa9b917b
commit 9e35c6c28c
7 changed files with 146 additions and 59 deletions

View File

@ -15,10 +15,13 @@
*/ */
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.net.Uri; import android.net.Uri;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.ParsingLoadable; import com.google.android.exoplayer2.upstream.ParsingLoadable;
@ -79,10 +82,8 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
@Nullable private volatile Thread downloadThread; @Nullable private volatile Thread downloadThread;
/** /**
* @param manifestUri The {@link Uri} of the manifest to be downloaded. * @param mediaItem The {@link MediaItem} to be downloaded.
* @param manifestParser A parser for the manifest. * @param manifestParser A parser for the manifest.
* @param streamKeys Keys defining which streams in the manifest should be selected for download.
* If empty, all streams are downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the * @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written. * download will be written.
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
@ -90,14 +91,14 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
*/ */
public SegmentDownloader( public SegmentDownloader(
Uri manifestUri, MediaItem mediaItem,
Parser<M> manifestParser, Parser<M> manifestParser,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory, CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) { Executor executor) {
this.manifestDataSpec = getCompressibleDataSpec(manifestUri); checkNotNull(mediaItem.playbackProperties);
this.manifestDataSpec = getCompressibleDataSpec(mediaItem.playbackProperties.uri);
this.manifestParser = manifestParser; this.manifestParser = manifestParser;
this.streamKeys = new ArrayList<>(streamKeys); this.streamKeys = new ArrayList<>(mediaItem.playbackProperties.streamKeys);
this.cacheDataSourceFactory = cacheDataSourceFactory; this.cacheDataSourceFactory = cacheDataSourceFactory;
this.executor = executor; this.executor = executor;
isCanceled = new AtomicBoolean(); isCanceled = new AtomicBoolean();

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.dash.offline;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.extractor.ChunkIndex; import com.google.android.exoplayer2.extractor.ChunkIndex;
import com.google.android.exoplayer2.offline.DownloadException; import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.SegmentDownloader; import com.google.android.exoplayer2.offline.SegmentDownloader;
@ -54,7 +55,11 @@ import java.util.concurrent.Executor;
* // period. * // period.
* DashDownloader dashDownloader = * DashDownloader dashDownloader =
* new DashDownloader( * new DashDownloader(
* manifestUrl, Collections.singletonList(new StreamKey(0, 0, 0)), cacheDataSourceFactory); * new MediaItem.Builder()
* .setUri(manifestUrl)
* .setStreamKeys(Collections.singletonList(new StreamKey(0, 0, 0)))
* .build(),
* cacheDataSourceFactory);
* // Perform the download. * // Perform the download.
* dashDownloader.download(progressListener); * dashDownloader.download(progressListener);
* // Use the downloaded data for playback. * // Use the downloaded data for playback.
@ -64,22 +69,44 @@ import java.util.concurrent.Executor;
*/ */
public final class DashDownloader extends SegmentDownloader<DashManifest> { public final class DashDownloader extends SegmentDownloader<DashManifest> {
/** /** @deprecated Use {@link #DashDownloader(MediaItem, CacheDataSource.Factory)} instead. */
* @param manifestUri The {@link Uri} of the manifest to be downloaded. @SuppressWarnings("deprecation")
* @param streamKeys Keys defining which representations in the manifest should be selected for @Deprecated
* download. If empty, all representations are downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public DashDownloader( public DashDownloader(
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) { Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
this(manifestUri, streamKeys, cacheDataSourceFactory, Runnable::run); this(manifestUri, streamKeys, cacheDataSourceFactory, Runnable::run);
} }
/** /**
* @param manifestUri The {@link Uri} of the manifest to be downloaded. * Creates a new instance.
* @param streamKeys Keys defining which representations in the manifest should be selected for *
* download. If empty, all representations are downloaded. * @param mediaItem The {@link MediaItem} to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public DashDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory) {
this(mediaItem, cacheDataSourceFactory, Runnable::run);
}
/**
* @deprecated Use {@link #DashDownloader(MediaItem, CacheDataSource.Factory, Executor)} instead.
*/
@Deprecated
public DashDownloader(
Uri manifestUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
this(
new MediaItem.Builder().setUri(manifestUri).setStreamKeys(streamKeys).build(),
cacheDataSourceFactory,
executor);
}
/**
* Creates a new instance.
*
* @param mediaItem The {@link MediaItem} to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the * @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written. * download will be written.
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
@ -87,11 +114,8 @@ public final class DashDownloader extends SegmentDownloader<DashManifest> {
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
*/ */
public DashDownloader( public DashDownloader(
Uri manifestUri, MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) {
List<StreamKey> streamKeys, super(mediaItem, new DashManifestParser(), cacheDataSourceFactory, executor);
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super(manifestUri, new DashManifestParser(), streamKeys, cacheDataSourceFactory, executor);
} }
@Override @Override

View File

@ -28,6 +28,7 @@ import static org.mockito.Mockito.when;
import android.net.Uri; import android.net.Uri;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory; import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadException; import com.google.android.exoplayer2.offline.DownloadException;
import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadRequest;
@ -337,7 +338,9 @@ public class DashDownloaderTest {
new CacheDataSource.Factory() new CacheDataSource.Factory()
.setCache(cache) .setCache(cache)
.setUpstreamDataSourceFactory(upstreamDataSourceFactory); .setUpstreamDataSourceFactory(upstreamDataSourceFactory);
return new DashDownloader(TEST_MPD_URI, keysList(keys), cacheDataSourceFactory); return new DashDownloader(
new MediaItem.Builder().setUri(TEST_MPD_URI).setStreamKeys(keysList(keys)).build(),
cacheDataSourceFactory);
} }
private static ArrayList<StreamKey> keysList(StreamKey... keys) { private static ArrayList<StreamKey> keysList(StreamKey... keys) {

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source.hls.offline;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.offline.SegmentDownloader; import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
@ -47,8 +48,13 @@ import java.util.concurrent.Executor;
* // Create a downloader for the first variant in a master playlist. * // Create a downloader for the first variant in a master playlist.
* HlsDownloader hlsDownloader = * HlsDownloader hlsDownloader =
* new HlsDownloader( * new HlsDownloader(
* playlistUri, * new MediaItem.Builder()
* Collections.singletonList(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)); * .setUri(playlistUri)
* .setStreamKeys(
* Collections.singletonList(
* new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)))
* .build(),
* Collections.singletonList();
* // Perform the download. * // Perform the download.
* hlsDownloader.download(progressListener); * hlsDownloader.download(progressListener);
* // Use the downloaded data for playback. * // Use the downloaded data for playback.
@ -58,22 +64,44 @@ import java.util.concurrent.Executor;
*/ */
public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> { public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
/** /** @deprecated Use {@link #HlsDownloader(MediaItem, CacheDataSource.Factory)} instead. */
* @param playlistUri The {@link Uri} of the playlist to be downloaded. @SuppressWarnings("deprecation")
* @param streamKeys Keys defining which renditions in the playlist should be selected for @Deprecated
* download. If empty, all renditions are downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public HlsDownloader( public HlsDownloader(
Uri playlistUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) { Uri playlistUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
this(playlistUri, streamKeys, cacheDataSourceFactory, Runnable::run); this(playlistUri, streamKeys, cacheDataSourceFactory, Runnable::run);
} }
/** /**
* @param playlistUri The {@link Uri} of the playlist to be downloaded. * Creates a new instance.
* @param streamKeys Keys defining which renditions in the playlist should be selected for *
* download. If empty, all renditions are downloaded. * @param mediaItem The {@link MediaItem} to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public HlsDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory) {
this(mediaItem, cacheDataSourceFactory, Runnable::run);
}
/**
* @deprecated Use {@link #HlsDownloader(MediaItem, CacheDataSource.Factory, Executor)} instead.
*/
@Deprecated
public HlsDownloader(
Uri playlistUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
this(
new MediaItem.Builder().setUri(playlistUri).setStreamKeys(streamKeys).build(),
cacheDataSourceFactory,
executor);
}
/**
* Creates a new instance.
*
* @param mediaItem The {@link MediaItem} to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the * @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written. * download will be written.
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
@ -81,11 +109,8 @@ public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
*/ */
public HlsDownloader( public HlsDownloader(
Uri playlistUri, MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) {
List<StreamKey> streamKeys, super(mediaItem, new HlsPlaylistParser(), cacheDataSourceFactory, executor);
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super(playlistUri, new HlsPlaylistParser(), streamKeys, cacheDataSourceFactory, executor);
} }
@Override @Override

View File

@ -37,6 +37,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.offline.DefaultDownloaderFactory; import com.google.android.exoplayer2.offline.DefaultDownloaderFactory;
import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.offline.Downloader; import com.google.android.exoplayer2.offline.Downloader;
@ -219,7 +220,9 @@ public class HlsDownloaderTest {
new CacheDataSource.Factory() new CacheDataSource.Factory()
.setCache(cache) .setCache(cache)
.setUpstreamDataSourceFactory(new FakeDataSource.Factory().setFakeDataSet(fakeDataSet)); .setUpstreamDataSourceFactory(new FakeDataSource.Factory().setFakeDataSet(fakeDataSet));
return new HlsDownloader(Uri.parse(mediaPlaylistUri), keys, cacheDataSourceFactory); return new HlsDownloader(
new MediaItem.Builder().setUri(mediaPlaylistUri).setStreamKeys(keys).build(),
cacheDataSourceFactory);
} }
private static ArrayList<StreamKey> getKeys(int... variantIndices) { private static ArrayList<StreamKey> getKeys(int... variantIndices) {

View File

@ -15,7 +15,10 @@
*/ */
package com.google.android.exoplayer2.source.smoothstreaming.offline; package com.google.android.exoplayer2.source.smoothstreaming.offline;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.net.Uri; import android.net.Uri;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.offline.SegmentDownloader; import com.google.android.exoplayer2.offline.SegmentDownloader;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
@ -43,8 +46,10 @@ import java.util.concurrent.Executor;
* // Create a downloader for the first track of the first stream element. * // Create a downloader for the first track of the first stream element.
* SsDownloader ssDownloader = * SsDownloader ssDownloader =
* new SsDownloader( * new SsDownloader(
* manifestUrl, * new MediaItem.Builder()
* Collections.singletonList(new StreamKey(0, 0)), * .setUri(manifestUri)
* .setStreamKeys(Collections.singletonList(new StreamKey(0, 0)))
* .build(),
* cacheDataSourceFactory); * cacheDataSourceFactory);
* // Perform the download. * // Perform the download.
* ssDownloader.download(progressListener); * ssDownloader.download(progressListener);
@ -56,21 +61,45 @@ import java.util.concurrent.Executor;
public final class SsDownloader extends SegmentDownloader<SsManifest> { public final class SsDownloader extends SegmentDownloader<SsManifest> {
/** /**
* @param manifestUri The {@link Uri} of the manifest to be downloaded. * @deprecated Use {@link #SsDownloader(MediaItem, CacheDataSource.Factory, Executor)} instead.
* @param streamKeys Keys defining which streams in the manifest should be selected for download.
* If empty, all streams are downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/ */
@SuppressWarnings("deprecation")
@Deprecated
public SsDownloader( public SsDownloader(
Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) { Uri manifestUri, List<StreamKey> streamKeys, CacheDataSource.Factory cacheDataSourceFactory) {
this(manifestUri, streamKeys, cacheDataSourceFactory, Runnable::run); this(manifestUri, streamKeys, cacheDataSourceFactory, Runnable::run);
} }
/** /**
* @param manifestUri The {@link Uri} of the manifest to be downloaded. * Creates an instance.
* @param streamKeys Keys defining which streams in the manifest should be selected for download. *
* If empty, all streams are downloaded. * @param mediaItem The {@link MediaItem} to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written.
*/
public SsDownloader(MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory) {
this(mediaItem, cacheDataSourceFactory, Runnable::run);
}
/**
* @deprecated Use {@link #SsDownloader(MediaItem, CacheDataSource.Factory, Executor)} instead.
*/
@Deprecated
public SsDownloader(
Uri manifestUri,
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
this(
new MediaItem.Builder().setUri(manifestUri).setStreamKeys(streamKeys).build(),
cacheDataSourceFactory,
executor);
}
/**
* Creates an instance.
*
* @param mediaItem The {@link MediaItem} to be downloaded.
* @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the * @param cacheDataSourceFactory A {@link CacheDataSource.Factory} for the cache into which the
* download will be written. * download will be written.
* @param executor An {@link Executor} used to make requests for the media being downloaded. * @param executor An {@link Executor} used to make requests for the media being downloaded.
@ -78,14 +107,13 @@ public final class SsDownloader extends SegmentDownloader<SsManifest> {
* allowing parts of it to be executed in parallel. * allowing parts of it to be executed in parallel.
*/ */
public SsDownloader( public SsDownloader(
Uri manifestUri, MediaItem mediaItem, CacheDataSource.Factory cacheDataSourceFactory, Executor executor) {
List<StreamKey> streamKeys,
CacheDataSource.Factory cacheDataSourceFactory,
Executor executor) {
super( super(
SsUtil.fixManifestUri(manifestUri), mediaItem
.buildUpon()
.setUri(SsUtil.fixManifestUri(checkNotNull(mediaItem.playbackProperties).uri))
.build(),
new SsManifestParser(), new SsManifestParser(),
streamKeys,
cacheDataSourceFactory, cacheDataSourceFactory,
executor); executor);
} }

View File

@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
import android.net.Uri; import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.rule.ActivityTestRule; import androidx.test.rule.ActivityTestRule;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.offline.StreamKey; import com.google.android.exoplayer2.offline.StreamKey;
import com.google.android.exoplayer2.source.dash.DashUtil; import com.google.android.exoplayer2.source.dash.DashUtil;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
@ -120,7 +121,9 @@ public final class DashDownloadTest {
new CacheDataSource.Factory() new CacheDataSource.Factory()
.setCache(cache) .setCache(cache)
.setUpstreamDataSourceFactory(httpDataSourceFactory); .setUpstreamDataSourceFactory(httpDataSourceFactory);
return new DashDownloader(MANIFEST_URI, keys, cacheDataSourceFactory); return new DashDownloader(
new MediaItem.Builder().setUri(MANIFEST_URI).setStreamKeys(keys).build(),
cacheDataSourceFactory);
} }
} }