From 9ec14d1ada60d5db4ddeced0f3fb74e90c75dd74 Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Tue, 31 Jul 2018 04:06:22 -0700 Subject: [PATCH] Fix SCTE-35 timestamp adjustment Issue:#4573 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=206737252 --- RELEASENOTES.md | 7 +- .../exoplayer2/util/TimestampAdjuster.java | 80 +++++++++---------- 2 files changed, 44 insertions(+), 43 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7363215fe2a..a92688bc249 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -4,8 +4,11 @@ * Add `AudioListener` for listening to changes in audio configuration during playback ([#3994](https://github.com/google/ExoPlayer/issues/3994)). -* MPEG-TS: Support CEA-608/708 in H262 - ([#2565](https://github.com/google/ExoPlayer/issues/2565)). +* MPEG-TS: + * Support CEA-608/708 in H262 + ([#2565](https://github.com/google/ExoPlayer/issues/2565)). + * Fix bug preventing SCTE-35 cues from being output + ([#4573](https://github.com/google/ExoPlayer/issues/4573)). * MPEG-PS: Support reading duration from MPEG-PS Streams ([#4476](https://github.com/google/ExoPlayer/issues/4476)). * MediaSession extension: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java b/library/core/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java index 08e2bd06698..439374a0861 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/TimestampAdjuster.java @@ -30,7 +30,8 @@ public final class TimestampAdjuster { 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; @@ -38,13 +39,13 @@ public final class TimestampAdjuster { private long timestampOffsetUs; // 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)}. */ public TimestampAdjuster(long firstSampleTimestampUs) { - lastSampleTimestamp = C.TIME_UNSET; + lastSampleTimestampUs = C.TIME_UNSET; setFirstSampleTimestampUs(firstSampleTimestampUs); } @@ -56,30 +57,24 @@ public TimestampAdjuster(long firstSampleTimestampUs) { * {@link #DO_NOT_OFFSET} if presentation timestamps should not be offset. */ public synchronized void setFirstSampleTimestampUs(long firstSampleTimestampUs) { - Assertions.checkState(lastSampleTimestamp == C.TIME_UNSET); + Assertions.checkState(lastSampleTimestampUs == C.TIME_UNSET); this.firstSampleTimestampUs = firstSampleTimestampUs; } - /** - * Returns the first adjusted sample timestamp in microseconds. - * - * @return The first adjusted sample timestamp in microseconds. - */ + /** Returns the last value passed to {@link #setFirstSampleTimestampUs(long)}. */ public long getFirstSampleTimestampUs() { return firstSampleTimestampUs; } /** - * Returns the last adjusted timestamp. If no timestamp has been adjusted, returns - * {@code firstSampleTimestampUs} as provided to the constructor. 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. + * Returns the last value obtained from {@link #adjustSampleTimestamp}. If {@link + * #adjustSampleTimestamp} has not been called, returns the result of calling {@link + * #getFirstSampleTimestampUs()}. If this value is {@link #DO_NOT_OFFSET}, returns {@link + * C#TIME_UNSET}. */ public long getLastAdjustedTimestampUs() { - return lastSampleTimestamp != C.TIME_UNSET ? lastSampleTimestamp + return lastSampleTimestampUs != C.TIME_UNSET + ? (lastSampleTimestampUs + timestampOffsetUs) : firstSampleTimestampUs != DO_NOT_OFFSET ? firstSampleTimestampUs : C.TIME_UNSET; } @@ -93,44 +88,47 @@ public long getLastAdjustedTimestampUs() { * be offset. */ public long getTimestampOffsetUs() { - return firstSampleTimestampUs == DO_NOT_OFFSET ? 0 - : lastSampleTimestamp == C.TIME_UNSET ? C.TIME_UNSET : timestampOffsetUs; + return firstSampleTimestampUs == DO_NOT_OFFSET + ? 0 + : lastSampleTimestampUs == C.TIME_UNSET ? C.TIME_UNSET : timestampOffsetUs; } /** * Resets the instance to its initial state. */ public void reset() { - lastSampleTimestamp = C.TIME_UNSET; + lastSampleTimestampUs = C.TIME_UNSET; } /** * 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. */ - public long adjustTsTimestamp(long pts) { - if (pts == C.TIME_UNSET) { + public long adjustTsTimestamp(long pts90Khz) { + if (pts90Khz == 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), - // and we need to snap to the one closest to lastSampleTimestamp. - long lastPts = usToPts(lastSampleTimestamp); + // and we need to snap to the one closest to lastSampleTimestampUs. + long lastPts = usToPts(lastSampleTimestampUs); long closestWrapCount = (lastPts + (MAX_PTS_PLUS_ONE / 2)) / MAX_PTS_PLUS_ONE; - long ptsWrapBelow = pts + (MAX_PTS_PLUS_ONE * (closestWrapCount - 1)); - long ptsWrapAbove = pts + (MAX_PTS_PLUS_ONE * closestWrapCount); - pts = Math.abs(ptsWrapBelow - lastPts) < Math.abs(ptsWrapAbove - lastPts) - ? ptsWrapBelow : ptsWrapAbove; + long ptsWrapBelow = pts90Khz + (MAX_PTS_PLUS_ONE * (closestWrapCount - 1)); + long ptsWrapAbove = pts90Khz + (MAX_PTS_PLUS_ONE * closestWrapCount); + pts90Khz = + 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. */ public long adjustSampleTimestamp(long timeUs) { @@ -138,15 +136,15 @@ public long adjustSampleTimestamp(long timeUs) { return C.TIME_UNSET; } // Record the adjusted PTS to adjust for wraparound next time. - if (lastSampleTimestamp != C.TIME_UNSET) { - lastSampleTimestamp = timeUs; + if (lastSampleTimestampUs != C.TIME_UNSET) { + lastSampleTimestampUs = timeUs; } else { if (firstSampleTimestampUs != DO_NOT_OFFSET) { // Calculate the timestamp offset. timestampOffsetUs = firstSampleTimestampUs - timeUs; } synchronized (this) { - lastSampleTimestamp = timeUs; + lastSampleTimestampUs = timeUs; // Notify threads waiting for this adjuster to be initialized. notifyAll(); } @@ -160,15 +158,15 @@ public long adjustSampleTimestamp(long timeUs) { * @throws InterruptedException If the thread was interrupted. */ public synchronized void waitUntilInitialized() throws InterruptedException { - while (lastSampleTimestamp == C.TIME_UNSET) { + while (lastSampleTimestampUs == C.TIME_UNSET) { 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. */ public static long ptsToUs(long pts) { @@ -176,10 +174,10 @@ public static long ptsToUs(long pts) { } /** - * 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. - * @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) { return (us * 90000) / C.MICROS_PER_SECOND;