From 1ddd5c6e166e97cda0b02b47d11365f1632d11a7 Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Mon, 8 Sep 2014 11:23:35 +0100 Subject: [PATCH] Parse some DASH manifest components for DVB LIVE. --- .../mpd/MediaPresentationDescription.java | 14 ++++- .../MediaPresentationDescriptionFetcher.java | 8 +-- .../MediaPresentationDescriptionParser.java | 54 ++++++++++++++----- .../exoplayer/dash/mpd/UtcTimingElement.java | 31 +++++++++++ .../SmoothStreamingManifestFetcher.java | 8 +-- .../SmoothStreamingManifestParser.java | 15 +++--- 6 files changed, 95 insertions(+), 35 deletions(-) create mode 100644 library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElement.java diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescription.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescription.java index 6d7b35a450..98e85ac40b 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescription.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescription.java @@ -23,6 +23,8 @@ import java.util.List; */ public final class MediaPresentationDescription { + public final long availabilityStartTime; + public final long duration; public final long minBufferTime; @@ -31,14 +33,22 @@ public final class MediaPresentationDescription { public final long minUpdatePeriod; + public final long timeShiftBufferDepth; + public final List periods; - public MediaPresentationDescription(long duration, long minBufferTime, boolean dynamic, - long minUpdatePeriod, List periods) { + public final UtcTimingElement utcTiming; + + public MediaPresentationDescription(long availabilityStartTime, long duration, long minBufferTime, + boolean dynamic, long minUpdatePeriod, long timeShiftBufferDepth, UtcTimingElement utcTiming, + List periods) { + this.availabilityStartTime = availabilityStartTime; this.duration = duration; this.minBufferTime = minBufferTime; this.dynamic = dynamic; this.minUpdatePeriod = minUpdatePeriod; + this.timeShiftBufferDepth = timeShiftBufferDepth; + this.utcTiming = utcTiming; this.periods = Collections.unmodifiableList(periods); } diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionFetcher.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionFetcher.java index da294190f7..45885cfc90 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionFetcher.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionFetcher.java @@ -20,8 +20,6 @@ import com.google.android.exoplayer.util.ManifestFetcher; import android.net.Uri; -import org.xmlpull.v1.XmlPullParserException; - import java.io.IOException; import java.io.InputStream; @@ -60,11 +58,7 @@ public final class MediaPresentationDescriptionFetcher extends @Override protected MediaPresentationDescription parse(InputStream stream, String inputEncoding, String contentId, Uri baseUrl) throws IOException, ParserException { - try { - return parser.parseMediaPresentationDescription(stream, inputEncoding, contentId, baseUrl); - } catch (XmlPullParserException e) { - throw new ParserException(e); - } + return parser.parseMediaPresentationDescription(stream, inputEncoding, contentId, baseUrl); } } diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java index 2bd53d998b..ba6746f398 100644 --- a/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/MediaPresentationDescriptionParser.java @@ -34,8 +34,11 @@ import org.xmlpull.v1.XmlPullParserFactory; import java.io.IOException; import java.io.InputStream; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,42 +72,57 @@ public class MediaPresentationDescriptionParser extends DefaultHandler { * @param baseUrl The url that any relative urls defined within the manifest are relative to. * @return The parsed manifest. * @throws IOException If a problem occurred reading from the stream. - * @throws XmlPullParserException If a problem occurred parsing the stream as xml. * @throws ParserException If a problem occurred parsing the xml as a DASH mpd. */ public MediaPresentationDescription parseMediaPresentationDescription(InputStream inputStream, - String inputEncoding, String contentId, Uri baseUrl) throws XmlPullParserException, - IOException, ParserException { - XmlPullParser xpp = xmlParserFactory.newPullParser(); - xpp.setInput(inputStream, inputEncoding); - int eventType = xpp.next(); - if (eventType != XmlPullParser.START_TAG || !"MPD".equals(xpp.getName())) { - throw new ParserException( - "inputStream does not contain a valid media presentation description"); + String inputEncoding, String contentId, Uri baseUrl) throws IOException, ParserException { + try { + XmlPullParser xpp = xmlParserFactory.newPullParser(); + xpp.setInput(inputStream, inputEncoding); + int eventType = xpp.next(); + if (eventType != XmlPullParser.START_TAG || !"MPD".equals(xpp.getName())) { + throw new ParserException( + "inputStream does not contain a valid media presentation description"); + } + return parseMediaPresentationDescription(xpp, contentId, baseUrl); + } catch (XmlPullParserException e) { + throw new ParserException(e); + } catch (ParseException e) { + throw new ParserException(e); } - return parseMediaPresentationDescription(xpp, contentId, baseUrl); } private MediaPresentationDescription parseMediaPresentationDescription(XmlPullParser xpp, - String contentId, Uri baseUrl) throws XmlPullParserException, IOException { + String contentId, Uri baseUrl) throws XmlPullParserException, IOException, ParseException { + long availabilityStartTime = parseDateTime(xpp, "availabilityStartTime", -1); long durationMs = parseDurationMs(xpp, "mediaPresentationDuration"); long minBufferTimeMs = parseDurationMs(xpp, "minBufferTime"); String typeString = xpp.getAttributeValue(null, "type"); boolean dynamic = (typeString != null) ? typeString.equals("dynamic") : false; long minUpdateTimeMs = (dynamic) ? parseDurationMs(xpp, "minimumUpdatePeriod", -1) : -1; + long timeShiftBufferDepthMs = (dynamic) ? parseDurationMs(xpp, "timeShiftBufferDepth", -1) : -1; + UtcTimingElement utcTiming = null; List periods = new ArrayList(); do { xpp.next(); if (isStartTag(xpp, "BaseURL")) { baseUrl = parseBaseUrl(xpp, baseUrl); + } else if (isStartTag(xpp, "UTCTiming")) { + utcTiming = parseUtcTiming(xpp); } else if (isStartTag(xpp, "Period")) { periods.add(parsePeriod(xpp, contentId, baseUrl, durationMs)); } } while (!isEndTag(xpp, "MPD")); - return new MediaPresentationDescription(durationMs, minBufferTimeMs, dynamic, minUpdateTimeMs, - periods); + return new MediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs, + dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, utcTiming, periods); + } + + private UtcTimingElement parseUtcTiming(XmlPullParser xpp) { + String schemeIdUri = xpp.getAttributeValue(null, "schemeIdUri"); + String value = xpp.getAttributeValue(null, "value"); + return new UtcTimingElement(schemeIdUri, value); } private Period parsePeriod(XmlPullParser xpp, String contentId, Uri baseUrl, long mpdDurationMs) @@ -429,6 +447,16 @@ public class MediaPresentationDescriptionParser extends DefaultHandler { return parseDurationMs(xpp, name, -1); } + private static long parseDateTime(XmlPullParser xpp, String name, long defaultValue) + throws ParseException { + String value = xpp.getAttributeValue(null, name); + if (value != null) { + SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss'Z'", Locale.US); + return parser.parse(value).getTime(); + } + return defaultValue; + } + private static long parseDurationMs(XmlPullParser xpp, String name, long defaultValue) { String value = xpp.getAttributeValue(null, name); if (value != null) { diff --git a/library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElement.java b/library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElement.java new file mode 100644 index 0000000000..cbcc30de7e --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer/dash/mpd/UtcTimingElement.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer.dash.mpd; + +/** + * Represents a UTCTiming element. + */ +public class UtcTimingElement { + + public final String schemeIdUri; + public final String value; + + public UtcTimingElement(String schemeIdUri, String value) { + this.schemeIdUri = schemeIdUri; + this.value = value; + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifestFetcher.java b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifestFetcher.java index f19a054346..8fb6e66e40 100644 --- a/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifestFetcher.java +++ b/library/src/main/java/com/google/android/exoplayer/smoothstreaming/SmoothStreamingManifestFetcher.java @@ -20,8 +20,6 @@ import com.google.android.exoplayer.util.ManifestFetcher; import android.net.Uri; -import org.xmlpull.v1.XmlPullParserException; - import java.io.IOException; import java.io.InputStream; @@ -59,11 +57,7 @@ public final class SmoothStreamingManifestFetcher extends ManifestFetcher