Use TrackKey in place of RepresentetionKey, StreamKey, RenditionKey
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=199767518
This commit is contained in:
parent
8e65696f02
commit
a406dc8bee
@ -37,6 +37,7 @@ import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
|
||||
import com.google.android.exoplayer2.offline.DownloadService;
|
||||
import com.google.android.exoplayer2.offline.ProgressiveDownloadHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.offline.TrackKey;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
@ -111,7 +112,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <K> List<K> getOfflineStreamKeys(Uri uri) {
|
||||
public List<StreamKey> getOfflineStreamKeys(Uri uri) {
|
||||
if (!trackedDownloadStates.containsKey(uri)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -282,6 +283,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
||||
Toast.makeText(
|
||||
context.getApplicationContext(), R.string.download_start_error, Toast.LENGTH_LONG)
|
||||
.show();
|
||||
Log.e(TAG, "Failed to start download", e);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,6 +49,7 @@ import com.google.android.exoplayer2.drm.UnsupportedDrmException;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.DecoderInitializationException;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
|
||||
import com.google.android.exoplayer2.offline.FilteringManifestParser;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.BehindLiveWindowException;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
@ -59,14 +60,11 @@ import com.google.android.exoplayer2.source.ads.AdsMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DashMediaSource;
|
||||
import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.StreamKey;
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
|
||||
@ -446,22 +444,19 @@ public class PlayerActivity extends Activity
|
||||
new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
|
||||
buildDataSourceFactory(false))
|
||||
.setManifestParser(
|
||||
new FilteringManifestParser<>(
|
||||
new DashManifestParser(), (List<RepresentationKey>) getOfflineStreamKeys(uri)))
|
||||
new FilteringManifestParser<>(new DashManifestParser(), getOfflineStreamKeys(uri)))
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_SS:
|
||||
return new SsMediaSource.Factory(
|
||||
new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
|
||||
buildDataSourceFactory(false))
|
||||
.setManifestParser(
|
||||
new FilteringManifestParser<>(
|
||||
new SsManifestParser(), (List<StreamKey>) getOfflineStreamKeys(uri)))
|
||||
new FilteringManifestParser<>(new SsManifestParser(), getOfflineStreamKeys(uri)))
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_HLS:
|
||||
return new HlsMediaSource.Factory(mediaDataSourceFactory)
|
||||
.setPlaylistParser(
|
||||
new FilteringManifestParser<>(
|
||||
new HlsPlaylistParser(), (List<RenditionKey>) getOfflineStreamKeys(uri)))
|
||||
new FilteringManifestParser<>(new HlsPlaylistParser(), getOfflineStreamKeys(uri)))
|
||||
.createMediaSource(uri);
|
||||
case C.TYPE_OTHER:
|
||||
return new ExtractorMediaSource.Factory(mediaDataSourceFactory).createMediaSource(uri);
|
||||
@ -471,7 +466,7 @@ public class PlayerActivity extends Activity
|
||||
}
|
||||
}
|
||||
|
||||
private List<?> getOfflineStreamKeys(Uri uri) {
|
||||
private List<StreamKey> getOfflineStreamKeys(Uri uri) {
|
||||
return ((DemoApplication) getApplication()).getDownloadTracker().getOfflineStreamKeys(uri);
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,8 @@ import java.util.List;
|
||||
* keys.
|
||||
*
|
||||
* @param <T> The manifest type.
|
||||
* @param <K> The stream key type.
|
||||
*/
|
||||
public interface FilterableManifest<T, K> {
|
||||
public interface FilterableManifest<T> {
|
||||
|
||||
/**
|
||||
* Returns a copy of the manifest including only the streams specified by the given keys. If the
|
||||
@ -33,5 +32,5 @@ public interface FilterableManifest<T, K> {
|
||||
* @param streamKeys A non-empty list of stream keys.
|
||||
* @return The filtered manifest.
|
||||
*/
|
||||
T copy(List<K> streamKeys);
|
||||
T copy(List<StreamKey> streamKeys);
|
||||
}
|
||||
|
@ -21,25 +21,24 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
/** A manifest parser that includes only the tracks identified by the given track keys. */
|
||||
public final class FilteringManifestParser<T extends FilterableManifest<T, K>, K>
|
||||
implements Parser<T> {
|
||||
/** A manifest parser that includes only the streams identified by the given stream keys. */
|
||||
public final class FilteringManifestParser<T extends FilterableManifest<T>> implements Parser<T> {
|
||||
|
||||
private final Parser<T> parser;
|
||||
private final List<K> trackKeys;
|
||||
private final List<StreamKey> streamKeys;
|
||||
|
||||
/**
|
||||
* @param parser A parser for the manifest that will be filtered.
|
||||
* @param trackKeys The track keys. If null or empty then filtering will not occur.
|
||||
* @param streamKeys The stream keys. If null or empty then filtering will not occur.
|
||||
*/
|
||||
public FilteringManifestParser(Parser<T> parser, List<K> trackKeys) {
|
||||
public FilteringManifestParser(Parser<T> parser, List<StreamKey> streamKeys) {
|
||||
this.parser = parser;
|
||||
this.trackKeys = trackKeys;
|
||||
this.streamKeys = streamKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T parse(Uri uri, InputStream inputStream) throws IOException {
|
||||
T manifest = parser.parse(uri, inputStream);
|
||||
return trackKeys == null || trackKeys.isEmpty() ? manifest : manifest.copy(trackKeys);
|
||||
return streamKeys == null || streamKeys.isEmpty() ? manifest : manifest.copy(streamKeys);
|
||||
}
|
||||
}
|
||||
|
@ -25,19 +25,11 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link DownloadAction} for {@link SegmentDownloader}s.
|
||||
*
|
||||
* @param <K> The type of the representation key object.
|
||||
*/
|
||||
public abstract class SegmentDownloadAction<K extends Comparable<K>> extends DownloadAction {
|
||||
/** {@link DownloadAction} for {@link SegmentDownloader}s. */
|
||||
public abstract class SegmentDownloadAction extends DownloadAction {
|
||||
|
||||
/**
|
||||
* Base class for {@link SegmentDownloadAction} {@link Deserializer}s.
|
||||
*
|
||||
* @param <K> The type of the representation key object.
|
||||
*/
|
||||
protected abstract static class SegmentDownloadActionDeserializer<K> extends Deserializer {
|
||||
/** Base class for {@link SegmentDownloadAction} {@link Deserializer}s. */
|
||||
protected abstract static class SegmentDownloadActionDeserializer extends Deserializer {
|
||||
|
||||
public SegmentDownloadActionDeserializer(String type, int version) {
|
||||
super(type, version);
|
||||
@ -52,7 +44,7 @@ public abstract class SegmentDownloadAction<K extends Comparable<K>> extends Dow
|
||||
byte[] data = new byte[dataLength];
|
||||
input.readFully(data);
|
||||
int keyCount = input.readInt();
|
||||
List<K> keys = new ArrayList<>();
|
||||
List<StreamKey> keys = new ArrayList<>();
|
||||
for (int i = 0; i < keyCount; i++) {
|
||||
keys.add(readKey(input));
|
||||
}
|
||||
@ -60,14 +52,14 @@ public abstract class SegmentDownloadAction<K extends Comparable<K>> extends Dow
|
||||
}
|
||||
|
||||
/** Deserializes a key from the {@code input}. */
|
||||
protected abstract K readKey(DataInputStream input) throws IOException;
|
||||
protected abstract StreamKey readKey(DataInputStream input) throws IOException;
|
||||
|
||||
/** Returns a {@link DownloadAction}. */
|
||||
protected abstract DownloadAction createDownloadAction(
|
||||
Uri manifestUri, boolean isRemoveAction, byte[] data, List<K> keys);
|
||||
Uri manifestUri, boolean isRemoveAction, byte[] data, List<StreamKey> keys);
|
||||
}
|
||||
|
||||
public final List<K> keys;
|
||||
public final List<StreamKey> keys;
|
||||
|
||||
/**
|
||||
* @param type The type of the action.
|
||||
@ -84,13 +76,13 @@ public abstract class SegmentDownloadAction<K extends Comparable<K>> extends Dow
|
||||
Uri uri,
|
||||
boolean isRemoveAction,
|
||||
@Nullable byte[] data,
|
||||
List<K> keys) {
|
||||
List<StreamKey> keys) {
|
||||
super(type, version, uri, isRemoveAction, data);
|
||||
if (isRemoveAction) {
|
||||
Assertions.checkArgument(keys.isEmpty());
|
||||
this.keys = Collections.emptyList();
|
||||
} else {
|
||||
ArrayList<K> mutableKeys = new ArrayList<>(keys);
|
||||
ArrayList<StreamKey> mutableKeys = new ArrayList<>(keys);
|
||||
Collections.sort(mutableKeys);
|
||||
this.keys = Collections.unmodifiableList(mutableKeys);
|
||||
}
|
||||
@ -109,7 +101,7 @@ public abstract class SegmentDownloadAction<K extends Comparable<K>> extends Dow
|
||||
}
|
||||
|
||||
/** Serializes the {@code key} into the {@code output}. */
|
||||
protected abstract void writeKey(DataOutputStream output, K key) throws IOException;
|
||||
protected abstract void writeKey(DataOutputStream output, StreamKey key) throws IOException;
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
@ -119,7 +111,7 @@ public abstract class SegmentDownloadAction<K extends Comparable<K>> extends Dow
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
SegmentDownloadAction<?> that = (SegmentDownloadAction<?>) o;
|
||||
SegmentDownloadAction that = (SegmentDownloadAction) o;
|
||||
return keys.equals(that.keys);
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* Base class for multi segment stream downloaders.
|
||||
*
|
||||
* @param <M> The type of the manifest object.
|
||||
* @param <K> The type of the streams key object.
|
||||
*/
|
||||
public abstract class SegmentDownloader<M extends FilterableManifest<M, K>, K>
|
||||
implements Downloader {
|
||||
public abstract class SegmentDownloader<M extends FilterableManifest<M>> implements Downloader {
|
||||
|
||||
/** Smallest unit of content to be downloaded. */
|
||||
protected static class Segment implements Comparable<Segment> {
|
||||
@ -68,7 +66,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M, K>, K>
|
||||
private final Cache cache;
|
||||
private final CacheDataSource dataSource;
|
||||
private final CacheDataSource offlineDataSource;
|
||||
private final ArrayList<K> streamKeys;
|
||||
private final ArrayList<StreamKey> streamKeys;
|
||||
private final AtomicBoolean isCanceled;
|
||||
|
||||
private volatile int totalSegments;
|
||||
@ -82,7 +80,7 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M, K>, K>
|
||||
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
|
||||
*/
|
||||
public SegmentDownloader(
|
||||
Uri manifestUri, List<K> streamKeys, DownloaderConstructorHelper constructorHelper) {
|
||||
Uri manifestUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
|
||||
this.manifestUri = manifestUri;
|
||||
this.streamKeys = new ArrayList<>(streamKeys);
|
||||
this.cache = constructorHelper.getCache();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -13,25 +13,46 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.smoothstreaming.manifest;
|
||||
package com.google.android.exoplayer2.offline;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/** Uniquely identifies a track in a {@link SsManifest}. */
|
||||
/**
|
||||
* Identifies a given track by the index of the containing period, the index of the containing group
|
||||
* within the period, and the index of the track within the group.
|
||||
*/
|
||||
public final class StreamKey implements Comparable<StreamKey> {
|
||||
|
||||
public final int streamElementIndex;
|
||||
/** The period index. */
|
||||
public final int periodIndex;
|
||||
/** The group index. */
|
||||
public final int groupIndex;
|
||||
/** The track index. */
|
||||
public final int trackIndex;
|
||||
|
||||
public StreamKey(int streamElementIndex, int trackIndex) {
|
||||
this.streamElementIndex = streamElementIndex;
|
||||
/**
|
||||
* @param groupIndex The group index.
|
||||
* @param trackIndex The track index.
|
||||
*/
|
||||
public StreamKey(int groupIndex, int trackIndex) {
|
||||
this(0, groupIndex, trackIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param periodIndex The period index.
|
||||
* @param groupIndex The group index.
|
||||
* @param trackIndex The track index.
|
||||
*/
|
||||
public StreamKey(int periodIndex, int groupIndex, int trackIndex) {
|
||||
this.periodIndex = periodIndex;
|
||||
this.groupIndex = groupIndex;
|
||||
this.trackIndex = trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return streamElementIndex + "." + trackIndex;
|
||||
return periodIndex + "." + groupIndex + "." + trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,12 +65,15 @@ public final class StreamKey implements Comparable<StreamKey> {
|
||||
}
|
||||
|
||||
StreamKey that = (StreamKey) o;
|
||||
return streamElementIndex == that.streamElementIndex && trackIndex == that.trackIndex;
|
||||
return periodIndex == that.periodIndex
|
||||
&& groupIndex == that.groupIndex
|
||||
&& trackIndex == that.trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = streamElementIndex;
|
||||
int result = periodIndex;
|
||||
result = 31 * result + groupIndex;
|
||||
result = 31 * result + trackIndex;
|
||||
return result;
|
||||
}
|
||||
@ -58,10 +82,13 @@ public final class StreamKey implements Comparable<StreamKey> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull StreamKey o) {
|
||||
int result = streamElementIndex - o.streamElementIndex;
|
||||
int result = periodIndex - o.periodIndex;
|
||||
if (result == 0) {
|
||||
result = groupIndex - o.groupIndex;
|
||||
if (result == 0) {
|
||||
result = trackIndex - o.trackIndex;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package com.google.android.exoplayer2.source.dash.manifest;
|
||||
import android.net.Uri;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.FilterableManifest;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@ -27,7 +28,7 @@ import java.util.List;
|
||||
* Represents a DASH media presentation description (mpd), as defined by ISO/IEC 23009-1:2014
|
||||
* Section 5.3.1.2.
|
||||
*/
|
||||
public class DashManifest implements FilterableManifest<DashManifest, RepresentationKey> {
|
||||
public class DashManifest implements FilterableManifest<DashManifest> {
|
||||
|
||||
/**
|
||||
* The {@code availabilityStartTime} value in milliseconds since epoch, or {@link C#TIME_UNSET} if
|
||||
@ -123,10 +124,10 @@ public class DashManifest implements FilterableManifest<DashManifest, Representa
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DashManifest copy(List<RepresentationKey> streamKeys) {
|
||||
LinkedList<RepresentationKey> keys = new LinkedList<>(streamKeys);
|
||||
public final DashManifest copy(List<StreamKey> streamKeys) {
|
||||
LinkedList<StreamKey> keys = new LinkedList<>(streamKeys);
|
||||
Collections.sort(keys);
|
||||
keys.add(new RepresentationKey(-1, -1, -1)); // Add a stopper key to the end
|
||||
keys.add(new StreamKey(-1, -1, -1)); // Add a stopper key to the end
|
||||
|
||||
ArrayList<Period> copyPeriods = new ArrayList<>();
|
||||
long shiftMs = 0;
|
||||
@ -153,21 +154,21 @@ public class DashManifest implements FilterableManifest<DashManifest, Representa
|
||||
}
|
||||
|
||||
private static ArrayList<AdaptationSet> copyAdaptationSets(
|
||||
List<AdaptationSet> adaptationSets, LinkedList<RepresentationKey> keys) {
|
||||
RepresentationKey key = keys.poll();
|
||||
List<AdaptationSet> adaptationSets, LinkedList<StreamKey> keys) {
|
||||
StreamKey key = keys.poll();
|
||||
int periodIndex = key.periodIndex;
|
||||
ArrayList<AdaptationSet> copyAdaptationSets = new ArrayList<>();
|
||||
do {
|
||||
int adaptationSetIndex = key.adaptationSetIndex;
|
||||
int adaptationSetIndex = key.groupIndex;
|
||||
AdaptationSet adaptationSet = adaptationSets.get(adaptationSetIndex);
|
||||
|
||||
List<Representation> representations = adaptationSet.representations;
|
||||
ArrayList<Representation> copyRepresentations = new ArrayList<>();
|
||||
do {
|
||||
Representation representation = representations.get(key.representationIndex);
|
||||
Representation representation = representations.get(key.trackIndex);
|
||||
copyRepresentations.add(representation);
|
||||
key = keys.poll();
|
||||
} while(key.periodIndex == periodIndex && key.adaptationSetIndex == adaptationSetIndex);
|
||||
} while (key.periodIndex == periodIndex && key.groupIndex == adaptationSetIndex);
|
||||
|
||||
copyAdaptationSets.add(new AdaptationSet(adaptationSet.id, adaptationSet.type,
|
||||
copyRepresentations, adaptationSet.accessibilityDescriptors,
|
||||
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.dash.manifest;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/** Uniquely identifies a {@link Representation} in a {@link DashManifest}. */
|
||||
public final class RepresentationKey implements Comparable<RepresentationKey> {
|
||||
|
||||
public final int periodIndex;
|
||||
public final int adaptationSetIndex;
|
||||
public final int representationIndex;
|
||||
|
||||
public RepresentationKey(int periodIndex, int adaptationSetIndex, int representationIndex) {
|
||||
this.periodIndex = periodIndex;
|
||||
this.adaptationSetIndex = adaptationSetIndex;
|
||||
this.representationIndex = representationIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return periodIndex + "." + adaptationSetIndex + "." + representationIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RepresentationKey that = (RepresentationKey) o;
|
||||
return periodIndex == that.periodIndex
|
||||
&& adaptationSetIndex == that.adaptationSetIndex
|
||||
&& representationIndex == that.representationIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = periodIndex;
|
||||
result = 31 * result + adaptationSetIndex;
|
||||
result = 31 * result + representationIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Comparable implementation.
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull RepresentationKey o) {
|
||||
int result = periodIndex - o.periodIndex;
|
||||
if (result == 0) {
|
||||
result = adaptationSetIndex - o.adaptationSetIndex;
|
||||
if (result == 0) {
|
||||
result = representationIndex - o.representationIndex;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -20,29 +20,32 @@ import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/** An action to download or remove downloaded DASH streams. */
|
||||
public final class DashDownloadAction extends SegmentDownloadAction<RepresentationKey> {
|
||||
public final class DashDownloadAction extends SegmentDownloadAction {
|
||||
|
||||
private static final String TYPE = "dash";
|
||||
private static final int VERSION = 0;
|
||||
|
||||
public static final Deserializer DESERIALIZER =
|
||||
new SegmentDownloadActionDeserializer<RepresentationKey>(TYPE, VERSION) {
|
||||
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
||||
|
||||
@Override
|
||||
protected RepresentationKey readKey(DataInputStream input) throws IOException {
|
||||
return new RepresentationKey(input.readInt(), input.readInt(), input.readInt());
|
||||
protected StreamKey readKey(DataInputStream input) throws IOException {
|
||||
int periodIndex = input.readInt();
|
||||
int groupIndex = input.readInt();
|
||||
int trackIndex = input.readInt();
|
||||
return new StreamKey(periodIndex, groupIndex, trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DownloadAction createDownloadAction(
|
||||
Uri uri, boolean isRemoveAction, byte[] data, List<RepresentationKey> keys) {
|
||||
Uri uri, boolean isRemoveAction, byte[] data, List<StreamKey> keys) {
|
||||
return new DashDownloadAction(uri, isRemoveAction, data, keys);
|
||||
}
|
||||
};
|
||||
@ -55,7 +58,7 @@ public final class DashDownloadAction extends SegmentDownloadAction<Representati
|
||||
* downloaded. If {@code removeAction} is true, {@code keys} must be empty.
|
||||
*/
|
||||
public DashDownloadAction(
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<RepresentationKey> keys) {
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
||||
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
||||
}
|
||||
|
||||
@ -65,10 +68,10 @@ public final class DashDownloadAction extends SegmentDownloadAction<Representati
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeKey(DataOutputStream output, RepresentationKey key) throws IOException {
|
||||
protected void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
||||
output.writeInt(key.periodIndex);
|
||||
output.writeInt(key.adaptationSetIndex);
|
||||
output.writeInt(key.representationIndex);
|
||||
output.writeInt(key.groupIndex);
|
||||
output.writeInt(key.trackIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.DownloadHelper;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.offline.TrackKey;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
@ -26,7 +27,6 @@ import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifestParser;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
@ -51,9 +51,8 @@ public final class DashDownloadHelper extends DownloadHelper {
|
||||
|
||||
@Override
|
||||
protected void prepareInternal() throws IOException {
|
||||
manifest =
|
||||
ParsingLoadable.load(
|
||||
manifestDataSourceFactory.createDataSource(), new DashManifestParser(), uri);
|
||||
DataSource dataSource = manifestDataSourceFactory.createDataSource();
|
||||
manifest = ParsingLoadable.load(dataSource, new DashManifestParser(), uri);
|
||||
}
|
||||
|
||||
/** Returns the DASH manifest. Must not be called until after preparation completes. */
|
||||
@ -87,23 +86,20 @@ public final class DashDownloadHelper extends DownloadHelper {
|
||||
|
||||
@Override
|
||||
public DashDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
||||
return new DashDownloadAction(
|
||||
uri, /* isRemoveAction= */ false, data, toRepresentationKeys(trackKeys));
|
||||
return new DashDownloadAction(uri, /* isRemoveAction= */ false, data, toStreamKeys(trackKeys));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DashDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||
return new DashDownloadAction(
|
||||
uri, /* isRemoveAction= */ true, data, Collections.<RepresentationKey>emptyList());
|
||||
return new DashDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
||||
}
|
||||
|
||||
private static List<RepresentationKey> toRepresentationKeys(List<TrackKey> trackKeys) {
|
||||
List<RepresentationKey> representationKeys = new ArrayList<>(trackKeys.size());
|
||||
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys) {
|
||||
List<StreamKey> streamKeys = new ArrayList<>(trackKeys.size());
|
||||
for (int i = 0; i < trackKeys.size(); i++) {
|
||||
TrackKey trackKey = trackKeys.get(i);
|
||||
representationKeys.add(
|
||||
new RepresentationKey(trackKey.periodIndex, trackKey.groupIndex, trackKey.trackIndex));
|
||||
streamKeys.add(new StreamKey(trackKey.periodIndex, trackKey.groupIndex, trackKey.trackIndex));
|
||||
}
|
||||
return representationKeys;
|
||||
return streamKeys;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import com.google.android.exoplayer2.extractor.ChunkIndex;
|
||||
import com.google.android.exoplayer2.offline.DownloadException;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloader;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
||||
import com.google.android.exoplayer2.source.dash.DashUtil;
|
||||
import com.google.android.exoplayer2.source.dash.DashWrappingSegmentIndex;
|
||||
@ -30,7 +31,6 @@ import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.Period;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import java.io.IOException;
|
||||
@ -51,9 +51,7 @@ import java.util.List;
|
||||
* // period.
|
||||
* DashDownloader dashDownloader =
|
||||
* new DashDownloader(
|
||||
* manifestUrl,
|
||||
* Collections.singletonList(new RepresentationKey(0, 0, 0)),
|
||||
* constructorHelper);
|
||||
* manifestUrl, Collections.singletonList(new StreamKey(0, 0, 0)), constructorHelper);
|
||||
* // Perform the download.
|
||||
* dashDownloader.download();
|
||||
* // Access downloaded data using CacheDataSource
|
||||
@ -61,19 +59,17 @@ import java.util.List;
|
||||
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class DashDownloader extends SegmentDownloader<DashManifest, RepresentationKey> {
|
||||
public final class DashDownloader extends SegmentDownloader<DashManifest> {
|
||||
|
||||
/**
|
||||
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
|
||||
* @param representationKeys Keys defining which representations in the manifest should be
|
||||
* selected for download. If empty, all representations are downloaded.
|
||||
* @param streamKeys Keys defining which representations in the manifest should be selected for
|
||||
* download. If empty, all representations are downloaded.
|
||||
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
|
||||
*/
|
||||
public DashDownloader(
|
||||
Uri manifestUri,
|
||||
List<RepresentationKey> representationKeys,
|
||||
DownloaderConstructorHelper constructorHelper) {
|
||||
super(manifestUri, representationKeys, constructorHelper);
|
||||
Uri manifestUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
|
||||
super(manifestUri, streamKeys, constructorHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.net.Uri;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -58,17 +59,17 @@ public class DashManifestTest {
|
||||
newAdaptationSet(8, representations[2][0]),
|
||||
newAdaptationSet(9, representations[2][1])));
|
||||
|
||||
List<RepresentationKey> keys =
|
||||
List<StreamKey> keys =
|
||||
Arrays.asList(
|
||||
new RepresentationKey(0, 0, 0),
|
||||
new RepresentationKey(0, 0, 1),
|
||||
new RepresentationKey(0, 1, 2),
|
||||
new RepresentationKey(1, 0, 1),
|
||||
new RepresentationKey(1, 1, 0),
|
||||
new RepresentationKey(1, 1, 2),
|
||||
new RepresentationKey(2, 0, 1),
|
||||
new RepresentationKey(2, 0, 2),
|
||||
new RepresentationKey(2, 1, 0));
|
||||
new StreamKey(0, 0, 0),
|
||||
new StreamKey(0, 0, 1),
|
||||
new StreamKey(0, 1, 2),
|
||||
new StreamKey(1, 0, 1),
|
||||
new StreamKey(1, 1, 0),
|
||||
new StreamKey(1, 1, 2),
|
||||
new StreamKey(2, 0, 1),
|
||||
new StreamKey(2, 0, 2),
|
||||
new StreamKey(2, 1, 0));
|
||||
// Keys don't need to be in any particular order
|
||||
Collections.shuffle(keys, new Random(0));
|
||||
|
||||
@ -105,8 +106,7 @@ public class DashManifestTest {
|
||||
newPeriod("4", 4, newAdaptationSet(5, representations[1][0])));
|
||||
|
||||
DashManifest copyManifest =
|
||||
sourceManifest.copy(
|
||||
Arrays.asList(new RepresentationKey(0, 0, 0), new RepresentationKey(1, 0, 0)));
|
||||
sourceManifest.copy(Arrays.asList(new StreamKey(0, 0, 0), new StreamKey(1, 0, 0)));
|
||||
|
||||
DashManifest expectedManifest =
|
||||
newDashManifest(
|
||||
@ -141,12 +141,12 @@ public class DashManifestTest {
|
||||
DashManifest copyManifest =
|
||||
sourceManifest.copy(
|
||||
Arrays.asList(
|
||||
new RepresentationKey(0, 0, 0),
|
||||
new RepresentationKey(0, 0, 1),
|
||||
new RepresentationKey(0, 1, 2),
|
||||
new RepresentationKey(2, 0, 1),
|
||||
new RepresentationKey(2, 0, 2),
|
||||
new RepresentationKey(2, 1, 0)));
|
||||
new StreamKey(0, 0, 0),
|
||||
new StreamKey(0, 0, 1),
|
||||
new StreamKey(0, 1, 2),
|
||||
new StreamKey(2, 0, 1),
|
||||
new StreamKey(2, 0, 2),
|
||||
new StreamKey(2, 1, 0)));
|
||||
|
||||
DashManifest expectedManifest =
|
||||
newDashManifest(
|
||||
|
@ -21,7 +21,7 @@ import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.upstream.DummyDataSource;
|
||||
import com.google.android.exoplayer2.upstream.cache.Cache;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -104,16 +104,13 @@ public class DashDownloadActionTest {
|
||||
|
||||
DashDownloadAction action6 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
||||
DashDownloadAction action7 =
|
||||
newAction(
|
||||
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
|
||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(0, 0, 0));
|
||||
assertNotEqual(action6, action7);
|
||||
|
||||
DashDownloadAction action8 =
|
||||
newAction(
|
||||
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(1, 1, 1));
|
||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(1, 1, 1));
|
||||
DashDownloadAction action9 =
|
||||
newAction(
|
||||
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
|
||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(0, 0, 0));
|
||||
assertNotEqual(action8, action9);
|
||||
|
||||
DashDownloadAction action10 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
||||
@ -125,27 +122,26 @@ public class DashDownloadActionTest {
|
||||
uri1,
|
||||
/* isRemoveAction= */ false,
|
||||
/* data= */ null,
|
||||
new RepresentationKey(0, 0, 0),
|
||||
new RepresentationKey(1, 1, 1));
|
||||
new StreamKey(0, 0, 0),
|
||||
new StreamKey(1, 1, 1));
|
||||
DashDownloadAction action13 =
|
||||
newAction(
|
||||
uri1,
|
||||
/* isRemoveAction= */ false,
|
||||
/* data= */ null,
|
||||
new RepresentationKey(1, 1, 1),
|
||||
new RepresentationKey(0, 0, 0));
|
||||
new StreamKey(1, 1, 1),
|
||||
new StreamKey(0, 0, 0));
|
||||
assertEqual(action12, action13);
|
||||
|
||||
DashDownloadAction action14 =
|
||||
newAction(
|
||||
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
|
||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(0, 0, 0));
|
||||
DashDownloadAction action15 =
|
||||
newAction(
|
||||
uri1,
|
||||
/* isRemoveAction= */ false,
|
||||
/* data= */ null,
|
||||
new RepresentationKey(1, 1, 1),
|
||||
new RepresentationKey(0, 0, 0));
|
||||
new StreamKey(1, 1, 1),
|
||||
new StreamKey(0, 0, 0));
|
||||
assertNotEqual(action14, action15);
|
||||
|
||||
DashDownloadAction action16 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
||||
@ -168,8 +164,8 @@ public class DashDownloadActionTest {
|
||||
uri2,
|
||||
/* isRemoveAction= */ false,
|
||||
/* data= */ null,
|
||||
new RepresentationKey(0, 0, 0),
|
||||
new RepresentationKey(1, 1, 1)));
|
||||
new StreamKey(0, 0, 0),
|
||||
new StreamKey(1, 1, 1)));
|
||||
}
|
||||
|
||||
private static void assertNotEqual(DashDownloadAction action1, DashDownloadAction action2) {
|
||||
@ -197,8 +193,8 @@ public class DashDownloadActionTest {
|
||||
}
|
||||
|
||||
private static DashDownloadAction newAction(
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, RepresentationKey... keys) {
|
||||
ArrayList<RepresentationKey> keysList = new ArrayList<>();
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||
Collections.addAll(keysList, keys);
|
||||
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.android.exoplayer2.offline.DownloadException;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSource.Factory;
|
||||
@ -77,7 +77,7 @@ public class DashDownloaderTest {
|
||||
.setRandomData("audio_segment_2", 5)
|
||||
.setRandomData("audio_segment_3", 6);
|
||||
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new RepresentationKey(0, 0, 0));
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
|
||||
dashDownloader.download();
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
@ -96,7 +96,7 @@ public class DashDownloaderTest {
|
||||
.setRandomData("audio_segment_2", 5)
|
||||
.setRandomData("audio_segment_3", 6);
|
||||
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new RepresentationKey(0, 0, 0));
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
|
||||
dashDownloader.download();
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
@ -115,8 +115,7 @@ public class DashDownloaderTest {
|
||||
.setRandomData("text_segment_3", 3);
|
||||
|
||||
DashDownloader dashDownloader =
|
||||
getDashDownloader(
|
||||
fakeDataSet, new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0));
|
||||
getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0), new StreamKey(0, 1, 0));
|
||||
dashDownloader.download();
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
@ -159,7 +158,7 @@ public class DashDownloaderTest {
|
||||
when(factory.createDataSource()).thenReturn(fakeDataSource);
|
||||
|
||||
DashDownloader dashDownloader =
|
||||
getDashDownloader(factory, new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0));
|
||||
getDashDownloader(factory, new StreamKey(0, 0, 0), new StreamKey(0, 1, 0));
|
||||
dashDownloader.download();
|
||||
|
||||
DataSpec[] openedDataSpecs = fakeDataSource.getAndClearOpenedDataSpecs();
|
||||
@ -191,7 +190,7 @@ public class DashDownloaderTest {
|
||||
when(factory.createDataSource()).thenReturn(fakeDataSource);
|
||||
|
||||
DashDownloader dashDownloader =
|
||||
getDashDownloader(factory, new RepresentationKey(0, 0, 0), new RepresentationKey(1, 0, 0));
|
||||
getDashDownloader(factory, new StreamKey(0, 0, 0), new StreamKey(1, 0, 0));
|
||||
dashDownloader.download();
|
||||
|
||||
DataSpec[] openedDataSpecs = fakeDataSource.getAndClearOpenedDataSpecs();
|
||||
@ -220,7 +219,7 @@ public class DashDownloaderTest {
|
||||
.endData()
|
||||
.setRandomData("audio_segment_3", 6);
|
||||
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new RepresentationKey(0, 0, 0));
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
|
||||
try {
|
||||
dashDownloader.download();
|
||||
fail();
|
||||
@ -245,7 +244,7 @@ public class DashDownloaderTest {
|
||||
.endData()
|
||||
.setRandomData("audio_segment_3", 6);
|
||||
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new RepresentationKey(0, 0, 0));
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
|
||||
assertThat(dashDownloader.getDownloadedBytes()).isEqualTo(0);
|
||||
|
||||
try {
|
||||
@ -274,8 +273,7 @@ public class DashDownloaderTest {
|
||||
.setRandomData("text_segment_3", 3);
|
||||
|
||||
DashDownloader dashDownloader =
|
||||
getDashDownloader(
|
||||
fakeDataSet, new RepresentationKey(0, 0, 0), new RepresentationKey(0, 1, 0));
|
||||
getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0), new StreamKey(0, 1, 0));
|
||||
dashDownloader.download();
|
||||
dashDownloader.remove();
|
||||
assertCacheEmpty(cache);
|
||||
@ -288,7 +286,7 @@ public class DashDownloaderTest {
|
||||
.setData(TEST_MPD_URI, TEST_MPD_NO_INDEX)
|
||||
.setRandomData("test_segment_1", 4);
|
||||
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new RepresentationKey(0, 0, 0));
|
||||
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
|
||||
try {
|
||||
dashDownloader.download();
|
||||
fail();
|
||||
@ -299,17 +297,17 @@ public class DashDownloaderTest {
|
||||
assertCacheEmpty(cache);
|
||||
}
|
||||
|
||||
private DashDownloader getDashDownloader(FakeDataSet fakeDataSet, RepresentationKey... keys) {
|
||||
private DashDownloader getDashDownloader(FakeDataSet fakeDataSet, StreamKey... keys) {
|
||||
return getDashDownloader(new Factory(null).setFakeDataSet(fakeDataSet), keys);
|
||||
}
|
||||
|
||||
private DashDownloader getDashDownloader(Factory factory, RepresentationKey... keys) {
|
||||
private DashDownloader getDashDownloader(Factory factory, StreamKey... keys) {
|
||||
return new DashDownloader(
|
||||
TEST_MPD_URI, keysList(keys), new DownloaderConstructorHelper(cache, factory));
|
||||
}
|
||||
|
||||
private static ArrayList<RepresentationKey> keysList(RepresentationKey... keys) {
|
||||
ArrayList<RepresentationKey> keysList = new ArrayList<>();
|
||||
private static ArrayList<StreamKey> keysList(StreamKey... keys) {
|
||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||
Collections.addAll(keysList, keys);
|
||||
return keysList;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import android.os.ConditionVariable;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.offline.DownloadManager;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||
@ -62,8 +62,8 @@ public class DownloadManagerDashTest {
|
||||
private File tempFolder;
|
||||
private FakeDataSet fakeDataSet;
|
||||
private DownloadManager downloadManager;
|
||||
private RepresentationKey fakeRepresentationKey1;
|
||||
private RepresentationKey fakeRepresentationKey2;
|
||||
private StreamKey fakeStreamKey1;
|
||||
private StreamKey fakeStreamKey2;
|
||||
private TestDownloadManagerListener downloadManagerListener;
|
||||
private File actionFile;
|
||||
private DummyMainThread dummyMainThread;
|
||||
@ -88,8 +88,8 @@ public class DownloadManagerDashTest {
|
||||
.setRandomData("text_segment_2", 2)
|
||||
.setRandomData("text_segment_3", 3);
|
||||
|
||||
fakeRepresentationKey1 = new RepresentationKey(0, 0, 0);
|
||||
fakeRepresentationKey2 = new RepresentationKey(0, 1, 0);
|
||||
fakeStreamKey1 = new StreamKey(0, 0, 0);
|
||||
fakeStreamKey2 = new StreamKey(0, 1, 0);
|
||||
actionFile = new File(tempFolder, "actionFile");
|
||||
createDownloadManager();
|
||||
}
|
||||
@ -133,7 +133,7 @@ public class DownloadManagerDashTest {
|
||||
@Override
|
||||
public void run() {
|
||||
// Setup an Action and immediately release the DM.
|
||||
handleDownloadAction(fakeRepresentationKey1, fakeRepresentationKey2);
|
||||
handleDownloadAction(fakeStreamKey1, fakeStreamKey2);
|
||||
downloadManager.release();
|
||||
}
|
||||
});
|
||||
@ -160,15 +160,15 @@ public class DownloadManagerDashTest {
|
||||
|
||||
@Test
|
||||
public void testHandleDownloadAction() throws Throwable {
|
||||
handleDownloadAction(fakeRepresentationKey1, fakeRepresentationKey2);
|
||||
handleDownloadAction(fakeStreamKey1, fakeStreamKey2);
|
||||
blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleMultipleDownloadAction() throws Throwable {
|
||||
handleDownloadAction(fakeRepresentationKey1);
|
||||
handleDownloadAction(fakeRepresentationKey2);
|
||||
handleDownloadAction(fakeStreamKey1);
|
||||
handleDownloadAction(fakeStreamKey2);
|
||||
blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
@ -181,13 +181,13 @@ public class DownloadManagerDashTest {
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleDownloadAction(fakeRepresentationKey2);
|
||||
handleDownloadAction(fakeStreamKey2);
|
||||
}
|
||||
})
|
||||
.appendReadData(TestUtil.buildTestData(5))
|
||||
.endData();
|
||||
|
||||
handleDownloadAction(fakeRepresentationKey1);
|
||||
handleDownloadAction(fakeStreamKey1);
|
||||
|
||||
blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
@ -195,7 +195,7 @@ public class DownloadManagerDashTest {
|
||||
|
||||
@Test
|
||||
public void testHandleRemoveAction() throws Throwable {
|
||||
handleDownloadAction(fakeRepresentationKey1);
|
||||
handleDownloadAction(fakeStreamKey1);
|
||||
|
||||
blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
|
||||
@ -210,7 +210,7 @@ public class DownloadManagerDashTest {
|
||||
@Ignore
|
||||
@Test
|
||||
public void testHandleRemoveActionBeforeDownloadFinish() throws Throwable {
|
||||
handleDownloadAction(fakeRepresentationKey1);
|
||||
handleDownloadAction(fakeStreamKey1);
|
||||
handleRemoveAction();
|
||||
|
||||
blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
@ -233,7 +233,7 @@ public class DownloadManagerDashTest {
|
||||
.appendReadData(TestUtil.buildTestData(5))
|
||||
.endData();
|
||||
|
||||
handleDownloadAction(fakeRepresentationKey1);
|
||||
handleDownloadAction(fakeStreamKey1);
|
||||
|
||||
assertThat(downloadInProgressCondition.block(ASSERT_TRUE_TIMEOUT)).isTrue();
|
||||
|
||||
@ -248,7 +248,7 @@ public class DownloadManagerDashTest {
|
||||
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
}
|
||||
|
||||
private void handleDownloadAction(RepresentationKey... keys) {
|
||||
private void handleDownloadAction(StreamKey... keys) {
|
||||
downloadManager.handleAction(newAction(TEST_MPD_URI, false, null, keys));
|
||||
}
|
||||
|
||||
@ -280,8 +280,8 @@ public class DownloadManagerDashTest {
|
||||
}
|
||||
|
||||
private static DashDownloadAction newAction(
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, RepresentationKey... keys) {
|
||||
ArrayList<RepresentationKey> keysList = new ArrayList<>();
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||
Collections.addAll(keysList, keys);
|
||||
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
|
||||
}
|
||||
|
@ -29,9 +29,9 @@ import com.google.android.exoplayer2.offline.DownloadManager;
|
||||
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
|
||||
import com.google.android.exoplayer2.offline.DownloadService;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||
import com.google.android.exoplayer2.scheduler.Scheduler;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.testutil.DummyMainThread;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSource;
|
||||
@ -65,8 +65,8 @@ public class DownloadServiceDashTest {
|
||||
private SimpleCache cache;
|
||||
private File tempFolder;
|
||||
private FakeDataSet fakeDataSet;
|
||||
private RepresentationKey fakeRepresentationKey1;
|
||||
private RepresentationKey fakeRepresentationKey2;
|
||||
private StreamKey fakeStreamKey1;
|
||||
private StreamKey fakeStreamKey2;
|
||||
private Context context;
|
||||
private DownloadService dashDownloadService;
|
||||
private ConditionVariable pauseDownloadCondition;
|
||||
@ -108,8 +108,8 @@ public class DownloadServiceDashTest {
|
||||
.setRandomData("text_segment_3", 3);
|
||||
final DataSource.Factory fakeDataSourceFactory =
|
||||
new FakeDataSource.Factory(null).setFakeDataSet(fakeDataSet);
|
||||
fakeRepresentationKey1 = new RepresentationKey(0, 0, 0);
|
||||
fakeRepresentationKey2 = new RepresentationKey(0, 1, 0);
|
||||
fakeStreamKey1 = new StreamKey(0, 0, 0);
|
||||
fakeStreamKey2 = new StreamKey(0, 1, 0);
|
||||
|
||||
dummyMainThread.runOnMainThread(
|
||||
new Runnable() {
|
||||
@ -180,8 +180,8 @@ public class DownloadServiceDashTest {
|
||||
@Ignore // b/78877092
|
||||
@Test
|
||||
public void testMultipleDownloadAction() throws Throwable {
|
||||
downloadKeys(fakeRepresentationKey1);
|
||||
downloadKeys(fakeRepresentationKey2);
|
||||
downloadKeys(fakeStreamKey1);
|
||||
downloadKeys(fakeStreamKey2);
|
||||
|
||||
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
|
||||
@ -191,7 +191,7 @@ public class DownloadServiceDashTest {
|
||||
@Ignore // b/78877092
|
||||
@Test
|
||||
public void testRemoveAction() throws Throwable {
|
||||
downloadKeys(fakeRepresentationKey1, fakeRepresentationKey2);
|
||||
downloadKeys(fakeStreamKey1, fakeStreamKey2);
|
||||
|
||||
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
|
||||
@ -206,7 +206,7 @@ public class DownloadServiceDashTest {
|
||||
@Test
|
||||
public void testRemoveBeforeDownloadComplete() throws Throwable {
|
||||
pauseDownloadCondition = new ConditionVariable();
|
||||
downloadKeys(fakeRepresentationKey1, fakeRepresentationKey2);
|
||||
downloadKeys(fakeStreamKey1, fakeStreamKey2);
|
||||
|
||||
removeAll();
|
||||
|
||||
@ -219,7 +219,7 @@ public class DownloadServiceDashTest {
|
||||
callDownloadServiceOnStart(newAction(TEST_MPD_URI, true, null));
|
||||
}
|
||||
|
||||
private void downloadKeys(RepresentationKey... keys) {
|
||||
private void downloadKeys(StreamKey... keys) {
|
||||
callDownloadServiceOnStart(newAction(TEST_MPD_URI, false, null, keys));
|
||||
}
|
||||
|
||||
@ -236,8 +236,8 @@ public class DownloadServiceDashTest {
|
||||
}
|
||||
|
||||
private static DashDownloadAction newAction(
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, RepresentationKey... keys) {
|
||||
ArrayList<RepresentationKey> keysList = new ArrayList<>();
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||
Collections.addAll(keysList, keys);
|
||||
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
|
||||
}
|
||||
|
@ -20,31 +20,31 @@ import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/** An action to download or remove downloaded HLS streams. */
|
||||
public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey> {
|
||||
public final class HlsDownloadAction extends SegmentDownloadAction {
|
||||
|
||||
private static final String TYPE = "hls";
|
||||
private static final int VERSION = 0;
|
||||
|
||||
public static final Deserializer DESERIALIZER =
|
||||
new SegmentDownloadActionDeserializer<RenditionKey>(TYPE, VERSION) {
|
||||
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
||||
|
||||
@Override
|
||||
protected RenditionKey readKey(DataInputStream input) throws IOException {
|
||||
protected StreamKey readKey(DataInputStream input) throws IOException {
|
||||
int renditionGroup = input.readInt();
|
||||
int trackIndex = input.readInt();
|
||||
return new RenditionKey(renditionGroup, trackIndex);
|
||||
return new StreamKey(renditionGroup, trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DownloadAction createDownloadAction(
|
||||
Uri uri, boolean isRemoveAction, byte[] data, List<RenditionKey> keys) {
|
||||
Uri uri, boolean isRemoveAction, byte[] data, List<StreamKey> keys) {
|
||||
return new HlsDownloadAction(uri, isRemoveAction, data, keys);
|
||||
}
|
||||
};
|
||||
@ -57,7 +57,7 @@ public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey>
|
||||
* {@code removeAction} is true, {@code keys} must empty.
|
||||
*/
|
||||
public HlsDownloadAction(
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<RenditionKey> keys) {
|
||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
||||
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
||||
}
|
||||
|
||||
@ -67,8 +67,8 @@ public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeKey(DataOutputStream output, RenditionKey key) throws IOException {
|
||||
output.writeInt(key.type);
|
||||
protected void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
||||
output.writeInt(key.groupIndex);
|
||||
output.writeInt(key.trackIndex);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.DownloadHelper;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.offline.TrackKey;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
@ -26,7 +27,6 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
|
||||
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.RenditionKey;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
@ -44,7 +44,7 @@ public final class HlsDownloadHelper extends DownloadHelper {
|
||||
private final DataSource.Factory manifestDataSourceFactory;
|
||||
|
||||
private @MonotonicNonNull HlsPlaylist playlist;
|
||||
private int[] renditionTypes;
|
||||
private int[] renditionGroups;
|
||||
|
||||
public HlsDownloadHelper(Uri uri, DataSource.Factory manifestDataSourceFactory) {
|
||||
this.uri = uri;
|
||||
@ -78,18 +78,18 @@ public final class HlsDownloadHelper extends DownloadHelper {
|
||||
// TODO: Generate track groups as in playback. Reverse the mapping in getDownloadAction.
|
||||
HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
|
||||
TrackGroup[] trackGroups = new TrackGroup[3];
|
||||
renditionTypes = new int[3];
|
||||
renditionGroups = new int[3];
|
||||
int trackGroupIndex = 0;
|
||||
if (!masterPlaylist.variants.isEmpty()) {
|
||||
renditionTypes[trackGroupIndex] = RenditionKey.TYPE_VARIANT;
|
||||
renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_VARIANT;
|
||||
trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.variants));
|
||||
}
|
||||
if (!masterPlaylist.audios.isEmpty()) {
|
||||
renditionTypes[trackGroupIndex] = RenditionKey.TYPE_AUDIO;
|
||||
renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_AUDIO;
|
||||
trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.audios));
|
||||
}
|
||||
if (!masterPlaylist.subtitles.isEmpty()) {
|
||||
renditionTypes[trackGroupIndex] = RenditionKey.TYPE_SUBTITLE;
|
||||
renditionGroups[trackGroupIndex] = HlsMasterPlaylist.GROUP_INDEX_SUBTITLE;
|
||||
trackGroups[trackGroupIndex++] = new TrackGroup(toFormats(masterPlaylist.subtitles));
|
||||
}
|
||||
return new TrackGroupArray(Arrays.copyOf(trackGroups, trackGroupIndex));
|
||||
@ -97,15 +97,14 @@ public final class HlsDownloadHelper extends DownloadHelper {
|
||||
|
||||
@Override
|
||||
public HlsDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
||||
Assertions.checkNotNull(renditionTypes);
|
||||
Assertions.checkNotNull(renditionGroups);
|
||||
return new HlsDownloadAction(
|
||||
uri, /* isRemoveAction= */ false, data, toRenditionKeys(trackKeys, renditionTypes));
|
||||
uri, /* isRemoveAction= */ false, data, toStreamKeys(trackKeys, renditionGroups));
|
||||
}
|
||||
|
||||
@Override
|
||||
public HlsDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||
return new HlsDownloadAction(
|
||||
uri, /* isRemoveAction= */ true, data, Collections.<RenditionKey>emptyList());
|
||||
return new HlsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
||||
}
|
||||
|
||||
private static Format[] toFormats(List<HlsMasterPlaylist.HlsUrl> hlsUrls) {
|
||||
@ -116,11 +115,11 @@ public final class HlsDownloadHelper extends DownloadHelper {
|
||||
return formats;
|
||||
}
|
||||
|
||||
private static List<RenditionKey> toRenditionKeys(List<TrackKey> trackKeys, int[] groups) {
|
||||
List<RenditionKey> representationKeys = new ArrayList<>(trackKeys.size());
|
||||
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys, int[] groups) {
|
||||
List<StreamKey> representationKeys = new ArrayList<>(trackKeys.size());
|
||||
for (int i = 0; i < trackKeys.size(); i++) {
|
||||
TrackKey trackKey = trackKeys.get(i);
|
||||
representationKeys.add(new RenditionKey(groups[trackKey.groupIndex], trackKey.trackIndex));
|
||||
representationKeys.add(new StreamKey(groups[trackKey.groupIndex], trackKey.trackIndex));
|
||||
}
|
||||
return representationKeys;
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ import android.net.Uri;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloader;
|
||||
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.HlsUrl;
|
||||
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.RenditionKey;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||
@ -48,7 +48,7 @@ import java.util.List;
|
||||
* HlsDownloader hlsDownloader =
|
||||
* new HlsDownloader(
|
||||
* playlistUri,
|
||||
* Collections.singletonList(new RenditionKey(RenditionKey.TYPE_VARIANT, 0)),
|
||||
* Collections.singletonList(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)),
|
||||
* constructorHelper);
|
||||
* // Perform the download.
|
||||
* hlsDownloader.download();
|
||||
@ -57,19 +57,17 @@ import java.util.List;
|
||||
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class HlsDownloader extends SegmentDownloader<HlsPlaylist, RenditionKey> {
|
||||
public final class HlsDownloader extends SegmentDownloader<HlsPlaylist> {
|
||||
|
||||
/**
|
||||
* @param playlistUri The {@link Uri} of the playlist to be downloaded.
|
||||
* @param renditionKeys Keys defining which renditions in the playlist should be selected for
|
||||
* @param streamKeys Keys defining which renditions in the playlist should be selected for
|
||||
* download. If empty, all renditions are downloaded.
|
||||
* @param constructorHelper A {@link DownloaderConstructorHelper} instance.
|
||||
*/
|
||||
public HlsDownloader(
|
||||
Uri playlistUri,
|
||||
List<RenditionKey> renditionKeys,
|
||||
DownloaderConstructorHelper constructorHelper) {
|
||||
super(playlistUri, renditionKeys, constructorHelper);
|
||||
Uri playlistUri, List<StreamKey> streamKeys, DownloaderConstructorHelper constructorHelper) {
|
||||
super(playlistUri, streamKeys, constructorHelper);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.google.android.exoplayer2.source.hls.playlist;
|
||||
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -24,6 +25,10 @@ import java.util.List;
|
||||
/** Represents an HLS master playlist. */
|
||||
public final class HlsMasterPlaylist extends HlsPlaylist {
|
||||
|
||||
public static final int GROUP_INDEX_VARIANT = 0;
|
||||
public static final int GROUP_INDEX_AUDIO = 1;
|
||||
public static final int GROUP_INDEX_SUBTITLE = 2;
|
||||
|
||||
/**
|
||||
* Represents a url in an HLS master playlist.
|
||||
*/
|
||||
@ -108,13 +113,13 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HlsMasterPlaylist copy(List<RenditionKey> renditionKeys) {
|
||||
public HlsMasterPlaylist copy(List<StreamKey> streamKeys) {
|
||||
return new HlsMasterPlaylist(
|
||||
baseUri,
|
||||
tags,
|
||||
copyRenditionsList(variants, RenditionKey.TYPE_VARIANT, renditionKeys),
|
||||
copyRenditionsList(audios, RenditionKey.TYPE_AUDIO, renditionKeys),
|
||||
copyRenditionsList(subtitles, RenditionKey.TYPE_SUBTITLE, renditionKeys),
|
||||
copyRenditionsList(variants, GROUP_INDEX_VARIANT, streamKeys),
|
||||
copyRenditionsList(audios, GROUP_INDEX_AUDIO, streamKeys),
|
||||
copyRenditionsList(subtitles, GROUP_INDEX_SUBTITLE, streamKeys),
|
||||
muxedAudioFormat,
|
||||
muxedCaptionFormats);
|
||||
}
|
||||
@ -133,13 +138,13 @@ public final class HlsMasterPlaylist extends HlsPlaylist {
|
||||
}
|
||||
|
||||
private static List<HlsUrl> copyRenditionsList(
|
||||
List<HlsUrl> renditions, int renditionType, List<RenditionKey> renditionKeys) {
|
||||
List<HlsUrl> copiedRenditions = new ArrayList<>(renditionKeys.size());
|
||||
List<HlsUrl> renditions, int groupIndex, List<StreamKey> streamKeys) {
|
||||
List<HlsUrl> copiedRenditions = new ArrayList<>(streamKeys.size());
|
||||
for (int i = 0; i < renditions.size(); i++) {
|
||||
HlsUrl rendition = renditions.get(i);
|
||||
for (int j = 0; j < renditionKeys.size(); j++) {
|
||||
RenditionKey renditionKey = renditionKeys.get(j);
|
||||
if (renditionKey.type == renditionType && renditionKey.trackIndex == i) {
|
||||
for (int j = 0; j < streamKeys.size(); j++) {
|
||||
StreamKey streamKey = streamKeys.get(j);
|
||||
if (streamKey.groupIndex == groupIndex && streamKey.trackIndex == i) {
|
||||
copiedRenditions.add(rendition);
|
||||
break;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Collections;
|
||||
@ -256,7 +257,7 @@ public final class HlsMediaPlaylist extends HlsPlaylist {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HlsMediaPlaylist copy(List<RenditionKey> renditionKeys) {
|
||||
public HlsMediaPlaylist copy(List<StreamKey> streamKeys) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Represents an HLS playlist. */
|
||||
public abstract class HlsPlaylist implements FilterableManifest<HlsPlaylist, RenditionKey> {
|
||||
public abstract class HlsPlaylist implements FilterableManifest<HlsPlaylist> {
|
||||
|
||||
/**
|
||||
* The base uri. Used to resolve relative paths.
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.source.hls.playlist;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/** Uniquely identifies a rendition in an {@link HlsMasterPlaylist}. */
|
||||
public final class RenditionKey implements Comparable<RenditionKey> {
|
||||
|
||||
/** Types of rendition. */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({TYPE_VARIANT, TYPE_AUDIO, TYPE_SUBTITLE})
|
||||
public @interface Type {}
|
||||
|
||||
public static final int TYPE_VARIANT = 0;
|
||||
public static final int TYPE_AUDIO = 1;
|
||||
public static final int TYPE_SUBTITLE = 2;
|
||||
|
||||
public final @Type int type;
|
||||
public final int trackIndex;
|
||||
|
||||
public RenditionKey(@Type int type, int trackIndex) {
|
||||
this.type = type;
|
||||
this.trackIndex = trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + "." + trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RenditionKey that = (RenditionKey) o;
|
||||
return type == that.type && trackIndex == that.trackIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = type;
|
||||
result = 31 * result + trackIndex;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Comparable implementation.
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull RenditionKey other) {
|
||||
int result = type - other.type;
|
||||
if (result == 0) {
|
||||
result = trackIndex - other.trackIndex;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -36,7 +36,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.net.Uri;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSet;
|
||||
import com.google.android.exoplayer2.testutil.FakeDataSource.Factory;
|
||||
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
|
||||
@ -181,17 +182,18 @@ public class HlsDownloaderTest {
|
||||
assertCachedData(cache, fakeDataSet);
|
||||
}
|
||||
|
||||
private HlsDownloader getHlsDownloader(String mediaPlaylistUri, List<RenditionKey> keys) {
|
||||
private HlsDownloader getHlsDownloader(String mediaPlaylistUri, List<StreamKey> keys) {
|
||||
Factory factory = new Factory(null).setFakeDataSet(fakeDataSet);
|
||||
return new HlsDownloader(
|
||||
Uri.parse(mediaPlaylistUri), keys, new DownloaderConstructorHelper(cache, factory));
|
||||
}
|
||||
|
||||
private static ArrayList<RenditionKey> getKeys(int... variantIndices) {
|
||||
ArrayList<RenditionKey> renditionKeys = new ArrayList<>();
|
||||
private static ArrayList<StreamKey> getKeys(int... variantIndices) {
|
||||
ArrayList<StreamKey> streamKeys = new ArrayList<>();
|
||||
for (int variantIndex : variantIndices) {
|
||||
renditionKeys.add(new RenditionKey(RenditionKey.TYPE_VARIANT, variantIndex));
|
||||
final int trackIndex = variantIndex;
|
||||
streamKeys.add(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, trackIndex));
|
||||
}
|
||||
return renditionKeys;
|
||||
return streamKeys;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import android.net.Uri;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.FilterableManifest;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.UriUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
@ -33,7 +34,7 @@ import java.util.UUID;
|
||||
* @see <a href="http://msdn.microsoft.com/en-us/library/ee673436(v=vs.90).aspx">IIS Smooth
|
||||
* Streaming Client Manifest Format</a>
|
||||
*/
|
||||
public class SsManifest implements FilterableManifest<SsManifest, StreamKey> {
|
||||
public class SsManifest implements FilterableManifest<SsManifest> {
|
||||
|
||||
public static final int UNSET_LOOKAHEAD = -1;
|
||||
|
||||
@ -130,7 +131,7 @@ public class SsManifest implements FilterableManifest<SsManifest, StreamKey> {
|
||||
List<Format> copiedFormats = new ArrayList<>();
|
||||
for (int i = 0; i < sortedKeys.size(); i++) {
|
||||
StreamKey key = sortedKeys.get(i);
|
||||
StreamElement streamElement = streamElements[key.streamElementIndex];
|
||||
StreamElement streamElement = streamElements[key.groupIndex];
|
||||
if (streamElement != currentStreamElement && currentStreamElement != null) {
|
||||
// We're advancing to a new stream element. Add the current one.
|
||||
copiedStreamElements.add(currentStreamElement.copy(copiedFormats.toArray(new Format[0])));
|
||||
|
@ -20,24 +20,26 @@ import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.StreamKey;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/** An action to download or remove downloaded SmoothStreaming streams. */
|
||||
public final class SsDownloadAction extends SegmentDownloadAction<StreamKey> {
|
||||
public final class SsDownloadAction extends SegmentDownloadAction {
|
||||
|
||||
private static final String TYPE = "ss";
|
||||
private static final int VERSION = 0;
|
||||
|
||||
public static final Deserializer DESERIALIZER =
|
||||
new SegmentDownloadActionDeserializer<StreamKey>(TYPE, VERSION) {
|
||||
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
||||
|
||||
@Override
|
||||
protected StreamKey readKey(DataInputStream input) throws IOException {
|
||||
return new StreamKey(input.readInt(), input.readInt());
|
||||
int groupIndex = input.readInt();
|
||||
int trackIndex = input.readInt();
|
||||
return new StreamKey(groupIndex, trackIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,7 +68,7 @@ public final class SsDownloadAction extends SegmentDownloadAction<StreamKey> {
|
||||
|
||||
@Override
|
||||
protected void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
||||
output.writeInt(key.streamElementIndex);
|
||||
output.writeInt(key.groupIndex);
|
||||
output.writeInt(key.trackIndex);
|
||||
}
|
||||
|
||||
|
@ -18,12 +18,12 @@ package com.google.android.exoplayer2.source.smoothstreaming.offline;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.offline.DownloadHelper;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.offline.TrackKey;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.StreamKey;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
@ -82,8 +82,7 @@ public final class SsDownloadHelper extends DownloadHelper {
|
||||
|
||||
@Override
|
||||
public SsDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||
return new SsDownloadAction(
|
||||
uri, /* isRemoveAction= */ true, data, Collections.<StreamKey>emptyList());
|
||||
return new SsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
||||
}
|
||||
|
||||
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys) {
|
||||
|
@ -19,11 +19,11 @@ import android.net.Uri;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.SegmentDownloader;
|
||||
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.StreamElement;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifestParser;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsUtil;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.StreamKey;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
||||
@ -54,7 +54,7 @@ import java.util.List;
|
||||
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class SsDownloader extends SegmentDownloader<SsManifest, StreamKey> {
|
||||
public final class SsDownloader extends SegmentDownloader<SsManifest> {
|
||||
|
||||
/**
|
||||
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
|
||||
|
@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.ProtectionElement;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest.StreamElement;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
@ -20,11 +20,11 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import android.net.Uri;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
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.DashManifest;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
|
||||
import com.google.android.exoplayer2.source.dash.offline.DashDownloader;
|
||||
import com.google.android.exoplayer2.testutil.HostActivity;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||
@ -106,7 +106,7 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
|
||||
private DashDownloader downloadContent() throws Exception {
|
||||
DashManifest dashManifest =
|
||||
DashUtil.loadManifest(httpDataSourceFactory.createDataSource(), MANIFEST_URI);
|
||||
ArrayList<RepresentationKey> keys = new ArrayList<>();
|
||||
ArrayList<StreamKey> keys = new ArrayList<>();
|
||||
for (int pIndex = 0; pIndex < dashManifest.getPeriodCount(); pIndex++) {
|
||||
List<AdaptationSet> adaptationSets = dashManifest.getPeriod(pIndex).adaptationSets;
|
||||
for (int aIndex = 0; aIndex < adaptationSets.size(); aIndex++) {
|
||||
@ -116,7 +116,7 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
|
||||
String id = representations.get(rIndex).format.id;
|
||||
if (DashTestData.AAC_AUDIO_REPRESENTATION_ID.equals(id)
|
||||
|| DashTestData.H264_CDD_FIXED.equals(id)) {
|
||||
keys.add(new RepresentationKey(pIndex, aIndex, rIndex));
|
||||
keys.add(new StreamKey(pIndex, aIndex, rIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user