mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
added parsing for program information
This commit is contained in:
parent
7849a5eb52
commit
e42786d6f2
@ -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(
|
||||||
|
@ -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;
|
||||||
@ -173,16 +176,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) {
|
||||||
@ -978,6 +981,43 @@ 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 = "";
|
||||||
|
String source = "";
|
||||||
|
String copyright = "";
|
||||||
|
List<byte[]> customEvents = new ArrayList<>();
|
||||||
|
do {
|
||||||
|
xpp.next();
|
||||||
|
if (XmlPullParserUtil.isStartTag(xpp, "Title")) {
|
||||||
|
title = xpp.getText();
|
||||||
|
} else if (XmlPullParserUtil.isStartTag(xpp, "Source")) {
|
||||||
|
source = xpp.getText();
|
||||||
|
} else if (XmlPullParserUtil.isStartTag(xpp, "Copyright")) {
|
||||||
|
copyright = xpp.getText();
|
||||||
|
} else {
|
||||||
|
byte[] customElement = parseCustomElement(xpp, new ByteArrayOutputStream(512));
|
||||||
|
if (customElement.length > 0) {
|
||||||
|
customEvents.add(customElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!XmlPullParserUtil.isEndTag(xpp, "ProgramInformation"));
|
||||||
|
return new ProgramInformation(title, source, copyright, customEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] parseCustomElement(XmlPullParser xpp, ByteArrayOutputStream outputStream) throws IOException, XmlPullParserException {
|
||||||
|
XmlSerializer serializer = Xml.newSerializer();
|
||||||
|
serializer.setOutput(outputStream, C.UTF8_NAME);
|
||||||
|
if (xpp.getEventType() == XmlPullParser.START_TAG) {
|
||||||
|
serializer.startTag(xpp.getNamespace(), xpp.getName());
|
||||||
|
for (int i = 0; i < xpp.getAttributeCount(); i++) {
|
||||||
|
serializer.attribute(xpp.getAttributeNamespace(i), xpp.getAttributeName(i), xpp.getAttributeValue(i));
|
||||||
|
}
|
||||||
|
serializer.endTag(xpp.getNamespace(), xpp.getName());
|
||||||
|
}
|
||||||
|
serializer.flush();
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
// AudioChannelConfiguration parsing.
|
// AudioChannelConfiguration parsing.
|
||||||
|
|
||||||
protected int parseAudioChannelConfiguration(XmlPullParser xpp)
|
protected int parseAudioChannelConfiguration(XmlPullParser xpp)
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.google.android.exoplayer2.source.dash.manifest;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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 list of custom elements.
|
||||||
|
*/
|
||||||
|
public final List<byte[]> customEvents;
|
||||||
|
|
||||||
|
public ProgramInformation(String title, String source, String copyright, List<byte[]> customEvents) {
|
||||||
|
this.title = title;
|
||||||
|
this.source = source;
|
||||||
|
this.copyright = copyright;
|
||||||
|
this.customEvents = customEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
for (int i = 0; i < customEvents.size(); i++) {
|
||||||
|
result = 31 * result + Arrays.hashCode(customEvents.get(i));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return obj instanceof ProgramInformation
|
||||||
|
&& ((ProgramInformation)obj).title.equals(this.title)
|
||||||
|
&& ((ProgramInformation)obj).source.equals(this.source)
|
||||||
|
&& ((ProgramInformation)obj).copyright.equals(this.copyright)
|
||||||
|
&& validateEvents(((ProgramInformation)obj).customEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateEvents(List<byte[]> customEvents) {
|
||||||
|
for (int i = 0; i < customEvents.size() && i < this.customEvents.size(); i++) {
|
||||||
|
byte[] comparator = customEvents.get(i);
|
||||||
|
byte[] current = this.customEvents.get(i);
|
||||||
|
for (int j = 0; j < comparator.length && j < current.length; j++) {
|
||||||
|
if (current[j] != comparator[j]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,9 @@
|
|||||||
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>
|
||||||
|
<scte214:ContentIdentifier type="URN" value="5939026565177792163" />
|
||||||
|
</ProgramInformation>
|
||||||
<Period start="PT6462826.784S" >
|
<Period start="PT6462826.784S" >
|
||||||
<SegmentList
|
<SegmentList
|
||||||
presentationTimeOffset="34740095"
|
presentationTimeOffset="34740095"
|
||||||
|
@ -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,17 @@ 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));
|
||||||
|
List<byte[]> list = new ArrayList<>();
|
||||||
|
list.add("<scte214:ContentIdentifier type=\"URN\" value=\"5939026565177792163\" />".getBytes());
|
||||||
|
ProgramInformation programInformation = new ProgramInformation("", "", "", list);
|
||||||
|
assertThat(programInformation).isEqualTo(mpd.programInformation);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseCea608AccessibilityChannel() {
|
public void testParseCea608AccessibilityChannel() {
|
||||||
assertThat(
|
assertThat(
|
||||||
|
@ -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) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user