Use long segment indices for DASH
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=183389701
This commit is contained in:
parent
46c4ca7ddb
commit
8ba3335145
@ -37,9 +37,15 @@ public abstract class BaseMediaChunk extends MediaChunk {
|
||||
* @param endTimeUs The end time of the media contained by the chunk, in microseconds.
|
||||
* @param chunkIndex The index of the chunk.
|
||||
*/
|
||||
public BaseMediaChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat,
|
||||
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs,
|
||||
int chunkIndex) {
|
||||
public BaseMediaChunk(
|
||||
DataSource dataSource,
|
||||
DataSpec dataSpec,
|
||||
Format trackFormat,
|
||||
int trackSelectionReason,
|
||||
Object trackSelectionData,
|
||||
long startTimeUs,
|
||||
long endTimeUs,
|
||||
long chunkIndex) {
|
||||
super(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs,
|
||||
endTimeUs, chunkIndex);
|
||||
}
|
||||
|
@ -53,9 +53,18 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
||||
* @param sampleOffsetUs An offset to add to the sample timestamps parsed by the extractor.
|
||||
* @param extractorWrapper A wrapped extractor to use for parsing the data.
|
||||
*/
|
||||
public ContainerMediaChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat,
|
||||
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs,
|
||||
int chunkIndex, int chunkCount, long sampleOffsetUs, ChunkExtractorWrapper extractorWrapper) {
|
||||
public ContainerMediaChunk(
|
||||
DataSource dataSource,
|
||||
DataSpec dataSpec,
|
||||
Format trackFormat,
|
||||
int trackSelectionReason,
|
||||
Object trackSelectionData,
|
||||
long startTimeUs,
|
||||
long endTimeUs,
|
||||
long chunkIndex,
|
||||
int chunkCount,
|
||||
long sampleOffsetUs,
|
||||
ChunkExtractorWrapper extractorWrapper) {
|
||||
super(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs,
|
||||
endTimeUs, chunkIndex);
|
||||
this.chunkCount = chunkCount;
|
||||
|
@ -50,9 +50,17 @@ public final class SingleSampleMediaChunk extends BaseMediaChunk {
|
||||
* constants.
|
||||
* @param sampleFormat The {@link Format} of the sample in the chunk.
|
||||
*/
|
||||
public SingleSampleMediaChunk(DataSource dataSource, DataSpec dataSpec, Format trackFormat,
|
||||
int trackSelectionReason, Object trackSelectionData, long startTimeUs, long endTimeUs,
|
||||
int chunkIndex, int trackType, Format sampleFormat) {
|
||||
public SingleSampleMediaChunk(
|
||||
DataSource dataSource,
|
||||
DataSpec dataSpec,
|
||||
Format trackFormat,
|
||||
int trackSelectionReason,
|
||||
Object trackSelectionData,
|
||||
long startTimeUs,
|
||||
long endTimeUs,
|
||||
long chunkIndex,
|
||||
int trackType,
|
||||
Format sampleFormat) {
|
||||
super(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs,
|
||||
endTimeUs, chunkIndex);
|
||||
this.trackType = trackType;
|
||||
|
@ -64,7 +64,7 @@ public class DashManifestParserTest extends InstrumentationTestCase {
|
||||
if (representation instanceof Representation.MultiSegmentRepresentation) {
|
||||
Representation.MultiSegmentRepresentation multiSegmentRepresentation =
|
||||
(Representation.MultiSegmentRepresentation) representation;
|
||||
int firstSegmentIndex = multiSegmentRepresentation.getFirstSegmentNum();
|
||||
long firstSegmentIndex = multiSegmentRepresentation.getFirstSegmentNum();
|
||||
RangedUri uri = multiSegmentRepresentation.getSegmentUrl(firstSegmentIndex);
|
||||
assertThat(
|
||||
uri.resolveUriString(representation.baseUrl)
|
||||
|
@ -898,11 +898,11 @@ public final class DashMediaSource implements MediaSource {
|
||||
availableStartTimeUs = 0;
|
||||
availableEndTimeUs = 0;
|
||||
} else if (!seenEmptyIndex) {
|
||||
int firstSegmentNum = index.getFirstSegmentNum();
|
||||
long firstSegmentNum = index.getFirstSegmentNum();
|
||||
long adaptationSetAvailableStartTimeUs = index.getTimeUs(firstSegmentNum);
|
||||
availableStartTimeUs = Math.max(availableStartTimeUs, adaptationSetAvailableStartTimeUs);
|
||||
if (segmentCount != DashSegmentIndex.INDEX_UNBOUNDED) {
|
||||
int lastSegmentNum = firstSegmentNum + segmentCount - 1;
|
||||
long lastSegmentNum = firstSegmentNum + segmentCount - 1;
|
||||
long adaptationSetAvailableEndTimeUs = index.getTimeUs(lastSegmentNum)
|
||||
+ index.getDurationUs(lastSegmentNum, durationUs);
|
||||
availableEndTimeUs = Math.min(availableEndTimeUs, adaptationSetAvailableEndTimeUs);
|
||||
@ -1027,7 +1027,7 @@ public final class DashMediaSource implements MediaSource {
|
||||
// Video adaptation set does not include a non-empty index for snapping.
|
||||
return windowDefaultStartPositionUs;
|
||||
}
|
||||
int segmentNum = snapIndex.getSegmentNum(defaultStartPositionInPeriodUs, periodDurationUs);
|
||||
long segmentNum = snapIndex.getSegmentNum(defaultStartPositionInPeriodUs, periodDurationUs);
|
||||
return windowDefaultStartPositionUs + snapIndex.getTimeUs(segmentNum)
|
||||
- defaultStartPositionInPeriodUs;
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ public interface DashSegmentIndex {
|
||||
* Otherwise, returns the segment number of the segment containing the given media time.
|
||||
*
|
||||
* @param timeUs The time in microseconds.
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or
|
||||
* {@link C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or {@link
|
||||
* C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @return The segment number of the corresponding segment.
|
||||
*/
|
||||
int getSegmentNum(long timeUs, long periodDurationUs);
|
||||
long getSegmentNum(long timeUs, long periodDurationUs);
|
||||
|
||||
/**
|
||||
* Returns the start time of a segment.
|
||||
@ -44,17 +44,17 @@ public interface DashSegmentIndex {
|
||||
* @param segmentNum The segment number.
|
||||
* @return The corresponding start time in microseconds.
|
||||
*/
|
||||
long getTimeUs(int segmentNum);
|
||||
long getTimeUs(long segmentNum);
|
||||
|
||||
/**
|
||||
* Returns the duration of a segment.
|
||||
*
|
||||
* @param segmentNum The segment number.
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or
|
||||
* {@link C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @param periodDurationUs The duration of the enclosing period in microseconds, or {@link
|
||||
* C#TIME_UNSET} if the period's duration is not yet known.
|
||||
* @return The duration of the segment, in microseconds.
|
||||
*/
|
||||
long getDurationUs(int segmentNum, long periodDurationUs);
|
||||
long getDurationUs(long segmentNum, long periodDurationUs);
|
||||
|
||||
/**
|
||||
* Returns a {@link RangedUri} defining the location of a segment.
|
||||
@ -62,14 +62,14 @@ public interface DashSegmentIndex {
|
||||
* @param segmentNum The segment number.
|
||||
* @return The {@link RangedUri} defining the location of the data.
|
||||
*/
|
||||
RangedUri getSegmentUrl(int segmentNum);
|
||||
RangedUri getSegmentUrl(long segmentNum);
|
||||
|
||||
/**
|
||||
* Returns the segment number of the first segment.
|
||||
*
|
||||
* @return The segment number of the first segment.
|
||||
*/
|
||||
int getFirstSegmentNum();
|
||||
long getFirstSegmentNum();
|
||||
|
||||
/**
|
||||
* Returns the number of segments in the index, or {@link #INDEX_UNBOUNDED}.
|
||||
|
@ -34,7 +34,7 @@ public final class DashWrappingSegmentIndex implements DashSegmentIndex {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstSegmentNum() {
|
||||
public long getFirstSegmentNum() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -44,22 +44,23 @@ public final class DashWrappingSegmentIndex implements DashSegmentIndex {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeUs(int segmentNum) {
|
||||
return chunkIndex.timesUs[segmentNum];
|
||||
public long getTimeUs(long segmentNum) {
|
||||
return chunkIndex.timesUs[(int) segmentNum];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDurationUs(int segmentNum, long periodDurationUs) {
|
||||
return chunkIndex.durationsUs[segmentNum];
|
||||
public long getDurationUs(long segmentNum, long periodDurationUs) {
|
||||
return chunkIndex.durationsUs[(int) segmentNum];
|
||||
}
|
||||
|
||||
@Override
|
||||
public RangedUri getSegmentUrl(int segmentNum) {
|
||||
return new RangedUri(null, chunkIndex.offsets[segmentNum], chunkIndex.sizes[segmentNum]);
|
||||
public RangedUri getSegmentUrl(long segmentNum) {
|
||||
return new RangedUri(
|
||||
null, chunkIndex.offsets[(int) segmentNum], chunkIndex.sizes[(int) segmentNum]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
public long getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
return chunkIndex.getChunkIndex(timeUs);
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
// Segments are aligned across representations, so any segment index will do.
|
||||
for (RepresentationHolder representationHolder : representationHolders) {
|
||||
if (representationHolder.segmentIndex != null) {
|
||||
int segmentNum = representationHolder.getSegmentNum(positionUs);
|
||||
long segmentNum = representationHolder.getSegmentNum(positionUs);
|
||||
long firstSyncUs = representationHolder.getSegmentStartTimeUs(segmentNum);
|
||||
long secondSyncUs =
|
||||
firstSyncUs < positionUs && segmentNum < representationHolder.getSegmentCount() - 1
|
||||
@ -284,8 +284,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return;
|
||||
}
|
||||
|
||||
int firstAvailableSegmentNum = representationHolder.getFirstSegmentNum();
|
||||
int lastAvailableSegmentNum;
|
||||
long firstAvailableSegmentNum = representationHolder.getFirstSegmentNum();
|
||||
long lastAvailableSegmentNum;
|
||||
if (availableSegmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
|
||||
// The index is itself unbounded. We need to use the current time to calculate the range of
|
||||
// available segments.
|
||||
@ -306,12 +306,12 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
|
||||
updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum);
|
||||
|
||||
int segmentNum;
|
||||
long segmentNum;
|
||||
if (previous == null) {
|
||||
segmentNum = Util.constrainValue(representationHolder.getSegmentNum(loadPositionUs),
|
||||
firstAvailableSegmentNum, lastAvailableSegmentNum);
|
||||
} else {
|
||||
segmentNum = (int) previous.getNextChunkIndex();
|
||||
segmentNum = previous.getNextChunkIndex();
|
||||
if (segmentNum < firstAvailableSegmentNum) {
|
||||
// This is before the first chunk in the current manifest.
|
||||
fatalError = new BehindLiveWindowException();
|
||||
@ -326,7 +326,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return;
|
||||
}
|
||||
|
||||
int maxSegmentCount = Math.min(maxSegmentsPerLoad, lastAvailableSegmentNum - segmentNum + 1);
|
||||
int maxSegmentCount =
|
||||
(int) Math.min(maxSegmentsPerLoad, lastAvailableSegmentNum - segmentNum + 1);
|
||||
out.chunk = newMediaChunk(representationHolder, dataSource, trackType,
|
||||
trackSelection.getSelectedFormat(), trackSelection.getSelectionReason(),
|
||||
trackSelection.getSelectionData(), segmentNum, maxSegmentCount);
|
||||
@ -370,7 +371,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
representationHolders[trackSelection.indexOf(chunk.trackFormat)];
|
||||
int segmentCount = representationHolder.getSegmentCount();
|
||||
if (segmentCount != DashSegmentIndex.INDEX_UNBOUNDED && segmentCount != 0) {
|
||||
int lastAvailableSegmentNum = representationHolder.getFirstSegmentNum() + segmentCount - 1;
|
||||
long lastAvailableSegmentNum = representationHolder.getFirstSegmentNum() + segmentCount - 1;
|
||||
if (((MediaChunk) chunk).getNextChunkIndex() > lastAvailableSegmentNum) {
|
||||
missingLastSegment = true;
|
||||
return true;
|
||||
@ -393,8 +394,8 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return representations;
|
||||
}
|
||||
|
||||
private void updateLiveEdgeTimeUs(RepresentationHolder representationHolder,
|
||||
int lastAvailableSegmentNum) {
|
||||
private void updateLiveEdgeTimeUs(
|
||||
RepresentationHolder representationHolder, long lastAvailableSegmentNum) {
|
||||
liveEdgeTimeUs = manifest.dynamic
|
||||
? representationHolder.getSegmentEndTimeUs(lastAvailableSegmentNum) : C.TIME_UNSET;
|
||||
}
|
||||
@ -433,9 +434,15 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
trackSelectionReason, trackSelectionData, representationHolder.extractorWrapper);
|
||||
}
|
||||
|
||||
protected static Chunk newMediaChunk(RepresentationHolder representationHolder,
|
||||
DataSource dataSource, int trackType, Format trackFormat, int trackSelectionReason,
|
||||
Object trackSelectionData, int firstSegmentNum, int maxSegmentCount) {
|
||||
protected static Chunk newMediaChunk(
|
||||
RepresentationHolder representationHolder,
|
||||
DataSource dataSource,
|
||||
int trackType,
|
||||
Format trackFormat,
|
||||
int trackSelectionReason,
|
||||
Object trackSelectionData,
|
||||
long firstSegmentNum,
|
||||
int maxSegmentCount) {
|
||||
Representation representation = representationHolder.representation;
|
||||
long startTimeUs = representationHolder.getSegmentStartTimeUs(firstSegmentNum);
|
||||
RangedUri segmentUri = representationHolder.getSegmentUrl(firstSegmentNum);
|
||||
@ -481,7 +488,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
public DashSegmentIndex segmentIndex;
|
||||
|
||||
private long periodDurationUs;
|
||||
private int segmentNumShift;
|
||||
private long segmentNumShift;
|
||||
|
||||
/* package */ RepresentationHolder(
|
||||
long periodDurationUs,
|
||||
@ -547,10 +554,10 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1;
|
||||
long oldIndexLastSegmentNum = oldIndex.getFirstSegmentNum() + oldIndexSegmentCount - 1;
|
||||
long oldIndexEndTimeUs = oldIndex.getTimeUs(oldIndexLastSegmentNum)
|
||||
+ oldIndex.getDurationUs(oldIndexLastSegmentNum, periodDurationUs);
|
||||
int newIndexFirstSegmentNum = newIndex.getFirstSegmentNum();
|
||||
long newIndexFirstSegmentNum = newIndex.getFirstSegmentNum();
|
||||
long newIndexStartTimeUs = newIndex.getTimeUs(newIndexFirstSegmentNum);
|
||||
if (oldIndexEndTimeUs == newIndexStartTimeUs) {
|
||||
// The new index continues where the old one ended, with no overlap.
|
||||
@ -566,7 +573,7 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
}
|
||||
}
|
||||
|
||||
public int getFirstSegmentNum() {
|
||||
public long getFirstSegmentNum() {
|
||||
return segmentIndex.getFirstSegmentNum() + segmentNumShift;
|
||||
}
|
||||
|
||||
@ -574,20 +581,20 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
return segmentIndex.getSegmentCount(periodDurationUs);
|
||||
}
|
||||
|
||||
public long getSegmentStartTimeUs(int segmentNum) {
|
||||
public long getSegmentStartTimeUs(long segmentNum) {
|
||||
return segmentIndex.getTimeUs(segmentNum - segmentNumShift);
|
||||
}
|
||||
|
||||
public long getSegmentEndTimeUs(int segmentNum) {
|
||||
public long getSegmentEndTimeUs(long segmentNum) {
|
||||
return getSegmentStartTimeUs(segmentNum)
|
||||
+ segmentIndex.getDurationUs(segmentNum - segmentNumShift, periodDurationUs);
|
||||
}
|
||||
|
||||
public int getSegmentNum(long positionUs) {
|
||||
public long getSegmentNum(long positionUs) {
|
||||
return segmentIndex.getSegmentNum(positionUs, periodDurationUs) + segmentNumShift;
|
||||
}
|
||||
|
||||
public RangedUri getSegmentUrl(int segmentNum) {
|
||||
public RangedUri getSegmentUrl(long segmentNum) {
|
||||
return segmentIndex.getSegmentUrl(segmentNum - segmentNumShift);
|
||||
}
|
||||
|
||||
|
@ -602,7 +602,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
||||
parent != null ? parent.presentationTimeOffset : 0);
|
||||
long duration = parseLong(xpp, "duration", parent != null ? parent.duration : C.TIME_UNSET);
|
||||
int startNumber = parseInt(xpp, "startNumber", parent != null ? parent.startNumber : 1);
|
||||
long startNumber = parseLong(xpp, "startNumber", parent != null ? parent.startNumber : 1);
|
||||
|
||||
RangedUri initialization = null;
|
||||
List<SegmentTimelineElement> timeline = null;
|
||||
@ -632,9 +632,14 @@ public class DashManifestParser extends DefaultHandler
|
||||
startNumber, duration, timeline, segments);
|
||||
}
|
||||
|
||||
protected SegmentList buildSegmentList(RangedUri initialization, long timescale,
|
||||
long presentationTimeOffset, int startNumber, long duration,
|
||||
List<SegmentTimelineElement> timeline, List<RangedUri> segments) {
|
||||
protected SegmentList buildSegmentList(
|
||||
RangedUri initialization,
|
||||
long timescale,
|
||||
long presentationTimeOffset,
|
||||
long startNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> timeline,
|
||||
List<RangedUri> segments) {
|
||||
return new SegmentList(initialization, timescale, presentationTimeOffset,
|
||||
startNumber, duration, timeline, segments);
|
||||
}
|
||||
@ -645,7 +650,7 @@ public class DashManifestParser extends DefaultHandler
|
||||
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
||||
parent != null ? parent.presentationTimeOffset : 0);
|
||||
long duration = parseLong(xpp, "duration", parent != null ? parent.duration : C.TIME_UNSET);
|
||||
int startNumber = parseInt(xpp, "startNumber", parent != null ? parent.startNumber : 1);
|
||||
long startNumber = parseLong(xpp, "startNumber", parent != null ? parent.startNumber : 1);
|
||||
UrlTemplate mediaTemplate = parseUrlTemplate(xpp, "media",
|
||||
parent != null ? parent.mediaTemplate : null);
|
||||
UrlTemplate initializationTemplate = parseUrlTemplate(xpp, "initialization",
|
||||
@ -672,9 +677,14 @@ public class DashManifestParser extends DefaultHandler
|
||||
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
|
||||
}
|
||||
|
||||
protected SegmentTemplate buildSegmentTemplate(RangedUri initialization, long timescale,
|
||||
long presentationTimeOffset, int startNumber, long duration,
|
||||
List<SegmentTimelineElement> timeline, UrlTemplate initializationTemplate,
|
||||
protected SegmentTemplate buildSegmentTemplate(
|
||||
RangedUri initialization,
|
||||
long timescale,
|
||||
long presentationTimeOffset,
|
||||
long startNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> timeline,
|
||||
UrlTemplate initializationTemplate,
|
||||
UrlTemplate mediaTemplate) {
|
||||
return new SegmentTemplate(initialization, timescale, presentationTimeOffset,
|
||||
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
|
||||
|
@ -292,27 +292,27 @@ public abstract class Representation {
|
||||
// DashSegmentIndex implementation.
|
||||
|
||||
@Override
|
||||
public RangedUri getSegmentUrl(int segmentIndex) {
|
||||
public RangedUri getSegmentUrl(long segmentIndex) {
|
||||
return segmentBase.getSegmentUrl(this, segmentIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
public long getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
return segmentBase.getSegmentNum(timeUs, periodDurationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeUs(int segmentIndex) {
|
||||
public long getTimeUs(long segmentIndex) {
|
||||
return segmentBase.getSegmentTimeUs(segmentIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDurationUs(int segmentIndex, long periodDurationUs) {
|
||||
public long getDurationUs(long segmentIndex, long periodDurationUs) {
|
||||
return segmentBase.getSegmentDurationUs(segmentIndex, periodDurationUs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstSegmentNum() {
|
||||
public long getFirstSegmentNum() {
|
||||
return segmentBase.getFirstSegmentNum();
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ public abstract class SegmentBase {
|
||||
*/
|
||||
public abstract static class MultiSegmentBase extends SegmentBase {
|
||||
|
||||
/* package */ final int startNumber;
|
||||
/* package */ final long startNumber;
|
||||
/* package */ final long duration;
|
||||
/* package */ final List<SegmentTimelineElement> segmentTimeline;
|
||||
|
||||
@ -111,43 +111,46 @@ public abstract class SegmentBase {
|
||||
* division of this value and {@code timescale}.
|
||||
* @param startNumber The sequence number of the first segment.
|
||||
* @param duration The duration of each segment in the case of fixed duration segments. The
|
||||
* value in seconds is the division of this value and {@code timescale}. If
|
||||
* {@code segmentTimeline} is non-null then this parameter is ignored.
|
||||
* value in seconds is the division of this value and {@code timescale}. If {@code
|
||||
* segmentTimeline} is non-null then this parameter is ignored.
|
||||
* @param segmentTimeline A segment timeline corresponding to the segments. If null, then
|
||||
* segments are assumed to be of fixed duration as specified by the {@code duration}
|
||||
* parameter.
|
||||
*/
|
||||
public MultiSegmentBase(RangedUri initialization, long timescale, long presentationTimeOffset,
|
||||
int startNumber, long duration, List<SegmentTimelineElement> segmentTimeline) {
|
||||
public MultiSegmentBase(
|
||||
RangedUri initialization,
|
||||
long timescale,
|
||||
long presentationTimeOffset,
|
||||
long startNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> segmentTimeline) {
|
||||
super(initialization, timescale, presentationTimeOffset);
|
||||
this.startNumber = startNumber;
|
||||
this.duration = duration;
|
||||
this.segmentTimeline = segmentTimeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DashSegmentIndex#getSegmentNum(long, long)
|
||||
*/
|
||||
public int getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
final int firstSegmentNum = getFirstSegmentNum();
|
||||
final int segmentCount = getSegmentCount(periodDurationUs);
|
||||
/** @see DashSegmentIndex#getSegmentNum(long, long) */
|
||||
public long getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
final long firstSegmentNum = getFirstSegmentNum();
|
||||
final long segmentCount = getSegmentCount(periodDurationUs);
|
||||
if (segmentCount == 0) {
|
||||
return firstSegmentNum;
|
||||
}
|
||||
if (segmentTimeline == null) {
|
||||
// All segments are of equal duration (with the possible exception of the last one).
|
||||
long durationUs = (duration * C.MICROS_PER_SECOND) / timescale;
|
||||
int segmentNum = startNumber + (int) (timeUs / durationUs);
|
||||
long segmentNum = startNumber + timeUs / durationUs;
|
||||
// Ensure we stay within bounds.
|
||||
return segmentNum < firstSegmentNum ? firstSegmentNum
|
||||
: segmentCount == DashSegmentIndex.INDEX_UNBOUNDED ? segmentNum
|
||||
: Math.min(segmentNum, firstSegmentNum + segmentCount - 1);
|
||||
} else {
|
||||
// The index cannot be unbounded. Identify the segment using binary search.
|
||||
int lowIndex = firstSegmentNum;
|
||||
int highIndex = firstSegmentNum + segmentCount - 1;
|
||||
long lowIndex = firstSegmentNum;
|
||||
long highIndex = firstSegmentNum + segmentCount - 1;
|
||||
while (lowIndex <= highIndex) {
|
||||
int midIndex = lowIndex + (highIndex - lowIndex) / 2;
|
||||
long midIndex = lowIndex + (highIndex - lowIndex) / 2;
|
||||
long midTimeUs = getSegmentTimeUs(midIndex);
|
||||
if (midTimeUs < timeUs) {
|
||||
lowIndex = midIndex + 1;
|
||||
@ -161,12 +164,10 @@ public abstract class SegmentBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DashSegmentIndex#getDurationUs(int, long)
|
||||
*/
|
||||
public final long getSegmentDurationUs(int sequenceNumber, long periodDurationUs) {
|
||||
/** @see DashSegmentIndex#getDurationUs(long, long) */
|
||||
public final long getSegmentDurationUs(long sequenceNumber, long periodDurationUs) {
|
||||
if (segmentTimeline != null) {
|
||||
long duration = segmentTimeline.get(sequenceNumber - startNumber).duration;
|
||||
long duration = segmentTimeline.get((int) (sequenceNumber - startNumber)).duration;
|
||||
return (duration * C.MICROS_PER_SECOND) / timescale;
|
||||
} else {
|
||||
int segmentCount = getSegmentCount(periodDurationUs);
|
||||
@ -177,14 +178,13 @@ public abstract class SegmentBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DashSegmentIndex#getTimeUs(int)
|
||||
*/
|
||||
public final long getSegmentTimeUs(int sequenceNumber) {
|
||||
/** @see DashSegmentIndex#getTimeUs(long) */
|
||||
public final long getSegmentTimeUs(long sequenceNumber) {
|
||||
long unscaledSegmentTime;
|
||||
if (segmentTimeline != null) {
|
||||
unscaledSegmentTime = segmentTimeline.get(sequenceNumber - startNumber).startTime
|
||||
- presentationTimeOffset;
|
||||
unscaledSegmentTime =
|
||||
segmentTimeline.get((int) (sequenceNumber - startNumber)).startTime
|
||||
- presentationTimeOffset;
|
||||
} else {
|
||||
unscaledSegmentTime = (sequenceNumber - startNumber) * duration;
|
||||
}
|
||||
@ -195,14 +195,12 @@ public abstract class SegmentBase {
|
||||
* Returns a {@link RangedUri} defining the location of a segment for the given index in the
|
||||
* given representation.
|
||||
*
|
||||
* @see DashSegmentIndex#getSegmentUrl(int)
|
||||
* @see DashSegmentIndex#getSegmentUrl(long)
|
||||
*/
|
||||
public abstract RangedUri getSegmentUrl(Representation representation, int index);
|
||||
public abstract RangedUri getSegmentUrl(Representation representation, long index);
|
||||
|
||||
/**
|
||||
* @see DashSegmentIndex#getFirstSegmentNum()
|
||||
*/
|
||||
public int getFirstSegmentNum() {
|
||||
/** @see DashSegmentIndex#getFirstSegmentNum() */
|
||||
public long getFirstSegmentNum() {
|
||||
return startNumber;
|
||||
}
|
||||
|
||||
@ -235,15 +233,20 @@ public abstract class SegmentBase {
|
||||
* division of this value and {@code timescale}.
|
||||
* @param startNumber The sequence number of the first segment.
|
||||
* @param duration The duration of each segment in the case of fixed duration segments. The
|
||||
* value in seconds is the division of this value and {@code timescale}. If
|
||||
* {@code segmentTimeline} is non-null then this parameter is ignored.
|
||||
* value in seconds is the division of this value and {@code timescale}. If {@code
|
||||
* segmentTimeline} is non-null then this parameter is ignored.
|
||||
* @param segmentTimeline A segment timeline corresponding to the segments. If null, then
|
||||
* segments are assumed to be of fixed duration as specified by the {@code duration}
|
||||
* parameter.
|
||||
* @param mediaSegments A list of {@link RangedUri}s indicating the locations of the segments.
|
||||
*/
|
||||
public SegmentList(RangedUri initialization, long timescale, long presentationTimeOffset,
|
||||
int startNumber, long duration, List<SegmentTimelineElement> segmentTimeline,
|
||||
public SegmentList(
|
||||
RangedUri initialization,
|
||||
long timescale,
|
||||
long presentationTimeOffset,
|
||||
long startNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> segmentTimeline,
|
||||
List<RangedUri> mediaSegments) {
|
||||
super(initialization, timescale, presentationTimeOffset, startNumber, duration,
|
||||
segmentTimeline);
|
||||
@ -251,8 +254,8 @@ public abstract class SegmentBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RangedUri getSegmentUrl(Representation representation, int sequenceNumber) {
|
||||
return mediaSegments.get(sequenceNumber - startNumber);
|
||||
public RangedUri getSegmentUrl(Representation representation, long sequenceNumber) {
|
||||
return mediaSegments.get((int) (sequenceNumber - startNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -284,8 +287,8 @@ public abstract class SegmentBase {
|
||||
* division of this value and {@code timescale}.
|
||||
* @param startNumber The sequence number of the first segment.
|
||||
* @param duration The duration of each segment in the case of fixed duration segments. The
|
||||
* value in seconds is the division of this value and {@code timescale}. If
|
||||
* {@code segmentTimeline} is non-null then this parameter is ignored.
|
||||
* value in seconds is the division of this value and {@code timescale}. If {@code
|
||||
* segmentTimeline} is non-null then this parameter is ignored.
|
||||
* @param segmentTimeline A segment timeline corresponding to the segments. If null, then
|
||||
* segments are assumed to be of fixed duration as specified by the {@code duration}
|
||||
* parameter.
|
||||
@ -294,9 +297,15 @@ public abstract class SegmentBase {
|
||||
* null then {@code initialization} will be used.
|
||||
* @param mediaTemplate A template defining the location of each media segment.
|
||||
*/
|
||||
public SegmentTemplate(RangedUri initialization, long timescale, long presentationTimeOffset,
|
||||
int startNumber, long duration, List<SegmentTimelineElement> segmentTimeline,
|
||||
UrlTemplate initializationTemplate, UrlTemplate mediaTemplate) {
|
||||
public SegmentTemplate(
|
||||
RangedUri initialization,
|
||||
long timescale,
|
||||
long presentationTimeOffset,
|
||||
long startNumber,
|
||||
long duration,
|
||||
List<SegmentTimelineElement> segmentTimeline,
|
||||
UrlTemplate initializationTemplate,
|
||||
UrlTemplate mediaTemplate) {
|
||||
super(initialization, timescale, presentationTimeOffset, startNumber,
|
||||
duration, segmentTimeline);
|
||||
this.initializationTemplate = initializationTemplate;
|
||||
@ -315,10 +324,10 @@ public abstract class SegmentBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RangedUri getSegmentUrl(Representation representation, int sequenceNumber) {
|
||||
public RangedUri getSegmentUrl(Representation representation, long sequenceNumber) {
|
||||
long time;
|
||||
if (segmentTimeline != null) {
|
||||
time = segmentTimeline.get(sequenceNumber - startNumber).startTime;
|
||||
time = segmentTimeline.get((int) (sequenceNumber - startNumber)).startTime;
|
||||
} else {
|
||||
time = (sequenceNumber - startNumber) * duration;
|
||||
}
|
||||
|
@ -32,27 +32,27 @@ import com.google.android.exoplayer2.source.dash.DashSegmentIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
public long getSegmentNum(long timeUs, long periodDurationUs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimeUs(int segmentNum) {
|
||||
public long getTimeUs(long segmentNum) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDurationUs(int segmentNum, long periodDurationUs) {
|
||||
public long getDurationUs(long segmentNum, long periodDurationUs) {
|
||||
return periodDurationUs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RangedUri getSegmentUrl(int segmentNum) {
|
||||
public RangedUri getSegmentUrl(long segmentNum) {
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstSegmentNum() {
|
||||
public long getFirstSegmentNum() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -71,8 +71,8 @@ public final class UrlTemplate {
|
||||
|
||||
/**
|
||||
* Constructs a Uri from the template, substituting in the provided arguments.
|
||||
* <p>
|
||||
* Arguments whose corresponding identifiers are not present in the template will be ignored.
|
||||
*
|
||||
* <p>Arguments whose corresponding identifiers are not present in the template will be ignored.
|
||||
*
|
||||
* @param representationId The representation identifier.
|
||||
* @param segmentNumber The segment number.
|
||||
@ -80,7 +80,7 @@ public final class UrlTemplate {
|
||||
* @param time The time as specified by the segment timeline.
|
||||
* @return The built Uri.
|
||||
*/
|
||||
public String buildUri(String representationId, int segmentNumber, int bandwidth, long time) {
|
||||
public String buildUri(String representationId, long segmentNumber, int bandwidth, long time) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < identifierCount; i++) {
|
||||
builder.append(urlPieces[i]);
|
||||
|
@ -138,9 +138,9 @@ public final class DashDownloader extends SegmentDownloader<DashManifest, Repres
|
||||
addSegment(segments, startUs, baseUrl, indexUri);
|
||||
}
|
||||
|
||||
int firstSegmentNum = index.getFirstSegmentNum();
|
||||
int lastSegmentNum = firstSegmentNum + segmentCount - 1;
|
||||
for (int j = firstSegmentNum; j <= lastSegmentNum; j++) {
|
||||
long firstSegmentNum = index.getFirstSegmentNum();
|
||||
long lastSegmentNum = firstSegmentNum + segmentCount - 1;
|
||||
for (long j = firstSegmentNum; j <= lastSegmentNum; j++) {
|
||||
addSegment(segments, startUs + index.getTimeUs(j), baseUrl, index.getSegmentUrl(j));
|
||||
}
|
||||
}
|
||||
|
@ -450,11 +450,9 @@ public final class HlsPlaylistTracker implements Loader.Callback<ParsingLoadable
|
||||
|
||||
private static Segment getFirstOldOverlappingSegment(HlsMediaPlaylist oldPlaylist,
|
||||
HlsMediaPlaylist loadedPlaylist) {
|
||||
long mediaSequenceOffset = loadedPlaylist.mediaSequence - oldPlaylist.mediaSequence;
|
||||
int mediaSequenceOffset = (int) (loadedPlaylist.mediaSequence - oldPlaylist.mediaSequence);
|
||||
List<Segment> oldSegments = oldPlaylist.segments;
|
||||
return mediaSequenceOffset < oldSegments.size()
|
||||
? oldSegments.get((int) mediaSequenceOffset)
|
||||
: null;
|
||||
return mediaSequenceOffset < oldSegments.size() ? oldSegments.get(mediaSequenceOffset) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user