From 70ba4b197c7a54d89c49b6959dc65ca616a92c2f Mon Sep 17 00:00:00 2001 From: kimvde Date: Mon, 9 Dec 2019 18:42:55 +0000 Subject: [PATCH] Add peek() method to ExtractorInput PiperOrigin-RevId: 284586799 --- .../extractor/DefaultExtractorInput.java | 31 ++- .../exoplayer2/extractor/ExtractorInput.java | 44 ++-- .../extractor/DefaultExtractorInputTest.java | 226 +++++++++++++++--- .../testutil/FakeExtractorInput.java | 46 ++-- 4 files changed, 281 insertions(+), 66 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java index 450cca42b0..c6f1129da8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorInput.java @@ -58,7 +58,9 @@ public final class DefaultExtractorInput implements ExtractorInput { public int read(byte[] target, int offset, int length) throws IOException, InterruptedException { int bytesRead = readFromPeekBuffer(target, offset, length); if (bytesRead == 0) { - bytesRead = readFromDataSource(target, offset, length, 0, true); + bytesRead = + readFromDataSource( + target, offset, length, /* bytesAlreadyRead= */ 0, /* allowEndOfInput= */ true); } commitBytesRead(bytesRead); return bytesRead; @@ -110,6 +112,31 @@ public final class DefaultExtractorInput implements ExtractorInput { skipFully(length, false); } + @Override + public int peek(byte[] target, int offset, int length) throws IOException, InterruptedException { + ensureSpaceForPeek(length); + int peekBufferRemainingBytes = peekBufferLength - peekBufferPosition; + int bytesPeeked; + if (peekBufferRemainingBytes == 0) { + bytesPeeked = + readFromDataSource( + peekBuffer, + peekBufferPosition, + length, + /* bytesAlreadyRead= */ 0, + /* allowEndOfInput= */ true); + if (bytesPeeked == C.RESULT_END_OF_INPUT) { + return C.RESULT_END_OF_INPUT; + } + peekBufferLength += bytesPeeked; + } else { + bytesPeeked = Math.min(length, peekBufferRemainingBytes); + } + System.arraycopy(peekBuffer, peekBufferPosition, target, offset, bytesPeeked); + peekBufferPosition += bytesPeeked; + return bytesPeeked; + } + @Override public boolean peekFully(byte[] target, int offset, int length, boolean allowEndOfInput) throws IOException, InterruptedException { @@ -201,7 +228,7 @@ public final class DefaultExtractorInput implements ExtractorInput { } /** - * Reads from the peek buffer + * 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. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java index 461b059bad..8e5d6f0448 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ExtractorInput.java @@ -27,19 +27,19 @@ import java.io.InputStream; * for more info about each mode. * * * *

{@link InputStream}-like methods

* - *

The {@code read()} and {@code skip()} methods provide {@link InputStream}-like byte-level - * access operations. The {@code length} parameter is a maximum, and each method returns the number - * of bytes actually processed. This may be less than {@code length} because the end of the input - * was reached, or the method was interrupted, or the operation was aborted early for another - * reason. + *

The {@code read()/peek()} and {@code skip()} methods provide {@link InputStream}-like + * byte-level access operations. The {@code length} parameter is a maximum, and each method returns + * the number of bytes actually processed. This may be less than {@code length} because the end of + * the input was reached, or the method was interrupted, or the operation was aborted early for + * another reason. * *

Block-based methods

* @@ -102,7 +102,8 @@ public interface ExtractorInput { throws IOException, InterruptedException; /** - * Equivalent to {@code readFully(target, offset, length, false)}. + * Equivalent to {@link #readFully(byte[], int, int, boolean) readFully(target, offset, length, + * false)}. * * @param target A target array into which data should be written. * @param offset The offset into the target array at which to write. @@ -155,8 +156,11 @@ public interface ExtractorInput { void skipFully(int length) throws IOException, InterruptedException; /** - * Peeks {@code length} bytes from the peek position, writing them into {@code target} at index - * {@code offset}. The current read position is left unchanged. + * Peeks up to {@code length} bytes from the peek position. The current read position is left + * unchanged. + * + *

This method blocks until at least one byte of data can be peeked, the end of the input is + * detected, or an exception is thrown. * *

Calling {@link #resetPeekPosition()} resets the peek position to equal the current read * position, so the caller can peek the same data again. Reading or skipping also resets the peek @@ -164,6 +168,18 @@ public interface ExtractorInput { * * @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 peek from the input. + * @return The number of bytes peeked, or {@link C#RESULT_END_OF_INPUT} if the input has ended. + * @throws IOException If an error occurs peeking from the input. + * @throws InterruptedException If the thread has been interrupted. + */ + int peek(byte[] target, int offset, int length) throws IOException, InterruptedException; + + /** + * Like {@link #peek(byte[], int, int)}, but peeks the requested {@code length} in full. + * + * @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 number of bytes to peek from the input. * @param allowEndOfInput True if encountering the end of the input having peeked no data is * allowed, and should result in {@code false} being returned. False if it should be @@ -181,12 +197,8 @@ public interface ExtractorInput { throws IOException, InterruptedException; /** - * Peeks {@code length} bytes from the peek position, writing them into {@code target} at index - * {@code offset}. The current read position is left unchanged. - *

- * Calling {@link #resetPeekPosition()} resets the peek position to equal the current read - * position, so the caller can peek the same data again. Reading and skipping also reset the peek - * position. + * Equivalent to {@link #peekFully(byte[], int, int, boolean) peekFully(target, offset, length, + * false)}. * * @param target A target array into which data should be written. * @param offset The offset into the target array at which to write. diff --git a/library/core/src/test/java/com/google/android/exoplayer2/extractor/DefaultExtractorInputTest.java b/library/core/src/test/java/com/google/android/exoplayer2/extractor/DefaultExtractorInputTest.java index 6dbec3ecf4..ccc806fe61 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/extractor/DefaultExtractorInputTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/extractor/DefaultExtractorInputTest.java @@ -49,7 +49,7 @@ public class DefaultExtractorInputTest { } @Test - public void testRead() throws Exception { + public void testReadMultipleTimes() throws Exception { DefaultExtractorInput input = createDefaultExtractorInput(); byte[] target = new byte[TEST_DATA.length]; // We expect to perform three reads of three bytes, as setup in buildTestDataSource. @@ -60,39 +60,70 @@ public class DefaultExtractorInputTest { assertThat(bytesRead).isEqualTo(6); bytesRead += input.read(target, 6, TEST_DATA.length); assertThat(bytesRead).isEqualTo(9); - // Check the read data is correct. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); - // Check we're now indicated that the end of input is reached. - int expectedEndOfInput = input.read(target, 0, TEST_DATA.length); - assertThat(expectedEndOfInput).isEqualTo(RESULT_END_OF_INPUT); + assertThat(input.getPosition()).isEqualTo(9); + assertThat(TEST_DATA).isEqualTo(target); } @Test - public void testReadPeeked() throws Exception { + public void testReadAlreadyPeeked() throws Exception { DefaultExtractorInput input = createDefaultExtractorInput(); byte[] target = new byte[TEST_DATA.length]; input.advancePeekPosition(TEST_DATA.length); + int bytesRead = input.read(target, 0, TEST_DATA.length - 1); + assertThat(bytesRead).isEqualTo(TEST_DATA.length - 1); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length - 1); + assertThat(Arrays.copyOf(TEST_DATA, TEST_DATA.length - 1)) + .isEqualTo(Arrays.copyOf(target, TEST_DATA.length - 1)); + } + + @Test + public void testReadPartiallyPeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + input.advancePeekPosition(TEST_DATA.length - 1); int bytesRead = input.read(target, 0, TEST_DATA.length); - assertThat(bytesRead).isEqualTo(TEST_DATA.length); - // Check the read data is correct. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); + assertThat(bytesRead).isEqualTo(TEST_DATA.length - 1); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length - 1); + assertThat(Arrays.copyOf(TEST_DATA, TEST_DATA.length - 1)) + .isEqualTo(Arrays.copyOf(target, TEST_DATA.length - 1)); } @Test - public void testReadMoreDataPeeked() throws Exception { + public void testReadEndOfInputBeforeFirstByteRead() throws Exception { DefaultExtractorInput input = createDefaultExtractorInput(); byte[] target = new byte[TEST_DATA.length]; - input.advancePeekPosition(TEST_DATA.length); + input.skipFully(TEST_DATA.length); + int bytesRead = input.read(target, 0, TEST_DATA.length); - int bytesRead = input.read(target, 0, TEST_DATA.length + 1); - assertThat(bytesRead).isEqualTo(TEST_DATA.length); + assertThat(bytesRead).isEqualTo(RESULT_END_OF_INPUT); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); + } - // Check the read data is correct. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); + @Test + public void testReadEndOfInputAfterFirstByteRead() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + input.skipFully(TEST_DATA.length - 1); + int bytesRead = input.read(target, 0, TEST_DATA.length); + + assertThat(bytesRead).isEqualTo(1); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); + } + + @Test + public void testReadZeroLength() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + int bytesRead = input.read(target, /* offset= */ 0, /* length= */ 0); + + assertThat(bytesRead).isEqualTo(0); } @Test @@ -101,7 +132,7 @@ public class DefaultExtractorInputTest { byte[] target = new byte[TEST_DATA.length]; input.readFully(target, 0, TEST_DATA.length); // Check that we read the whole of TEST_DATA. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); + assertThat(TEST_DATA).isEqualTo(target); assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); // Check that we see end of input if we read again with allowEndOfInput set. boolean result = input.readFully(target, 0, 1, true); @@ -121,11 +152,11 @@ public class DefaultExtractorInputTest { DefaultExtractorInput input = createDefaultExtractorInput(); byte[] target = new byte[5]; input.readFully(target, 0, 5); - assertThat(Arrays.equals(copyOf(TEST_DATA, 5), target)).isTrue(); + assertThat(copyOf(TEST_DATA, 5)).isEqualTo(target); assertThat(input.getPosition()).isEqualTo(5); target = new byte[4]; input.readFully(target, 0, 4); - assertThat(Arrays.equals(copyOfRange(TEST_DATA, 5, 9), target)).isTrue(); + assertThat(copyOfRange(TEST_DATA, 5, 9)).isEqualTo(target); assertThat(input.getPosition()).isEqualTo(5 + 4); } @@ -180,27 +211,23 @@ public class DefaultExtractorInputTest { input.readFully(target, 0, TEST_DATA.length); // Check the read data is correct. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); + assertThat(TEST_DATA).isEqualTo(target); assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); } @Test - public void testSkip() throws Exception { - FakeDataSource testDataSource = buildDataSource(); - DefaultExtractorInput input = new DefaultExtractorInput(testDataSource, 0, C.LENGTH_UNSET); + public void testSkipMultipleTimes() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); // We expect to perform three skips of three bytes, as setup in buildTestDataSource. for (int i = 0; i < 3; i++) { assertThat(input.skip(TEST_DATA.length)).isEqualTo(3); } - // Check we're now indicated that the end of input is reached. - int expectedEndOfInput = input.skip(TEST_DATA.length); - assertThat(expectedEndOfInput).isEqualTo(RESULT_END_OF_INPUT); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); } @Test public void testLargeSkip() throws Exception { - FakeDataSource testDataSource = buildLargeDataSource(); - DefaultExtractorInput input = new DefaultExtractorInput(testDataSource, 0, C.LENGTH_UNSET); + DefaultExtractorInput input = createDefaultExtractorInput(); // Check that skipping the entire data source succeeds. int bytesToSkip = LARGE_TEST_DATA_LENGTH; while (bytesToSkip > 0) { @@ -208,6 +235,59 @@ public class DefaultExtractorInputTest { } } + @Test + public void testSkipAlreadyPeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + + input.advancePeekPosition(TEST_DATA.length); + int bytesSkipped = input.skip(TEST_DATA.length - 1); + + assertThat(bytesSkipped).isEqualTo(TEST_DATA.length - 1); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length - 1); + } + + @Test + public void testSkipPartiallyPeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + + input.advancePeekPosition(TEST_DATA.length - 1); + int bytesSkipped = input.skip(TEST_DATA.length); + + assertThat(bytesSkipped).isEqualTo(TEST_DATA.length - 1); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length - 1); + } + + @Test + public void testSkipEndOfInputBeforeFirstByteSkipped() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + + input.skipFully(TEST_DATA.length); + int bytesSkipped = input.skip(TEST_DATA.length); + + assertThat(bytesSkipped).isEqualTo(RESULT_END_OF_INPUT); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); + } + + @Test + public void testSkipEndOfInputAfterFirstByteSkipped() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + + input.skipFully(TEST_DATA.length - 1); + int bytesSkipped = input.skip(TEST_DATA.length); + + assertThat(bytesSkipped).isEqualTo(1); + assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); + } + + @Test + public void testSkipZeroLength() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + + int bytesRead = input.skip(0); + + assertThat(bytesRead).isEqualTo(0); + } + @Test public void testSkipFullyOnce() throws Exception { // Skip TEST_DATA. @@ -309,6 +389,86 @@ public class DefaultExtractorInputTest { } } + @Test + public void testPeekMultipleTimes() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + // We expect to perform three peeks of three bytes, as setup in buildTestDataSource. + int bytesPeeked = 0; + bytesPeeked += input.peek(target, 0, TEST_DATA.length); + assertThat(bytesPeeked).isEqualTo(3); + bytesPeeked += input.peek(target, 3, TEST_DATA.length); + assertThat(bytesPeeked).isEqualTo(6); + bytesPeeked += input.peek(target, 6, TEST_DATA.length); + assertThat(bytesPeeked).isEqualTo(9); + assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length); + assertThat(TEST_DATA).isEqualTo(target); + } + + @Test + public void testPeekAlreadyPeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + input.advancePeekPosition(TEST_DATA.length); + input.resetPeekPosition(); + int bytesPeeked = input.peek(target, 0, TEST_DATA.length - 1); + + assertThat(bytesPeeked).isEqualTo(TEST_DATA.length - 1); + assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length - 1); + assertThat(Arrays.copyOf(TEST_DATA, TEST_DATA.length - 1)) + .isEqualTo(Arrays.copyOf(target, TEST_DATA.length - 1)); + } + + @Test + public void testPeekPartiallyPeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + input.advancePeekPosition(TEST_DATA.length - 1); + input.resetPeekPosition(); + int bytesPeeked = input.peek(target, 0, TEST_DATA.length); + + assertThat(bytesPeeked).isEqualTo(TEST_DATA.length - 1); + assertThat(Arrays.copyOf(TEST_DATA, TEST_DATA.length - 1)) + .isEqualTo(Arrays.copyOf(target, TEST_DATA.length - 1)); + } + + @Test + public void testPeekEndOfInputBeforeFirstBytePeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + input.advancePeekPosition(TEST_DATA.length); + int bytesPeeked = input.peek(target, 0, TEST_DATA.length); + + assertThat(bytesPeeked).isEqualTo(RESULT_END_OF_INPUT); + assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length); + } + + @Test + public void testPeekEndOfInputAfterFirstBytePeeked() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + input.advancePeekPosition(TEST_DATA.length - 1); + int bytesPeeked = input.peek(target, 0, TEST_DATA.length); + + assertThat(bytesPeeked).isEqualTo(1); + assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length); + } + + @Test + public void testPeekZeroLength() throws Exception { + DefaultExtractorInput input = createDefaultExtractorInput(); + byte[] target = new byte[TEST_DATA.length]; + + int bytesPeeked = input.peek(target, /* offset= */ 0, /* length= */ 0); + + assertThat(bytesPeeked).isEqualTo(0); + } + @Test public void testPeekFully() throws Exception { DefaultExtractorInput input = createDefaultExtractorInput(); @@ -316,14 +476,14 @@ public class DefaultExtractorInputTest { input.peekFully(target, 0, TEST_DATA.length); // Check that we read the whole of TEST_DATA. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); + assertThat(TEST_DATA).isEqualTo(target); assertThat(input.getPosition()).isEqualTo(0); assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length); // Check that we can read again from the buffer byte[] target2 = new byte[TEST_DATA.length]; input.readFully(target2, 0, TEST_DATA.length); - assertThat(Arrays.equals(TEST_DATA, target2)).isTrue(); + assertThat(TEST_DATA).isEqualTo(target2); assertThat(input.getPosition()).isEqualTo(TEST_DATA.length); assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length); @@ -350,7 +510,7 @@ public class DefaultExtractorInputTest { input.peekFully(target, /* offset= */ 0, /* length= */ TEST_DATA.length); assertThat(input.getPeekPosition()).isEqualTo(TEST_DATA.length); - assertThat(Arrays.equals(TEST_DATA, Arrays.copyOf(target, TEST_DATA.length))).isTrue(); + assertThat(TEST_DATA).isEqualTo(Arrays.copyOf(target, TEST_DATA.length)); } @Test @@ -360,14 +520,14 @@ public class DefaultExtractorInputTest { input.peekFully(target, 0, TEST_DATA.length); // Check that we read the whole of TEST_DATA. - assertThat(Arrays.equals(TEST_DATA, target)).isTrue(); + assertThat(TEST_DATA).isEqualTo(target); assertThat(input.getPosition()).isEqualTo(0); // Check that we can peek again after resetting. input.resetPeekPosition(); byte[] target2 = new byte[TEST_DATA.length]; input.peekFully(target2, 0, TEST_DATA.length); - assertThat(Arrays.equals(TEST_DATA, target2)).isTrue(); + assertThat(TEST_DATA).isEqualTo(target2); // Check that we fail with EOFException if we peek past the end of the input. try { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorInput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorInput.java index 443ffdb12c..7323cfd0fe 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorInput.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorInput.java @@ -65,7 +65,8 @@ public final class FakeExtractorInput implements ExtractorInput { private int readPosition; private int peekPosition; - private final SparseBooleanArray partiallySatisfiedTargetPositions; + private final SparseBooleanArray partiallySatisfiedTargetReadPositions; + private final SparseBooleanArray partiallySatisfiedTargetPeekPositions; private final SparseBooleanArray failedReadPositions; private final SparseBooleanArray failedPeekPositions; @@ -75,7 +76,8 @@ public final class FakeExtractorInput implements ExtractorInput { this.simulateUnknownLength = simulateUnknownLength; this.simulatePartialReads = simulatePartialReads; this.simulateIOErrors = simulateIOErrors; - partiallySatisfiedTargetPositions = new SparseBooleanArray(); + partiallySatisfiedTargetReadPositions = new SparseBooleanArray(); + partiallySatisfiedTargetPeekPositions = new SparseBooleanArray(); failedReadPositions = new SparseBooleanArray(); failedPeekPositions = new SparseBooleanArray(); } @@ -84,7 +86,8 @@ public final class FakeExtractorInput implements ExtractorInput { public void reset() { readPosition = 0; peekPosition = 0; - partiallySatisfiedTargetPositions.clear(); + partiallySatisfiedTargetReadPositions.clear(); + partiallySatisfiedTargetPeekPositions.clear(); failedReadPositions.clear(); failedPeekPositions.clear(); } @@ -104,7 +107,7 @@ public final class FakeExtractorInput implements ExtractorInput { @Override public int read(byte[] target, int offset, int length) throws IOException { checkIOException(readPosition, failedReadPositions); - length = getReadLength(length); + length = getLengthToRead(readPosition, length, partiallySatisfiedTargetReadPositions); return readFullyInternal(target, offset, length, true) ? length : C.RESULT_END_OF_INPUT; } @@ -123,7 +126,7 @@ public final class FakeExtractorInput implements ExtractorInput { @Override public int skip(int length) throws IOException { checkIOException(readPosition, failedReadPositions); - length = getReadLength(length); + length = getLengthToRead(readPosition, length, partiallySatisfiedTargetReadPositions); return skipFullyInternal(length, true) ? length : C.RESULT_END_OF_INPUT; } @@ -138,16 +141,18 @@ public final class FakeExtractorInput implements ExtractorInput { skipFully(length, false); } + @Override + public int peek(byte[] target, int offset, int length) throws IOException { + checkIOException(peekPosition, failedPeekPositions); + length = getLengthToRead(peekPosition, length, partiallySatisfiedTargetPeekPositions); + return peekFullyInternal(target, offset, length, true) ? length : C.RESULT_END_OF_INPUT; + } + @Override public boolean peekFully(byte[] target, int offset, int length, boolean allowEndOfInput) throws IOException { checkIOException(peekPosition, failedPeekPositions); - if (!checkXFully(allowEndOfInput, peekPosition, length)) { - return false; - } - System.arraycopy(data, peekPosition, target, offset, length); - peekPosition += length; - return true; + return peekFullyInternal(target, offset, length, allowEndOfInput); } @Override @@ -221,18 +226,19 @@ public final class FakeExtractorInput implements ExtractorInput { return true; } - private int getReadLength(int requestedLength) { - if (readPosition == data.length) { + private int getLengthToRead( + int position, int requestedLength, SparseBooleanArray partiallySatisfiedTargetPositions) { + if (position == data.length) { // If the requested length is non-zero, the end of the input will be read. return requestedLength == 0 ? 0 : Integer.MAX_VALUE; } - int targetPosition = readPosition + requestedLength; + int targetPosition = position + requestedLength; if (simulatePartialReads && requestedLength > 1 && !partiallySatisfiedTargetPositions.get(targetPosition)) { partiallySatisfiedTargetPositions.put(targetPosition, true); return 1; } - return Math.min(requestedLength, data.length - readPosition); + return Math.min(requestedLength, data.length - position); } private boolean readFullyInternal(byte[] target, int offset, int length, boolean allowEndOfInput) @@ -255,6 +261,16 @@ public final class FakeExtractorInput implements ExtractorInput { return true; } + private boolean peekFullyInternal(byte[] target, int offset, int length, boolean allowEndOfInput) + throws EOFException { + if (!checkXFully(allowEndOfInput, peekPosition, length)) { + return false; + } + System.arraycopy(data, peekPosition, target, offset, length); + peekPosition += length; + return true; + } + /** * Builder of {@link FakeExtractorInput} instances. */