ExtractorInput new skip methods to make skip methods analogous to the three read methods.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=110155932
This commit is contained in:
parent
009b454b69
commit
f16b8baf75
101
README.md
101
README.md
@ -1,10 +1,14 @@
|
|||||||
# ExoPlayer #
|
# ExoPlayer Readme #
|
||||||
|
|
||||||
ExoPlayer is an application level media player for Android. It provides an alternative to Android’s
|
## Description ##
|
||||||
MediaPlayer API for playing audio and video both locally and over the Internet. ExoPlayer supports
|
|
||||||
features not currently supported by Android’s MediaPlayer API, including DASH and SmoothStreaming
|
ExoPlayer is an application level media player for Android. It provides an
|
||||||
adaptive playbacks. Unlike the MediaPlayer API, ExoPlayer is easy to customize and extend, and can
|
alternative to Android’s MediaPlayer API for playing audio and video both
|
||||||
be updated through Play Store application updates.
|
locally and over the Internet. ExoPlayer supports features not currently
|
||||||
|
supported by Android’s MediaPlayer API, including DASH and SmoothStreaming
|
||||||
|
adaptive playbacks. Unlike the MediaPlayer API, ExoPlayer is easy to
|
||||||
|
customize and extend, and can be updated through Play Store application
|
||||||
|
updates.
|
||||||
|
|
||||||
## News ##
|
## News ##
|
||||||
|
|
||||||
@ -14,7 +18,8 @@ Read news, hints and tips on the [news][] page.
|
|||||||
|
|
||||||
## Documentation ##
|
## Documentation ##
|
||||||
|
|
||||||
* The [developer guide][] provides a wealth of information to help you get started.
|
* The [developer guide][] provides a wealth of information to help you get
|
||||||
|
started.
|
||||||
* The [class reference][] documents the ExoPlayer library classes.
|
* The [class reference][] documents the ExoPlayer library classes.
|
||||||
* The [release notes][] document the major changes in each release.
|
* The [release notes][] document the major changes in each release.
|
||||||
|
|
||||||
@ -22,31 +27,37 @@ Read news, hints and tips on the [news][] page.
|
|||||||
[class reference]: https://google.github.io/ExoPlayer/doc/reference
|
[class reference]: https://google.github.io/ExoPlayer/doc/reference
|
||||||
[release notes]: https://github.com/google/ExoPlayer/blob/dev/RELEASENOTES.md
|
[release notes]: https://github.com/google/ExoPlayer/blob/dev/RELEASENOTES.md
|
||||||
|
|
||||||
## Using ExoPlayer ##
|
## Project branches ##
|
||||||
|
|
||||||
#### Via jCenter ####
|
* The [master][] branch holds the most recent minor release.
|
||||||
|
* Most development work happens on the [dev][] branch.
|
||||||
|
* Additional development branches may be established for major features.
|
||||||
|
|
||||||
The easiest way to get started using ExoPlayer is by including the following in your project's
|
[master]: https://github.com/google/ExoPlayer/tree/master
|
||||||
`build.gradle` file:
|
[dev]: https://github.com/google/ExoPlayer/tree/dev
|
||||||
|
|
||||||
|
## Using Eclipse ##
|
||||||
|
|
||||||
|
The repository includes Eclipse projects for both the ExoPlayer library and its
|
||||||
|
accompanying demo application. To get started:
|
||||||
|
|
||||||
|
1. Install Eclipse and setup the [Android SDK][].
|
||||||
|
|
||||||
|
1. Open Eclipse and navigate to File->Import->General->Existing Projects into
|
||||||
|
Workspace.
|
||||||
|
|
||||||
|
1. Select the root directory of the repository.
|
||||||
|
|
||||||
|
1. Import the ExoPlayerDemo and ExoPlayerLib projects.
|
||||||
|
|
||||||
|
[Android SDK]: http://developer.android.com/sdk/index.html
|
||||||
|
|
||||||
|
|
||||||
|
## Using Gradle ##
|
||||||
|
|
||||||
|
ExoPlayer can also be built using Gradle. You can include it as a dependent project and build from source:
|
||||||
|
|
||||||
```
|
```
|
||||||
gradle
|
|
||||||
compile 'com.google.android.exoplayer:exoplayer:rX.X.X'
|
|
||||||
```
|
|
||||||
|
|
||||||
where `rX.X.X` is the your preferred version. For the latest version, see the project's
|
|
||||||
[Releases][]. For more details, see the project on [Bintray][].
|
|
||||||
|
|
||||||
[Releases]: https://github.com/google/ExoPlayer/releases
|
|
||||||
[Bintray]: https://bintray.com/google/exoplayer/exoplayer/view
|
|
||||||
|
|
||||||
#### As source ####
|
|
||||||
|
|
||||||
ExoPlayer can also be built from source using Gradle. You can include it as a dependent project like
|
|
||||||
so:
|
|
||||||
|
|
||||||
```
|
|
||||||
gradle
|
|
||||||
// settings.gradle
|
// settings.gradle
|
||||||
include ':app', ':..:ExoPlayer:library'
|
include ':app', ':..:ExoPlayer:library'
|
||||||
|
|
||||||
@ -56,40 +67,18 @@ dependencies {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### As a jar ####
|
|
||||||
|
|
||||||
If you want to use ExoPlayer as a jar, run:
|
If you want to use ExoPlayer as a jar, run:
|
||||||
|
|
||||||
```
|
```
|
||||||
sh
|
|
||||||
./gradlew jarRelease
|
./gradlew jarRelease
|
||||||
```
|
```
|
||||||
|
|
||||||
and copy `library.jar` to the libs folder of your new project.
|
and copy library.jar to the libs-folder of your new project.
|
||||||
|
|
||||||
## Developing ExoPlayer ##
|
The project is also available on [jCenter](https://bintray.com/google/exoplayer/exoplayer/view):
|
||||||
|
|
||||||
#### Project branches ####
|
```
|
||||||
|
compile 'com.google.android.exoplayer:exoplayer:rX.X.X'
|
||||||
|
```
|
||||||
|
|
||||||
* The [`master`][master] branch holds the most recent minor release.
|
Where `rX.X.X` should be replaced with the desired version.
|
||||||
* Most development work happens on the [`dev`][dev] branch.
|
|
||||||
* Additional development branches may be established for major features.
|
|
||||||
|
|
||||||
[master]: https://github.com/google/ExoPlayer/tree/master
|
|
||||||
[dev]: https://github.com/google/ExoPlayer/tree/dev
|
|
||||||
|
|
||||||
#### Using Android Studio ####
|
|
||||||
|
|
||||||
To develop ExoPlayer using Android Studio, simply open the ExoPlayer project in the root directory
|
|
||||||
of the repository.
|
|
||||||
|
|
||||||
#### Using Eclipse ####
|
|
||||||
|
|
||||||
To develop ExoPlayer using Eclipse:
|
|
||||||
|
|
||||||
1. Install Eclipse and setup the [Android SDK][].
|
|
||||||
1. Open Eclipse and navigate to File->Import->General->Existing Projects into Workspace.
|
|
||||||
1. Select the root directory of the repository.
|
|
||||||
1. Import the projects.
|
|
||||||
|
|
||||||
[Android SDK]: http://developer.android.com/sdk/index.html
|
|
||||||
|
@ -157,11 +157,39 @@ public class DefaultExtractorInputTest extends TestCase {
|
|||||||
assertEquals(0, input.getPosition());
|
assertEquals(0, input.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testReadFullyHalfPeeked() throws IOException, InterruptedException {
|
||||||
|
DefaultExtractorInput input = createDefaultExtractorInput();
|
||||||
|
byte[] target = new byte[TEST_DATA.length];
|
||||||
|
|
||||||
|
input.advancePeekPosition(4);
|
||||||
|
|
||||||
|
input.readFully(target, 0, TEST_DATA.length);
|
||||||
|
|
||||||
|
// Check the read data is correct.
|
||||||
|
assertTrue(Arrays.equals(TEST_DATA, target));
|
||||||
|
assertEquals(TEST_DATA.length, input.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSkip() throws IOException, InterruptedException {
|
||||||
|
FakeDataSource testDataSource = buildDataSource();
|
||||||
|
DefaultExtractorInput input = new DefaultExtractorInput(testDataSource, 0, C.LENGTH_UNBOUNDED);
|
||||||
|
// We expect to perform three skips of three bytes, as setup in buildTestDataSource.
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
assertEquals(3, input.skip(TEST_DATA.length));
|
||||||
|
}
|
||||||
|
// Check we're now indicated that the end of input is reached.
|
||||||
|
int expectedEndOfInput = input.skip(TEST_DATA.length);
|
||||||
|
assertEquals(-1, expectedEndOfInput);
|
||||||
|
}
|
||||||
|
|
||||||
public void testSkipFullyOnce() throws IOException, InterruptedException {
|
public void testSkipFullyOnce() throws IOException, InterruptedException {
|
||||||
// Skip TEST_DATA.
|
// Skip TEST_DATA.
|
||||||
DefaultExtractorInput input = createDefaultExtractorInput();
|
DefaultExtractorInput input = createDefaultExtractorInput();
|
||||||
input.skipFully(TEST_DATA.length);
|
input.skipFully(TEST_DATA.length);
|
||||||
assertEquals(TEST_DATA.length, input.getPosition());
|
assertEquals(TEST_DATA.length, input.getPosition());
|
||||||
|
// Check that we see end of input if we skip again with allowEndOfInput set.
|
||||||
|
boolean result = input.skipFully(1, true);
|
||||||
|
assertFalse(result);
|
||||||
// Check that we fail with EOFException we skip again.
|
// Check that we fail with EOFException we skip again.
|
||||||
try {
|
try {
|
||||||
input.skipFully(1);
|
input.skipFully(1);
|
||||||
@ -180,6 +208,20 @@ public class DefaultExtractorInputTest extends TestCase {
|
|||||||
assertEquals(5 + 4, input.getPosition());
|
assertEquals(5 + 4, input.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testSkipFullyTwicePeeked() throws IOException, InterruptedException {
|
||||||
|
// Skip TEST_DATA.
|
||||||
|
DefaultExtractorInput input = createDefaultExtractorInput();
|
||||||
|
|
||||||
|
input.advancePeekPosition(TEST_DATA.length);
|
||||||
|
|
||||||
|
int halfLength = TEST_DATA.length / 2;
|
||||||
|
input.skipFully(halfLength);
|
||||||
|
assertEquals(halfLength, input.getPosition());
|
||||||
|
|
||||||
|
input.skipFully(TEST_DATA.length - halfLength);
|
||||||
|
assertEquals(TEST_DATA.length, input.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
public void testSkipFullyTooMuch() throws IOException, InterruptedException {
|
public void testSkipFullyTooMuch() throws IOException, InterruptedException {
|
||||||
// Skip more than TEST_DATA. Should fail with an EOFException. Position should not update.
|
// Skip more than TEST_DATA. Should fail with an EOFException. Position should not update.
|
||||||
DefaultExtractorInput input = createDefaultExtractorInput();
|
DefaultExtractorInput input = createDefaultExtractorInput();
|
||||||
@ -190,6 +232,17 @@ public class DefaultExtractorInputTest extends TestCase {
|
|||||||
// Expected.
|
// Expected.
|
||||||
}
|
}
|
||||||
assertEquals(0, input.getPosition());
|
assertEquals(0, input.getPosition());
|
||||||
|
|
||||||
|
// Skip more than TEST_DATA with allowEndOfInput set. Should fail with an EOFException because
|
||||||
|
// the end of input isn't encountered immediately. Position should not update.
|
||||||
|
input = createDefaultExtractorInput();
|
||||||
|
try {
|
||||||
|
input.skipFully(TEST_DATA.length + 1, true);
|
||||||
|
fail();
|
||||||
|
} catch (EOFException e) {
|
||||||
|
// Expected.
|
||||||
|
}
|
||||||
|
assertEquals(0, input.getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSkipFullyWithFailingDataSource() throws IOException, InterruptedException {
|
public void testSkipFullyWithFailingDataSource() throws IOException, InterruptedException {
|
||||||
@ -225,6 +278,29 @@ public class DefaultExtractorInputTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPeekFully() throws IOException, InterruptedException {
|
||||||
|
DefaultExtractorInput input = createDefaultExtractorInput();
|
||||||
|
byte[] target = new byte[TEST_DATA.length];
|
||||||
|
input.peekFully(target, 0, TEST_DATA.length);
|
||||||
|
|
||||||
|
// Check that we read the whole of TEST_DATA.
|
||||||
|
assertTrue(Arrays.equals(TEST_DATA, target));
|
||||||
|
assertEquals(0, input.getPosition());
|
||||||
|
|
||||||
|
// Check that we can read again from the buffer
|
||||||
|
byte[] target2 = new byte[TEST_DATA.length];
|
||||||
|
input.readFully(target2, 0, TEST_DATA.length);
|
||||||
|
assertTrue(Arrays.equals(TEST_DATA, target2));
|
||||||
|
|
||||||
|
// Check that we fail with EOFException if we peek again
|
||||||
|
try {
|
||||||
|
input.peekFully(target, 0, 1);
|
||||||
|
fail();
|
||||||
|
} catch (EOFException e) {
|
||||||
|
// Expected.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static FakeDataSource buildDataSource() throws IOException {
|
private static FakeDataSource buildDataSource() throws IOException {
|
||||||
FakeDataSource.Builder builder = new FakeDataSource.Builder();
|
FakeDataSource.Builder builder = new FakeDataSource.Builder();
|
||||||
builder.appendReadData(Arrays.copyOfRange(TEST_DATA, 0, 3));
|
builder.appendReadData(Arrays.copyOfRange(TEST_DATA, 0, 3));
|
||||||
|
@ -51,58 +51,13 @@ public final class DefaultExtractorInput implements ExtractorInput {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] target, int offset, int length) throws IOException, InterruptedException {
|
public int read(byte[] target, int offset, int length) throws IOException, InterruptedException {
|
||||||
if (Thread.interrupted()) {
|
return internalRead(target, offset, length, true, false, false);
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalBytesRead = 0;
|
|
||||||
|
|
||||||
if (peekBufferLength > 0) {
|
|
||||||
int peekBytes = Math.min(peekBufferLength, length);
|
|
||||||
System.arraycopy(peekBuffer, 0, target, offset, peekBytes);
|
|
||||||
updatePeekBuffer(peekBytes);
|
|
||||||
totalBytesRead += peekBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalBytesRead != length) {
|
|
||||||
int readBytes = dataSource.read(target, offset + totalBytesRead, length - totalBytesRead);
|
|
||||||
if (readBytes == C.RESULT_END_OF_INPUT) {
|
|
||||||
if (totalBytesRead == 0) {
|
|
||||||
return C.RESULT_END_OF_INPUT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
totalBytesRead += readBytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position += totalBytesRead;
|
|
||||||
return totalBytesRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean readFully(byte[] target, int offset, int length, boolean allowEndOfInput)
|
public boolean readFully(byte[] target, int offset, int length, boolean allowEndOfInput)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
int peekBytes = Math.min(peekBufferLength, length);
|
return internalReadFully(target, offset, length, allowEndOfInput, false);
|
||||||
System.arraycopy(peekBuffer, 0, target, offset, peekBytes);
|
|
||||||
offset += peekBytes;
|
|
||||||
int remaining = length - peekBytes;
|
|
||||||
while (remaining > 0) {
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
int bytesRead = dataSource.read(target, offset, remaining);
|
|
||||||
if (bytesRead == C.RESULT_END_OF_INPUT) {
|
|
||||||
if (allowEndOfInput && remaining == length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
offset += bytesRead;
|
|
||||||
remaining -= bytesRead;
|
|
||||||
}
|
|
||||||
updatePeekBuffer(peekBytes);
|
|
||||||
position += length;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -111,71 +66,39 @@ public final class DefaultExtractorInput implements ExtractorInput {
|
|||||||
readFully(target, offset, length, false);
|
readFully(target, offset, length, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int skip(int length) throws IOException, InterruptedException {
|
||||||
|
return internalRead(null, 0, Math.min(SCRATCH_SPACE.length + peekBufferLength, length), true,
|
||||||
|
true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean skipFully(final int length, boolean allowEndOfInput)
|
||||||
|
throws IOException, InterruptedException {
|
||||||
|
return internalReadFully(null, 0, length, allowEndOfInput, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void skipFully(int length) throws IOException, InterruptedException {
|
public void skipFully(int length) throws IOException, InterruptedException {
|
||||||
int peekBytes = Math.min(peekBufferLength, length);
|
skipFully(length, false);
|
||||||
int remaining = length - peekBytes;
|
|
||||||
while (remaining > 0) {
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
int bytesRead = dataSource.read(SCRATCH_SPACE, 0, Math.min(SCRATCH_SPACE.length, remaining));
|
|
||||||
if (bytesRead == C.RESULT_END_OF_INPUT) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
remaining -= bytesRead;
|
|
||||||
}
|
|
||||||
updatePeekBuffer(peekBytes);
|
|
||||||
position += length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void peekFully(byte[] target, int offset, int length)
|
public void peekFully(byte[] target, int offset, int length)
|
||||||
throws IOException, InterruptedException {
|
throws IOException, InterruptedException {
|
||||||
ensureSpaceForPeek(length);
|
advancePeekPosition(length);
|
||||||
int peekBytes = Math.min(peekBufferLength - peekBufferPosition, length);
|
System.arraycopy(peekBuffer, peekBufferPosition - length, target, offset, length);
|
||||||
System.arraycopy(peekBuffer, peekBufferPosition, target, offset, peekBytes);
|
|
||||||
offset += peekBytes;
|
|
||||||
int fillBytes = length - peekBytes;
|
|
||||||
int remaining = fillBytes;
|
|
||||||
int writePosition = peekBufferLength;
|
|
||||||
while (remaining > 0) {
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
int bytesRead = dataSource.read(peekBuffer, writePosition, remaining);
|
|
||||||
if (bytesRead == C.RESULT_END_OF_INPUT) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
System.arraycopy(peekBuffer, writePosition, target, offset, bytesRead);
|
|
||||||
remaining -= bytesRead;
|
|
||||||
writePosition += bytesRead;
|
|
||||||
offset += bytesRead;
|
|
||||||
}
|
|
||||||
peekBufferPosition += length;
|
|
||||||
peekBufferLength += fillBytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void advancePeekPosition(int length) throws IOException, InterruptedException {
|
public void advancePeekPosition(int length) throws IOException, InterruptedException {
|
||||||
ensureSpaceForPeek(length);
|
ensureSpaceForPeek(length);
|
||||||
int peekBytes = Math.min(peekBufferLength - peekBufferPosition, length);
|
|
||||||
int fillBytes = length - peekBytes;
|
|
||||||
int remaining = fillBytes;
|
|
||||||
int writePosition = peekBufferLength;
|
|
||||||
while (remaining > 0) {
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
int bytesRead = dataSource.read(peekBuffer, writePosition, remaining);
|
|
||||||
if (bytesRead == C.RESULT_END_OF_INPUT) {
|
|
||||||
throw new EOFException();
|
|
||||||
}
|
|
||||||
remaining -= bytesRead;
|
|
||||||
writePosition += bytesRead;
|
|
||||||
}
|
|
||||||
peekBufferPosition += length;
|
peekBufferPosition += length;
|
||||||
peekBufferLength += fillBytes;
|
if (peekBufferPosition > peekBufferLength) {
|
||||||
|
readFromDataSource(peekBuffer, peekBufferLength, peekBufferPosition - peekBufferLength,
|
||||||
|
false, false, 0, true);
|
||||||
|
peekBufferLength = peekBufferPosition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -215,4 +138,101 @@ public final class DefaultExtractorInput implements ExtractorInput {
|
|||||||
System.arraycopy(peekBuffer, bytesConsumed, peekBuffer, 0, peekBufferLength);
|
System.arraycopy(peekBuffer, bytesConsumed, peekBuffer, 0, peekBufferLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal read method.
|
||||||
|
*
|
||||||
|
* @see #internalRead(byte[], int, int, boolean, boolean, boolean)
|
||||||
|
*/
|
||||||
|
private boolean internalReadFully(byte[] target, int offset, int length, boolean allowEndOfInput,
|
||||||
|
boolean skip) throws InterruptedException, IOException {
|
||||||
|
return internalRead(target, offset, length, allowEndOfInput, skip, true)
|
||||||
|
!= C.RESULT_END_OF_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal read method.
|
||||||
|
*
|
||||||
|
* @see #readFromPeekBuffer(byte[], int, int, boolean)
|
||||||
|
* @see #readFromDataSource(byte[], int, int, boolean, boolean, int, boolean)
|
||||||
|
*/
|
||||||
|
private int internalRead(byte[] target, int offset, int length, boolean allowEndOfInput,
|
||||||
|
boolean skip, boolean readFully) throws InterruptedException, IOException {
|
||||||
|
int totalBytesRead = readFromPeekBuffer(target, offset, length, skip);
|
||||||
|
totalBytesRead = readFromDataSource(target, offset, length, allowEndOfInput, skip,
|
||||||
|
totalBytesRead, readFully);
|
||||||
|
if (totalBytesRead != C.RESULT_END_OF_INPUT) {
|
||||||
|
position += totalBytesRead;
|
||||||
|
}
|
||||||
|
return totalBytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads from the peek buffer
|
||||||
|
*
|
||||||
|
* @param target A target array into which data should be written.
|
||||||
|
* @param offset The offset into the target array at which to write.
|
||||||
|
* @param length The maximum number of bytes to read from the input.
|
||||||
|
* @param skip If true, instead of reading skip the data
|
||||||
|
* @return The number of bytes read
|
||||||
|
*/
|
||||||
|
private int readFromPeekBuffer(byte[] target, int offset, int length, boolean skip) {
|
||||||
|
if (peekBufferLength == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int peekBytes = Math.min(peekBufferLength, length);
|
||||||
|
if (!skip) {
|
||||||
|
System.arraycopy(peekBuffer, 0, target, offset, peekBytes);
|
||||||
|
}
|
||||||
|
updatePeekBuffer(peekBytes);
|
||||||
|
return peekBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads from the data source
|
||||||
|
*
|
||||||
|
* @param target A target array into which data should be written.
|
||||||
|
* @param offset The offset into the target array at which to write.
|
||||||
|
* @param length The maximum number of bytes to read from the input.
|
||||||
|
* @param returnEOIifNoReadBytes If true on encountering the end of the input having read no data
|
||||||
|
* should result in {@link C#RESULT_END_OF_INPUT} being returned.
|
||||||
|
* @param skip If true, instead of reading skip the data
|
||||||
|
* @param totalBytesRead Number of bytes read until now for the external request
|
||||||
|
* @param readFully If true reads the requested {@code length} in full.
|
||||||
|
* @return The number of bytes read, or {@link C#RESULT_END_OF_INPUT} if the input has ended.
|
||||||
|
* @throws EOFException If the end of input was encountered.
|
||||||
|
* @throws IOException If an error occurs reading from the input.
|
||||||
|
* @throws InterruptedException If the thread is interrupted.
|
||||||
|
*/
|
||||||
|
private int readFromDataSource(byte[] target, int offset, int length,
|
||||||
|
boolean returnEOIifNoReadBytes, boolean skip, int totalBytesRead, boolean readFully)
|
||||||
|
throws InterruptedException, IOException {
|
||||||
|
while (totalBytesRead < length) {
|
||||||
|
if (Thread.interrupted()) {
|
||||||
|
throw new InterruptedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesRead = !skip
|
||||||
|
? dataSource.read(target, offset + totalBytesRead, length - totalBytesRead)
|
||||||
|
: dataSource.read(SCRATCH_SPACE, 0,
|
||||||
|
Math.min(SCRATCH_SPACE.length, length - totalBytesRead));
|
||||||
|
|
||||||
|
if (bytesRead == C.RESULT_END_OF_INPUT) {
|
||||||
|
if (returnEOIifNoReadBytes && totalBytesRead == 0) {
|
||||||
|
return C.RESULT_END_OF_INPUT;
|
||||||
|
}
|
||||||
|
if (readFully) {
|
||||||
|
throw new EOFException();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
totalBytesRead += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readFully) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return totalBytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,33 @@ public interface ExtractorInput {
|
|||||||
*/
|
*/
|
||||||
void readFully(byte[] target, int offset, int length) throws IOException, InterruptedException;
|
void readFully(byte[] target, int offset, int length) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like {@link #read(byte[], int, int)}, except the data is skipped instead of read.
|
||||||
|
*
|
||||||
|
* @param length The maximum number of bytes to skip from the input.
|
||||||
|
* @return The number of bytes skipped, or {@link C#RESULT_END_OF_INPUT} if the input has ended.
|
||||||
|
* @throws IOException If an error occurs reading from the input.
|
||||||
|
* @throws InterruptedException If the thread has been interrupted.
|
||||||
|
*/
|
||||||
|
int skip(int length) throws IOException, InterruptedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like {@link #readFully(byte[], int, int, boolean)}, except the data is skipped instead of read.
|
||||||
|
*
|
||||||
|
* @param length The number of bytes to skip from the input.
|
||||||
|
* @param allowEndOfInput True if encountering the end of the input having skipped no data is
|
||||||
|
* allowed, and should result in {@code false} being returned. False if it should be
|
||||||
|
* considered an error, causing an {@link EOFException} to be thrown.
|
||||||
|
* @return True if the skip was successful. False if the end of the input was encountered having
|
||||||
|
* skipped no data.
|
||||||
|
* @throws EOFException If the end of input was encountered having partially satisfied the skip
|
||||||
|
* (i.e. having skipped at least one byte, but fewer than {@code length}), or if no bytes were
|
||||||
|
* skipped and {@code allowEndOfInput} is false.
|
||||||
|
* @throws IOException If an error occurs reading from the input.
|
||||||
|
* @throws InterruptedException If the thread has been interrupted.
|
||||||
|
*/
|
||||||
|
boolean skipFully(int length, boolean allowEndOfInput) throws IOException, InterruptedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link #readFully(byte[], int, int)}, except the data is skipped instead of read.
|
* Like {@link #readFully(byte[], int, int)}, except the data is skipped instead of read.
|
||||||
* <p>
|
* <p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user