Commit fa1049ec by aquilescanta Committed by Oliver Woodman

Fix SCTE-35 timestamp adjustment

Issue:#4573

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=206737252
parent c41f955f
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
([#4029](https://github.com/google/ExoPlayer/issues/4029)). ([#4029](https://github.com/google/ExoPlayer/issues/4029)).
* DRM: Allow DrmInitData to carry a license server URL * DRM: Allow DrmInitData to carry a license server URL
([#3393](https://github.com/google/ExoPlayer/issues/3393)). ([#3393](https://github.com/google/ExoPlayer/issues/3393)).
* MPEG-TS: Fix bug preventing SCTE-35 cues from being output
([#4573](https://github.com/google/ExoPlayer/issues/4573)).
* Expose all internal ID3 data stored in MP4 udta boxes, and switch from using * Expose all internal ID3 data stored in MP4 udta boxes, and switch from using
CommentFrame to InternalFrame for frames with gapless metadata in MP4. CommentFrame to InternalFrame for frames with gapless metadata in MP4.
* Add `PlayerView.isControllerVisible` * Add `PlayerView.isControllerVisible`
......
...@@ -30,7 +30,8 @@ public final class TimestampAdjuster { ...@@ -30,7 +30,8 @@ public final class TimestampAdjuster {
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) MPEG-2 TS presentation timestamp. * The value one greater than the largest representable (33 bit) MPEG-2 TS 90 kHz clock
* presentation timestamp.
*/ */
private static final long MAX_PTS_PLUS_ONE = 0x200000000L; private static final long MAX_PTS_PLUS_ONE = 0x200000000L;
...@@ -38,13 +39,13 @@ public final class TimestampAdjuster { ...@@ -38,13 +39,13 @@ public final class TimestampAdjuster {
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 lastSampleTimestampUs;
/** /**
* @param firstSampleTimestampUs See {@link #setFirstSampleTimestampUs(long)}. * @param firstSampleTimestampUs See {@link #setFirstSampleTimestampUs(long)}.
*/ */
public TimestampAdjuster(long firstSampleTimestampUs) { public TimestampAdjuster(long firstSampleTimestampUs) {
lastSampleTimestamp = C.TIME_UNSET; lastSampleTimestampUs = C.TIME_UNSET;
setFirstSampleTimestampUs(firstSampleTimestampUs); setFirstSampleTimestampUs(firstSampleTimestampUs);
} }
...@@ -56,30 +57,24 @@ public final class TimestampAdjuster { ...@@ -56,30 +57,24 @@ public final class TimestampAdjuster {
* {@link #DO_NOT_OFFSET} if presentation timestamps should not be offset. * {@link #DO_NOT_OFFSET} if presentation timestamps should not be offset.
*/ */
public synchronized void setFirstSampleTimestampUs(long firstSampleTimestampUs) { public synchronized void setFirstSampleTimestampUs(long firstSampleTimestampUs) {
Assertions.checkState(lastSampleTimestamp == C.TIME_UNSET); Assertions.checkState(lastSampleTimestampUs == C.TIME_UNSET);
this.firstSampleTimestampUs = firstSampleTimestampUs; this.firstSampleTimestampUs = firstSampleTimestampUs;
} }
/** /** Returns the last value passed to {@link #setFirstSampleTimestampUs(long)}. */
* Returns the first adjusted sample timestamp in microseconds.
*
* @return The first adjusted sample timestamp in microseconds.
*/
public long getFirstSampleTimestampUs() { public long getFirstSampleTimestampUs() {
return firstSampleTimestampUs; return firstSampleTimestampUs;
} }
/** /**
* Returns the last adjusted timestamp. If no timestamp has been adjusted, returns * Returns the last value obtained from {@link #adjustSampleTimestamp}. If {@link
* {@code firstSampleTimestampUs} as provided to the constructor. If this value is * #adjustSampleTimestamp} has not been called, returns the result of calling {@link
* {@link #DO_NOT_OFFSET}, returns {@link C#TIME_UNSET}. * #getFirstSampleTimestampUs()}. If this value is {@link #DO_NOT_OFFSET}, returns {@link
* * C#TIME_UNSET}.
* @return The last adjusted timestamp. If not present, {@code firstSampleTimestampUs} is
* returned unless equal to {@link #DO_NOT_OFFSET}, in which case {@link C#TIME_UNSET} is
* returned.
*/ */
public long getLastAdjustedTimestampUs() { public long getLastAdjustedTimestampUs() {
return lastSampleTimestamp != C.TIME_UNSET ? lastSampleTimestamp return lastSampleTimestampUs != C.TIME_UNSET
? (lastSampleTimestampUs + timestampOffsetUs)
: firstSampleTimestampUs != DO_NOT_OFFSET ? firstSampleTimestampUs : C.TIME_UNSET; : firstSampleTimestampUs != DO_NOT_OFFSET ? firstSampleTimestampUs : C.TIME_UNSET;
} }
...@@ -93,44 +88,47 @@ public final class TimestampAdjuster { ...@@ -93,44 +88,47 @@ public final class TimestampAdjuster {
* be offset. * be offset.
*/ */
public long getTimestampOffsetUs() { public long getTimestampOffsetUs() {
return firstSampleTimestampUs == DO_NOT_OFFSET ? 0 return firstSampleTimestampUs == DO_NOT_OFFSET
: lastSampleTimestamp == C.TIME_UNSET ? C.TIME_UNSET : timestampOffsetUs; ? 0
: lastSampleTimestampUs == C.TIME_UNSET ? C.TIME_UNSET : timestampOffsetUs;
} }
/** /**
* Resets the instance to its initial state. * Resets the instance to its initial state.
*/ */
public void reset() { public void reset() {
lastSampleTimestamp = C.TIME_UNSET; lastSampleTimestampUs = C.TIME_UNSET;
} }
/** /**
* Scales and offsets an MPEG-2 TS presentation timestamp considering wraparound. * Scales and offsets an MPEG-2 TS presentation timestamp considering wraparound.
* *
* @param pts The MPEG-2 TS presentation timestamp. * @param pts90Khz A 90 kHz clock MPEG-2 TS presentation timestamp.
* @return The adjusted timestamp in microseconds. * @return The adjusted timestamp in microseconds.
*/ */
public long adjustTsTimestamp(long pts) { public long adjustTsTimestamp(long pts90Khz) {
if (pts == C.TIME_UNSET) { if (pts90Khz == C.TIME_UNSET) {
return C.TIME_UNSET; return C.TIME_UNSET;
} }
if (lastSampleTimestamp != C.TIME_UNSET) { if (lastSampleTimestampUs != 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 lastSampleTimestamp. // and we need to snap to the one closest to lastSampleTimestampUs.
long lastPts = usToPts(lastSampleTimestamp); long lastPts = usToPts(lastSampleTimestampUs);
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 = pts90Khz + (MAX_PTS_PLUS_ONE * (closestWrapCount - 1));
long ptsWrapAbove = pts + (MAX_PTS_PLUS_ONE * closestWrapCount); long ptsWrapAbove = pts90Khz + (MAX_PTS_PLUS_ONE * closestWrapCount);
pts = Math.abs(ptsWrapBelow - lastPts) < Math.abs(ptsWrapAbove - lastPts) pts90Khz =
? ptsWrapBelow : ptsWrapAbove; Math.abs(ptsWrapBelow - lastPts) < Math.abs(ptsWrapAbove - lastPts)
? ptsWrapBelow
: ptsWrapAbove;
} }
return adjustSampleTimestamp(ptsToUs(pts)); return adjustSampleTimestamp(ptsToUs(pts90Khz));
} }
/** /**
* Offsets a sample timestamp in microseconds. * Offsets a timestamp in microseconds.
* *
* @param timeUs The timestamp of a sample to adjust. * @param timeUs The timestamp to adjust in microseconds.
* @return The adjusted timestamp in microseconds. * @return The adjusted timestamp in microseconds.
*/ */
public long adjustSampleTimestamp(long timeUs) { public long adjustSampleTimestamp(long timeUs) {
...@@ -138,15 +136,15 @@ public final class TimestampAdjuster { ...@@ -138,15 +136,15 @@ public final class TimestampAdjuster {
return C.TIME_UNSET; return C.TIME_UNSET;
} }
// Record the adjusted PTS to adjust for wraparound next time. // Record the adjusted PTS to adjust for wraparound next time.
if (lastSampleTimestamp != C.TIME_UNSET) { if (lastSampleTimestampUs != C.TIME_UNSET) {
lastSampleTimestamp = timeUs; lastSampleTimestampUs = timeUs;
} else { } else {
if (firstSampleTimestampUs != DO_NOT_OFFSET) { if (firstSampleTimestampUs != DO_NOT_OFFSET) {
// Calculate the timestamp offset. // Calculate the timestamp offset.
timestampOffsetUs = firstSampleTimestampUs - timeUs; timestampOffsetUs = firstSampleTimestampUs - timeUs;
} }
synchronized (this) { synchronized (this) {
lastSampleTimestamp = timeUs; lastSampleTimestampUs = timeUs;
// Notify threads waiting for this adjuster to be initialized. // Notify threads waiting for this adjuster to be initialized.
notifyAll(); notifyAll();
} }
...@@ -160,15 +158,15 @@ public final class TimestampAdjuster { ...@@ -160,15 +158,15 @@ public final class TimestampAdjuster {
* @throws InterruptedException If the thread was interrupted. * @throws InterruptedException If the thread was interrupted.
*/ */
public synchronized void waitUntilInitialized() throws InterruptedException { public synchronized void waitUntilInitialized() throws InterruptedException {
while (lastSampleTimestamp == C.TIME_UNSET) { while (lastSampleTimestampUs == C.TIME_UNSET) {
wait(); wait();
} }
} }
/** /**
* Converts a value in MPEG-2 timestamp units to the corresponding value in microseconds. * Converts a 90 kHz clock timestamp to a timestamp in microseconds.
* *
* @param pts A value in MPEG-2 timestamp units. * @param pts A 90 kHz clock timestamp.
* @return The corresponding value in microseconds. * @return The corresponding value in microseconds.
*/ */
public static long ptsToUs(long pts) { public static long ptsToUs(long pts) {
...@@ -176,10 +174,10 @@ public final class TimestampAdjuster { ...@@ -176,10 +174,10 @@ public final class TimestampAdjuster {
} }
/** /**
* Converts a value in microseconds to the corresponding values in MPEG-2 timestamp units. * Converts a timestamp in microseconds to a 90 kHz clock timestamp.
* *
* @param us A value in microseconds. * @param us A value in microseconds.
* @return The corresponding value in MPEG-2 timestamp units. * @return The corresponding value as a 90 kHz clock timestamp.
*/ */
public static long usToPts(long us) { public static long usToPts(long us) {
return (us * 90000) / C.MICROS_PER_SECOND; return (us * 90000) / C.MICROS_PER_SECOND;
......
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