|
|
|
|
@ -77,7 +77,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MediaPresentationDescription parseMediaPresentationDescription(XmlPullParser xpp,
|
|
|
|
|
protected MediaPresentationDescription parseMediaPresentationDescription(XmlPullParser xpp,
|
|
|
|
|
String contentId, Uri baseUrl) throws XmlPullParserException, IOException, ParseException {
|
|
|
|
|
long availabilityStartTime = parseDateTime(xpp, "availabilityStartTime", -1);
|
|
|
|
|
long durationMs = parseDuration(xpp, "mediaPresentationDuration", -1);
|
|
|
|
|
@ -101,17 +101,29 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
}
|
|
|
|
|
} while (!isEndTag(xpp, "MPD"));
|
|
|
|
|
|
|
|
|
|
return buildMediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs,
|
|
|
|
|
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, periods);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected MediaPresentationDescription buildMediaPresentationDescription(
|
|
|
|
|
long availabilityStartTime, long durationMs, long minBufferTimeMs, boolean dynamic,
|
|
|
|
|
long minUpdateTimeMs, long timeShiftBufferDepthMs, UtcTimingElement utcTiming,
|
|
|
|
|
List<Period> periods) {
|
|
|
|
|
return new MediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs,
|
|
|
|
|
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, periods);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private UtcTimingElement parseUtcTiming(XmlPullParser xpp) {
|
|
|
|
|
protected UtcTimingElement parseUtcTiming(XmlPullParser xpp) {
|
|
|
|
|
String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri");
|
|
|
|
|
String value = xpp.getAttributeValue(null, "value");
|
|
|
|
|
return buildUtcTimingElement(schemeIdUri, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected UtcTimingElement buildUtcTimingElement(String schemeIdUri, String value) {
|
|
|
|
|
return new UtcTimingElement(schemeIdUri, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Period parsePeriod(XmlPullParser xpp, String contentId, Uri baseUrl, long mpdDurationMs)
|
|
|
|
|
protected Period parsePeriod(XmlPullParser xpp, String contentId, Uri baseUrl, long mpdDurationMs)
|
|
|
|
|
throws XmlPullParserException, IOException {
|
|
|
|
|
String id = xpp.getAttributeValue(null, "id");
|
|
|
|
|
long startMs = parseDuration(xpp, "start", 0);
|
|
|
|
|
@ -134,12 +146,17 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
}
|
|
|
|
|
} while (!isEndTag(xpp, "Period"));
|
|
|
|
|
|
|
|
|
|
return buildPeriod(id, startMs, durationMs, adaptationSets);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Period buildPeriod(
|
|
|
|
|
String id, long startMs, long durationMs, List<AdaptationSet> adaptationSets) {
|
|
|
|
|
return new Period(id, startMs, durationMs, adaptationSets);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AdaptationSet parsing.
|
|
|
|
|
|
|
|
|
|
private AdaptationSet parseAdaptationSet(XmlPullParser xpp, String contentId, Uri baseUrl,
|
|
|
|
|
protected AdaptationSet parseAdaptationSet(XmlPullParser xpp, String contentId, Uri baseUrl,
|
|
|
|
|
long periodStartMs, long periodDurationMs, SegmentBase segmentBase)
|
|
|
|
|
throws XmlPullParserException, IOException {
|
|
|
|
|
|
|
|
|
|
@ -176,13 +193,20 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
} else if (isStartTag(xpp, "SegmentTemplate")) {
|
|
|
|
|
segmentBase = parseSegmentTemplate(xpp, baseUrl, (SegmentTemplate) segmentBase,
|
|
|
|
|
periodDurationMs);
|
|
|
|
|
} else if (isStartTag(xpp)) {
|
|
|
|
|
parseAdaptationSetChild(xpp);
|
|
|
|
|
}
|
|
|
|
|
} while (!isEndTag(xpp, "AdaptationSet"));
|
|
|
|
|
|
|
|
|
|
return buildAdaptationSet(id, contentType, representations, contentProtections);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected AdaptationSet buildAdaptationSet(int id, int contentType,
|
|
|
|
|
List<Representation> representations, List<ContentProtection> contentProtections) {
|
|
|
|
|
return new AdaptationSet(id, contentType, representations, contentProtections);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int parseAdaptationSetType(String contentType) {
|
|
|
|
|
protected int parseAdaptationSetType(String contentType) {
|
|
|
|
|
return TextUtils.isEmpty(contentType) ? AdaptationSet.TYPE_UNKNOWN
|
|
|
|
|
: MimeTypes.BASE_TYPE_AUDIO.equals(contentType) ? AdaptationSet.TYPE_AUDIO
|
|
|
|
|
: MimeTypes.BASE_TYPE_VIDEO.equals(contentType) ? AdaptationSet.TYPE_VIDEO
|
|
|
|
|
@ -190,7 +214,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
: AdaptationSet.TYPE_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int parseAdaptationSetTypeFromMimeType(String mimeType) {
|
|
|
|
|
protected int parseAdaptationSetTypeFromMimeType(String mimeType) {
|
|
|
|
|
return TextUtils.isEmpty(mimeType) ? AdaptationSet.TYPE_UNKNOWN
|
|
|
|
|
: MimeTypes.isAudio(mimeType) ? AdaptationSet.TYPE_AUDIO
|
|
|
|
|
: MimeTypes.isVideo(mimeType) ? AdaptationSet.TYPE_VIDEO
|
|
|
|
|
@ -228,13 +252,29 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
**/
|
|
|
|
|
protected ContentProtection parseContentProtection(XmlPullParser xpp)
|
|
|
|
|
throws XmlPullParserException, IOException {
|
|
|
|
|
String schemeUriId = xpp.getAttributeValue(null, "schemeUriId");
|
|
|
|
|
return new ContentProtection(schemeUriId, null);
|
|
|
|
|
String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri");
|
|
|
|
|
return buildContentProtection(schemeIdUri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected ContentProtection buildContentProtection(String schemeIdUri) {
|
|
|
|
|
return new ContentProtection(schemeIdUri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Parses children of AdaptationSet elements not specifically parsed elsewhere.
|
|
|
|
|
*
|
|
|
|
|
* @param xpp The XmpPullParser from which the AdaptationSet child should be parsed.
|
|
|
|
|
* @throws XmlPullParserException If an error occurs parsing the element.
|
|
|
|
|
* @throws IOException If an error occurs reading the element.
|
|
|
|
|
**/
|
|
|
|
|
protected void parseAdaptationSetChild(XmlPullParser xpp)
|
|
|
|
|
throws XmlPullParserException, IOException {
|
|
|
|
|
// pass
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Representation parsing.
|
|
|
|
|
|
|
|
|
|
private Representation parseRepresentation(XmlPullParser xpp, String contentId, Uri baseUrl,
|
|
|
|
|
protected Representation parseRepresentation(XmlPullParser xpp, String contentId, Uri baseUrl,
|
|
|
|
|
long periodStartMs, long periodDurationMs, String mimeType, String language,
|
|
|
|
|
SegmentBase segmentBase) throws XmlPullParserException, IOException {
|
|
|
|
|
String id = xpp.getAttributeValue(null, "id");
|
|
|
|
|
@ -261,15 +301,27 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
}
|
|
|
|
|
} while (!isEndTag(xpp, "Representation"));
|
|
|
|
|
|
|
|
|
|
Format format = new Format(id, mimeType, width, height, numChannels, audioSamplingRate,
|
|
|
|
|
Format format = buildFormat(id, mimeType, width, height, numChannels, audioSamplingRate,
|
|
|
|
|
bandwidth, language);
|
|
|
|
|
return Representation.newInstance(periodStartMs, periodDurationMs, contentId, -1, format,
|
|
|
|
|
return buildRepresentation(periodStartMs, periodDurationMs, contentId, -1, format,
|
|
|
|
|
segmentBase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Format buildFormat(String id, String mimeType, int width, int height, int numChannels,
|
|
|
|
|
int audioSamplingRate, int bandwidth, String language) {
|
|
|
|
|
return new Format(id, mimeType, width, height, numChannels, audioSamplingRate,
|
|
|
|
|
bandwidth, language);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Representation buildRepresentation(long periodStartMs, long periodDurationMs,
|
|
|
|
|
String contentId, int revisionId, Format format, SegmentBase segmentBase) {
|
|
|
|
|
return Representation.newInstance(periodStartMs, periodDurationMs, contentId, revisionId,
|
|
|
|
|
format, segmentBase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SegmentBase, SegmentList and SegmentTemplate parsing.
|
|
|
|
|
|
|
|
|
|
private SingleSegmentBase parseSegmentBase(XmlPullParser xpp, Uri baseUrl,
|
|
|
|
|
protected SingleSegmentBase parseSegmentBase(XmlPullParser xpp, Uri baseUrl,
|
|
|
|
|
SingleSegmentBase parent) throws XmlPullParserException, IOException {
|
|
|
|
|
|
|
|
|
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
|
|
|
|
@ -293,11 +345,17 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
}
|
|
|
|
|
} while (!isEndTag(xpp, "SegmentBase"));
|
|
|
|
|
|
|
|
|
|
return buildSingleSegmentBase(initialization, timescale, presentationTimeOffset, baseUrl,
|
|
|
|
|
indexStart, indexLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected SingleSegmentBase buildSingleSegmentBase(RangedUri initialization, long timescale,
|
|
|
|
|
long presentationTimeOffset, Uri baseUrl, long indexStart, long indexLength) {
|
|
|
|
|
return new SingleSegmentBase(initialization, timescale, presentationTimeOffset, baseUrl,
|
|
|
|
|
indexStart, indexLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SegmentList parseSegmentList(XmlPullParser xpp, Uri baseUrl, SegmentList parent,
|
|
|
|
|
protected SegmentList parseSegmentList(XmlPullParser xpp, Uri baseUrl, SegmentList parent,
|
|
|
|
|
long periodDuration) throws XmlPullParserException, IOException {
|
|
|
|
|
|
|
|
|
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
|
|
|
|
@ -330,11 +388,18 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
segments = segments != null ? segments : parent.mediaSegments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buildSegmentList(initialization, timescale, presentationTimeOffset, periodDuration,
|
|
|
|
|
startNumber, duration, timeline, segments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected SegmentList buildSegmentList(RangedUri initialization, long timescale,
|
|
|
|
|
long presentationTimeOffset, long periodDuration, int startNumber, long duration,
|
|
|
|
|
List<SegmentTimelineElement> timeline, List<RangedUri> segments) {
|
|
|
|
|
return new SegmentList(initialization, timescale, presentationTimeOffset, periodDuration,
|
|
|
|
|
startNumber, duration, timeline, segments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, Uri baseUrl,
|
|
|
|
|
protected SegmentTemplate parseSegmentTemplate(XmlPullParser xpp, Uri baseUrl,
|
|
|
|
|
SegmentTemplate parent, long periodDuration) throws XmlPullParserException, IOException {
|
|
|
|
|
|
|
|
|
|
long timescale = parseLong(xpp, "timescale", parent != null ? parent.timescale : 1);
|
|
|
|
|
@ -364,11 +429,19 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
timeline = timeline != null ? timeline : parent.segmentTimeline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buildSegmentTemplate(initialization, timescale, presentationTimeOffset, periodDuration,
|
|
|
|
|
startNumber, duration, timeline, initializationTemplate, mediaTemplate, baseUrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected SegmentTemplate buildSegmentTemplate(RangedUri initialization, long timescale,
|
|
|
|
|
long presentationTimeOffset, long periodDuration, int startNumber, long duration,
|
|
|
|
|
List<SegmentTimelineElement> timeline, UrlTemplate initializationTemplate,
|
|
|
|
|
UrlTemplate mediaTemplate, Uri baseUrl) {
|
|
|
|
|
return new SegmentTemplate(initialization, timescale, presentationTimeOffset, periodDuration,
|
|
|
|
|
startNumber, duration, timeline, initializationTemplate, mediaTemplate, baseUrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)
|
|
|
|
|
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)
|
|
|
|
|
throws XmlPullParserException, IOException {
|
|
|
|
|
List<SegmentTimelineElement> segmentTimeline = new ArrayList<SegmentTimelineElement>();
|
|
|
|
|
long elapsedTime = 0;
|
|
|
|
|
@ -379,7 +452,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
long duration = parseLong(xpp, "d");
|
|
|
|
|
int count = 1 + parseInt(xpp, "r", 0);
|
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
|
segmentTimeline.add(new SegmentTimelineElement(elapsedTime, duration));
|
|
|
|
|
segmentTimeline.add(buildSegmentTimelineElement(elapsedTime, duration));
|
|
|
|
|
elapsedTime += duration;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -387,7 +460,11 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
return segmentTimeline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name,
|
|
|
|
|
protected SegmentTimelineElement buildSegmentTimelineElement(long elapsedTime, long duration) {
|
|
|
|
|
return new SegmentTimelineElement(elapsedTime, duration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected UrlTemplate parseUrlTemplate(XmlPullParser xpp, String name,
|
|
|
|
|
UrlTemplate defaultValue) {
|
|
|
|
|
String valueString = xpp.getAttributeValue(null, name);
|
|
|
|
|
if (valueString != null) {
|
|
|
|
|
@ -396,15 +473,15 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
return defaultValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private RangedUri parseInitialization(XmlPullParser xpp, Uri baseUrl) {
|
|
|
|
|
protected RangedUri parseInitialization(XmlPullParser xpp, Uri baseUrl) {
|
|
|
|
|
return parseRangedUrl(xpp, baseUrl, "sourceURL", "range");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private RangedUri parseSegmentUrl(XmlPullParser xpp, Uri baseUrl) {
|
|
|
|
|
protected RangedUri parseSegmentUrl(XmlPullParser xpp, Uri baseUrl) {
|
|
|
|
|
return parseRangedUrl(xpp, baseUrl, "media", "mediaRange");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private RangedUri parseRangedUrl(XmlPullParser xpp, Uri baseUrl, String urlAttribute,
|
|
|
|
|
protected RangedUri parseRangedUrl(XmlPullParser xpp, Uri baseUrl, String urlAttribute,
|
|
|
|
|
String rangeAttribute) {
|
|
|
|
|
String urlText = xpp.getAttributeValue(null, urlAttribute);
|
|
|
|
|
long rangeStart = 0;
|
|
|
|
|
@ -415,6 +492,11 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
rangeStart = Long.parseLong(rangeTextArray[0]);
|
|
|
|
|
rangeLength = Long.parseLong(rangeTextArray[1]) - rangeStart + 1;
|
|
|
|
|
}
|
|
|
|
|
return buildRangedUri(baseUrl, urlText, rangeStart, rangeLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected RangedUri buildRangedUri(Uri baseUrl, String urlText, long rangeStart,
|
|
|
|
|
long rangeLength) {
|
|
|
|
|
return new RangedUri(baseUrl, urlText, rangeStart, rangeLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -429,7 +511,11 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
return xpp.getEventType() == XmlPullParser.START_TAG && name.equals(xpp.getName());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long parseDuration(XmlPullParser xpp, String name, long defaultValue) {
|
|
|
|
|
protected static boolean isStartTag(XmlPullParser xpp) throws XmlPullParserException {
|
|
|
|
|
return xpp.getEventType() == XmlPullParser.START_TAG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static long parseDuration(XmlPullParser xpp, String name, long defaultValue) {
|
|
|
|
|
String value = xpp.getAttributeValue(null, name);
|
|
|
|
|
if (value == null) {
|
|
|
|
|
return defaultValue;
|
|
|
|
|
@ -438,7 +524,7 @@ public class MediaPresentationDescriptionParser extends DefaultHandler
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long parseDateTime(XmlPullParser xpp, String name, long defaultValue)
|
|
|
|
|
protected static long parseDateTime(XmlPullParser xpp, String name, long defaultValue)
|
|
|
|
|
throws ParseException {
|
|
|
|
|
String value = xpp.getAttributeValue(null, name);
|
|
|
|
|
if (value == null) {
|
|
|
|
|
|