SegmentDownloader loadManifest cleanup.

- HlsDownloader.loadManifest (previously called getHlsPlaylist)
  suppressed errors for the offline case, where-as the DashUtil
  equivalent method did not. This change makes them consistent
  and moves both other to use ParsingLoadable.
- Enable GZIP for manifest loads in both cases.
- Use Uri rather than String to represent Uris. Previously the
  strings were parsed into Uris quite deep in the code, which
  isn't ideal if the parsing fails; you'd probably prefer the
  error to occur early at the top level.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=165181398
This commit is contained in:
olly 2017-08-14 08:31:59 -07:00 committed by Oliver Woodman
parent fb83872365
commit cf6534ea5b
5 changed files with 77 additions and 36 deletions

View File

@ -72,8 +72,19 @@ public final class ParsingLoadable<T> implements Loadable {
* @param parser Parses the object from the response. * @param parser Parses the object from the response.
*/ */
public ParsingLoadable(DataSource dataSource, Uri uri, int type, Parser<? extends T> parser) { public ParsingLoadable(DataSource dataSource, Uri uri, int type, Parser<? extends T> parser) {
this(dataSource, new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP), type, parser);
}
/**
* @param dataSource A {@link DataSource} to use when loading the data.
* @param dataSpec The {@link DataSpec} from which the object should be loaded.
* @param type See {@link #type}.
* @param parser Parses the object from the response.
*/
public ParsingLoadable(DataSource dataSource, DataSpec dataSpec, int type,
Parser<? extends T> parser) {
this.dataSource = dataSource; this.dataSource = dataSource;
this.dataSpec = new DataSpec(uri, DataSpec.FLAG_ALLOW_GZIP); this.dataSpec = dataSpec;
this.type = type; this.type = type;
this.parser = parser; this.parser = parser;
} }
@ -108,7 +119,7 @@ public final class ParsingLoadable<T> implements Loadable {
} }
@Override @Override
public final void load() throws IOException, InterruptedException { public final void load() throws IOException {
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec); DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, dataSpec);
try { try {
inputStream.open(); inputStream.open();

View File

@ -31,9 +31,9 @@ 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.RangedUri;
import com.google.android.exoplayer2.source.dash.manifest.Representation; import com.google.android.exoplayer2.source.dash.manifest.Representation;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSourceInputStream;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.ParsingLoadable;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -47,21 +47,18 @@ public final class DashUtil {
* Loads a DASH manifest. * Loads a DASH manifest.
* *
* @param dataSource The {@link HttpDataSource} from which the manifest should be read. * @param dataSource The {@link HttpDataSource} from which the manifest should be read.
* @param manifestUri The URI of the manifest to be read. * @param uri The {@link Uri} of the manifest to be read.
* @return An instance of {@link DashManifest}. * @return An instance of {@link DashManifest}.
* @throws IOException Thrown when there is an error while loading. * @throws IOException Thrown when there is an error while loading.
*/ */
public static DashManifest loadManifest(DataSource dataSource, String manifestUri) public static DashManifest loadManifest(DataSource dataSource, Uri uri)
throws IOException { throws IOException {
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, DataSpec dataSpec = new DataSpec(uri,
new DataSpec(Uri.parse(manifestUri), DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH)); DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH | DataSpec.FLAG_ALLOW_GZIP);
try { ParsingLoadable<DashManifest> loadable = new ParsingLoadable<>(dataSource, dataSpec,
inputStream.open(); C.DATA_TYPE_MANIFEST, new DashManifestParser());
DashManifestParser parser = new DashManifestParser(); loadable.load();
return parser.parse(dataSource.getUri(), inputStream); return loadable.getResult();
} finally {
inputStream.close();
}
} }
/** /**

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.playbacktests.gts; package com.google.android.exoplayer2.playbacktests.gts;
import android.media.MediaDrm.MediaDrmStateException; import android.media.MediaDrm.MediaDrmStateException;
import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2; import android.test.ActivityInstrumentationTestCase2;
import android.util.Pair; import android.util.Pair;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
@ -170,7 +171,7 @@ public final class DashWidevineOfflineTest extends ActivityInstrumentationTestCa
private void downloadLicense() throws InterruptedException, DrmSessionException, IOException { private void downloadLicense() throws InterruptedException, DrmSessionException, IOException {
DataSource dataSource = httpDataSourceFactory.createDataSource(); DataSource dataSource = httpDataSourceFactory.createDataSource();
DashManifest dashManifest = DashUtil.loadManifest(dataSource, DashManifest dashManifest = DashUtil.loadManifest(dataSource,
DashTestData.WIDEVINE_H264_MANIFEST); Uri.parse(DashTestData.WIDEVINE_H264_MANIFEST));
DrmInitData drmInitData = DashUtil.loadDrmInitData(dataSource, dashManifest.getPeriod(0)); DrmInitData drmInitData = DashUtil.loadDrmInitData(dataSource, dashManifest.getPeriod(0));
offlineLicenseKeySetId = offlineLicenseHelper.downloadLicense(drmInitData); offlineLicenseKeySetId = offlineLicenseHelper.downloadLicense(drmInitData);
Assert.assertNotNull(offlineLicenseKeySetId); Assert.assertNotNull(offlineLicenseKeySetId);

View File

@ -39,11 +39,11 @@ public final class CacheAsserts {
/** Asserts that the cache content is equal to the data in the {@code fakeDataSet}. */ /** Asserts that the cache content is equal to the data in the {@code fakeDataSet}. */
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet) throws IOException { public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet) throws IOException {
ArrayList<FakeData> allData = fakeDataSet.getAllData(); ArrayList<FakeData> allData = fakeDataSet.getAllData();
String[] uriStrings = new String[allData.size()]; Uri[] uris = new Uri[allData.size()];
for (int i = 0; i < allData.size(); i++) { for (int i = 0; i < allData.size(); i++) {
uriStrings[i] = allData.get(i).uri; uris[i] = allData.get(i).uri;
} }
assertCachedData(cache, fakeDataSet, uriStrings); assertCachedData(cache, fakeDataSet, uris);
} }
/** /**
@ -51,30 +51,41 @@ public final class CacheAsserts {
*/ */
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings) public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings)
throws IOException { throws IOException {
Uri[] uris = new Uri[uriStrings.length];
for (int i = 0; i < uriStrings.length; i++) {
uris[i] = Uri.parse(uriStrings[i]);
}
assertCachedData(cache, fakeDataSet, uris);
}
/**
* Asserts that the cache content is equal to the given subset of data in the {@code fakeDataSet}.
*/
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, Uri... uris)
throws IOException {
int totalLength = 0; int totalLength = 0;
for (String uriString : uriStrings) { for (Uri uri : uris) {
byte[] data = fakeDataSet.getData(uriString).getData(); byte[] data = fakeDataSet.getData(uri).getData();
assertDataCached(cache, uriString, data); assertDataCached(cache, uri, data);
totalLength += data.length; totalLength += data.length;
} }
assertEquals(totalLength, cache.getCacheSpace()); assertEquals(totalLength, cache.getCacheSpace());
} }
/** Asserts that the cache contains the given subset of data in the {@code fakeDataSet}. */ /** Asserts that the cache contains the given subset of data in the {@code fakeDataSet}. */
public static void assertDataCached(Cache cache, FakeDataSet fakeDataSet, String... uriStrings) public static void assertDataCached(Cache cache, FakeDataSet fakeDataSet, Uri... uris)
throws IOException { throws IOException {
for (String uriString : uriStrings) { for (Uri uri : uris) {
assertDataCached(cache, uriString, fakeDataSet.getData(uriString).getData()); assertDataCached(cache, uri, fakeDataSet.getData(uri).getData());
} }
} }
/** Asserts that the cache contains the given data for {@code uriString}. */ /** Asserts that the cache contains the given data for {@code uriString}. */
public static void assertDataCached(Cache cache, String uriString, byte[] expected) public static void assertDataCached(Cache cache, Uri uri, byte[] expected) throws IOException {
throws IOException {
CacheDataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0); CacheDataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DataSourceInputStream inputStream = new DataSourceInputStream(dataSource, DataSourceInputStream inputStream = new DataSourceInputStream(dataSource,
new DataSpec(Uri.parse(uriString), DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH)); new DataSpec(uri, DataSpec.FLAG_ALLOW_CACHING_UNKNOWN_LENGTH));
try { try {
inputStream.open(); inputStream.open();
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
@ -87,7 +98,7 @@ public final class CacheAsserts {
} finally { } finally {
inputStream.close(); inputStream.close();
} }
MoreAsserts.assertEquals("Cached data doesn't match expected for '" + uriString + "',", MoreAsserts.assertEquals("Cached data doesn't match expected for '" + uri + "',",
expected, outputStream.toByteArray()); expected, outputStream.toByteArray());
} }

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
@ -28,11 +29,11 @@ import java.util.List;
/** /**
* Collection of {@link FakeData} to be served by a {@link FakeDataSource}. * Collection of {@link FakeData} to be served by a {@link FakeDataSource}.
* *
* <p>Multiple fake data can be defined by {@link FakeDataSet#setData(String, byte[])} and {@link * <p>Multiple fake data can be defined by {@link FakeDataSet#setData(Uri, byte[])} and {@link
* FakeDataSet#newData(String)} methods. It's also possible to define a default data by {@link * FakeDataSet#newData(Uri)} methods. It's also possible to define a default data by {@link
* FakeDataSet#newDefaultData()}. * FakeDataSet#newDefaultData()}.
* *
* <p>{@link FakeDataSet#newData(String)} and {@link FakeDataSet#newDefaultData()} return a {@link * <p>{@link FakeDataSet#newData(Uri)} and {@link FakeDataSet#newDefaultData()} return a {@link
* FakeData} instance which can be used to define specific results during * FakeData} instance which can be used to define specific results during
* {@link FakeDataSource#read(byte[], int, int)} calls. * {@link FakeDataSource#read(byte[], int, int)} calls.
* *
@ -104,8 +105,8 @@ public class FakeDataSet {
this(null, 0, null, action, previousSegment); this(null, 0, null, action, previousSegment);
} }
private Segment(byte[] data, int length, IOException exception, Runnable action, private Segment(@Nullable byte[] data, int length, @Nullable IOException exception,
Segment previousSegment) { @Nullable Runnable action, Segment previousSegment) {
this.exception = exception; this.exception = exception;
this.action = action; this.action = action;
this.data = data; this.data = data;
@ -125,12 +126,12 @@ public class FakeDataSet {
} }
/** Uri of the data or null if this is the default FakeData. */ /** Uri of the data or null if this is the default FakeData. */
public final String uri; public final Uri uri;
private final ArrayList<Segment> segments; private final ArrayList<Segment> segments;
private final FakeDataSet dataSet; private final FakeDataSet dataSet;
private boolean simulateUnknownLength; private boolean simulateUnknownLength;
private FakeData(FakeDataSet dataSet, String uri) { private FakeData(FakeDataSet dataSet, Uri uri) {
this.uri = uri; this.uri = uri;
this.segments = new ArrayList<>(); this.segments = new ArrayList<>();
this.dataSet = dataSet; this.dataSet = dataSet;
@ -219,7 +220,7 @@ public class FakeDataSet {
} }
private final HashMap<String, FakeData> dataMap; private final HashMap<Uri, FakeData> dataMap;
private FakeData defaultData; private FakeData defaultData;
public FakeDataSet() { public FakeDataSet() {
@ -234,16 +235,31 @@ public class FakeDataSet {
/** Sets random data with the given {@code length} for the given {@code uri}. */ /** Sets random data with the given {@code length} for the given {@code uri}. */
public FakeDataSet setRandomData(String uri, int length) { public FakeDataSet setRandomData(String uri, int length) {
return setRandomData(Uri.parse(uri), length);
}
/** Sets random data with the given {@code length} for the given {@code uri}. */
public FakeDataSet setRandomData(Uri uri, int length) {
return setData(uri, TestUtil.buildTestData(length)); return setData(uri, TestUtil.buildTestData(length));
} }
/** Sets the given {@code data} for the given {@code uri}. */ /** Sets the given {@code data} for the given {@code uri}. */
public FakeDataSet setData(String uri, byte[] data) { public FakeDataSet setData(String uri, byte[] data) {
return setData(Uri.parse(uri), data);
}
/** Sets the given {@code data} for the given {@code uri}. */
public FakeDataSet setData(Uri uri, byte[] data) {
return newData(uri).appendReadData(data).endData(); return newData(uri).appendReadData(data).endData();
} }
/** Returns a new {@link FakeData} with the given {@code uri}. */ /** Returns a new {@link FakeData} with the given {@code uri}. */
public FakeData newData(String uri) { public FakeData newData(String uri) {
return newData(Uri.parse(uri));
}
/** Returns a new {@link FakeData} with the given {@code uri}. */
public FakeData newData(Uri uri) {
FakeData data = new FakeData(this, uri); FakeData data = new FakeData(this, uri);
dataMap.put(uri, data); dataMap.put(uri, data);
return data; return data;
@ -251,6 +267,11 @@ public class FakeDataSet {
/** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */ /** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */
public FakeData getData(String uri) { public FakeData getData(String uri) {
return getData(Uri.parse(uri));
}
/** Returns the data for the given {@code uri}, or {@code defaultData} if no data is set. */
public FakeData getData(Uri uri) {
FakeData data = dataMap.get(uri); FakeData data = dataMap.get(uri);
return data != null ? data : defaultData; return data != null ? data : defaultData;
} }