Commit e181d4bd by aquilescanta Committed by Oliver Woodman

Fix DataSchemeDataSource re-opening and range requests

Issue:#6192
PiperOrigin-RevId: 258592902
parent 962d5e70
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* Flac extension: Parse `VORBIS_COMMENT` metadata * Flac extension: Parse `VORBIS_COMMENT` metadata
([#5527](https://github.com/google/ExoPlayer/issues/5527)). ([#5527](https://github.com/google/ExoPlayer/issues/5527)).
* Fix issue where initial seek positions get ignored when playing a preroll ad. * Fix issue where initial seek positions get ignored when playing a preroll ad.
* Fix `DataSchemeDataSource` re-opening and range requests
([#6192](https://github.com/google/ExoPlayer/issues/6192)).
### 2.10.3 ### ### 2.10.3 ###
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.upstream; package com.google.android.exoplayer2.upstream;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import android.util.Base64; import android.util.Base64;
...@@ -29,9 +31,10 @@ public final class DataSchemeDataSource extends BaseDataSource { ...@@ -29,9 +31,10 @@ public final class DataSchemeDataSource extends BaseDataSource {
public static final String SCHEME_DATA = "data"; public static final String SCHEME_DATA = "data";
private @Nullable DataSpec dataSpec; @Nullable private DataSpec dataSpec;
private int bytesRead; @Nullable private byte[] data;
private @Nullable byte[] data; private int endPosition;
private int readPosition;
public DataSchemeDataSource() { public DataSchemeDataSource() {
super(/* isNetwork= */ false); super(/* isNetwork= */ false);
...@@ -41,6 +44,7 @@ public final class DataSchemeDataSource extends BaseDataSource { ...@@ -41,6 +44,7 @@ public final class DataSchemeDataSource extends BaseDataSource {
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
transferInitializing(dataSpec); transferInitializing(dataSpec);
this.dataSpec = dataSpec; this.dataSpec = dataSpec;
readPosition = (int) dataSpec.position;
Uri uri = dataSpec.uri; Uri uri = dataSpec.uri;
String scheme = uri.getScheme(); String scheme = uri.getScheme();
if (!SCHEME_DATA.equals(scheme)) { if (!SCHEME_DATA.equals(scheme)) {
...@@ -61,8 +65,14 @@ public final class DataSchemeDataSource extends BaseDataSource { ...@@ -61,8 +65,14 @@ public final class DataSchemeDataSource extends BaseDataSource {
// TODO: Add support for other charsets. // TODO: Add support for other charsets.
data = Util.getUtf8Bytes(URLDecoder.decode(dataString, C.ASCII_NAME)); data = Util.getUtf8Bytes(URLDecoder.decode(dataString, C.ASCII_NAME));
} }
endPosition =
dataSpec.length != C.LENGTH_UNSET ? (int) dataSpec.length + readPosition : data.length;
if (endPosition > data.length || readPosition > endPosition) {
data = null;
throw new DataSourceException(DataSourceException.POSITION_OUT_OF_RANGE);
}
transferStarted(dataSpec); transferStarted(dataSpec);
return data.length; return (long) endPosition - readPosition;
} }
@Override @Override
...@@ -70,29 +80,29 @@ public final class DataSchemeDataSource extends BaseDataSource { ...@@ -70,29 +80,29 @@ public final class DataSchemeDataSource extends BaseDataSource {
if (readLength == 0) { if (readLength == 0) {
return 0; return 0;
} }
int remainingBytes = data.length - bytesRead; int remainingBytes = endPosition - readPosition;
if (remainingBytes == 0) { if (remainingBytes == 0) {
return C.RESULT_END_OF_INPUT; return C.RESULT_END_OF_INPUT;
} }
readLength = Math.min(readLength, remainingBytes); readLength = Math.min(readLength, remainingBytes);
System.arraycopy(data, bytesRead, buffer, offset, readLength); System.arraycopy(castNonNull(data), readPosition, buffer, offset, readLength);
bytesRead += readLength; readPosition += readLength;
bytesTransferred(readLength); bytesTransferred(readLength);
return readLength; return readLength;
} }
@Override @Override
public @Nullable Uri getUri() { @Nullable
public Uri getUri() {
return dataSpec != null ? dataSpec.uri : null; return dataSpec != null ? dataSpec.uri : null;
} }
@Override @Override
public void close() throws IOException { public void close() {
if (data != null) { if (data != null) {
data = null; data = null;
transferEnded(); transferEnded();
} }
dataSpec = null; dataSpec = null;
} }
} }
...@@ -21,6 +21,7 @@ import static org.junit.Assert.fail; ...@@ -21,6 +21,7 @@ import static org.junit.Assert.fail;
import android.net.Uri; import android.net.Uri;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import org.junit.Before; import org.junit.Before;
...@@ -31,6 +32,9 @@ import org.junit.runner.RunWith; ...@@ -31,6 +32,9 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public final class DataSchemeDataSourceTest { public final class DataSchemeDataSourceTest {
private static final String DATA_SCHEME_URI =
"data:text/plain;base64,eyJwcm92aWRlciI6IndpZGV2aW5lX3Rlc3QiLCJjb250ZW50X2lkIjoiTWpBeE5WOTBaV"
+ "0Z5Y3c9PSIsImtleV9pZHMiOlsiMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAiXX0=";
private DataSource schemeDataDataSource; private DataSource schemeDataDataSource;
@Before @Before
...@@ -40,9 +44,7 @@ public final class DataSchemeDataSourceTest { ...@@ -40,9 +44,7 @@ public final class DataSchemeDataSourceTest {
@Test @Test
public void testBase64Data() throws IOException { public void testBase64Data() throws IOException {
DataSpec dataSpec = buildDataSpec("data:text/plain;base64,eyJwcm92aWRlciI6IndpZGV2aW5lX3Rlc3QiL" DataSpec dataSpec = buildDataSpec(DATA_SCHEME_URI);
+ "CJjb250ZW50X2lkIjoiTWpBeE5WOTBaV0Z5Y3c9PSIsImtleV9pZHMiOlsiMDAwMDAwMDAwMDAwMDAwMDAwMDAwM"
+ "DAwMDAwMDAwMDAiXX0=");
DataSourceAsserts.assertDataSourceContent( DataSourceAsserts.assertDataSourceContent(
schemeDataDataSource, schemeDataDataSource,
dataSpec, dataSpec,
...@@ -73,6 +75,52 @@ public final class DataSchemeDataSourceTest { ...@@ -73,6 +75,52 @@ public final class DataSchemeDataSourceTest {
} }
@Test @Test
public void testSequentialRangeRequests() throws IOException {
DataSpec dataSpec =
buildDataSpec(DATA_SCHEME_URI, /* position= */ 1, /* length= */ C.LENGTH_UNSET);
DataSourceAsserts.assertDataSourceContent(
schemeDataDataSource,
dataSpec,
Util.getUtf8Bytes(
"\"provider\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
+ "[\"00000000000000000000000000000000\"]}"));
dataSpec = buildDataSpec(DATA_SCHEME_URI, /* position= */ 10, /* length= */ C.LENGTH_UNSET);
DataSourceAsserts.assertDataSourceContent(
schemeDataDataSource,
dataSpec,
Util.getUtf8Bytes(
"\":\"widevine_test\",\"content_id\":\"MjAxNV90ZWFycw==\",\"key_ids\":"
+ "[\"00000000000000000000000000000000\"]}"));
dataSpec = buildDataSpec(DATA_SCHEME_URI, /* position= */ 15, /* length= */ 5);
DataSourceAsserts.assertDataSourceContent(
schemeDataDataSource, dataSpec, Util.getUtf8Bytes("devin"));
}
@Test
public void testInvalidStartPositionRequest() throws IOException {
try {
// Try to open a range starting one byte beyond the resource's length.
schemeDataDataSource.open(
buildDataSpec(DATA_SCHEME_URI, /* position= */ 108, /* length= */ C.LENGTH_UNSET));
fail();
} catch (DataSourceException e) {
assertThat(e.reason).isEqualTo(DataSourceException.POSITION_OUT_OF_RANGE);
}
}
@Test
public void testRangeExceedingResourceLengthRequest() throws IOException {
try {
// Try to open a range exceeding the resource's length.
schemeDataDataSource.open(
buildDataSpec(DATA_SCHEME_URI, /* position= */ 97, /* length= */ 11));
fail();
} catch (DataSourceException e) {
assertThat(e.reason).isEqualTo(DataSourceException.POSITION_OUT_OF_RANGE);
}
}
@Test
public void testIncorrectScheme() { public void testIncorrectScheme() {
try { try {
schemeDataDataSource.open(buildDataSpec("http://www.google.com")); schemeDataDataSource.open(buildDataSpec("http://www.google.com"));
...@@ -99,7 +147,11 @@ public final class DataSchemeDataSourceTest { ...@@ -99,7 +147,11 @@ public final class DataSchemeDataSourceTest {
} }
private static DataSpec buildDataSpec(String uriString) { private static DataSpec buildDataSpec(String uriString) {
return new DataSpec(Uri.parse(uriString)); return buildDataSpec(uriString, /* position= */ 0, /* length= */ C.LENGTH_UNSET);
}
private static DataSpec buildDataSpec(String uriString, int position, int length) {
return new DataSpec(Uri.parse(uriString), position, length, /* key= */ null);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment