diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index b4e2e2be940..997e0e2ff74 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -1103,13 +1103,15 @@ protected EventStream parseEventStream(XmlPullParser xpp) String schemeIdUri = parseString(xpp, "schemeIdUri", ""); String value = parseString(xpp, "value", ""); long timescale = parseLong(xpp, "timescale", 1); + long presentationTimeOffset = parseLong(xpp, "presentationTimeOffset", 0); List> eventMessages = new ArrayList<>(); ByteArrayOutputStream scratchOutputStream = new ByteArrayOutputStream(512); do { xpp.next(); if (XmlPullParserUtil.isStartTag(xpp, "Event")) { Pair event = - parseEvent(xpp, schemeIdUri, value, timescale, scratchOutputStream); + parseEvent( + xpp, schemeIdUri, value, timescale, presentationTimeOffset, scratchOutputStream); eventMessages.add(event); } else { maybeSkipTag(xpp); @@ -1142,6 +1144,7 @@ protected EventStream buildEventStream( * @param schemeIdUri The schemeIdUri of the parent EventStream. * @param value The schemeIdUri 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 * objects. * @return A pair containing the node's presentation timestamp in microseconds and the parsed @@ -1154,6 +1157,7 @@ protected Pair parseEvent( String schemeIdUri, String value, long timescale, + long presentationTimeOffset, ByteArrayOutputStream scratchOutputStream) throws IOException, XmlPullParserException { long id = parseLong(xpp, "id", 0); @@ -1161,7 +1165,8 @@ protected Pair parseEvent( long presentationTime = parseLong(xpp, "presentationTime", 0); long durationMs = Util.scaleLargeTimestamp(duration, C.MILLIS_PER_SECOND, timescale); 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); byte[] eventObject = parseEventObject(xpp, scratchOutputStream); return Pair.create( diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java index b95fb4206cc..854ae54d63d 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParserTest.java @@ -139,7 +139,7 @@ public void parseMediaPresentationDescription_eventStream() throws IOException { ApplicationProvider.getApplicationContext(), SAMPLE_MPD_EVENT_STREAM)); Period period = manifest.getPeriod(0); - assertThat(period.eventStreams).hasSize(3); + assertThat(period.eventStreams).hasSize(4); // assert text-only event stream EventStream eventStream1 = period.eventStreams.get(0); @@ -150,10 +150,18 @@ public void parseMediaPresentationDescription_eventStream() throws IOException { assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1); assertThat(eventStream1.presentationTimesUs[0]).isEqualTo(0); - // assert CData-structured event stream + // assert event stream with presentationTimeOffset EventStream eventStream2 = period.eventStreams.get(1); assertThat(eventStream2.events.length).isEqualTo(1); 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( "urn:dvb:iptv:cpm:2014", "", @@ -173,13 +181,13 @@ public void parseMediaPresentationDescription_eventStream() throws IOException { + " \n" + " ]]>")); - assertThat(eventStream2.events[0]).isEqualTo(expectedEvent2); - assertThat(eventStream2.presentationTimesUs[0]).isEqualTo(300000000); + assertThat(eventStream3.events[0]).isEqualTo(expectedEvent3); + assertThat(eventStream3.presentationTimesUs[0]).isEqualTo(300000000); // assert xml-structured event stream - EventStream eventStream3 = period.eventStreams.get(2); - assertThat(eventStream3.events.length).isEqualTo(1); - EventMessage expectedEvent3 = + EventStream eventStream4 = period.eventStreams.get(3); + assertThat(eventStream4.events.length).isEqualTo(1); + EventMessage expectedEvent4 = new EventMessage( "urn:scte:scte35:2014:xml+bin", "", @@ -191,8 +199,8 @@ public void parseMediaPresentationDescription_eventStream() throws IOException { + " /DAIAAAAAAAAAAAQAAZ/I0VniQAQAgBDVUVJQAAAAH+cAAAAAA==\n" + " \n" + " ")); - assertThat(eventStream3.events[0]).isEqualTo(expectedEvent3); - assertThat(eventStream3.presentationTimesUs[0]).isEqualTo(1000000000); + assertThat(eventStream4.events[0]).isEqualTo(expectedEvent4); + assertThat(eventStream4.presentationTimesUs[0]).isEqualTo(1000000000); } @Test diff --git a/testdata/src/test/assets/media/mpd/sample_mpd_event_stream b/testdata/src/test/assets/media/mpd/sample_mpd_event_stream index 15e3e07b89a..8ad7ed4cd06 100644 --- a/testdata/src/test/assets/media/mpd/sample_mpd_event_stream +++ b/testdata/src/test/assets/media/mpd/sample_mpd_event_stream @@ -4,6 +4,9 @@ + + +