Merge pull request #4930 from Comcast/program_information

Add Support for Parsing ProgramInformation
This commit is contained in:
ojw28 2018-10-31 20:21:44 +00:00 committed by Oliver Woodman
parent 8200fe5ae6
commit b88c88e21e
6 changed files with 133 additions and 6 deletions

View File

@ -86,12 +86,17 @@ public class DashManifest implements FilterableManifest<DashManifest> {
*/ */
public final Uri location; public final Uri location;
/**
* The ProgramInformation of this manifest.
*/
public final ProgramInformation programInformation;
private final List<Period> periods; private final List<Period> periods;
public DashManifest(long availabilityStartTimeMs, long durationMs, long minBufferTimeMs, public DashManifest(long availabilityStartTimeMs, long durationMs, long minBufferTimeMs,
boolean dynamic, long minUpdatePeriodMs, long timeShiftBufferDepthMs, boolean dynamic, long minUpdatePeriodMs, long timeShiftBufferDepthMs,
long suggestedPresentationDelayMs, long publishTimeMs, UtcTimingElement utcTiming, long suggestedPresentationDelayMs, long publishTimeMs, UtcTimingElement utcTiming,
Uri location, List<Period> periods) { Uri location, ProgramInformation programInformation, List<Period> periods) {
this.availabilityStartTimeMs = availabilityStartTimeMs; this.availabilityStartTimeMs = availabilityStartTimeMs;
this.durationMs = durationMs; this.durationMs = durationMs;
this.minBufferTimeMs = minBufferTimeMs; this.minBufferTimeMs = minBufferTimeMs;
@ -102,6 +107,7 @@ public class DashManifest implements FilterableManifest<DashManifest> {
this.publishTimeMs = publishTimeMs; this.publishTimeMs = publishTimeMs;
this.utcTiming = utcTiming; this.utcTiming = utcTiming;
this.location = location; this.location = location;
this.programInformation = programInformation;
this.periods = periods == null ? Collections.emptyList() : periods; this.periods = periods == null ? Collections.emptyList() : periods;
} }
@ -150,7 +156,7 @@ public class DashManifest implements FilterableManifest<DashManifest> {
long newDuration = durationMs != C.TIME_UNSET ? durationMs - shiftMs : C.TIME_UNSET; long newDuration = durationMs != C.TIME_UNSET ? durationMs - shiftMs : C.TIME_UNSET;
return new DashManifest(availabilityStartTimeMs, newDuration, minBufferTimeMs, dynamic, return new DashManifest(availabilityStartTimeMs, newDuration, minBufferTimeMs, dynamic,
minUpdatePeriodMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, publishTimeMs, minUpdatePeriodMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, publishTimeMs,
utcTiming, location, copyPeriods); utcTiming, location, programInformation, copyPeriods);
} }
private static ArrayList<AdaptationSet> copyAdaptationSets( private static ArrayList<AdaptationSet> copyAdaptationSets(

View File

@ -122,6 +122,7 @@ public class DashManifestParser extends DefaultHandler
long publishTimeMs = parseDateTime(xpp, "publishTime", C.TIME_UNSET); long publishTimeMs = parseDateTime(xpp, "publishTime", C.TIME_UNSET);
UtcTimingElement utcTiming = null; UtcTimingElement utcTiming = null;
Uri location = null; Uri location = null;
ProgramInformation programInformation = null;
List<Period> periods = new ArrayList<>(); List<Period> periods = new ArrayList<>();
long nextPeriodStartMs = dynamic ? C.TIME_UNSET : 0; long nextPeriodStartMs = dynamic ? C.TIME_UNSET : 0;
@ -138,6 +139,8 @@ public class DashManifestParser extends DefaultHandler
utcTiming = parseUtcTiming(xpp); utcTiming = parseUtcTiming(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Location")) { } else if (XmlPullParserUtil.isStartTag(xpp, "Location")) {
location = Uri.parse(xpp.nextText()); location = Uri.parse(xpp.nextText());
} else if (XmlPullParserUtil.isStartTag(xpp, "ProgramInformation")) {
programInformation = parseProgramInformation(xpp);
} else if (XmlPullParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) { } else if (XmlPullParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) {
Pair<Period, Long> periodWithDurationMs = parsePeriod(xpp, baseUrl, nextPeriodStartMs); Pair<Period, Long> periodWithDurationMs = parsePeriod(xpp, baseUrl, nextPeriodStartMs);
Period period = periodWithDurationMs.first; Period period = periodWithDurationMs.first;
@ -175,16 +178,16 @@ public class DashManifestParser extends DefaultHandler
return buildMediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs, return buildMediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs,
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs,
publishTimeMs, utcTiming, location, periods); publishTimeMs, utcTiming, location, programInformation, periods);
} }
protected DashManifest buildMediaPresentationDescription(long availabilityStartTime, protected DashManifest buildMediaPresentationDescription(long availabilityStartTime,
long durationMs, long minBufferTimeMs, boolean dynamic, long minUpdateTimeMs, long durationMs, long minBufferTimeMs, boolean dynamic, long minUpdateTimeMs,
long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, long publishTimeMs, long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, long publishTimeMs,
UtcTimingElement utcTiming, Uri location, List<Period> periods) { UtcTimingElement utcTiming, Uri location, ProgramInformation programInformation, List<Period> periods) {
return new DashManifest(availabilityStartTime, durationMs, minBufferTimeMs, return new DashManifest(availabilityStartTime, durationMs, minBufferTimeMs,
dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs,
publishTimeMs, utcTiming, location, periods); publishTimeMs, utcTiming, location, programInformation, periods);
} }
protected UtcTimingElement parseUtcTiming(XmlPullParser xpp) { protected UtcTimingElement parseUtcTiming(XmlPullParser xpp) {
@ -998,6 +1001,27 @@ public class DashManifestParser extends DefaultHandler
return new RangedUri(urlText, rangeStart, rangeLength); return new RangedUri(urlText, rangeStart, rangeLength);
} }
protected ProgramInformation parseProgramInformation(XmlPullParser xpp) throws IOException, XmlPullParserException {
String title = null;
String source = null;
String copyright = null;
String moreInformationURL = parseString(xpp, "moreInformationURL", null);
String lang = parseString(xpp, "lang", null);
do {
xpp.next();
if (XmlPullParserUtil.isStartTag(xpp, "Title")) {
title = xpp.nextText();
} else if (XmlPullParserUtil.isStartTag(xpp, "Source")) {
source = xpp.nextText();
} else if (XmlPullParserUtil.isStartTag(xpp, "Copyright")) {
copyright = xpp.nextText();
} else {
maybeSkipTag(xpp);
}
} while (!XmlPullParserUtil.isEndTag(xpp, "ProgramInformation"));
return new ProgramInformation(title, source, copyright, moreInformationURL, lang);
}
// AudioChannelConfiguration parsing. // AudioChannelConfiguration parsing.
protected int parseAudioChannelConfiguration(XmlPullParser xpp) protected int parseAudioChannelConfiguration(XmlPullParser xpp)

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2018 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.exoplayer2.source.dash.manifest;
import com.google.android.exoplayer2.util.Util;
/**
* A parsed ProgramInformation element.
*/
public class ProgramInformation {
/**
* The title for the media presentation.
*/
public final String title;
/**
* Information about the original source of the media presentation.
*/
public final String source;
/**
* A copyright statement for the media presentation.
*/
public final String copyright;
/**
* A URL that provides more information about the media presentation.
*/
public final String moreInformationURL;
/**
* Declares the language code(s) for this ProgramInformation.
*/
public final String lang;
public ProgramInformation(String title, String source, String copyright, String moreInformationURL, String lang) {
this.title = title;
this.source = source;
this.copyright = copyright;
this.moreInformationURL = moreInformationURL;
this.lang = lang;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ProgramInformation)) {
return false;
}
ProgramInformation other = (ProgramInformation) obj;
return Util.areEqual(this.title, other.title)
&& Util.areEqual(this.source, other.source)
&& Util.areEqual(this.copyright, other.copyright)
&& Util.areEqual(this.moreInformationURL, other.moreInformationURL)
&& Util.areEqual(this.lang, other.lang);
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (title != null ? title.hashCode() : 0);
result = 31 * result + (source != null ? source.hashCode() : 0);
result = 31 * result + (copyright != null ? copyright.hashCode() : 0);
result = 31 * result + (moreInformationURL != null ? moreInformationURL.hashCode() : 0);
result = 31 * result + (lang != null ? lang.hashCode() : 0);
return result;
}
}

