diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/SegmentBase.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/SegmentBase.java index 89a9dd49be..df92d029bc 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/mpd/SegmentBase.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/SegmentBase.java @@ -15,6 +15,8 @@ */ package com.google.android.exoplayer.dash.mpd; +import com.google.android.exoplayer.util.Util; + import android.net.Uri; import java.util.List; @@ -155,7 +157,7 @@ public abstract class SegmentBase { } else { unscaledSegmentTime = (sequenceNumber - startNumber) * duration; } - return (unscaledSegmentTime * 1000000) / timescale; + return Util.scaleLargeTimestamp(unscaledSegmentTime, 1000000, timescale); } public abstract RangedUri getSegmentUrl(Representation representation, int index); diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java index a26ca6a48e..7b45aed9cc 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifest.java @@ -53,19 +53,8 @@ public class SmoothStreamingManifest { this.isLive = isLive; this.protectionElement = protectionElement; this.streamElements = streamElements; - if (timescale >= MICROS_PER_SECOND && (timescale % MICROS_PER_SECOND) == 0) { - long divisionFactor = timescale / MICROS_PER_SECOND; - dvrWindowLengthUs = dvrWindowLength / divisionFactor; - durationUs = duration / divisionFactor; - } else if (timescale < MICROS_PER_SECOND && (MICROS_PER_SECOND % timescale) == 0) { - long multiplicationFactor = MICROS_PER_SECOND / timescale; - dvrWindowLengthUs = dvrWindowLength * multiplicationFactor; - durationUs = duration * multiplicationFactor; - } else { - double multiplicationFactor = (double) MICROS_PER_SECOND / timescale; - dvrWindowLengthUs = (long) (dvrWindowLength * multiplicationFactor); - durationUs = (long) (duration * multiplicationFactor); - } + dvrWindowLengthUs = Util.scaleLargeTimestamp(dvrWindowLength, MICROS_PER_SECOND, timescale); + durationUs = Util.scaleLargeTimestamp(duration, MICROS_PER_SECOND, timescale); } /** @@ -186,26 +175,10 @@ public class SmoothStreamingManifest { this.tracks = tracks; this.chunkCount = chunkStartTimes.size(); this.chunkStartTimes = chunkStartTimes; - chunkStartTimesUs = new long[chunkStartTimes.size()]; - if (timescale >= MICROS_PER_SECOND && (timescale % MICROS_PER_SECOND) == 0) { - long divisionFactor = timescale / MICROS_PER_SECOND; - for (int i = 0; i < chunkStartTimesUs.length; i++) { - chunkStartTimesUs[i] = chunkStartTimes.get(i) / divisionFactor; - } - lastChunkDurationUs = lastChunkDuration / divisionFactor; - } else if (timescale < MICROS_PER_SECOND && (MICROS_PER_SECOND % timescale) == 0) { - long multiplicationFactor = MICROS_PER_SECOND / timescale; - for (int i = 0; i < chunkStartTimesUs.length; i++) { - chunkStartTimesUs[i] = chunkStartTimes.get(i) * multiplicationFactor; - } - lastChunkDurationUs = lastChunkDuration * multiplicationFactor; - } else { - double multiplicationFactor = (double) MICROS_PER_SECOND / timescale; - for (int i = 0; i < chunkStartTimesUs.length; i++) { - chunkStartTimesUs[i] = (long) (chunkStartTimes.get(i) * multiplicationFactor); - } - lastChunkDurationUs = (long) (lastChunkDuration * multiplicationFactor); - } + lastChunkDurationUs = + Util.scaleLargeTimestamp(lastChunkDuration, MICROS_PER_SECOND, timescale); + chunkStartTimesUs = + Util.scaleLargeTimestamps(chunkStartTimes, MICROS_PER_SECOND, timescale); } /** diff --git a/library/src/main/java/com/google/android/exoplayer/util/Util.java b/library/src/main/java/com/google/android/exoplayer/util/Util.java index 4c08c5a528..b8cd40215d 100644 --- a/library/src/main/java/com/google/android/exoplayer/util/Util.java +++ b/library/src/main/java/com/google/android/exoplayer/util/Util.java @@ -346,4 +346,57 @@ public final class Util { return time; } + /** + * Scales a large timestamp. + *
+ * Logically, scaling consists of a multiplication followed by a division. The actual operations
+ * performed are designed to minimize the probability of overflow.
+ *
+ * @param timestamp The timestamp to scale.
+ * @param multiplier The multiplier.
+ * @param divisor The divisor.
+ * @return The scaled timestamp.
+ */
+ public static long scaleLargeTimestamp(long timestamp, long multiplier, long divisor) {
+ if (divisor >= multiplier && (divisor % multiplier) == 0) {
+ long divisionFactor = divisor / multiplier;
+ return timestamp / divisionFactor;
+ } else if (divisor < multiplier && (multiplier % divisor) == 0) {
+ long multiplicationFactor = multiplier / divisor;
+ return timestamp * multiplicationFactor;
+ } else {
+ double multiplicationFactor = (double) multiplier / divisor;
+ return (long) (timestamp * multiplicationFactor);
+ }
+ }
+
+ /**
+ * Applies {@link #scaleLargeTimestamp(long, long, long)} to a list of unscaled timestamps.
+ *
+ * @param timestamps The timestamps to scale.
+ * @param multiplier The multiplier.
+ * @param divisor The divisor.
+ * @return The scaled timestamps.
+ */
+ public static long[] scaleLargeTimestamps(List