Ensure only timestamp adjustment masters set first sample timestamps
Without this, it is possible that a non timestamp master instances the adjuster with its own chunk start time. When chunks are not aligned, this breaks adjustment. Issue:#2424 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=149764488
This commit is contained in:
parent
15aad266b6
commit
952bde700b
@ -383,7 +383,8 @@ public final class TsExtractor implements Extractor {
|
|||||||
if (mode == MODE_SINGLE_PMT || mode == MODE_HLS || remainingPmts == 1) {
|
if (mode == MODE_SINGLE_PMT || mode == MODE_HLS || remainingPmts == 1) {
|
||||||
timestampAdjuster = timestampAdjusters.get(0);
|
timestampAdjuster = timestampAdjusters.get(0);
|
||||||
} else {
|
} else {
|
||||||
timestampAdjuster = new TimestampAdjuster(timestampAdjusters.get(0).firstSampleTimestampUs);
|
timestampAdjuster = new TimestampAdjuster(
|
||||||
|
timestampAdjusters.get(0).getFirstSampleTimestampUs());
|
||||||
timestampAdjusters.add(timestampAdjuster);
|
timestampAdjusters.add(timestampAdjuster);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,9 @@ public final class SpliceInfoDecoder implements MetadataDecoder {
|
|||||||
case TYPE_PRIVATE_COMMAND:
|
case TYPE_PRIVATE_COMMAND:
|
||||||
command = PrivateCommand.parseFromSection(sectionData, spliceCommandLength, ptsAdjustment);
|
command = PrivateCommand.parseFromSection(sectionData, spliceCommandLength, ptsAdjustment);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
// Do nothing.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return command == null ? new Metadata() : new Metadata(command);
|
return command == null ? new Metadata() : new Metadata(command);
|
||||||
}
|
}
|
||||||
|
@ -282,7 +282,7 @@ import java.util.Locale;
|
|||||||
int discontinuitySequence = mediaPlaylist.discontinuitySequence
|
int discontinuitySequence = mediaPlaylist.discontinuitySequence
|
||||||
+ segment.relativeDiscontinuitySequence;
|
+ segment.relativeDiscontinuitySequence;
|
||||||
TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(
|
TimestampAdjuster timestampAdjuster = timestampAdjusterProvider.getAdjuster(
|
||||||
discontinuitySequence, startTimeUs);
|
discontinuitySequence);
|
||||||
|
|
||||||
// Configure the data source and spec for the chunk.
|
// Configure the data source and spec for the chunk.
|
||||||
Uri chunkUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.url);
|
Uri chunkUri = UriUtil.resolveToUri(mediaPlaylist.baseUri, segment.url);
|
||||||
|
@ -242,6 +242,9 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
}
|
}
|
||||||
if (!isMasterTimestampSource) {
|
if (!isMasterTimestampSource) {
|
||||||
timestampAdjuster.waitUntilInitialized();
|
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 {
|
try {
|
||||||
ExtractorInput input = new DefaultExtractorInput(dataSource,
|
ExtractorInput input = new DefaultExtractorInput(dataSource,
|
||||||
|
@ -36,13 +36,12 @@ public final class TimestampAdjusterProvider {
|
|||||||
* a chunk with a given discontinuity sequence.
|
* a chunk with a given discontinuity sequence.
|
||||||
*
|
*
|
||||||
* @param discontinuitySequence The chunk's discontinuity sequence.
|
* @param discontinuitySequence The chunk's discontinuity sequence.
|
||||||
* @param startTimeUs The chunk's start time.
|
|
||||||
* @return A {@link TimestampAdjuster}.
|
* @return A {@link TimestampAdjuster}.
|
||||||
*/
|
*/
|
||||||
public TimestampAdjuster getAdjuster(int discontinuitySequence, long startTimeUs) {
|
public TimestampAdjuster getAdjuster(int discontinuitySequence) {
|
||||||
TimestampAdjuster adjuster = timestampAdjusters.get(discontinuitySequence);
|
TimestampAdjuster adjuster = timestampAdjusters.get(discontinuitySequence);
|
||||||
if (adjuster == null) {
|
if (adjuster == null) {
|
||||||
adjuster = new TimestampAdjuster(startTimeUs);
|
adjuster = new TimestampAdjuster(TimestampAdjuster.DO_NOT_OFFSET);
|
||||||
timestampAdjusters.put(discontinuitySequence, adjuster);
|
timestampAdjusters.put(discontinuitySequence, adjuster);
|
||||||
}
|
}
|
||||||
return adjuster;
|
return adjuster;
|
||||||
|
@ -34,21 +34,39 @@ public final class TimestampAdjuster {
|
|||||||
*/
|
*/
|
||||||
private static final long MAX_PTS_PLUS_ONE = 0x200000000L;
|
private static final long MAX_PTS_PLUS_ONE = 0x200000000L;
|
||||||
|
|
||||||
public final long firstSampleTimestampUs;
|
private long firstSampleTimestampUs;
|
||||||
|
|
||||||
private long timestampOffsetUs;
|
private long timestampOffsetUs;
|
||||||
|
|
||||||
// Volatile to allow isInitialized to be called on a different thread to adjustSampleTimestamp.
|
// Volatile to allow isInitialized to be called on a different thread to adjustSampleTimestamp.
|
||||||
private volatile long lastSampleTimestamp;
|
private volatile long lastSampleTimestamp;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param firstSampleTimestampUs The desired result of the first call to
|
* @param firstSampleTimestampUs See {@link #setFirstSampleTimestampUs(long)}.
|
||||||
* {@link #adjustSampleTimestamp(long)}, or {@link #DO_NOT_OFFSET} if presentation timestamps
|
|
||||||
* should not be offset.
|
|
||||||
*/
|
*/
|
||||||
public TimestampAdjuster(long firstSampleTimestampUs) {
|
public TimestampAdjuster(long firstSampleTimestampUs) {
|
||||||
this.firstSampleTimestampUs = firstSampleTimestampUs;
|
|
||||||
lastSampleTimestamp = C.TIME_UNSET;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user