From 2091aa5cf971055857209c10ec7f9f12b58f419f Mon Sep 17 00:00:00 2001 From: sr1990 Date: Sat, 18 May 2019 19:41:30 -0700 Subject: [PATCH 1/4] Support signalling of last segment number via supplemental descriptor in mpd --- .../source/dash/DefaultDashChunkSource.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) 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 057f0262d0..2877b2a1cc 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,6 +42,7 @@ 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; @@ -325,10 +326,34 @@ 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 = - representationHolder.getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs); + Math.min(representationHolder. + getLastAvailableSegmentNum(manifest, periodIndex, nowUnixTimeUs), + lastSegmentNumberSchemeIdUri); updateLiveEdgeTimeUs(representationHolder, lastAvailableSegmentNum); From 5b02f92dad9c5725ed32e67f326b1499ca3e5dde Mon Sep 17 00:00:00 2001 From: sr1990 Date: Mon, 10 Jun 2019 22:15:04 -0700 Subject: [PATCH 2/4] [Patch V2] Support signalling of last segment number via supplemental descriptor in mpd --- .../source/dash/DefaultDashChunkSource.java | 28 +------ .../dash/manifest/DashManifestParser.java | 35 ++++++--- .../source/dash/manifest/SegmentBase.java | 74 ++++++++++++++++++- 3 files changed, 100 insertions(+), 37 deletions(-) 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; From 5f6a7fc7f10134db7815e2f0c08e97fe427eedc3 Mon Sep 17 00:00:00 2001 From: sr1990 Date: Sat, 22 Jun 2019 18:56:06 -0700 Subject: [PATCH 3/4] [Patch V3] Support signalling of last segment number via supplemental descriptor in mpd. --- .../dash/manifest/DashManifestParser.java | 55 ++++++++++++++----- .../source/dash/manifest/SegmentBase.java | 9 ++- 2 files changed, 44 insertions(+), 20 deletions(-) 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 37230696f8..7e735e4844 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,null); + segmentBase = parseSegmentTemplate(xpp, null,null,null); } else { maybeSkipTag(xpp); } @@ -333,7 +333,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,supplementalProperties); + segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase, + supplementalProperties,null); } else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) { inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream")); } else if (XmlPullParserUtil.isStartTag(xpp)) { @@ -487,7 +488,7 @@ public class DashManifestParser extends DefaultHandler List adaptationSetRoleDescriptors, List adaptationSetAccessibilityDescriptors, SegmentBase segmentBase, - ArrayList parentSupplementalProperties) + ArrayList adaptationSetSupplementalProperties) throws XmlPullParserException, IOException { String id = xpp.getAttributeValue(null, "id"); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); @@ -520,7 +521,7 @@ public class DashManifestParser extends DefaultHandler segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase); } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) { segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase, - parentSupplementalProperties); + adaptationSetSupplementalProperties,supplementalProperties); } else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) { Pair contentProtection = parseContentProtection(xpp); if (contentProtection.first != null) { @@ -760,7 +761,8 @@ public class DashManifestParser extends DefaultHandler } protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent, - ArrayList parentSupplementalProperties) + ArrayList adaptationSetSupplementalProperties, + ArrayList representationSupplementalProperties) throws XmlPullParserException, IOException { long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset", @@ -793,7 +795,18 @@ public class DashManifestParser extends DefaultHandler return buildSegmentTemplate(initialization, timescale, presentationTimeOffset, startNumber, duration, timeline, initializationTemplate, mediaTemplate, - parentSupplementalProperties); + adaptationSetSupplementalProperties,representationSupplementalProperties); + } + + protected String parseLastSegmentNumberSupplementalProperty + (List supplementalProperties){ + for (Descriptor descriptor : supplementalProperties) { + if (descriptor.schemeIdUri.equalsIgnoreCase + ("http://dashif.org/guidelines/last-segment-number")) { + return descriptor.value; + } + } + return null; } protected SegmentTemplate buildSegmentTemplate( @@ -804,16 +817,28 @@ public class DashManifestParser extends DefaultHandler long duration, List timeline, UrlTemplate initializationTemplate, - UrlTemplate mediaTemplate,ArrayList supplementalProperties ) { + UrlTemplate mediaTemplate,ArrayList adaptationSetSupplementalProperties, + ArrayList representationSupplementalProperties ) { - 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); - } + if (representationSupplementalProperties != null) { + if (parseLastSegmentNumberSupplementalProperty + (representationSupplementalProperties) != null) { + String lastSegment = parseLastSegmentNumberSupplementalProperty + (representationSupplementalProperties); + return new SegmentTemplate(initialization, timescale, presentationTimeOffset, + startNumber, Integer.valueOf(lastSegment),duration, timeline, + initializationTemplate, mediaTemplate); + } + } + + if (adaptationSetSupplementalProperties != null) { + if (parseLastSegmentNumberSupplementalProperty(adaptationSetSupplementalProperties) != null) + { + String lastSegment = parseLastSegmentNumberSupplementalProperty + (adaptationSetSupplementalProperties); + return new SegmentTemplate(initialization, timescale, presentationTimeOffset, + startNumber, Integer.valueOf(lastSegment),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 720c20eed2..9eae69b345 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 @@ -140,7 +140,7 @@ public abstract class SegmentBase { * 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" + * 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. @@ -408,10 +408,10 @@ public abstract class SegmentBase { @Override public int getSegmentCount(long periodDurationUs) { - if( endNumber != C.INDEX_UNSET) { - return endNumber; - } else if (segmentTimeline != null) { + if (segmentTimeline != null) { return segmentTimeline.size(); + } else if (endNumber != C.INDEX_UNSET) { + return endNumber - (int) startNumber + 1; } else if (periodDurationUs != C.TIME_UNSET) { long durationUs = (duration * C.MICROS_PER_SECOND) / timescale; return (int) Util.ceilDivide(periodDurationUs, durationUs); @@ -419,7 +419,6 @@ public abstract class SegmentBase { return DashSegmentIndex.INDEX_UNBOUNDED; } } - } /** From ec6604b4f716b01d4cd0d99019bf30ce2d029630 Mon Sep 17 00:00:00 2001 From: sr1990 Date: Wed, 26 Jun 2019 20:29:37 -0700 Subject: [PATCH 4/4] [Patch V4] Support signalling of last segment number via supplemental descriptor in mpd. --- .../dash/manifest/DashManifestParser.java | 62 ++++++++----------- .../source/dash/manifest/SegmentBase.java | 44 +++---------- 2 files changed, 32 insertions(+), 74 deletions(-) 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 7e735e4844..912f7d1611 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,null,null); + segmentBase = parseSegmentTemplate(xpp, null,null); } else { maybeSkipTag(xpp); } @@ -323,8 +323,8 @@ public class DashManifestParser extends DefaultHandler language, roleDescriptors, accessibilityDescriptors, - segmentBase, - supplementalProperties); + supplementalProperties, + segmentBase); contentType = checkContentTypeConsistency(contentType, getContentType(representationInfo.format)); representationInfos.add(representationInfo); @@ -334,7 +334,7 @@ public class DashManifestParser extends DefaultHandler segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase); } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) { segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase, - supplementalProperties,null); + supplementalProperties); } else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) { inbandEventStreams.add(parseDescriptor(xpp, "InbandEventStream")); } else if (XmlPullParserUtil.isStartTag(xpp)) { @@ -487,8 +487,8 @@ public class DashManifestParser extends DefaultHandler String adaptationSetLanguage, List adaptationSetRoleDescriptors, List adaptationSetAccessibilityDescriptors, - SegmentBase segmentBase, - ArrayList adaptationSetSupplementalProperties) + List adaptationSetSupplementalProperties, + SegmentBase segmentBase) throws XmlPullParserException, IOException { String id = xpp.getAttributeValue(null, "id"); int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE); @@ -521,7 +521,7 @@ public class DashManifestParser extends DefaultHandler segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase); } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) { segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase, - adaptationSetSupplementalProperties,supplementalProperties); + adaptationSetSupplementalProperties); } else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) { Pair contentProtection = parseContentProtection(xpp); if (contentProtection.first != null) { @@ -761,8 +761,7 @@ public class DashManifestParser extends DefaultHandler } protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, SegmentTemplate parent, - ArrayList adaptationSetSupplementalProperties, - ArrayList representationSupplementalProperties) + List adaptationSetSupplementalProperties) throws XmlPullParserException, IOException { long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1); long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset", @@ -793,20 +792,27 @@ public class DashManifestParser extends DefaultHandler timeline = timeline != null ? timeline : parent.segmentTimeline; } + long endNumber = C.INDEX_UNSET; + + if (adaptationSetSupplementalProperties != null) { + endNumber = parseLastSegmentNumberSupplementalProperty + (adaptationSetSupplementalProperties); + } + return buildSegmentTemplate(initialization, timescale, presentationTimeOffset, startNumber, duration, timeline, initializationTemplate, mediaTemplate, - adaptationSetSupplementalProperties,representationSupplementalProperties); + endNumber); } - protected String parseLastSegmentNumberSupplementalProperty + protected long parseLastSegmentNumberSupplementalProperty (List supplementalProperties){ for (Descriptor descriptor : supplementalProperties) { - if (descriptor.schemeIdUri.equalsIgnoreCase - ("http://dashif.org/guidelines/last-segment-number")) { - return descriptor.value; + if ("http://dashif.org/guidelines/last-segment-number" + .equalsIgnoreCase(descriptor.schemeIdUri)) { + return Long.parseLong(descriptor.value); } } - return null; + return C.INDEX_UNSET; } protected SegmentTemplate buildSegmentTemplate( @@ -817,29 +823,11 @@ public class DashManifestParser extends DefaultHandler long duration, List timeline, UrlTemplate initializationTemplate, - UrlTemplate mediaTemplate,ArrayList adaptationSetSupplementalProperties, - ArrayList representationSupplementalProperties ) { + UrlTemplate mediaTemplate,long endNumber ) { - if (representationSupplementalProperties != null) { - if (parseLastSegmentNumberSupplementalProperty - (representationSupplementalProperties) != null) { - String lastSegment = parseLastSegmentNumberSupplementalProperty - (representationSupplementalProperties); - return new SegmentTemplate(initialization, timescale, presentationTimeOffset, - startNumber, Integer.valueOf(lastSegment),duration, timeline, - initializationTemplate, mediaTemplate); - } - } - - if (adaptationSetSupplementalProperties != null) { - if (parseLastSegmentNumberSupplementalProperty(adaptationSetSupplementalProperties) != null) - { - String lastSegment = parseLastSegmentNumberSupplementalProperty - (adaptationSetSupplementalProperties); - return new SegmentTemplate(initialization, timescale, presentationTimeOffset, - startNumber, Integer.valueOf(lastSegment),duration, timeline, - initializationTemplate, mediaTemplate); - } + if (endNumber!=C.INDEX_UNSET) { + return new SegmentTemplate(initialization, timescale, presentationTimeOffset, + startNumber, endNumber,duration, timeline, initializationTemplate, mediaTemplate); } return new SegmentTemplate(initialization, timescale, presentationTimeOffset, 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 9eae69b345..7db44dd629 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,7 +102,6 @@ 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 @@ -129,38 +128,6 @@ 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) */ @@ -310,6 +277,7 @@ public abstract class SegmentBase { /* package */ final UrlTemplate initializationTemplate; /* package */ final UrlTemplate mediaTemplate; + /* package */ final long endNumber; /** * @param initialization A {@link RangedUri} corresponding to initialization data, if such data @@ -343,6 +311,7 @@ public abstract class SegmentBase { duration, segmentTimeline); this.initializationTemplate = initializationTemplate; this.mediaTemplate = mediaTemplate; + this.endNumber = C.INDEX_UNSET; } /** @@ -371,15 +340,16 @@ public abstract class SegmentBase { long timescale, long presentationTimeOffset, long startNumber, - int endNumber, + long endNumber, long duration, List segmentTimeline, UrlTemplate initializationTemplate, UrlTemplate mediaTemplate) { - super(initialization, timescale, presentationTimeOffset, startNumber,endNumber, - duration, segmentTimeline); + super(initialization, timescale, presentationTimeOffset, startNumber, duration, + segmentTimeline); this.initializationTemplate = initializationTemplate; this.mediaTemplate = mediaTemplate; + this.endNumber = endNumber; } @Override @@ -411,7 +381,7 @@ public abstract class SegmentBase { if (segmentTimeline != null) { return segmentTimeline.size(); } else if (endNumber != C.INDEX_UNSET) { - return endNumber - (int) startNumber + 1; + return (int) (endNumber - startNumber + 1); } else if (periodDurationUs != C.TIME_UNSET) { long durationUs = (duration * C.MICROS_PER_SECOND) / timescale; return (int) Util.ceilDivide(periodDurationUs, durationUs);