diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java index 022b5b4c754..e9842611455 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/BinarySearchSeeker.java @@ -42,31 +42,16 @@ public abstract class BinarySearchSeeker { protected interface TimestampSeeker { /** - * Searches for a given timestamp from the input. + * Searches a limited window of the provided input for a target timestamp. The size of the + * window is implementation specific, but should be small enough such that it's reasonable for + * multiple such reads to occur during a seek operation. * - *
Given a target timestamp and an input stream, this seeker will try to read up to a range - * of {@code searchRangeBytes} bytes from that input, look for all available timestamps from all - * frames in that range, compare those with the target timestamp, and return one of the {@link - * TimestampSearchResult}. - * - * @param input The {@link ExtractorInput} from which data should be read. - * @param targetTimestamp The target timestamp that we are looking for. - * @param outputFrameHolder If {@link TimestampSearchResult#RESULT_TARGET_TIMESTAMP_FOUND} is + * @param input The {@link ExtractorInput} from which data should be peeked. + * @param targetTimestamp The target timestamp. + * @param outputFrameHolder If {@link TimestampSearchResult#TYPE_TARGET_TIMESTAMP_FOUND} is * returned, this holder may be updated to hold the extracted frame that contains the target * frame/sample associated with the target timestamp. - * @return A {@link TimestampSearchResult}, that includes a {@link TimestampSearchResult#result} - * value, and other necessary info: - *
Note that when this value is returned from {@link @@ -509,7 +498,7 @@ public static TimestampSearchResult underestimatedResult( */ public static TimestampSearchResult targetFoundResult(long resultBytePosition) { return new TimestampSearchResult( - RESULT_TARGET_TIMESTAMP_FOUND, C.TIME_UNSET, resultBytePosition); + TYPE_TARGET_TIMESTAMP_FOUND, C.TIME_UNSET, resultBytePosition); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java index e8c207f75d7..1180dd486e9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsBinarySearchSeeker.java @@ -53,10 +53,9 @@ public PsBinarySearchSeeker( /** * A seeker that looks for a given SCR timestamp at a given position in a PS stream. * - *
Given a SCR timestamp, and a position within a PS stream, this seeker will try to read a - * range of up to {@link #TIMESTAMP_SEARCH_BYTES} bytes from that stream position, look for all - * packs in that range, and then compare the SCR timestamps (if available) of these packets vs the - * target timestamp. + *
Given a SCR timestamp, and a position within a PS stream, this seeker will peek up to {@link + * #TIMESTAMP_SEARCH_BYTES} bytes from that stream position, look for all packs in that range, and + * then compare the SCR timestamps (if available) of these packets to the target timestamp. */ private static final class PsScrSeeker implements TimestampSeeker { @@ -73,10 +72,10 @@ public TimestampSearchResult searchForTimestamp( ExtractorInput input, long targetTimestamp, OutputFrameHolder outputFrameHolder) throws IOException, InterruptedException { long inputPosition = input.getPosition(); - int bytesToRead = - (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength() - input.getPosition()); - packetBuffer.reset(bytesToRead); - input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); + int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength() - inputPosition); + + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch); + packetBuffer.reset(bytesToSearch); return searchForScrValueInBuffer(packetBuffer, targetTimestamp, inputPosition); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java index 3b522062358..077a35f4a73 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/PsDurationReader.java @@ -38,7 +38,7 @@ */ /* package */ final class PsDurationReader { - private static final int DURATION_READ_BYTES = 20000; + private static final int TIMESTAMP_SEARCH_BYTES = 20000; private final TimestampAdjuster scrTimestampAdjuster; private final ParsableByteArray packetBuffer; @@ -56,7 +56,7 @@ firstScrValue = C.TIME_UNSET; lastScrValue = C.TIME_UNSET; durationUs = C.TIME_UNSET; - packetBuffer = new ParsableByteArray(DURATION_READ_BYTES); + packetBuffer = new ParsableByteArray(TIMESTAMP_SEARCH_BYTES); } /** Returns true if a PS duration has been read. */ @@ -136,16 +136,16 @@ private int finishReadDuration(ExtractorInput input) { private int readFirstScrValue(ExtractorInput input, PositionHolder seekPositionHolder) throws IOException, InterruptedException { - if (input.getPosition() != 0) { - seekPositionHolder.position = 0; + int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength()); + int searchStartPosition = 0; + if (input.getPosition() != searchStartPosition) { + seekPositionHolder.position = searchStartPosition; return Extractor.RESULT_SEEK; } - int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); input.resetPeekPosition(); - input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); - packetBuffer.setPosition(0); - packetBuffer.setLimit(bytesToRead); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch); + packetBuffer.reset(bytesToSearch); firstScrValue = readFirstScrValueFromBuffer(packetBuffer); isFirstScrValueRead = true; @@ -172,17 +172,17 @@ private long readFirstScrValueFromBuffer(ParsableByteArray packetBuffer) { private int readLastScrValue(ExtractorInput input, PositionHolder seekPositionHolder) throws IOException, InterruptedException { - int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); - long bufferStartStreamPosition = input.getLength() - bytesToRead; - if (input.getPosition() != bufferStartStreamPosition) { - seekPositionHolder.position = bufferStartStreamPosition; + long inputLength = input.getLength(); + int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, inputLength); + long searchStartPosition = inputLength - bytesToSearch; + if (input.getPosition() != searchStartPosition) { + seekPositionHolder.position = searchStartPosition; return Extractor.RESULT_SEEK; } input.resetPeekPosition(); - input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); - packetBuffer.setPosition(0); - packetBuffer.setLimit(bytesToRead); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch); + packetBuffer.reset(bytesToSearch); lastScrValue = readLastScrValueFromBuffer(packetBuffer); isLastScrValueRead = true; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java index 29aa0d55d27..e9b051592de 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java @@ -33,10 +33,8 @@ /* package */ final class TsBinarySearchSeeker extends BinarySearchSeeker { private static final long SEEK_TOLERANCE_US = 100_000; - private static final int MINIMUM_SEARCH_RANGE_BYTES = TsExtractor.TS_PACKET_SIZE * 5; - private static final int TIMESTAMP_SEARCH_PACKETS = 200; - private static final int TIMESTAMP_SEARCH_BYTES = - TsExtractor.TS_PACKET_SIZE * TIMESTAMP_SEARCH_PACKETS; + private static final int MINIMUM_SEARCH_RANGE_BYTES = 5 * TsExtractor.TS_PACKET_SIZE; + private static final int TIMESTAMP_SEARCH_BYTES = 200 * TsExtractor.TS_PACKET_SIZE; public TsBinarySearchSeeker( TimestampAdjuster pcrTimestampAdjuster, long streamDurationUs, long inputLength, int pcrPid) { @@ -56,10 +54,10 @@ public TsBinarySearchSeeker( * A {@link TimestampSeeker} implementation that looks for a given PCR timestamp at a given * position in a TS stream. * - *
Given a PCR timestamp, and a position within a TS stream, this seeker will try to read up to - * {@link #TIMESTAMP_SEARCH_PACKETS} TS packets from that stream position, look for all packet - * with PID equals to PCR_PID, and then compare the PCR timestamps (if available) of these packets - * vs the target timestamp. + *
Given a PCR timestamp, and a position within a TS stream, this seeker will peek up to {@link + * #TIMESTAMP_SEARCH_BYTES} from that stream position, look for all packets with PID equal to + * PCR_PID, and then compare the PCR timestamps (if available) of these packets to the target + * timestamp. */ private static final class TsPcrSeeker implements TimestampSeeker { @@ -78,10 +76,10 @@ public TimestampSearchResult searchForTimestamp( ExtractorInput input, long targetTimestamp, OutputFrameHolder outputFrameHolder) throws IOException, InterruptedException { long inputPosition = input.getPosition(); - int bytesToRead = - (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength() - input.getPosition()); - packetBuffer.reset(bytesToRead); - input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); + int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength() - inputPosition); + + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch); + packetBuffer.reset(bytesToSearch); return searchForPcrValueInBuffer(packetBuffer, targetTimestamp, inputPosition); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java index 350337cc860..44010833245 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java @@ -35,8 +35,7 @@ */ /* package */ final class TsDurationReader { - private static final int DURATION_READ_PACKETS = 200; - private static final int DURATION_READ_BYTES = TsExtractor.TS_PACKET_SIZE * DURATION_READ_PACKETS; + private static final int TIMESTAMP_SEARCH_BYTES = 200 * TsExtractor.TS_PACKET_SIZE; private final TimestampAdjuster pcrTimestampAdjuster; private final ParsableByteArray packetBuffer; @@ -54,7 +53,7 @@ firstPcrValue = C.TIME_UNSET; lastPcrValue = C.TIME_UNSET; durationUs = C.TIME_UNSET; - packetBuffer = new ParsableByteArray(DURATION_READ_BYTES); + packetBuffer = new ParsableByteArray(TIMESTAMP_SEARCH_BYTES); } /** Returns true if a TS duration has been read. */ @@ -124,16 +123,16 @@ private int finishReadDuration(ExtractorInput input) { private int readFirstPcrValue(ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid) throws IOException, InterruptedException { - if (input.getPosition() != 0) { - seekPositionHolder.position = 0; + int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, input.getLength()); + int searchStartPosition = 0; + if (input.getPosition() != searchStartPosition) { + seekPositionHolder.position = searchStartPosition; return Extractor.RESULT_SEEK; } - int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); input.resetPeekPosition(); - input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); - packetBuffer.setPosition(0); - packetBuffer.setLimit(bytesToRead); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch); + packetBuffer.reset(bytesToSearch); firstPcrValue = readFirstPcrValueFromBuffer(packetBuffer, pcrPid); isFirstPcrValueRead = true; @@ -159,17 +158,17 @@ private long readFirstPcrValueFromBuffer(ParsableByteArray packetBuffer, int pcr private int readLastPcrValue(ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid) throws IOException, InterruptedException { - int bytesToRead = (int) Math.min(DURATION_READ_BYTES, input.getLength()); - long bufferStartStreamPosition = input.getLength() - bytesToRead; - if (input.getPosition() != bufferStartStreamPosition) { - seekPositionHolder.position = bufferStartStreamPosition; + long inputLength = input.getLength(); + int bytesToSearch = (int) Math.min(TIMESTAMP_SEARCH_BYTES, inputLength); + long searchStartPosition = inputLength - bytesToSearch; + if (input.getPosition() != searchStartPosition) { + seekPositionHolder.position = searchStartPosition; return Extractor.RESULT_SEEK; } input.resetPeekPosition(); - input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToRead); - packetBuffer.setPosition(0); - packetBuffer.setLimit(bytesToRead); + input.peekFully(packetBuffer.data, /* offset= */ 0, bytesToSearch); + packetBuffer.reset(bytesToSearch); lastPcrValue = readLastPcrValueFromBuffer(packetBuffer, pcrPid); isLastPcrValueRead = true;