Fix SmoothStreamingManifest to handle large timestamps.

This commit is contained in:
Oliver Woodman 2014-09-23 11:13:09 +01:00
parent c4e1c3543c
commit 4fdd68facf
2 changed files with 44 additions and 34 deletions

View File

@ -77,7 +77,7 @@ public class SmoothStreamingChunkSource implements ChunkSource {
public SmoothStreamingChunkSource(SmoothStreamingManifest manifest, int streamElementIndex,
int[] trackIndices, DataSource dataSource, FormatEvaluator formatEvaluator) {
this.streamElement = manifest.streamElements[streamElementIndex];
this.trackInfo = new TrackInfo(streamElement.tracks[0].mimeType, manifest.getDurationUs());
this.trackInfo = new TrackInfo(streamElement.tracks[0].mimeType, manifest.durationUs);
this.dataSource = dataSource;
this.formatEvaluator = formatEvaluator;
this.evaluation = new Evaluation();

View File

@ -31,6 +31,8 @@ import java.util.UUID;
*/
public class SmoothStreamingManifest {
private static final long MICROS_PER_SECOND = 1000000L;
public final int majorVersion;
public final int minorVersion;
public final long timescale;
@ -38,9 +40,8 @@ public class SmoothStreamingManifest {
public final boolean isLive;
public final ProtectionElement protectionElement;
public final StreamElement[] streamElements;
private final long duration;
private final long dvrWindowLength;
public final long durationUs;
public final long dvrWindowLengthUs;
public SmoothStreamingManifest(int majorVersion, int minorVersion, long timescale, long duration,
long dvrWindowLength, int lookAheadCount, boolean isLive, ProtectionElement protectionElement,
@ -48,33 +49,23 @@ public class SmoothStreamingManifest {
this.majorVersion = majorVersion;
this.minorVersion = minorVersion;
this.timescale = timescale;
this.duration = duration;
this.dvrWindowLength = dvrWindowLength;
this.lookAheadCount = lookAheadCount;
this.isLive = isLive;
this.protectionElement = protectionElement;
this.streamElements = streamElements;
}
/**
* Gets the duration of the media.
* <p>
* For a live presentation the duration may be an approximation of the eventual final duration,
* or 0 if an approximate duration is not known.
*
* @return The duration of the media in microseconds.
*/
public long getDurationUs() {
return (duration * 1000000L) / timescale;
}
/**
* Gets the DVR window length, or 0 if no window length was specified.
*
* @return The duration of the DVR window in microseconds, or 0 if no window length was specified.
*/
public long getDvrWindowLengthUs() {
return (dvrWindowLength * 1000000L) / timescale;
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);
}
}
/**
@ -173,7 +164,8 @@ public class SmoothStreamingManifest {
private final String chunkTemplate;
private final List<Long> chunkStartTimes;
private final long lastChunkDuration;
private final long[] chunkStartTimesUs;
private final long lastChunkDurationUs;
public StreamElement(Uri baseUri, String chunkTemplate, int type, String subType,
long timescale, String name, int qualityLevels, int maxWidth, int maxHeight,
@ -194,7 +186,26 @@ public class SmoothStreamingManifest {
this.tracks = tracks;
this.chunkCount = chunkStartTimes.size();
this.chunkStartTimes = chunkStartTimes;
this.lastChunkDuration = lastChunkDuration;
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);
}
}
/**
@ -204,7 +215,7 @@ public class SmoothStreamingManifest {
* @return The index of the corresponding chunk.
*/
public int getChunkIndex(long timeUs) {
return Util.binarySearchFloor(chunkStartTimes, (timeUs * timescale) / 1000000L, true, true);
return Util.binarySearchFloor(chunkStartTimesUs, timeUs, true, true);
}
/**
@ -214,7 +225,7 @@ public class SmoothStreamingManifest {
* @return The start time of the chunk, in microseconds.
*/
public long getStartTimeUs(int chunkIndex) {
return (chunkStartTimes.get(chunkIndex) * 1000000L) / timescale;
return chunkStartTimesUs[chunkIndex];
}
/**
@ -224,9 +235,8 @@ public class SmoothStreamingManifest {
* @return The duration of the chunk, in microseconds.
*/
public long getChunkDurationUs(int chunkIndex) {
long chunkDuration = (chunkIndex == chunkCount - 1) ? lastChunkDuration
: chunkStartTimes.get(chunkIndex + 1) - chunkStartTimes.get(chunkIndex);
return chunkDuration / timescale;
return (chunkIndex == chunkCount - 1) ? lastChunkDurationUs
: chunkStartTimesUs[chunkIndex + 1] - chunkStartTimesUs[chunkIndex];
}
/**