mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
[Patch V2] Support signalling of last segment number via supplemental descriptor in mpd
This commit is contained in:
parent
2091aa5cf9
commit
5b02f92dad
3 changed files with 100 additions and 37 deletions
|
|
@ -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.PlayerEmsgHandler.PlayerTrackEmsgHandler;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
|
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.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.RangedUri;
|
||||||
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
import com.google.android.exoplayer2.source.dash.manifest.Representation;
|
||||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||||
|
|
@ -326,35 +325,10 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||||
return;
|
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 =
|
long firstAvailableSegmentNum =
|
||||||
representationHolder.getFirstAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
representationHolder.getFirstAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
||||||
long lastAvailableSegmentNum =
|
long lastAvailableSegmentNum =
|
||||||
Math.min(representationHolder.
|
representationHolder.getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs);
|
||||||
getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs),
|
|
||||||
lastSegmentNumberSchemeIdUri);
|
|
||||||
|
|
||||||
updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum);
|
updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum);
|
||||||
|
|
||||||
long segmentNum =
|
long segmentNum =
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
segmentBase = parseSegmentList(xpp, null);
|
segmentBase = parseSegmentList(xpp, null);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, null);
|
segmentBase = parseSegmentTemplate(xpp, null,null);
|
||||||
} else {
|
} else {
|
||||||
maybeSkipTag(xpp);
|
maybeSkipTag(xpp);
|
||||||
}
|
}
|
||||||
|
|
@ -323,7 +323,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
language,
|
language,
|
||||||
roleDescriptors,
|
roleDescriptors,
|
||||||
accessibilityDescriptors,
|
accessibilityDescriptors,
|
||||||
segmentBase);
|
segmentBase,
|
||||||
|
supplementalProperties);
|
||||||
contentType = checkContentTypeConsistency(contentType,
|
contentType = checkContentTypeConsistency(contentType,
|
||||||
getContentType(representationInfo.format));
|
getContentType(representationInfo.format));
|
||||||
representationInfos.add(representationInfo);
|
representationInfos.add(representationInfo);
|
||||||
|
|
@ -332,7 +333,7 @@ public class DashManifestParser extends DefaultHandler
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
|
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
|
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase,supplementalProperties);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
|
||||||
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
|
inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream"));
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp)) {
|
} else if (XmlPullParserUtil.isStartTag(xpp)) {
|
||||||
|
|
@ -485,7 +486,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
String adaptationSetLanguage,
|
String adaptationSetLanguage,
|
||||||
List<Descriptor> adaptationSetRoleDescriptors,
|
List<Descriptor> adaptationSetRoleDescriptors,
|
||||||
List<Descriptor> adaptationSetAccessibilityDescriptors,
|
List<Descriptor> adaptationSetAccessibilityDescriptors,
|
||||||
SegmentBase segmentBase)
|
SegmentBase segmentBase,
|
||||||
|
ArrayList<Descriptor> parentSupplementalProperties)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
String id = xpp.getAttributeValue(null, "id");
|
String id = xpp.getAttributeValue(null, "id");
|
||||||
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
|
||||||
|
|
@ -517,7 +519,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
|
||||||
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
|
segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
|
||||||
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
|
segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase,
|
||||||
|
parentSupplementalProperties);
|
||||||
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
|
} else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
|
||||||
Pair<String, SchemeData> contentProtection = parseContentProtection(xpp);
|
Pair<String, SchemeData> contentProtection = parseContentProtection(xpp);
|
||||||
if (contentProtection.first != null) {
|
if (contentProtection.first != null) {
|
||||||
|
|
@ -756,7 +759,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
startNumber, duration, timeline, segments);
|
startNumber, duration, timeline, segments);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent)
|
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent,
|
||||||
|
ArrayList<Descriptor> parentSupplementalProperties)
|
||||||
throws XmlPullParserException, IOException {
|
throws XmlPullParserException, IOException {
|
||||||
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
||||||
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset",
|
||||||
|
|
@ -788,7 +792,8 @@ public class DashManifestParser extends DefaultHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildSegmentTemplate(initialization, timescale, presentationTimeOffset,
|
return buildSegmentTemplate(initialization, timescale, presentationTimeOffset,
|
||||||
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
|
startNumber, duration, timeline, initializationTemplate, mediaTemplate,
|
||||||
|
parentSupplementalProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SegmentTemplate buildSegmentTemplate(
|
protected SegmentTemplate buildSegmentTemplate(
|
||||||
|
|
@ -799,9 +804,21 @@ public class DashManifestParser extends DefaultHandler
|
||||||
long duration,
|
long duration,
|
||||||
List<SegmentTimelineElement> timeline,
|
List<SegmentTimelineElement> timeline,
|
||||||
UrlTemplate initializationTemplate,
|
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,
|
return new SegmentTemplate(initialization, timescale, presentationTimeOffset,
|
||||||
startNumber, duration, timeline, initializationTemplate, mediaTemplate);
|
startNumber,duration, timeline, initializationTemplate, mediaTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ public abstract class SegmentBase {
|
||||||
/* package */ final long startNumber;
|
/* package */ final long startNumber;
|
||||||
/* package */ final long duration;
|
/* package */ final long duration;
|
||||||
/* package */ final List<SegmentTimelineElement> segmentTimeline;
|
/* package */ final List<SegmentTimelineElement> segmentTimeline;
|
||||||
|
/* package */ final int endNumber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
* @param initialization A {@link RangedUri} corresponding to initialization data, if such data
|
||||||
|
|
@ -128,6 +129,38 @@ public abstract class SegmentBase {
|
||||||
this.startNumber = startNumber;
|
this.startNumber = startNumber;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.segmentTimeline = segmentTimeline;
|
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) */
|
/** @see DashSegmentIndex#getSegmentNum(long, long) */
|
||||||
|
|
@ -312,6 +345,43 @@ public abstract class SegmentBase {
|
||||||
this.mediaTemplate = mediaTemplate;
|
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
|
@Override
|
||||||
public RangedUri getInitialization(Representation representation) {
|
public RangedUri getInitialization(Representation representation) {
|
||||||
if (initializationTemplate != null) {
|
if (initializationTemplate != null) {
|
||||||
|
|
@ -338,7 +408,9 @@ public abstract class SegmentBase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSegmentCount(long periodDurationUs) {
|
public int getSegmentCount(long periodDurationUs) {
|
||||||
if (segmentTimeline != null) {
|
if( endNumber != C.INDEX_UNSET) {
|
||||||
|
return endNumber;
|
||||||
|
} else if (segmentTimeline != null) {
|
||||||
return segmentTimeline.size();
|
return segmentTimeline.size();
|
||||||
} else if (periodDurationUs != C.TIME_UNSET) {
|
} else if (periodDurationUs != C.TIME_UNSET) {
|
||||||
long durationUs = (duration * C.MICROS_PER_SECOND) / timescale;
|
long durationUs = (duration * C.MICROS_PER_SECOND) / timescale;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue