diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java index ca3ea7ce39..65b97c8a73 100644 --- a/library/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/ts/TsExtractor.java @@ -383,7 +383,8 @@ public final class TsExtractor implements Extractor { if (mode == MODE_SINGLE_PMT || mode == MODE_HLS || remainingPmts == 1) { timestampAdjuster = timestampAdjusters.get(0); } else { - timestampAdjuster = new TimestampAdjuster(timestampAdjusters.get(0).firstSampleTimestampUs); + timestampAdjuster = new TimestampAdjuster( + timestampAdjusters.get(0).getFirstSampleTimestampUs()); timestampAdjusters.add(timestampAdjuster); } diff --git a/library/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java b/library/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java index 58c23d253a..4050daa1cb 100644 --- a/library/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java +++ b/library/src/main/java/com/google/android/exoplayer2/metadata/scte35/SpliceInfoDecoder.java @@ -88,6 +88,9 @@ public final class SpliceInfoDecoder implements MetadataDecoder { case TYPE_PRIVATE_COMMAND: command = PrivateCommand.parseFromSection(sectionData, spliceCommandLength, ptsAdjustment); break; + default: + // Do nothing. + break; } return command == null ? new Metadata() : new Metadata(command); } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java index 5775e4ec38..ea99dae345 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsChunkSource.java @@ -282,7 +282,7 @@ import java.util.Locale; int discontinuitySequence = mediaPlaylist.discontinuitySequence + segment.relativeDiscontinuitySequence; TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster( - discontinuitySequence, startTimeUs); + discontinuitySequence); // Configure the data source and spec for the chunk. Uri chunkUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.url); diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java index 5615db1264..6f516923f9 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaChunk.java @@ -242,6 +242,9 @@ import java.util.concurrent.atomic.AtomicInteger; } if (!isMasterTimestampSource) { timestampAdjuster.waitUntilInitialized(); + } else if (timestampAdjuster.getFirstSampleTimestampUs() == TimestampAdjuster.DO_NOT_OFFSET) { + // We're the master and we haven't set the desired first sample timestamp yet. + timestampAdjuster.setFirstSampleTimestampUs(startTimeUs); } try { ExtractorInput input = new DefaultExtractorInput(dataSource, diff --git a/library/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java b/library/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java index 41fb2c1512..85a4276ea2 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/hls/TimestampAdjusterProvider.java @@ -36,13 +36,12 @@ public final class TimestampAdjusterProvider { * a chunk with a given discontinuity sequence. * * @param discontinuitySequence The chunk's discontinuity sequence. - * @param startTimeUs The chunk's start time. * @return A {@link TimestampAdjuster}. */ - public TimestampAdjuster getAdjuster(int discontinuitySequence, long startTimeUs) { + public TimestampAdjuster getAdjuster(int discontinuitySequence) { TimestampAdjuster adjuster = timestampAdjusters.get(discontinuitySequence); if (adjuster == null) { - adjuster = new TimestampAdjuster(startTimeUs); + adjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET); timestampAdjusters.put(discontinuitySequence, adjuster); } return adjuster; diff --git a/library/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java b/library/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java index ace300c6b1..08e2bd0669 100644 --- a/library/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java +++ b/library/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java @@ -34,21 +34,39 @@ public final class TimestampAdjuster { */ private static final long MAX_PTS_PLUS_ONE = 0x200000000L; - public final long firstSampleTimestampUs; - + private long firstSampleTimestampUs; private long timestampOffsetUs; // Volatile to allow isInitialized to be called on a different thread to adjustSampleTimestamp. private volatile long lastSampleTimestamp; /** - * @param firstSampleTimestampUs The desired result of the first call to - * {@link #adjustSampleTimestamp(long)}, or {@link #DO_NOT_OFFSET} if presentation timestamps - * should not be offset. + * @param firstSampleTimestampUs See {@link #setFirstSampleTimestampUs(long)}. */ public TimestampAdjuster(long firstSampleTimestampUs) { - this.firstSampleTimestampUs = firstSampleTimestampUs; lastSampleTimestamp = C.TIME_UNSET; + setFirstSampleTimestampUs(firstSampleTimestampUs); + } + + /** + * Sets the desired result of the first call to {@link #adjustSampleTimestamp(long)}. Can only be + * called before any timestamps have been adjusted. + * + * @param firstSampleTimestampUs The first adjusted sample timestamp in microseconds, or + * {@link #DO_NOT_OFFSET} if presentation timestamps should not be offset. + */ + public synchronized void setFirstSampleTimestampUs(long firstSampleTimestampUs) { + Assertions.checkState(lastSampleTimestamp == C.TIME_UNSET); + this.firstSampleTimestampUs = firstSampleTimestampUs; + } + + /** + * Returns the first adjusted sample timestamp in microseconds. + * + * @return The first adjusted sample timestamp in microseconds. + */ + public long getFirstSampleTimestampUs() { + return firstSampleTimestampUs; } /**