mirror of
https://github.com/samsonjs/media.git
synced 2026-04-16 13:05:46 +00:00
Add DataSpec.Builder
PiperOrigin-RevId: 294518763
This commit is contained in:
parent
7a849e11f7
commit
14d3ed09d5
5 changed files with 274 additions and 64 deletions
|
|
@ -19,6 +19,7 @@
|
|||
* Move player message-related constants from `C` to `Renderer`, to avoid
|
||||
having the constants class depend on player/renderer classes.
|
||||
* Split out `common` and `extractor` submodules.
|
||||
* Add `DataSpec.Builder`.
|
||||
* Text:
|
||||
* Parse `<ruby>` and `<rt>` tags in WebVTT subtitles (rendering is coming
|
||||
later).
|
||||
|
|
|
|||
|
|
@ -924,16 +924,12 @@ public class CronetDataSource extends BaseDataSource implements HttpDataSource {
|
|||
// For POST redirects that aren't 307 or 308, the redirect is followed but request is
|
||||
// transformed into a GET.
|
||||
redirectUrlDataSpec =
|
||||
new DataSpec(
|
||||
Uri.parse(newLocationUrl),
|
||||
DataSpec.HTTP_METHOD_GET,
|
||||
/* httpBody= */ null,
|
||||
dataSpec.absoluteStreamPosition,
|
||||
dataSpec.position,
|
||||
dataSpec.length,
|
||||
dataSpec.key,
|
||||
dataSpec.flags,
|
||||
dataSpec.httpRequestHeaders);
|
||||
dataSpec
|
||||
.buildUpon()
|
||||
.setUri(Uri.parse(newLocationUrl))
|
||||
.setHttpMethod(DataSpec.HTTP_METHOD_GET)
|
||||
.setHttpBody(null)
|
||||
.build();
|
||||
} else {
|
||||
redirectUrlDataSpec = dataSpec.withUri(Uri.parse(newLocationUrl));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,163 @@ import java.util.Map;
|
|||
*/
|
||||
public final class DataSpec {
|
||||
|
||||
/** Builds {@link DataSpec} instances. */
|
||||
public static final class Builder {
|
||||
|
||||
@Nullable private Uri uri;
|
||||
private long uriPositionOffset;
|
||||
@HttpMethod private int httpMethod;
|
||||
@Nullable private byte[] httpBody;
|
||||
private Map<String, String> httpRequestHeaders;
|
||||
private long position;
|
||||
private long length;
|
||||
@Nullable private String key;
|
||||
@Flags private int flags;
|
||||
|
||||
/** Creates a new instance with default values. */
|
||||
public Builder() {
|
||||
httpMethod = HTTP_METHOD_GET;
|
||||
httpRequestHeaders = Collections.emptyMap();
|
||||
length = C.LENGTH_UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance to build upon the provided {@link DataSpec}.
|
||||
*
|
||||
* @param dataSpec The {@link DataSpec} to build upon.
|
||||
*/
|
||||
private Builder(DataSpec dataSpec) {
|
||||
uri = dataSpec.uri;
|
||||
uriPositionOffset = dataSpec.uriPositionOffset;
|
||||
httpMethod = dataSpec.httpMethod;
|
||||
httpBody = dataSpec.httpBody;
|
||||
httpRequestHeaders = dataSpec.httpRequestHeaders;
|
||||
position = dataSpec.position;
|
||||
length = dataSpec.length;
|
||||
key = dataSpec.key;
|
||||
flags = dataSpec.flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link DataSpec#uri}. Must be called before {@link #build()}.
|
||||
*
|
||||
* @param uri The {@link DataSpec#uri}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setUri(Uri uri) {
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DataSpec#uriPositionOffset}. The default value is 0.
|
||||
*
|
||||
* @param uriPositionOffset The {@link DataSpec#uriPositionOffset}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setUriPositionOffset(long uriPositionOffset) {
|
||||
this.uriPositionOffset = uriPositionOffset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link DataSpec#httpMethod}. The default value is {@link #HTTP_METHOD_GET}.
|
||||
*
|
||||
* @param httpMethod The {@link DataSpec#httpMethod}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setHttpMethod(@HttpMethod int httpMethod) {
|
||||
this.httpMethod = httpMethod;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@link DataSpec#httpBody}. The default value is {@code null}.
|
||||
*
|
||||
* @param httpBody The {@link DataSpec#httpBody}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setHttpBody(@Nullable byte[] httpBody) {
|
||||
this.httpBody = httpBody;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DataSpec#httpRequestHeaders}. The default value is an empty map.
|
||||
*
|
||||
* @param httpRequestHeaders The {@link DataSpec#httpRequestHeaders}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setHttpRequestHeaders(Map<String, String> httpRequestHeaders) {
|
||||
this.httpRequestHeaders = httpRequestHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DataSpec#position}. The default value is 0.
|
||||
*
|
||||
* @param position The {@link DataSpec#position}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setPosition(long position) {
|
||||
this.position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DataSpec#length}. The default value is {@link C#LENGTH_UNSET}.
|
||||
*
|
||||
* @param length The {@link DataSpec#length}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setLength(long length) {
|
||||
this.length = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DataSpec#key}. The default value is {@code null}.
|
||||
*
|
||||
* @param key The {@link DataSpec#key}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setKey(@Nullable String key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DataSpec#flags}. The default value is 0.
|
||||
*
|
||||
* @param flags The {@link DataSpec#flags}.
|
||||
* @return The builder.
|
||||
*/
|
||||
public Builder setFlags(@Flags int flags) {
|
||||
this.flags = flags;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a {@link DataSpec} with the builder's current values.
|
||||
*
|
||||
* @return The build {@link DataSpec}.
|
||||
* @throws IllegalStateException If {@link #setUri(Uri)} has not been called.
|
||||
*/
|
||||
public DataSpec build() {
|
||||
Assertions.checkStateNotNull(uri, "The uri must be set.");
|
||||
return new DataSpec(
|
||||
uri,
|
||||
uriPositionOffset,
|
||||
httpMethod,
|
||||
httpBody,
|
||||
httpRequestHeaders,
|
||||
position,
|
||||
length,
|
||||
key,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The flags that apply to any request for data. Possible flag values are {@link
|
||||
* #FLAG_ALLOW_GZIP}, {@link #FLAG_DONT_CACHE_IF_LENGTH_UNKNOWN}, {@link
|
||||
|
|
@ -131,7 +288,7 @@ public final class DataSpec {
|
|||
* The HTTP method to use when requesting the data. This value will be ignored by non-HTTP {@link
|
||||
* DataSource} implementations.
|
||||
*/
|
||||
public final @HttpMethod int httpMethod;
|
||||
@HttpMethod public final int httpMethod;
|
||||
|
||||
/**
|
||||
* The HTTP request body, null otherwise. If the body is non-null, then {@code httpBody.length}
|
||||
|
|
@ -166,7 +323,7 @@ public final class DataSpec {
|
|||
@Nullable public final String key;
|
||||
|
||||
/** Request {@link Flags flags}. */
|
||||
public final @Flags int flags;
|
||||
@Flags public final int flags;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
|
|
@ -408,6 +565,11 @@ public final class DataSpec {
|
|||
return getStringForHttpMethod(httpMethod);
|
||||
}
|
||||
|
||||
/** Returns a {@link DataSpec.Builder} initialized with the values of this instance. */
|
||||
public DataSpec.Builder buildUpon() {
|
||||
return new Builder(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a data spec that represents a subrange of the data defined by this DataSpec. The
|
||||
* subrange includes data from the offset up to the end of this DataSpec.
|
||||
|
|
|
|||
|
|
@ -94,13 +94,19 @@ public class DataSpecTest {
|
|||
assertDefaultDataSpec(dataSpec, uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void createDataSpec_setsCustomValues() {
|
||||
public void createDataSpec_withBuilder_withDefaultValues() {
|
||||
Uri uri = Uri.parse("www.google.com");
|
||||
|
||||
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
|
||||
DataSpec dataSpec = new DataSpec.Builder().setUri(uri).build();
|
||||
assertDefaultDataSpec(dataSpec, uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void createDataSpec_setsValues() {
|
||||
Uri uri = Uri.parse("www.google.com");
|
||||
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
|
||||
byte[] httpBody = new byte[] {0, 1, 2, 3};
|
||||
|
||||
DataSpec dataSpec =
|
||||
|
|
@ -129,6 +135,77 @@ public class DataSpecTest {
|
|||
assertHttpRequestHeadersReadOnly(dataSpec);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void createDataSpec_withBuilder_setsValues() {
|
||||
Uri uri = Uri.parse("www.google.com");
|
||||
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
|
||||
byte[] httpBody = new byte[] {0, 1, 2, 3};
|
||||
|
||||
DataSpec dataSpec =
|
||||
new DataSpec.Builder()
|
||||
.setUri(uri)
|
||||
.setUriPositionOffset(50)
|
||||
.setHttpMethod(DataSpec.HTTP_METHOD_POST)
|
||||
.setHttpBody(httpBody)
|
||||
.setPosition(150)
|
||||
.setLength(5)
|
||||
.setKey("key")
|
||||
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
|
||||
.setHttpRequestHeaders(httpRequestHeaders)
|
||||
.build();
|
||||
|
||||
assertThat(dataSpec.uri).isEqualTo(uri);
|
||||
assertThat(dataSpec.uriPositionOffset).isEqualTo(50);
|
||||
assertThat(dataSpec.httpMethod).isEqualTo(DataSpec.HTTP_METHOD_POST);
|
||||
assertThat(dataSpec.httpBody).isEqualTo(httpBody);
|
||||
assertThat(dataSpec.httpRequestHeaders).isEqualTo(httpRequestHeaders);
|
||||
// absoluteStreamPosition = uriPositionOffset + position
|
||||
assertThat(dataSpec.absoluteStreamPosition).isEqualTo(200);
|
||||
assertThat(dataSpec.position).isEqualTo(150);
|
||||
assertThat(dataSpec.length).isEqualTo(5);
|
||||
assertThat(dataSpec.key).isEqualTo("key");
|
||||
assertThat(dataSpec.flags).isEqualTo(DataSpec.FLAG_ALLOW_GZIP);
|
||||
assertHttpRequestHeadersReadOnly(dataSpec);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void buildUponDataSpec_setsValues() {
|
||||
Uri uri = Uri.parse("www.google.com");
|
||||
Map<String, String> httpRequestHeaders = createHttpRequestHeaders(3);
|
||||
byte[] httpBody = new byte[] {0, 1, 2, 3};
|
||||
|
||||
DataSpec dataSpec =
|
||||
new DataSpec.Builder()
|
||||
.setUri(uri)
|
||||
.setUriPositionOffset(50)
|
||||
.setHttpMethod(DataSpec.HTTP_METHOD_POST)
|
||||
.setHttpBody(httpBody)
|
||||
.setPosition(150)
|
||||
.setLength(5)
|
||||
.setKey("key")
|
||||
.setFlags(DataSpec.FLAG_ALLOW_GZIP)
|
||||
.setHttpRequestHeaders(httpRequestHeaders)
|
||||
.build();
|
||||
|
||||
// Build upon the DataSpec.
|
||||
dataSpec = dataSpec.buildUpon().build();
|
||||
|
||||
assertThat(dataSpec.uri).isEqualTo(uri);
|
||||
assertThat(dataSpec.uriPositionOffset).isEqualTo(50);
|
||||
assertThat(dataSpec.httpMethod).isEqualTo(DataSpec.HTTP_METHOD_POST);
|
||||
assertThat(dataSpec.httpBody).isEqualTo(httpBody);
|
||||
assertThat(dataSpec.httpRequestHeaders).isEqualTo(httpRequestHeaders);
|
||||
// absoluteStreamPosition = uriPositionOffset + position
|
||||
assertThat(dataSpec.absoluteStreamPosition).isEqualTo(200);
|
||||
assertThat(dataSpec.position).isEqualTo(150);
|
||||
assertThat(dataSpec.length).isEqualTo(5);
|
||||
assertThat(dataSpec.key).isEqualTo("key");
|
||||
assertThat(dataSpec.flags).isEqualTo(DataSpec.FLAG_ALLOW_GZIP);
|
||||
assertHttpRequestHeadersReadOnly(dataSpec);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createDataSpec_setsHttpMethodAndPostBody() {
|
||||
Uri uri = Uri.parse("www.google.com");
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.DataSink;
|
|||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DataSourceException;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec;
|
||||
import com.google.android.exoplayer2.upstream.DataSpec.HttpMethod;
|
||||
import com.google.android.exoplayer2.upstream.FileDataSource;
|
||||
import com.google.android.exoplayer2.upstream.TeeDataSource;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
|
|
@ -132,15 +131,10 @@ public final class CacheDataSource implements DataSource {
|
|||
private final boolean ignoreCacheOnError;
|
||||
private final boolean ignoreCacheForUnsetLengthRequests;
|
||||
|
||||
@Nullable private Uri actualUri;
|
||||
@Nullable private DataSpec requestDataSpec;
|
||||
@Nullable private DataSource currentDataSource;
|
||||
private boolean currentDataSpecLengthUnset;
|
||||
@Nullable private Uri uri;
|
||||
@Nullable private Uri actualUri;
|
||||
@HttpMethod private int httpMethod;
|
||||
@Nullable private byte[] httpBody;
|
||||
private Map<String, String> httpRequestHeaders = Collections.emptyMap();
|
||||
@DataSpec.Flags private int flags;
|
||||
@Nullable private String key;
|
||||
private long readPosition;
|
||||
private long bytesRemaining;
|
||||
@Nullable private CacheSpan currentHoleSpan;
|
||||
|
|
@ -259,13 +253,9 @@ public final class CacheDataSource implements DataSource {
|
|||
@Override
|
||||
public long open(DataSpec dataSpec) throws IOException {
|
||||
try {
|
||||
key = cacheKeyFactory.buildCacheKey(dataSpec);
|
||||
uri = dataSpec.uri;
|
||||
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri);
|
||||
httpMethod = dataSpec.httpMethod;
|
||||
httpBody = dataSpec.httpBody;
|
||||
httpRequestHeaders = dataSpec.httpRequestHeaders;
|
||||
flags = dataSpec.flags;
|
||||
String key = cacheKeyFactory.buildCacheKey(dataSpec);
|
||||
requestDataSpec = dataSpec.buildUpon().setKey(key).build();
|
||||
actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ requestDataSpec.uri);
|
||||
readPosition = dataSpec.position;
|
||||
|
||||
int reason = shouldIgnoreCacheForRequest(dataSpec);
|
||||
|
|
@ -351,14 +341,9 @@ public final class CacheDataSource implements DataSource {
|
|||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
uri = null;
|
||||
requestDataSpec = null;
|
||||
actualUri = null;
|
||||
httpMethod = DataSpec.HTTP_METHOD_GET;
|
||||
httpBody = null;
|
||||
httpRequestHeaders = Collections.emptyMap();
|
||||
flags = 0;
|
||||
readPosition = 0;
|
||||
key = null;
|
||||
notifyBytesRead();
|
||||
try {
|
||||
closeCurrentSource();
|
||||
|
|
@ -384,6 +369,7 @@ public final class CacheDataSource implements DataSource {
|
|||
*/
|
||||
private void openNextSource(boolean checkCache) throws IOException {
|
||||
@Nullable CacheSpan nextSpan;
|
||||
String key = requestDataSpec.key;
|
||||
if (currentRequestIgnoresCache) {
|
||||
nextSpan = null;
|
||||
} else if (blockOnCache) {
|
||||
|
|
@ -404,27 +390,24 @@ public final class CacheDataSource implements DataSource {
|
|||
// from upstream.
|
||||
nextDataSource = upstreamDataSource;
|
||||
nextDataSpec =
|
||||
new DataSpec(
|
||||
uri,
|
||||
httpMethod,
|
||||
httpBody,
|
||||
readPosition,
|
||||
readPosition,
|
||||
bytesRemaining,
|
||||
key,
|
||||
flags,
|
||||
httpRequestHeaders);
|
||||
requestDataSpec.buildUpon().setPosition(readPosition).setLength(bytesRemaining).build();
|
||||
} else if (nextSpan.isCached) {
|
||||
// Data is cached, read from cache.
|
||||
// Data is cached in a span file starting at nextSpan.position.
|
||||
Uri fileUri = Uri.fromFile(nextSpan.file);
|
||||
long filePosition = readPosition - nextSpan.position;
|
||||
long length = nextSpan.length - filePosition;
|
||||
long filePositionOffset = nextSpan.position;
|
||||
long positionInFile = readPosition - filePositionOffset;
|
||||
long length = nextSpan.length - positionInFile;
|
||||
if (bytesRemaining != C.LENGTH_UNSET) {
|
||||
length = Math.min(length, bytesRemaining);
|
||||
}
|
||||
// Deliberately skip the HTTP-related parameters since we're reading from the cache, not
|
||||
// making an HTTP request.
|
||||
nextDataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags);
|
||||
nextDataSpec =
|
||||
requestDataSpec
|
||||
.buildUpon()
|
||||
.setUri(fileUri)
|
||||
.setUriPositionOffset(filePositionOffset)
|
||||
.setPosition(positionInFile)
|
||||
.setLength(length)
|
||||
.build();
|
||||
nextDataSource = cacheReadDataSource;
|
||||
} else {
|
||||
// Data is not cached, and data is not locked, read from upstream with cache backing.
|
||||
|
|
@ -438,16 +421,7 @@ public final class CacheDataSource implements DataSource {
|
|||
}
|
||||
}
|
||||
nextDataSpec =
|
||||
new DataSpec(
|
||||
uri,
|
||||
httpMethod,
|
||||
httpBody,
|
||||
readPosition,
|
||||
readPosition,
|
||||
length,
|
||||
key,
|
||||
flags,
|
||||
httpRequestHeaders);
|
||||
requestDataSpec.buildUpon().setPosition(readPosition).setLength(length).build();
|
||||
if (cacheWriteDataSource != null) {
|
||||
nextDataSource = cacheWriteDataSource;
|
||||
} else {
|
||||
|
|
@ -494,7 +468,7 @@ public final class CacheDataSource implements DataSource {
|
|||
}
|
||||
if (isReadingFromUpstream()) {
|
||||
actualUri = currentDataSource.getUri();
|
||||
boolean isRedirected = !uri.equals(actualUri);
|
||||
boolean isRedirected = !requestDataSpec.uri.equals(actualUri);
|
||||
ContentMetadataMutations.setRedirectedUri(mutations, isRedirected ? actualUri : null);
|
||||
}
|
||||
if (isWritingToCache()) {
|
||||
|
|
@ -507,7 +481,7 @@ public final class CacheDataSource implements DataSource {
|
|||
if (isWritingToCache()) {
|
||||
ContentMetadataMutations mutations = new ContentMetadataMutations();
|
||||
ContentMetadataMutations.setContentLength(mutations, readPosition);
|
||||
cache.applyContentMetadataMutations(key, mutations);
|
||||
cache.applyContentMetadataMutations(requestDataSpec.key, mutations);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue