[Patch V2] Support signalling of last segment number via supplemental descriptor in mpd

This commit is contained in:
sr1990 2019-06-10 22:15:04 -07:00 committed by sanil
parent 2091aa5cf9
commit 5b02f92dad
3 changed files with 100 additions and 37 deletions

View File

@ -42,7 +42,6 @@ import com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk;
import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerTrackEmsgHandler;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
import com.google.android.exoplayer2.source.dash.manifest.Descriptor;
import com.google.android.exoplayer2.source.dash.manifest.RangedUri;
import com.google.android.exoplayer2.source.dash.manifest.Representation;
import com.google.android.exoplayer2.trackselection.TrackSelection;
@ -326,35 +325,10 @@ public class DefaultDashChunkSource implements DashChunkSource {
return;
}
List<Descriptor> listDescriptors;
Integer lastSegmentNumberSchemeIdUri = Integer.MAX_VALUE;
String sampleMimeType = trackSelection.getFormat(periodIndex).sampleMimeType;
if (sampleMimeType.contains("video") || sampleMimeType.contains("audio")) {
int track_type = sampleMimeType.contains("video")? C.TRACK_TYPE_VIDEO : C.TRACK_TYPE_AUDIO;
if (!manifest.getPeriod(periodIndex).adaptationSets.get(manifest.getPeriod(periodIndex)
.getAdaptationSetIndex(track_type)).supplementalProperties.isEmpty()) {
listDescriptors = manifest.getPeriod(periodIndex).adaptationSets
.get(manifest.getPeriod(periodIndex).getAdaptationSetIndex(track_type))
.supplementalProperties;
for ( Descriptor descriptor: listDescriptors ) {
if (descriptor.schemeIdUri.equalsIgnoreCase
("http://dashif.org/guidelines/last-segment-number")) {
lastSegmentNumberSchemeIdUri = Integer.valueOf(descriptor.value);
}
}
}
}
long firstAvailableSegmentNum =
representationHolder.getFirstAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
long lastAvailableSegmentNum =
Math.min(representationHolder.
getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs),
lastSegmentNumberSchemeIdUri);
representationHolder.getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum);
long segmentNum =

View File

@ -242,7 +242,7 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
segmentBase = parseSegmentList(xpp, null);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase = parseSegmentTemplate(xpp, null);
segmentBase = parseSegmentTemplate(xpp, null,null);
} else {
maybeSkipTag(xpp);
}
@ -323,7 +323,8 @@ public class DashManifestParser extends DefaultHandler
language,
roleDescriptors,
accessibilityDescriptors,
segmentBase);
segmentBase,
supplementalProperties);
contentType = checkContentTypeConsistency(contentType,
getContentType(representationInfo.format));
representationInfos.add(representationInfo);
@ -332,7 +333,7 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase,supplementalProperties);
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
} else if (XmlPullParserUtil.isStartTag(xpp)) {
@ -485,7 +486,8 @@ public class DashManifestParser extends DefaultHandler
String adaptationSetLanguage,
List<Descriptor> adaptationSetRoleDescriptors,
List<Descriptor> adaptationSetAccessibilityDescriptors,
SegmentBase segmentBase)
SegmentBase segmentBase,
ArrayList<Descriptor> parentSupplementalProperties)
throws XmlPullParserException, IOException {
String id = xpp.getAttributeValue(null, "id");
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
@ -517,7 +519,8 @@ public class DashManifestParser extends DefaultHandler
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase,
parentSupplementalProperties);
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
Pair<String, SchemeData> contentProtection = parseContentProtection(xpp);
if (contentProtection.first != null) {
@ -756,7 +759,8 @@ public class DashManifestParser extends DefaultHandler
startNumber, duration, timeline, segments);
}
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent)
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent,
ArrayList<Descriptor> parentSupplementalProperties)
throws XmlPullParserException, IOException {
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
@ -788,7 +792,8 @@ public class DashManifestParser extends DefaultHandler
}
return buildSegmentTemplate(initialization, timescale, presentationTimeOffset,
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
startNumber, duration, timeline, initializationTemplate, mediaTemplate,
parentSupplementalProperties);
}
protected SegmentTemplate buildSegmentTemplate(
@ -799,9 +804,21 @@ public class DashManifestParser extends DefaultHandler
long duration,
List<SegmentTimelineElement> timeline,
UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate) {
UrlTemplate mediaTemplate,ArrayList<Descriptor> supplementalProperties ) {
if (supplementalProperties != null) {
for (Descriptor descriptor : supplementalProperties) {
if (descriptor.schemeIdUri.equalsIgnoreCase
("http://dashif.org/guidelines/last-segment-number")) {
return new SegmentTemplate(initialization, timescale, presentationTimeOffset,
startNumber, Integer.valueOf(descriptor.value),duration, timeline,
initializationTemplate, mediaTemplate);
}
}
}
return new SegmentTemplate(initialization, timescale, presentationTimeOffset,
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
startNumber,duration, timeline, initializationTemplate, mediaTemplate);
}
/**

View File

@ -102,6 +102,7 @@ public abstract class SegmentBase {
/* package */ final long startNumber;
/* package */ final long duration;
/* package */ final List<SegmentTimelineElement> segmentTimeline;
/* package */ final int endNumber;
/**
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
@ -128,6 +129,38 @@ public abstract class SegmentBase {
this.startNumber = startNumber;
this.duration = duration;
this.segmentTimeline = segmentTimeline;
this.endNumber = C.INDEX_UNSET;
}
/**
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
* exists.
* @param timescale The timescale in units per second.
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
* division of this value and {@code timescale}.
* @param startNumber The sequence number of the first segment.
* @param endNumber The sequence number of the last segment specified by SupplementalProperty
* schemeIdUri="http://dashif.org/guidelines/last-segment-number"
* @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.
* @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,
long startNumber,
int endNumber,
long duration,
List<SegmentTimelineElement> segmentTimeline) {
super(initialization, timescale, presentationTimeOffset);
this.startNumber = startNumber;
this.duration = duration;
this.segmentTimeline = segmentTimeline;
this.endNumber = endNumber;
}
/** @see DashSegmentIndex#getSegmentNum(long, long) */
@ -312,6 +345,43 @@ public abstract class SegmentBase {
this.mediaTemplate = mediaTemplate;
}
/**
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
* exists. The value of this parameter is ignored if {@code initializationTemplate} is
* non-null.
* @param timescale The timescale in units per second.
* @param presentationTimeOffset The presentation time offset. The value in seconds is the
* division of this value and {@code timescale}.
* @param startNumber The sequence number of the first segment.
* @param endNumber The sequence number of the last segment specified by SupplementalProperty
* schemeIdUri="http://dashif.org/guidelines/last-segment-number"
* @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.
* @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 initializationTemplate A template defining the location of initialization data, if
* such data exists. If non-null then the {@code initialization} parameter is ignored. If
* 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,
long startNumber,
int endNumber,
long duration,
List<SegmentTimelineElement> segmentTimeline,
UrlTemplate initializationTemplate,
UrlTemplate mediaTemplate) {
super(initialization, timescale, presentationTimeOffset, startNumber,endNumber,
duration, segmentTimeline);
this.initializationTemplate = initializationTemplate;
this.mediaTemplate = mediaTemplate;
}
@Override
public RangedUri getInitialization(Representation representation) {
if (initializationTemplate != null) {
@ -338,7 +408,9 @@ public abstract class SegmentBase {
@Override
public int getSegmentCount(long periodDurationUs) {
if (segmentTimeline != null) {
if( endNumber != C.INDEX_UNSET) {
return endNumber;
} else if (segmentTimeline != null) {
return segmentTimeline.size();
} else if (periodDurationUs != C.TIME_UNSET) {
long durationUs = (duration * C.MICROS_PER_SECOND) / timescale;