View File

@ -9,6 +9,12 @@
xmlns="urn:mpeg:DASH:schema:MPD:2011" xmlns="urn:mpeg:DASH:schema:MPD:2011"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd" xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 DASH-MPD.xsd"
yt:earliestMediaSequence="1266404" > yt:earliestMediaSequence="1266404" >
<ProgramInformation lang="enUs"
moreInformationURL="www.example.com">
<Title>MediaTitle</Title>
<Source>MediaSource</Source>
<Copyright>MediaCopyright</Copyright>
</ProgramInformation>
<Period start="PT6462826.784S" > <Period start="PT6462826.784S" >
<SegmentList <SegmentList
presentationTimeOffset="34740095" presentationTimeOffset="34740095"

View File

@ -25,6 +25,7 @@ import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
@ -152,6 +153,16 @@ public class DashManifestParserTest {
1000000000)); 1000000000));
} }
@Test
public void testParseMediaPresentationDescriptionCanParseProgramInformation() throws IOException {
DashManifestParser parser = new DashManifestParser();
DashManifest mpd = parser.parse(Uri.parse("Https://example.com/test.mpd"),
TestUtil.getInputStream(RuntimeEnvironment.application, SAMPLE_MPD_1));
ProgramInformation programInformation = new ProgramInformation("MediaTitle", "MediaSource",
"MediaCopyright", "www.example.com", "enUs");
assertThat(programInformation).isEqualTo(mpd.programInformation);
}
@Test @Test
public void testParseCea608AccessibilityChannel() { public void testParseCea608AccessibilityChannel() {
assertThat( assertThat(

View File

@ -219,7 +219,7 @@ public class DashManifestTest {
private static DashManifest newDashManifest(int duration, Period... periods) { private static DashManifest newDashManifest(int duration, Period... periods) {
return new DashManifest( return new DashManifest(
0, duration, 1, false, 2, 3, 4, 12345, DUMMY_UTC_TIMING, Uri.EMPTY, Arrays.asList(periods)); 0, duration, 1, false, 2, 3, 4, 12345, DUMMY_UTC_TIMING, Uri.EMPTY, null, Arrays.asList(periods));
} }
private static Period newPeriod(String id, int startMs, AdaptationSet... adaptationSets) { private static Period newPeriod(String id, int startMs, AdaptationSet... adaptationSets) {