diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index 2877b2a1cc..02b2990193 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -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 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 = diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index 64ec1adb43..37230696f8 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -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 adaptationSetRoleDescriptors, List adaptationSetAccessibilityDescriptors, - SegmentBase segmentBase) + SegmentBase segmentBase, + ArrayList 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 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 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 timeline, UrlTemplate initializationTemplate, - UrlTemplate mediaTemplate) { + UrlTemplate mediaTemplate,ArrayList 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); } /** diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java index f033232590..720c20eed2 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/SegmentBase.java @@ -102,6 +102,7 @@ public abstract class SegmentBase { /* package */ final long startNumber; /* package */ final long duration; /* package */ final List 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 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 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;