DASH: Parse and use EventStream.presentationTimeOffset

Issue: google/ExoPlayer#10460
#minor-release
PiperOrigin-RevId: 463163839
(cherry picked from commit 3786b64217a5044ed505c2e3939f07bece0605a6)
This commit is contained in:
olly 2022-07-25 20:28:20 +00:00 committed by microkatz
parent c4ce6b7511
commit 7b969e8df0
4 changed files with 30 additions and 11 deletions

View File

@ -14,6 +14,9 @@
`MetadataRenderer(MetadataOutput, Looper, MetadataDecoderFactory, `MetadataRenderer(MetadataOutput, Looper, MetadataDecoderFactory,
boolean)` to specify whether the renderer will output metadata early or boolean)` to specify whether the renderer will output metadata early or
in sync with the player position. in sync with the player position.
* DASH:
* Parse `EventStream.presentationTimeOffset` from manifests
([#10460](https://github.com/google/ExoPlayer/issues/10460)).
* UI: * UI:
* Use current overrides of the player as preset in * Use current overrides of the player as preset in
`TrackSelectionDialogBuilder` `TrackSelectionDialogBuilder`

View File

@ -1105,13 +1105,15 @@ public class DashManifestParser extends DefaultHandler
String schemeIdUri = parseString(xpp, "schemeIdUri", ""); String schemeIdUri = parseString(xpp, "schemeIdUri", "");
String value = parseString(xpp, "value", ""); String value = parseString(xpp, "value", "");
long timescale = parseLong(xpp, "timescale", 1); long timescale = parseLong(xpp, "timescale", 1);
long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset", 0);
List<Pair<Long, EventMessage>> eventMessages = new ArrayList<>(); List<Pair<Long, EventMessage>> eventMessages = new ArrayList<>();
ByteArrayOutputStream scratchOutputStream = new ByteArrayOutputStream(512); ByteArrayOutputStream scratchOutputStream = new ByteArrayOutputStream(512);
do { do {
xpp.next(); xpp.next();
if (XmlPullParserUtil.isStartTag(xpp, "Event")) { if (XmlPullParserUtil.isStartTag(xpp, "Event")) {
Pair<Long, EventMessage> event = Pair<Long, EventMessage> event =
parseEvent(xpp, schemeIdUri, value, timescale, scratchOutputStream); parseEvent(
xpp, schemeIdUri, value, timescale, presentationTimeOffset, scratchOutputStream);
eventMessages.add(event); eventMessages.add(event);
} else { } else {
maybeSkipTag(xpp); maybeSkipTag(xpp);
@ -1144,6 +1146,7 @@ public class DashManifestParser extends DefaultHandler
* @param schemeIdUri The schemeIdUri of the parent EventStream. * @param schemeIdUri The schemeIdUri of the parent EventStream.
* @param value The schemeIdUri of the parent EventStream. * @param value The schemeIdUri of the parent EventStream.
* @param timescale The timescale of the parent EventStream. * @param timescale The timescale of the parent EventStream.
* @param presentationTimeOffset The unscaled presentation time offset of the parent EventStream.
* @param scratchOutputStream A {@link ByteArrayOutputStream} that is used when parsing event * @param scratchOutputStream A {@link ByteArrayOutputStream} that is used when parsing event
* objects. * objects.
* @return A pair containing the node's presentation timestamp in microseconds and the parsed * @return A pair containing the node's presentation timestamp in microseconds and the parsed
@ -1156,6 +1159,7 @@ public class DashManifestParser extends DefaultHandler
String schemeIdUri, String schemeIdUri,
String value, String value,
long timescale, long timescale,
long presentationTimeOffset,
ByteArrayOutputStream scratchOutputStream) ByteArrayOutputStream scratchOutputStream)
throws IOException, XmlPullParserException { throws IOException, XmlPullParserException {
long id = parseLong(xpp, "id", 0); long id = parseLong(xpp, "id", 0);
@ -1163,7 +1167,8 @@ public class DashManifestParser extends DefaultHandler
long presentationTime = parseLong(xpp, "presentationTime", 0); long presentationTime = parseLong(xpp, "presentationTime", 0);
long durationMs = Util.scaleLargeTimestamp(duration, C.MILLIS_PER_SECOND, timescale); long durationMs = Util.scaleLargeTimestamp(duration, C.MILLIS_PER_SECOND, timescale);
long presentationTimesUs = long presentationTimesUs =
Util.scaleLargeTimestamp(presentationTime, C.MICROS_PER_SECOND, timescale); Util.scaleLargeTimestamp(
presentationTime - presentationTimeOffset, C.MICROS_PER_SECOND, timescale);
String messageData = parseString(xpp, "messageData", null); String messageData = parseString(xpp, "messageData", null);
byte[] eventObject = parseEventObject(xpp, scratchOutputStream); byte[] eventObject = parseEventObject(xpp, scratchOutputStream);
return Pair.create( return Pair.create(

View File

@ -139,7 +139,7 @@ public class DashManifestParserTest {
ApplicationProvider.getApplicationContext(), SAMPLE_MPD_EVENT_STREAM)); ApplicationProvider.getApplicationContext(), SAMPLE_MPD_EVENT_STREAM));
Period period = manifest.getPeriod(0); Period period = manifest.getPeriod(0);
assertThat(period.eventStreams).hasSize(3); assertThat(period.eventStreams).hasSize(4);
// assert text-only event stream // assert text-only event stream
EventStream eventStream1 = period.eventStreams.get(0); EventStream eventStream1 = period.eventStreams.get(0);
@ -150,10 +150,18 @@ public class DashManifestParserTest {
assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1); assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1);
assertThat(eventStream1.presentationTimesUs[0]).isEqualTo(0); assertThat(eventStream1.presentationTimesUs[0]).isEqualTo(0);
// assert CData-structured event stream // assert event stream with presentationTimeOffset
EventStream eventStream2 = period.eventStreams.get(1); EventStream eventStream2 = period.eventStreams.get(1);
assertThat(eventStream2.events.length).isEqualTo(1); assertThat(eventStream2.events.length).isEqualTo(1);
EventMessage expectedEvent2 = EventMessage expectedEvent2 =
new EventMessage("urn:uuid:with-pto", "pto-4s", 10000, 0, "pt=1s".getBytes(Charsets.UTF_8));
assertThat(eventStream2.events[0]).isEqualTo(expectedEvent2);
assertThat(eventStream2.presentationTimesUs[0]).isEqualTo(1000000);
// assert CData-structured event stream
EventStream eventStream3 = period.eventStreams.get(2);
assertThat(eventStream3.events.length).isEqualTo(1);
EventMessage expectedEvent3 =
new EventMessage( new EventMessage(
"urn:dvb:iptv:cpm:2014", "urn:dvb:iptv:cpm:2014",
"", "",
@ -173,13 +181,13 @@ public class DashManifestParserTest {
+ " </InstanceDescription>\n" + " </InstanceDescription>\n"
+ " </BroadcastEvent>]]>")); + " </BroadcastEvent>]]>"));
assertThat(eventStream2.events[0]).isEqualTo(expectedEvent2); assertThat(eventStream3.events[0]).isEqualTo(expectedEvent3);
assertThat(eventStream2.presentationTimesUs[0]).isEqualTo(300000000); assertThat(eventStream3.presentationTimesUs[0]).isEqualTo(300000000);
// assert xml-structured event stream // assert xml-structured event stream
EventStream eventStream3 = period.eventStreams.get(2); EventStream eventStream4 = period.eventStreams.get(3);
assertThat(eventStream3.events.length).isEqualTo(1); assertThat(eventStream4.events.length).isEqualTo(1);
EventMessage expectedEvent3 = EventMessage expectedEvent4 =
new EventMessage( new EventMessage(
"urn:scte:scte35:2014:xml+bin", "urn:scte:scte35:2014:xml+bin",
"", "",
@ -191,8 +199,8 @@ public class DashManifestParserTest {
+ " /DAIAAAAAAAAAAAQAAZ/I0VniQAQAgBDVUVJQAAAAH+cAAAAAA==\n" + " /DAIAAAAAAAAAAAQAAZ/I0VniQAQAgBDVUVJQAAAAH+cAAAAAA==\n"
+ " </scte35:Binary>\n" + " </scte35:Binary>\n"
+ " </scte35:Signal>")); + " </scte35:Signal>"));
assertThat(eventStream3.events[0]).isEqualTo(expectedEvent3); assertThat(eventStream4.events[0]).isEqualTo(expectedEvent4);
assertThat(eventStream3.presentationTimesUs[0]).isEqualTo(1000000000); assertThat(eventStream4.presentationTimesUs[0]).isEqualTo(1000000000);
} }
@Test @Test

View File

@ -4,6 +4,9 @@
<EventStream schemeIdUri="urn:uuid:XYZY" timescale="1000" value="call"> <EventStream schemeIdUri="urn:uuid:XYZY" timescale="1000" value="call">
<Event presentationTime="0" duration="10000" id="0" messageData="+ 1 800 10101010"/> <Event presentationTime="0" duration="10000" id="0" messageData="+ 1 800 10101010"/>
</EventStream> </EventStream>
<EventStream schemeIdUri="urn:uuid:with-pto" timescale="1000" presentationTimeOffset="4000" value="pto-4s">
<Event presentationTime="5000" duration="10000" id="0" messageData="pt=1s"/>
</EventStream>
<EventStream schemeIdUri="urn:dvb:iptv:cpm:2014"> <EventStream schemeIdUri="urn:dvb:iptv:cpm:2014">
<Event presentationTime="300" duration="1500" id="1"><![CDATA[<BroadcastEvent> <Event presentationTime="300" duration="1500" id="1"><![CDATA[<BroadcastEvent>
<Program crid="crid://broadcaster.example.com/ABCDEF"/> <Program crid="crid://broadcaster.example.com/ABCDEF"/>