mirror of
https://github.com/samsonjs/media.git
synced 2026-04-10 12:05:47 +00:00
Add flags to DataSpec. Support GZIP option.
Also remove uriIsFullStream. It's not doing anything particularly useful, so I think it makes sense to remove it from the public API; it's unlikely anyone is using it. Issue: #329
This commit is contained in:
parent
3868b1d4cb
commit
0c6566bce7
7 changed files with 80 additions and 58 deletions
|
|
@ -438,13 +438,14 @@ public class HlsChunkSource {
|
|||
|
||||
private MediaPlaylistChunk newMediaPlaylistChunk(int variantIndex) {
|
||||
Uri mediaPlaylistUri = Util.getMergedUri(baseUri, enabledVariants[variantIndex].url);
|
||||
DataSpec dataSpec = new DataSpec(mediaPlaylistUri, 0, C.LENGTH_UNBOUNDED, null);
|
||||
DataSpec dataSpec = new DataSpec(mediaPlaylistUri, 0, C.LENGTH_UNBOUNDED, null,
|
||||
DataSpec.FLAG_ALLOW_GZIP);
|
||||
return new MediaPlaylistChunk(variantIndex, upstreamDataSource, dataSpec,
|
||||
mediaPlaylistUri.toString());
|
||||
}
|
||||
|
||||
private EncryptionKeyChunk newEncryptionKeyChunk(Uri keyUri, String iv) {
|
||||
DataSpec dataSpec = new DataSpec(keyUri, 0, C.LENGTH_UNBOUNDED, null);
|
||||
DataSpec dataSpec = new DataSpec(keyUri, 0, C.LENGTH_UNBOUNDED, null, DataSpec.FLAG_ALLOW_GZIP);
|
||||
return new EncryptionKeyChunk(upstreamDataSource, dataSpec, iv);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -230,7 +230,7 @@ public final class DataSourceStream implements Loadable, NonBlockingInputStream
|
|||
long remainingLength = resolvedLength != C.LENGTH_UNBOUNDED
|
||||
? resolvedLength - loadPosition : C.LENGTH_UNBOUNDED;
|
||||
loadDataSpec = new DataSpec(dataSpec.uri, dataSpec.position + loadPosition,
|
||||
remainingLength, dataSpec.key);
|
||||
remainingLength, dataSpec.key, dataSpec.flags);
|
||||
dataSource.open(loadDataSpec);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,22 +25,32 @@ import android.net.Uri;
|
|||
*/
|
||||
public final class DataSpec {
|
||||
|
||||
/**
|
||||
* Permits an underlying network stack to request that the server use gzip compression.
|
||||
* <p>
|
||||
* Should not typically be set if the data being requested is already compressed (e.g. most audio
|
||||
* and video requests). May be set when requesting other data.
|
||||
* <p>
|
||||
* When a {@link DataSource} is used to request data with this flag set, and if the
|
||||
* {@link DataSource} does make a network request, then the value returned from
|
||||
* {@link DataSource#open(DataSpec)} will typically be {@link C#LENGTH_UNBOUNDED}. The data read
|
||||
* from {@link DataSource#read(byte[], int, int)} will be the decompressed data.
|
||||
*/
|
||||
public static final int FLAG_ALLOW_GZIP = 1;
|
||||
|
||||
/**
|
||||
* Identifies the source from which data should be read.
|
||||
*/
|
||||
public final Uri uri;
|
||||
/**
|
||||
* True if the data at {@link #uri} is the full stream. False otherwise. An example where this
|
||||
* may be false is if {@link #uri} defines the location of a cached part of the stream.
|
||||
*/
|
||||
public final boolean uriIsFullStream;
|
||||
/**
|
||||
* The absolute position of the data in the full stream.
|
||||
*/
|
||||
public final long absoluteStreamPosition;
|
||||
/**
|
||||
* The position of the data when read from {@link #uri}. Always equal to
|
||||
* {@link #absoluteStreamPosition} if {@link #uriIsFullStream}.
|
||||
* The position of the data when read from {@link #uri}.
|
||||
* <p>
|
||||
* Always equal to {@link #absoluteStreamPosition} unless the {@link #uri} defines the location
|
||||
* of a subset of the underyling data.
|
||||
*/
|
||||
public final long position;
|
||||
/**
|
||||
|
|
@ -52,6 +62,10 @@ public final class DataSpec {
|
|||
* {@link DataSpec} is not intended to be used in conjunction with a cache.
|
||||
*/
|
||||
public final String key;
|
||||
/**
|
||||
* Request flags. Currently {@link #FLAG_ALLOW_GZIP} is the only supported flag.
|
||||
*/
|
||||
public final int flags;
|
||||
|
||||
/**
|
||||
* Construct a {@link DataSpec} for the given uri and with {@link #key} set to null.
|
||||
|
|
@ -59,11 +73,21 @@ public final class DataSpec {
|
|||
* @param uri {@link #uri}.
|
||||
*/
|
||||
public DataSpec(Uri uri) {
|
||||
this(uri, 0, C.LENGTH_UNBOUNDED, null);
|
||||
this(uri, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link DataSpec} for which {@link #uriIsFullStream} is true.
|
||||
* Construct a {@link DataSpec} for the given uri and with {@link #key} set to null.
|
||||
*
|
||||
* @param uri {@link #uri}.
|
||||
* @param flags {@link #flags}.
|
||||
*/
|
||||
public DataSpec(Uri uri, int flags) {
|
||||
this(uri, 0, C.LENGTH_UNBOUNDED, null, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link DataSpec} where {@link #position} equals {@link #absoluteStreamPosition}.
|
||||
*
|
||||
* @param uri {@link #uri}.
|
||||
* @param absoluteStreamPosition {@link #absoluteStreamPosition}, equal to {@link #position}.
|
||||
|
|
@ -71,50 +95,50 @@ public final class DataSpec {
|
|||
* @param key {@link #key}.
|
||||
*/
|
||||
public DataSpec(Uri uri, long absoluteStreamPosition, long length, String key) {
|
||||
this(uri, absoluteStreamPosition, length, key, absoluteStreamPosition, true);
|
||||
this(uri, absoluteStreamPosition, absoluteStreamPosition, length, key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link DataSpec} for which {@link #uriIsFullStream} is false.
|
||||
* Construct a {@link DataSpec} where {@link #position} equals {@link #absoluteStreamPosition}.
|
||||
*
|
||||
* @param uri {@link #uri}.
|
||||
* @param absoluteStreamPosition {@link #absoluteStreamPosition}.
|
||||
* @param absoluteStreamPosition {@link #absoluteStreamPosition}, equal to {@link #position}.
|
||||
* @param length {@link #length}.
|
||||
* @param key {@link #key}.
|
||||
* @param position {@link #position}.
|
||||
* @param flags {@link #flags}.
|
||||
*/
|
||||
public DataSpec(Uri uri, long absoluteStreamPosition, long length, String key, long position) {
|
||||
this(uri, absoluteStreamPosition, length, key, position, false);
|
||||
public DataSpec(Uri uri, long absoluteStreamPosition, long length, String key, int flags) {
|
||||
this(uri, absoluteStreamPosition, absoluteStreamPosition, length, key, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link DataSpec}.
|
||||
* Construct a {@link DataSpec} where {@link #position} may differ from
|
||||
* {@link #absoluteStreamPosition}.
|
||||
*
|
||||
* @param uri {@link #uri}.
|
||||
* @param absoluteStreamPosition {@link #absoluteStreamPosition}.
|
||||
* @param position {@link #position}.
|
||||
* @param length {@link #length}.
|
||||
* @param key {@link #key}.
|
||||
* @param position {@link #position}.
|
||||
* @param uriIsFullStream {@link #uriIsFullStream}.
|
||||
* @param flags {@link #flags}.
|
||||
*/
|
||||
public DataSpec(Uri uri, long absoluteStreamPosition, long length, String key, long position,
|
||||
boolean uriIsFullStream) {
|
||||
public DataSpec(Uri uri, long absoluteStreamPosition, long position, long length, String key,
|
||||
int flags) {
|
||||
Assertions.checkArgument(absoluteStreamPosition >= 0);
|
||||
Assertions.checkArgument(position >= 0);
|
||||
Assertions.checkArgument(length > 0 || length == C.LENGTH_UNBOUNDED);
|
||||
Assertions.checkArgument(absoluteStreamPosition == position || !uriIsFullStream);
|
||||
this.uri = uri;
|
||||
this.uriIsFullStream = uriIsFullStream;
|
||||
this.absoluteStreamPosition = absoluteStreamPosition;
|
||||
this.position = position;
|
||||
this.length = length;
|
||||
this.key = key;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataSpec[" + uri + ", " + uriIsFullStream + ", " + absoluteStreamPosition + ", " +
|
||||
position + ", " + length + ", " + key + "]";
|
||||
return "DataSpec[" + uri + ", " + ", " + absoluteStreamPosition + ", " +
|
||||
position + ", " + length + ", " + key + ", " + flags + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,19 +132,6 @@ public class DefaultHttpDataSource implements HttpDataSource {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: If the server uses gzip compression when serving the response, this may end up returning
|
||||
* the size of the compressed response, where-as it should be returning the decompressed size or
|
||||
* -1. See: developer.android.com/reference/java/net/HttpURLConnection.html
|
||||
*
|
||||
* To fix this we should:
|
||||
*
|
||||
* 1. Explicitly require no compression for media requests (since media should be compressed
|
||||
* already) by setting the Accept-Encoding header to "identity"
|
||||
* 2. In other cases, for example when requesting manifests, we don't want to disable compression.
|
||||
* For these cases we should ensure that we return -1 here (and avoid performing any sanity
|
||||
* checks on the content length).
|
||||
*/
|
||||
@Override
|
||||
public long open(DataSpec dataSpec) throws HttpDataSourceException {
|
||||
this.dataSpec = dataSpec;
|
||||
|
|
@ -177,16 +164,23 @@ public class DefaultHttpDataSource implements HttpDataSource {
|
|||
throw new InvalidContentTypeException(contentType, dataSpec);
|
||||
}
|
||||
|
||||
long contentLength = getContentLength(connection);
|
||||
dataLength = dataSpec.length == C.LENGTH_UNBOUNDED ? contentLength : dataSpec.length;
|
||||
|
||||
if (dataSpec.length != C.LENGTH_UNBOUNDED && contentLength != C.LENGTH_UNBOUNDED
|
||||
&& contentLength != dataSpec.length) {
|
||||
// The DataSpec specified a length and we resolved a length from the response headers, but
|
||||
// the two lengths do not match.
|
||||
closeConnection();
|
||||
throw new HttpDataSourceException(
|
||||
new UnexpectedLengthException(dataSpec.length, contentLength), dataSpec);
|
||||
if ((dataSpec.flags & DataSpec.FLAG_ALLOW_GZIP) == 0) {
|
||||
long contentLength = getContentLength(connection);
|
||||
dataLength = dataSpec.length == C.LENGTH_UNBOUNDED ? contentLength : dataSpec.length;
|
||||
if (dataSpec.length != C.LENGTH_UNBOUNDED && contentLength != C.LENGTH_UNBOUNDED
|
||||
&& contentLength != dataSpec.length) {
|
||||
// The DataSpec specified a length and we resolved a length from the response headers, but
|
||||
// the two lengths do not match.
|
||||
closeConnection();
|
||||
throw new HttpDataSourceException(
|
||||
new UnexpectedLengthException(dataSpec.length, contentLength), dataSpec);
|
||||
}
|
||||
} else {
|
||||
// Gzip is enabled. If the server opts to use gzip then the content length in the response
|
||||
// will be that of the compressed data, which isn't what we want. Furthermore, there isn't a
|
||||
// reliable way to determine whether the gzip was used or not. Hence we always treat the
|
||||
// length as unknown.
|
||||
dataLength = C.LENGTH_UNBOUNDED;
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -301,6 +295,9 @@ public class DefaultHttpDataSource implements HttpDataSource {
|
|||
}
|
||||
setRangeHeader(connection, dataSpec);
|
||||
connection.setRequestProperty("User-Agent", userAgent);
|
||||
if ((dataSpec.flags & DataSpec.FLAG_ALLOW_GZIP) == 0) {
|
||||
connection.setRequestProperty("Accept-Encoding", "identity");
|
||||
}
|
||||
connection.connect();
|
||||
return connection;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public final class NetworkLoadable<T> implements Loadable {
|
|||
public NetworkLoadable(String url, HttpDataSource httpDataSource, Parser<T> parser) {
|
||||
this.httpDataSource = httpDataSource;
|
||||
this.parser = parser;
|
||||
dataSpec = new DataSpec(Uri.parse(url));
|
||||
dataSpec = new DataSpec(Uri.parse(url), DataSpec.FLAG_ALLOW_GZIP);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ public final class TeeDataSource implements DataSource {
|
|||
long dataLength = upstream.open(dataSpec);
|
||||
if (dataSpec.length == C.LENGTH_UNBOUNDED && dataLength != C.LENGTH_UNBOUNDED) {
|
||||
// Reconstruct dataSpec in order to provide the resolved length to the sink.
|
||||
dataSpec = new DataSpec(dataSpec.uri, dataSpec.absoluteStreamPosition, dataLength,
|
||||
dataSpec.key, dataSpec.position, dataSpec.uriIsFullStream);
|
||||
dataSpec = new DataSpec(dataSpec.uri, dataSpec.absoluteStreamPosition, dataSpec.position,
|
||||
dataLength, dataSpec.key, dataSpec.flags);
|
||||
}
|
||||
dataSink.open(dataSpec);
|
||||
return dataLength;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import com.google.android.exoplayer.upstream.DataSpec;
|
|||
import com.google.android.exoplayer.upstream.FileDataSource;
|
||||
import com.google.android.exoplayer.upstream.TeeDataSource;
|
||||
import com.google.android.exoplayer.upstream.cache.CacheDataSink.CacheDataSinkException;
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
|
@ -64,6 +63,7 @@ public final class CacheDataSource implements DataSource {
|
|||
|
||||
private DataSource currentDataSource;
|
||||
private Uri uri;
|
||||
private int flags;
|
||||
private String key;
|
||||
private long readPosition;
|
||||
private long bytesRemaining;
|
||||
|
|
@ -125,9 +125,9 @@ public final class CacheDataSource implements DataSource {
|
|||
|
||||
@Override
|
||||
public long open(DataSpec dataSpec) throws IOException {
|
||||
Assertions.checkState(dataSpec.uriIsFullStream);
|
||||
try {
|
||||
uri = dataSpec.uri;
|
||||
flags = dataSpec.flags;
|
||||
key = dataSpec.key;
|
||||
readPosition = dataSpec.position;
|
||||
bytesRemaining = dataSpec.length;
|
||||
|
|
@ -201,19 +201,19 @@ public final class CacheDataSource implements DataSource {
|
|||
// The data is locked in the cache, or we're ignoring the cache. Bypass the cache and read
|
||||
// from upstream.
|
||||
currentDataSource = upstreamDataSource;
|
||||
dataSpec = new DataSpec(uri, readPosition, bytesRemaining, key);
|
||||
dataSpec = new DataSpec(uri, readPosition, bytesRemaining, key, flags);
|
||||
} else if (span.isCached) {
|
||||
// Data is cached, read from cache.
|
||||
Uri fileUri = Uri.fromFile(span.file);
|
||||
long filePosition = readPosition - span.position;
|
||||
long length = Math.min(span.length - filePosition, bytesRemaining);
|
||||
dataSpec = new DataSpec(fileUri, readPosition, length, key, filePosition);
|
||||
dataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags);
|
||||
currentDataSource = cacheReadDataSource;
|
||||
} else {
|
||||
// Data is not cached, and data is not locked, read from upstream with cache backing.
|
||||
lockedSpan = span;
|
||||
long length = span.isOpenEnded() ? bytesRemaining : Math.min(span.length, bytesRemaining);
|
||||
dataSpec = new DataSpec(uri, readPosition, length, key);
|
||||
dataSpec = new DataSpec(uri, readPosition, length, key, flags);
|
||||
currentDataSource = cacheWriteDataSource != null ? cacheWriteDataSource
|
||||
: upstreamDataSource;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue