mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix DataSchemeDataSource re-opening and range requests
Issue:#6192 PiperOrigin-RevId: 258592902
This commit is contained in:
parent
bee35ed9d7
commit
80d5dabd52
3 changed files with 72 additions and 14 deletions
|
|
@ -25,6 +25,8 @@
|
||||||
* Add `enable` and `disable` methods to `MediaSource` to improve resource
|
* Add `enable` and `disable` methods to `MediaSource` to improve resource
|
||||||
management in playlists.
|
management in playlists.
|
||||||
* 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 ###
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ public final class DataSchemeDataSource extends BaseDataSource {
|
||||||
|
|
||||||
@Nullable private DataSpec dataSpec;
|
@Nullable private DataSpec dataSpec;
|
||||||
@Nullable private byte[] data;
|
@Nullable private byte[] data;
|
||||||
private int dataLength;
|
private int endPosition;
|
||||||
private int bytesRead;
|
private int readPosition;
|
||||||
|
|
||||||
public DataSchemeDataSource() {
|
public DataSchemeDataSource() {
|
||||||
super(/* isNetwork= */ false);
|
super(/* isNetwork= */ false);
|
||||||
|
|
@ -44,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)) {
|
||||||
|
|
@ -57,17 +58,21 @@ public final class DataSchemeDataSource extends BaseDataSource {
|
||||||
if (uriParts[0].contains(";base64")) {
|
if (uriParts[0].contains(";base64")) {
|
||||||
try {
|
try {
|
||||||
data = Base64.decode(dataString, 0);
|
data = Base64.decode(dataString, 0);
|
||||||
dataLength = data.length;
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new ParserException("Error while parsing Base64 encoded string: " + dataString, e);
|
throw new ParserException("Error while parsing Base64 encoded string: " + dataString, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 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));
|
||||||
dataLength = data.length;
|
}
|
||||||
|
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 dataLength;
|
return (long) endPosition - readPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -75,13 +80,13 @@ public final class DataSchemeDataSource extends BaseDataSource {
|
||||||
if (readLength == 0) {
|
if (readLength == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int remainingBytes = dataLength - 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(castNonNull(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;
|
||||||
}
|
}
|
||||||
|
|
@ -93,12 +98,11 @@ public final class DataSchemeDataSource extends BaseDataSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@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;
|
||||||
|
|
||||||
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;
|
||||||
@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 {
|
||||||
|
|
||||||
@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,
|
||||||
|
|
@ -72,6 +74,52 @@ public final class DataSchemeDataSourceTest {
|
||||||
assertThat(Util.fromUtf8Bytes(buffer, 0, 18)).isEqualTo("012345678901234567");
|
assertThat(Util.fromUtf8Bytes(buffer, 0, 18)).isEqualTo("012345678901234567");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Test
|
||||||
public void testIncorrectScheme() {
|
public void testIncorrectScheme() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue