Commit cab02289 by aquilescanta Committed by Santiago Seifert

Generalize the PtsTimestampAdjuster

This allows the adjustment of timestamps in microseconds along with
TS timestamps. This is useful for containers that include the
timestamps in microseconds format, like fMP4 and WebVTT.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=132547521
parent 04c28c6d
...@@ -56,7 +56,7 @@ public final class PsExtractor implements Extractor { ...@@ -56,7 +56,7 @@ public final class PsExtractor implements Extractor {
public static final int VIDEO_STREAM = 0xE0; public static final int VIDEO_STREAM = 0xE0;
public static final int VIDEO_STREAM_MASK = 0xF0; public static final int VIDEO_STREAM_MASK = 0xF0;
private final PtsTimestampAdjuster ptsTimestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final SparseArray<PesReader> psPayloadReaders; // Indexed by pid private final SparseArray<PesReader> psPayloadReaders; // Indexed by pid
private final ParsableByteArray psPacketBuffer; private final ParsableByteArray psPacketBuffer;
private boolean foundAllTracks; private boolean foundAllTracks;
...@@ -67,11 +67,11 @@ public final class PsExtractor implements Extractor { ...@@ -67,11 +67,11 @@ public final class PsExtractor implements Extractor {
private ExtractorOutput output; private ExtractorOutput output;
public PsExtractor() { public PsExtractor() {
this(new PtsTimestampAdjuster(0)); this(new TimestampAdjuster(0));
} }
public PsExtractor(PtsTimestampAdjuster ptsTimestampAdjuster) { public PsExtractor(TimestampAdjuster timestampAdjuster) {
this.ptsTimestampAdjuster = ptsTimestampAdjuster; this.timestampAdjuster = timestampAdjuster;
psPacketBuffer = new ParsableByteArray(4096); psPacketBuffer = new ParsableByteArray(4096);
psPayloadReaders = new SparseArray<>(); psPayloadReaders = new SparseArray<>();
} }
...@@ -125,7 +125,7 @@ public final class PsExtractor implements Extractor { ...@@ -125,7 +125,7 @@ public final class PsExtractor implements Extractor {
@Override @Override
public void seek(long position) { public void seek(long position) {
ptsTimestampAdjuster.reset(); timestampAdjuster.reset();
for (int i = 0; i < psPayloadReaders.size(); i++) { for (int i = 0; i < psPayloadReaders.size(); i++) {
psPayloadReaders.valueAt(i).seek(); psPayloadReaders.valueAt(i).seek();
} }
...@@ -199,7 +199,7 @@ public final class PsExtractor implements Extractor { ...@@ -199,7 +199,7 @@ public final class PsExtractor implements Extractor {
foundVideoTrack = true; foundVideoTrack = true;
} }
if (elementaryStreamReader != null) { if (elementaryStreamReader != null) {
payloadReader = new PesReader(elementaryStreamReader, ptsTimestampAdjuster); payloadReader = new PesReader(elementaryStreamReader, timestampAdjuster);
psPayloadReaders.put(streamId, payloadReader); psPayloadReaders.put(streamId, payloadReader);
} }
} }
...@@ -244,7 +244,7 @@ public final class PsExtractor implements Extractor { ...@@ -244,7 +244,7 @@ public final class PsExtractor implements Extractor {
private static final int PES_SCRATCH_SIZE = 64; private static final int PES_SCRATCH_SIZE = 64;
private final ElementaryStreamReader pesPayloadReader; private final ElementaryStreamReader pesPayloadReader;
private final PtsTimestampAdjuster ptsTimestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final ParsableBitArray pesScratch; private final ParsableBitArray pesScratch;
private boolean ptsFlag; private boolean ptsFlag;
...@@ -254,9 +254,9 @@ public final class PsExtractor implements Extractor { ...@@ -254,9 +254,9 @@ public final class PsExtractor implements Extractor {
private long timeUs; private long timeUs;
public PesReader(ElementaryStreamReader pesPayloadReader, public PesReader(ElementaryStreamReader pesPayloadReader,
PtsTimestampAdjuster ptsTimestampAdjuster) { TimestampAdjuster timestampAdjuster) {
this.pesPayloadReader = pesPayloadReader; this.pesPayloadReader = pesPayloadReader;
this.ptsTimestampAdjuster = ptsTimestampAdjuster; this.timestampAdjuster = timestampAdjuster;
pesScratch = new ParsableBitArray(new byte[PES_SCRATCH_SIZE]); pesScratch = new ParsableBitArray(new byte[PES_SCRATCH_SIZE]);
} }
...@@ -327,10 +327,10 @@ public final class PsExtractor implements Extractor { ...@@ -327,10 +327,10 @@ public final class PsExtractor implements Extractor {
// decode timestamp to the adjuster here so that in the case that this is the first to be // decode timestamp to the adjuster here so that in the case that this is the first to be
// fed, the adjuster will be able to compute an offset to apply such that the adjusted // fed, the adjuster will be able to compute an offset to apply such that the adjusted
// presentation timestamps of all future packets are non-negative. // presentation timestamps of all future packets are non-negative.
ptsTimestampAdjuster.adjustTimestamp(dts); timestampAdjuster.adjustTsTimestamp(dts);
seenFirstDts = true; seenFirstDts = true;
} }
timeUs = ptsTimestampAdjuster.adjustTimestamp(pts); timeUs = timestampAdjuster.adjustTsTimestamp(pts);
} }
} }
......
...@@ -18,10 +18,10 @@ package com.google.android.exoplayer2.extractor.ts; ...@@ -18,10 +18,10 @@ package com.google.android.exoplayer2.extractor.ts;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
/** /**
* Scales and adjusts MPEG-2 TS presentation timestamps, taking into account an initial offset and * Offsets timestamps according to an initial sample timestamp offset. MPEG-2 TS timestamps scaling
* timestamp rollover. * and adjustment is supported, taking into account timestamp rollover.
*/ */
public final class PtsTimestampAdjuster { public final class TimestampAdjuster {
/** /**
* A special {@code firstSampleTimestampUs} value indicating that presentation timestamps should * A special {@code firstSampleTimestampUs} value indicating that presentation timestamps should
...@@ -30,7 +30,7 @@ public final class PtsTimestampAdjuster { ...@@ -30,7 +30,7 @@ public final class PtsTimestampAdjuster {
public static final long DO_NOT_OFFSET = Long.MAX_VALUE; public static final long DO_NOT_OFFSET = Long.MAX_VALUE;
/** /**
* The value one greater than the largest representable (33 bit) presentation timestamp. * The value one greater than the largest representable (33 bit) MPEG-2 TS presentation timestamp.
*/ */
private static final long MAX_PTS_PLUS_ONE = 0x200000000L; private static final long MAX_PTS_PLUS_ONE = 0x200000000L;
...@@ -38,57 +38,66 @@ public final class PtsTimestampAdjuster { ...@@ -38,57 +38,66 @@ public final class PtsTimestampAdjuster {
private long timestampOffsetUs; private long timestampOffsetUs;
// Volatile to allow isInitialized to be called on a different thread to adjustTimestamp. // Volatile to allow isInitialized to be called on a different thread to adjustSampleTimestamp.
private volatile long lastPts; private volatile long lastSampleTimestamp;
/** /**
* @param firstSampleTimestampUs The desired result of the first call to * @param firstSampleTimestampUs The desired result of the first call to
* {@link #adjustTimestamp(long)}, or {@link #DO_NOT_OFFSET} if presentation timestamps * {@link #adjustSampleTimestamp(long)}, or {@link #DO_NOT_OFFSET} if presentation timestamps
* should not be offset. * should not be offset.
*/ */
public PtsTimestampAdjuster(long firstSampleTimestampUs) { public TimestampAdjuster(long firstSampleTimestampUs) {
this.firstSampleTimestampUs = firstSampleTimestampUs; this.firstSampleTimestampUs = firstSampleTimestampUs;
lastPts = Long.MIN_VALUE; lastSampleTimestamp = C.TIME_UNSET;
} }
/** /**
* Resets the instance to its initial state. * Resets the instance to its initial state.
*/ */
public void reset() { public void reset() {
lastPts = Long.MIN_VALUE; lastSampleTimestamp = C.TIME_UNSET;
} }
/** /**
* Whether this adjuster has been initialized with a first MPEG-2 TS presentation timestamp. * Whether this adjuster has been initialized with a first MPEG-2 TS presentation timestamp.
*/ */
public boolean isInitialized() { public boolean isInitialized() {
return lastPts != Long.MIN_VALUE; return lastSampleTimestamp != C.TIME_UNSET;
} }
/** /**
* Scales and offsets an MPEG-2 TS presentation timestamp. * Scales and offsets an MPEG-2 TS presentation timestamp considering wraparound.
* *
* @param pts The MPEG-2 TS presentation timestamp. * @param pts The MPEG-2 TS presentation timestamp.
* @return The adjusted timestamp in microseconds. * @return The adjusted timestamp in microseconds.
*/ */
public long adjustTimestamp(long pts) { public long adjustTsTimestamp(long pts) {
if (lastPts != Long.MIN_VALUE) { if (lastSampleTimestamp != C.TIME_UNSET) {
// The wrap count for the current PTS may be closestWrapCount or (closestWrapCount - 1), // The wrap count for the current PTS may be closestWrapCount or (closestWrapCount - 1),
// and we need to snap to the one closest to lastPts. // and we need to snap to the one closest to lastSampleTimestamp.
long lastPts = usToPts(lastSampleTimestamp);
long closestWrapCount = (lastPts + (MAX_PTS_PLUS_ONE / 2)) / MAX_PTS_PLUS_ONE; long closestWrapCount = (lastPts + (MAX_PTS_PLUS_ONE / 2)) / MAX_PTS_PLUS_ONE;
long ptsWrapBelow = pts + (MAX_PTS_PLUS_ONE * (closestWrapCount - 1)); long ptsWrapBelow = pts + (MAX_PTS_PLUS_ONE * (closestWrapCount - 1));
long ptsWrapAbove = pts + (MAX_PTS_PLUS_ONE * closestWrapCount); long ptsWrapAbove = pts + (MAX_PTS_PLUS_ONE * closestWrapCount);
pts = Math.abs(ptsWrapBelow - lastPts) < Math.abs(ptsWrapAbove - lastPts) pts = Math.abs(ptsWrapBelow - lastPts) < Math.abs(ptsWrapAbove - lastPts)
? ptsWrapBelow : ptsWrapAbove; ? ptsWrapBelow : ptsWrapAbove;
} }
// Calculate the corresponding timestamp. return adjustSampleTimestamp(ptsToUs(pts));
long timeUs = ptsToUs(pts); }
if (firstSampleTimestampUs != DO_NOT_OFFSET && lastPts == Long.MIN_VALUE) {
/**
* Offsets a sample timestamp in microseconds.
*
* @param timeUs The timestamp of a sample to adjust.
* @return The adjusted timestamp in microseconds.
*/
public long adjustSampleTimestamp(long timeUs) {
if (firstSampleTimestampUs != DO_NOT_OFFSET && lastSampleTimestamp == C.TIME_UNSET) {
// Calculate the timestamp offset. // Calculate the timestamp offset.
timestampOffsetUs = firstSampleTimestampUs - timeUs; timestampOffsetUs = firstSampleTimestampUs - timeUs;
} }
// Record the adjusted PTS to adjust for wraparound next time. // Record the adjusted PTS to adjust for wraparound next time.
lastPts = pts; lastSampleTimestamp = timeUs;
return timeUs + timestampOffsetUs; return timeUs + timestampOffsetUs;
} }
......
...@@ -81,7 +81,7 @@ public final class TsExtractor implements Extractor { ...@@ -81,7 +81,7 @@ public final class TsExtractor implements Extractor {
private static final int BUFFER_PACKET_COUNT = 5; // Should be at least 2 private static final int BUFFER_PACKET_COUNT = 5; // Should be at least 2
private static final int BUFFER_SIZE = TS_PACKET_SIZE * BUFFER_PACKET_COUNT; private static final int BUFFER_SIZE = TS_PACKET_SIZE * BUFFER_PACKET_COUNT;
private final PtsTimestampAdjuster ptsTimestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final int workaroundFlags; private final int workaroundFlags;
private final ParsableByteArray tsPacketBuffer; private final ParsableByteArray tsPacketBuffer;
private final ParsableBitArray tsScratch; private final ParsableBitArray tsScratch;
...@@ -94,15 +94,15 @@ public final class TsExtractor implements Extractor { ...@@ -94,15 +94,15 @@ public final class TsExtractor implements Extractor {
/* package */ Id3Reader id3Reader; /* package */ Id3Reader id3Reader;
public TsExtractor() { public TsExtractor() {
this(new PtsTimestampAdjuster(0)); this(new TimestampAdjuster(0));
} }
public TsExtractor(PtsTimestampAdjuster ptsTimestampAdjuster) { public TsExtractor(TimestampAdjuster timestampAdjuster) {
this(ptsTimestampAdjuster, 0); this(timestampAdjuster, 0);
} }
public TsExtractor(PtsTimestampAdjuster ptsTimestampAdjuster, int workaroundFlags) { public TsExtractor(TimestampAdjuster timestampAdjuster, int workaroundFlags) {
this.ptsTimestampAdjuster = ptsTimestampAdjuster; this.timestampAdjuster = timestampAdjuster;
this.workaroundFlags = workaroundFlags; this.workaroundFlags = workaroundFlags;
tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE); tsPacketBuffer = new ParsableByteArray(BUFFER_SIZE);
tsScratch = new ParsableBitArray(new byte[3]); tsScratch = new ParsableBitArray(new byte[3]);
...@@ -140,7 +140,7 @@ public final class TsExtractor implements Extractor { ...@@ -140,7 +140,7 @@ public final class TsExtractor implements Extractor {
@Override @Override
public void seek(long position) { public void seek(long position) {
ptsTimestampAdjuster.reset(); timestampAdjuster.reset();
for (int i = 0; i < tsPayloadReaders.size(); i++) { for (int i = 0; i < tsPayloadReaders.size(); i++) {
tsPayloadReaders.valueAt(i).seek(); tsPayloadReaders.valueAt(i).seek();
} }
...@@ -486,7 +486,7 @@ public final class TsExtractor implements Extractor { ...@@ -486,7 +486,7 @@ public final class TsExtractor implements Extractor {
if (pesPayloadReader != null) { if (pesPayloadReader != null) {
trackIds.put(trackId, true); trackIds.put(trackId, true);
tsPayloadReaders.put(elementaryPid, tsPayloadReaders.put(elementaryPid,
new PesReader(pesPayloadReader, ptsTimestampAdjuster)); new PesReader(pesPayloadReader, timestampAdjuster));
} }
} }
...@@ -554,7 +554,7 @@ public final class TsExtractor implements Extractor { ...@@ -554,7 +554,7 @@ public final class TsExtractor implements Extractor {
private static final int PES_SCRATCH_SIZE = 10; // max(HEADER_SIZE, MAX_HEADER_EXTENSION_SIZE) private static final int PES_SCRATCH_SIZE = 10; // max(HEADER_SIZE, MAX_HEADER_EXTENSION_SIZE)
private final ElementaryStreamReader pesPayloadReader; private final ElementaryStreamReader pesPayloadReader;
private final PtsTimestampAdjuster ptsTimestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final ParsableBitArray pesScratch; private final ParsableBitArray pesScratch;
private int state; private int state;
...@@ -569,9 +569,9 @@ public final class TsExtractor implements Extractor { ...@@ -569,9 +569,9 @@ public final class TsExtractor implements Extractor {
private long timeUs; private long timeUs;
public PesReader(ElementaryStreamReader pesPayloadReader, public PesReader(ElementaryStreamReader pesPayloadReader,
PtsTimestampAdjuster ptsTimestampAdjuster) { TimestampAdjuster timestampAdjuster) {
this.pesPayloadReader = pesPayloadReader; this.pesPayloadReader = pesPayloadReader;
this.ptsTimestampAdjuster = ptsTimestampAdjuster; this.timestampAdjuster = timestampAdjuster;
pesScratch = new ParsableBitArray(new byte[PES_SCRATCH_SIZE]); pesScratch = new ParsableBitArray(new byte[PES_SCRATCH_SIZE]);
state = STATE_FINDING_HEADER; state = STATE_FINDING_HEADER;
} }
...@@ -734,10 +734,10 @@ public final class TsExtractor implements Extractor { ...@@ -734,10 +734,10 @@ public final class TsExtractor implements Extractor {
// decode timestamp to the adjuster here so that in the case that this is the first to be // decode timestamp to the adjuster here so that in the case that this is the first to be
// fed, the adjuster will be able to compute an offset to apply such that the adjusted // fed, the adjuster will be able to compute an offset to apply such that the adjusted
// presentation timestamps of all future packets are non-negative. // presentation timestamps of all future packets are non-negative.
ptsTimestampAdjuster.adjustTimestamp(dts); timestampAdjuster.adjustTsTimestamp(dts);
seenFirstDts = true; seenFirstDts = true;
} }
timeUs = ptsTimestampAdjuster.adjustTimestamp(pts); timeUs = timestampAdjuster.adjustTsTimestamp(pts);
} }
} }
......
...@@ -24,7 +24,7 @@ import com.google.android.exoplayer2.extractor.Extractor; ...@@ -24,7 +24,7 @@ import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor; import com.google.android.exoplayer2.extractor.mp3.Mp3Extractor;
import com.google.android.exoplayer2.extractor.ts.Ac3Extractor; import com.google.android.exoplayer2.extractor.ts.Ac3Extractor;
import com.google.android.exoplayer2.extractor.ts.AdtsExtractor; import com.google.android.exoplayer2.extractor.ts.AdtsExtractor;
import com.google.android.exoplayer2.extractor.ts.PtsTimestampAdjuster; import com.google.android.exoplayer2.extractor.ts.TimestampAdjuster;
import com.google.android.exoplayer2.extractor.ts.TsExtractor; import com.google.android.exoplayer2.extractor.ts.TsExtractor;
import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
...@@ -107,7 +107,7 @@ import java.util.Locale; ...@@ -107,7 +107,7 @@ import java.util.Locale;
private final String baseUri; private final String baseUri;
private final DataSource dataSource; private final DataSource dataSource;
private final HlsPlaylistParser playlistParser; private final HlsPlaylistParser playlistParser;
private final PtsTimestampAdjusterProvider timestampAdjusterProvider; private final TimestampAdjusterProvider timestampAdjusterProvider;
private final HlsMasterPlaylist.HlsUrl[] variants; private final HlsMasterPlaylist.HlsUrl[] variants;
private final HlsMediaPlaylist[] variantPlaylists; private final HlsMediaPlaylist[] variantPlaylists;
private final TrackGroup trackGroup; private final TrackGroup trackGroup;
...@@ -132,12 +132,12 @@ import java.util.Locale; ...@@ -132,12 +132,12 @@ import java.util.Locale;
* @param baseUri The playlist's base uri. * @param baseUri The playlist's base uri.
* @param variants The available variants. * @param variants The available variants.
* @param dataSource A {@link DataSource} suitable for loading the media data. * @param dataSource A {@link DataSource} suitable for loading the media data.
* @param timestampAdjusterProvider A provider of {@link PtsTimestampAdjuster} instances. If * @param timestampAdjusterProvider A provider of {@link TimestampAdjuster} instances. If
* multiple {@link HlsChunkSource}s are used for a single playback, they should all share the * multiple {@link HlsChunkSource}s are used for a single playback, they should all share the
* same provider. * same provider.
*/ */
public HlsChunkSource(String baseUri, HlsMasterPlaylist.HlsUrl[] variants, DataSource dataSource, public HlsChunkSource(String baseUri, HlsMasterPlaylist.HlsUrl[] variants, DataSource dataSource,
PtsTimestampAdjusterProvider timestampAdjusterProvider) { TimestampAdjusterProvider timestampAdjusterProvider) {
this.baseUri = baseUri; this.baseUri = baseUri;
this.variants = variants; this.variants = variants;
this.dataSource = dataSource; this.dataSource = dataSource;
...@@ -343,7 +343,7 @@ import java.util.Locale; ...@@ -343,7 +343,7 @@ import java.util.Locale;
extractor = new Mp3Extractor(startTimeUs); extractor = new Mp3Extractor(startTimeUs);
} else if (lastPathSegment.endsWith(WEBVTT_FILE_EXTENSION) } else if (lastPathSegment.endsWith(WEBVTT_FILE_EXTENSION)
|| lastPathSegment.endsWith(VTT_FILE_EXTENSION)) { || lastPathSegment.endsWith(VTT_FILE_EXTENSION)) {
PtsTimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(false, TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(false,
segment.discontinuitySequenceNumber, startTimeUs); segment.discontinuitySequenceNumber, startTimeUs);
if (timestampAdjuster == null) { if (timestampAdjuster == null) {
// The master source has yet to instantiate an adjuster for the discontinuity sequence. // The master source has yet to instantiate an adjuster for the discontinuity sequence.
...@@ -356,7 +356,7 @@ import java.util.Locale; ...@@ -356,7 +356,7 @@ import java.util.Locale;
|| previous.discontinuitySequenceNumber != segment.discontinuitySequenceNumber || previous.discontinuitySequenceNumber != segment.discontinuitySequenceNumber
|| format != previous.trackFormat) { || format != previous.trackFormat) {
// MPEG-2 TS segments, but we need a new extractor. // MPEG-2 TS segments, but we need a new extractor.
PtsTimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(true, TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(true,
segment.discontinuitySequenceNumber, startTimeUs); segment.discontinuitySequenceNumber, startTimeUs);
if (timestampAdjuster == null) { if (timestampAdjuster == null) {
// The master source has yet to instantiate an adjuster for the discontinuity sequence. // The master source has yet to instantiate an adjuster for the discontinuity sequence.
......
...@@ -57,7 +57,7 @@ import java.util.List; ...@@ -57,7 +57,7 @@ import java.util.List;
private final Callback callback; private final Callback callback;
private final Allocator allocator; private final Allocator allocator;
private final IdentityHashMap<SampleStream, Integer> streamWrapperIndices; private final IdentityHashMap<SampleStream, Integer> streamWrapperIndices;
private final PtsTimestampAdjusterProvider timestampAdjusterProvider; private final TimestampAdjusterProvider timestampAdjusterProvider;
private final HlsPlaylistParser manifestParser; private final HlsPlaylistParser manifestParser;
private final Handler continueLoadingHandler; private final Handler continueLoadingHandler;
private final Loader manifestFetcher; private final Loader manifestFetcher;
...@@ -85,7 +85,7 @@ import java.util.List; ...@@ -85,7 +85,7 @@ import java.util.List;
this.callback = callback; this.callback = callback;
this.allocator = allocator; this.allocator = allocator;
streamWrapperIndices = new IdentityHashMap<>(); streamWrapperIndices = new IdentityHashMap<>();
timestampAdjusterProvider = new PtsTimestampAdjusterProvider(); timestampAdjusterProvider = new TimestampAdjusterProvider();
manifestParser = new HlsPlaylistParser(); manifestParser = new HlsPlaylistParser();
continueLoadingHandler = new Handler(); continueLoadingHandler = new Handler();
manifestFetcher = new Loader("Loader:ManifestFetcher"); manifestFetcher = new Loader("Loader:ManifestFetcher");
......
...@@ -16,23 +16,23 @@ ...@@ -16,23 +16,23 @@
package com.google.android.exoplayer2.source.hls; package com.google.android.exoplayer2.source.hls;
import android.util.SparseArray; import android.util.SparseArray;
import com.google.android.exoplayer2.extractor.ts.PtsTimestampAdjuster; import com.google.android.exoplayer2.extractor.ts.TimestampAdjuster;
/** /**
* Provides {@link PtsTimestampAdjuster} instances for use during HLS playbacks. * Provides {@link TimestampAdjuster} instances for use during HLS playbacks.
*/ */
public final class PtsTimestampAdjusterProvider { public final class TimestampAdjusterProvider {
// TODO: Prevent this array from growing indefinitely large by removing adjusters that are no // TODO: Prevent this array from growing indefinitely large by removing adjusters that are no
// longer required. // longer required.
private final SparseArray<PtsTimestampAdjuster> ptsTimestampAdjusters; private final SparseArray<TimestampAdjuster> timestampAdjusters;
public PtsTimestampAdjusterProvider() { public TimestampAdjusterProvider() {
ptsTimestampAdjusters = new SparseArray<>(); timestampAdjusters = new SparseArray<>();
} }
/** /**
* Returns a {@link PtsTimestampAdjuster} suitable for adjusting the pts timestamps contained in * Returns a {@link TimestampAdjuster} suitable for adjusting the pts timestamps contained in
* a chunk with a given discontinuity sequence. * a chunk with a given discontinuity sequence.
* <p> * <p>
* This method may return null if the master source has yet to initialize a suitable adjuster. * This method may return null if the master source has yet to initialize a suitable adjuster.
...@@ -40,14 +40,14 @@ public final class PtsTimestampAdjusterProvider { ...@@ -40,14 +40,14 @@ public final class PtsTimestampAdjusterProvider {
* @param isMasterSource True if the calling chunk source is the master. * @param isMasterSource True if the calling chunk source is the master.
* @param discontinuitySequence The chunk's discontinuity sequence. * @param discontinuitySequence The chunk's discontinuity sequence.
* @param startTimeUs The chunk's start time. * @param startTimeUs The chunk's start time.
* @return A {@link PtsTimestampAdjuster}. * @return A {@link TimestampAdjuster}.
*/ */
public PtsTimestampAdjuster getAdjuster(boolean isMasterSource, int discontinuitySequence, public TimestampAdjuster getAdjuster(boolean isMasterSource, int discontinuitySequence,
long startTimeUs) { long startTimeUs) {
PtsTimestampAdjuster adjuster = ptsTimestampAdjusters.get(discontinuitySequence); TimestampAdjuster adjuster = timestampAdjusters.get(discontinuitySequence);
if (isMasterSource && adjuster == null) { if (isMasterSource && adjuster == null) {
adjuster = new PtsTimestampAdjuster(startTimeUs); adjuster = new TimestampAdjuster(startTimeUs);
ptsTimestampAdjusters.put(discontinuitySequence, adjuster); timestampAdjusters.put(discontinuitySequence, adjuster);
} }
return isMasterSource || (adjuster != null && adjuster.isInitialized()) ? adjuster : null; return isMasterSource || (adjuster != null && adjuster.isInitialized()) ? adjuster : null;
} }
...@@ -56,7 +56,7 @@ public final class PtsTimestampAdjusterProvider { ...@@ -56,7 +56,7 @@ public final class PtsTimestampAdjusterProvider {
* Resets the provider. * Resets the provider.
*/ */
public void reset() { public void reset() {
ptsTimestampAdjusters.clear(); timestampAdjusters.clear();
} }
} }
...@@ -25,7 +25,7 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput; ...@@ -25,7 +25,7 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.PositionHolder; import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput; import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.extractor.ts.PtsTimestampAdjuster; import com.google.android.exoplayer2.extractor.ts.TimestampAdjuster;
import com.google.android.exoplayer2.text.SubtitleDecoderException; import com.google.android.exoplayer2.text.SubtitleDecoderException;
import com.google.android.exoplayer2.text.webvtt.WebvttParserUtil; import com.google.android.exoplayer2.text.webvtt.WebvttParserUtil;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
...@@ -49,7 +49,7 @@ import java.util.regex.Pattern; ...@@ -49,7 +49,7 @@ import java.util.regex.Pattern;
private static final Pattern MEDIA_TIMESTAMP = Pattern.compile("MPEGTS:(\\d+)"); private static final Pattern MEDIA_TIMESTAMP = Pattern.compile("MPEGTS:(\\d+)");
private final String language; private final String language;
private final PtsTimestampAdjuster ptsTimestampAdjuster; private final TimestampAdjuster timestampAdjuster;
private final ParsableByteArray sampleDataWrapper; private final ParsableByteArray sampleDataWrapper;
private ExtractorOutput output; private ExtractorOutput output;
...@@ -57,9 +57,9 @@ import java.util.regex.Pattern; ...@@ -57,9 +57,9 @@ import java.util.regex.Pattern;
private byte[] sampleData; private byte[] sampleData;
private int sampleSize; private int sampleSize;
public WebvttExtractor(String language, PtsTimestampAdjuster ptsTimestampAdjuster) { public WebvttExtractor(String language, TimestampAdjuster timestampAdjuster) {
this.language = language; this.language = language;
this.ptsTimestampAdjuster = ptsTimestampAdjuster; this.timestampAdjuster = timestampAdjuster;
this.sampleDataWrapper = new ParsableByteArray(); this.sampleDataWrapper = new ParsableByteArray();
sampleData = new byte[1024]; sampleData = new byte[1024];
} }
...@@ -141,7 +141,7 @@ import java.util.regex.Pattern; ...@@ -141,7 +141,7 @@ import java.util.regex.Pattern;
throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line); throw new ParserException("X-TIMESTAMP-MAP doesn't contain media timestamp: " + line);
} }
vttTimestampUs = WebvttParserUtil.parseTimestampUs(localTimestampMatcher.group(1)); vttTimestampUs = WebvttParserUtil.parseTimestampUs(localTimestampMatcher.group(1));
tsTimestampUs = PtsTimestampAdjuster.ptsToUs( tsTimestampUs = TimestampAdjuster.ptsToUs(
Long.parseLong(mediaTimestampMatcher.group(1))); Long.parseLong(mediaTimestampMatcher.group(1)));
} }
} }
...@@ -155,8 +155,8 @@ import java.util.regex.Pattern; ...@@ -155,8 +155,8 @@ import java.util.regex.Pattern;
} }
long firstCueTimeUs = WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1)); long firstCueTimeUs = WebvttParserUtil.parseTimestampUs(cueHeaderMatcher.group(1));
long sampleTimeUs = ptsTimestampAdjuster.adjustTimestamp( long sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(
PtsTimestampAdjuster.usToPts(firstCueTimeUs + tsTimestampUs - vttTimestampUs)); firstCueTimeUs + tsTimestampUs - vttTimestampUs);
long subsampleOffsetUs = sampleTimeUs - firstCueTimeUs; long subsampleOffsetUs = sampleTimeUs - firstCueTimeUs;
// Output the track. // Output the track.
TrackOutput trackOutput = buildTrackOutput(subsampleOffsetUs); TrackOutput trackOutput = buildTrackOutput(subsampleOffsetUs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment