diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3b2aa2e158..bffb735a47 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -15,9 +15,6 @@ ([#7985](https://github.com/google/ExoPlayer/issues/7985)). * Fix NPE in `TextRenderer` when playing content with a single subtitle buffer ([#8017](https://github.com/google/ExoPlayer/issues/8017)). -* UI: - * Do not require subtitleButton in custom layouts of StyledPlayerView - ([#7962](https://github.com/google/ExoPlayer/issues/7962)). * Audio: * Fix the default audio sink position not advancing correctly when using `AudioTrack`-based speed adjustment @@ -29,7 +26,12 @@ ([#7949](https://github.com/google/ExoPlayer/issues/7949)). * Fix regression for Ogg files with packets that span multiple pages ([#7992](https://github.com/google/ExoPlayer/issues/7992)). + * Add TS extractor parameter to configure the number of bytes in which + to search for a timestamp to determine the duration and to seek. + ([#7988](https://github.com/google/ExoPlayer/issues/7988)). * UI + * Do not require subtitleButton in custom layouts of StyledPlayerView + ([#7962](https://github.com/google/ExoPlayer/issues/7962)). * Add the option to sort tracks by `Format` in `TrackSelectionView` and `TrackSelectionDialogBuilder` ([#7709](https://github.com/google/ExoPlayer/issues/7709)). diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java index 2eba1b1cca..2068853d9e 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/DefaultExtractorsFactory.java @@ -131,9 +131,11 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { @Mp3Extractor.Flags private int mp3Flags; @TsExtractor.Mode private int tsMode; @DefaultTsPayloadReaderFactory.Flags private int tsFlags; + private int tsTimestampSearchBytes; public DefaultExtractorsFactory() { tsMode = TsExtractor.MODE_SINGLE_PMT; + tsTimestampSearchBytes = TsExtractor.DEFAULT_TIMESTAMP_SEARCH_BYTES; } /** @@ -246,7 +248,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { /** * Sets the mode for {@link TsExtractor} instances created by the factory. * - * @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory) + * @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory, int) * @param mode The mode to use. * @return The factory, for convenience. */ @@ -269,6 +271,20 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { return this; } + /** + * Sets the number of bytes searched to find a timestamp for {@link TsExtractor} instances created + * by the factory. + * + * @see TsExtractor#TsExtractor(int, TimestampAdjuster, TsPayloadReader.Factory, int) + * @param timestampSearchBytes The number of search bytes to use. + * @return The factory, for convenience. + */ + public synchronized DefaultExtractorsFactory setTsExtractorTimestampSearchBytes( + int timestampSearchBytes) { + tsTimestampSearchBytes = timestampSearchBytes; + return this; + } + @Override public synchronized Extractor[] createExtractors() { return createExtractors(Uri.EMPTY, new HashMap<>()); @@ -361,7 +377,7 @@ public final class DefaultExtractorsFactory implements ExtractorsFactory { extractors.add(new PsExtractor()); break; case FileTypes.TS: - extractors.add(new TsExtractor(tsMode, tsFlags)); + extractors.add(new TsExtractor(tsMode, tsFlags, tsTimestampSearchBytes)); break; case FileTypes.WAV: extractors.add(new WavExtractor()); diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java index 8286189780..fa9792079c 100644 --- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java +++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsBinarySearchSeeker.java @@ -37,13 +37,16 @@ import java.io.IOException; private static final long SEEK_TOLERANCE_US = 100_000; private static final int MINIMUM_SEARCH_RANGE_BYTES = 5 * TsExtractor.TS_PACKET_SIZE; - private static final int TIMESTAMP_SEARCH_BYTES = 600 * TsExtractor.TS_PACKET_SIZE; public TsBinarySearchSeeker( - TimestampAdjuster pcrTimestampAdjuster, long streamDurationUs, long inputLength, int pcrPid) { + TimestampAdjuster pcrTimestampAdjuster, + long streamDurationUs, + long inputLength, + int pcrPid, + int timestampSearchBytes) { super( new DefaultSeekTimestampConverter(), - new TsPcrSeeker(pcrPid, pcrTimestampAdjuster), + new TsPcrSeeker(pcrPid, pcrTimestampAdjuster, timestampSearchBytes), streamDurationUs, /* floorTimePosition= */ 0, /* ceilingTimePosition= */ streamDurationUs + 1, @@ -58,7 +61,7 @@ import java.io.IOException; * position in a TS stream. * *
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
+ * #timestampSearchBytes} 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.
*/
@@ -67,10 +70,13 @@ import java.io.IOException;
private final TimestampAdjuster pcrTimestampAdjuster;
private final ParsableByteArray packetBuffer;
private final int pcrPid;
+ private final int timestampSearchBytes;
- public TsPcrSeeker(int pcrPid, TimestampAdjuster pcrTimestampAdjuster) {
+ public TsPcrSeeker(
+ int pcrPid, TimestampAdjuster pcrTimestampAdjuster, int timestampSearchBytes) {
this.pcrPid = pcrPid;
this.pcrTimestampAdjuster = pcrTimestampAdjuster;
+ this.timestampSearchBytes = timestampSearchBytes;
packetBuffer = new ParsableByteArray();
}
@@ -78,7 +84,7 @@ import java.io.IOException;
public TimestampSearchResult searchForTimestamp(ExtractorInput input, long targetTimestamp)
throws IOException {
long inputPosition = input.getPosition();
- int bytesToSearch = (int) min(TIMESTAMP_SEARCH_BYTES, input.getLength() - inputPosition);
+ int bytesToSearch = (int) min(timestampSearchBytes, input.getLength() - inputPosition);
packetBuffer.reset(bytesToSearch);
input.peekFully(packetBuffer.getData(), /* offset= */ 0, bytesToSearch);
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java
index 5020f4c76d..504b84d575 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsDurationReader.java
@@ -38,8 +38,7 @@ import java.io.IOException;
*/
/* package */ final class TsDurationReader {
- private static final int TIMESTAMP_SEARCH_BYTES = 600 * TsExtractor.TS_PACKET_SIZE;
-
+ private final int timestampSearchBytes;
private final TimestampAdjuster pcrTimestampAdjuster;
private final ParsableByteArray packetBuffer;
@@ -51,7 +50,8 @@ import java.io.IOException;
private long lastPcrValue;
private long durationUs;
- /* package */ TsDurationReader() {
+ /* package */ TsDurationReader(int timestampSearchBytes) {
+ this.timestampSearchBytes = timestampSearchBytes;
pcrTimestampAdjuster = new TimestampAdjuster(/* firstSampleTimestampUs= */ 0);
firstPcrValue = C.TIME_UNSET;
lastPcrValue = C.TIME_UNSET;
@@ -125,7 +125,7 @@ import java.io.IOException;
private int readFirstPcrValue(ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid)
throws IOException {
- int bytesToSearch = (int) min(TIMESTAMP_SEARCH_BYTES, input.getLength());
+ int bytesToSearch = (int) min(timestampSearchBytes, input.getLength());
int searchStartPosition = 0;
if (input.getPosition() != searchStartPosition) {
seekPositionHolder.position = searchStartPosition;
@@ -161,7 +161,7 @@ import java.io.IOException;
private int readLastPcrValue(ExtractorInput input, PositionHolder seekPositionHolder, int pcrPid)
throws IOException {
long inputLength = input.getLength();
- int bytesToSearch = (int) min(TIMESTAMP_SEARCH_BYTES, inputLength);
+ int bytesToSearch = (int) min(timestampSearchBytes, inputLength);
long searchStartPosition = inputLength - bytesToSearch;
if (input.getPosition() != searchStartPosition) {
seekPositionHolder.position = searchStartPosition;
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
index 2fcfd422a0..2a9613f7f4 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java
@@ -80,6 +80,9 @@ public final class TsExtractor implements Extractor {
*/
public static final int MODE_HLS = 2;
+ public static final int TS_PACKET_SIZE = 188;
+ public static final int DEFAULT_TIMESTAMP_SEARCH_BYTES = 600 * TS_PACKET_SIZE;
+
public static final int TS_STREAM_TYPE_MPA = 0x03;
public static final int TS_STREAM_TYPE_MPA_LSF = 0x04;
public static final int TS_STREAM_TYPE_AAC_ADTS = 0x0F;
@@ -100,7 +103,6 @@ public final class TsExtractor implements Extractor {
// Stream types that aren't defined by the MPEG-2 TS specification.
public static final int TS_STREAM_TYPE_AIT = 0x101;
- public static final int TS_PACKET_SIZE = 188;
public static final int TS_SYNC_BYTE = 0x47; // First byte of each TS packet.
private static final int TS_PAT_PID = 0;
@@ -115,6 +117,7 @@ public final class TsExtractor implements Extractor {
private static final int SNIFF_TS_PACKET_COUNT = 5;
private final @Mode int mode;
+ private final int timestampSearchBytes;
private final List