diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java index 0f1fd8f6495..d7ed1c0c5bf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/FragmentedMp4Extractor.java @@ -591,6 +591,14 @@ private void onEmsgLeafAtomRead(ParsableByteArray atom) { long presentationTimeDeltaUs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MICROS_PER_SECOND, timescale); + // The presentation_time_delta is accounted for by adjusting the sample timestamp, so we zero it + // in the sample data before writing it to the track outputs. + int position = atom.getPosition(); + atom.data[position - 4] = 0; + atom.data[position - 3] = 0; + atom.data[position - 2] = 0; + atom.data[position - 1] = 0; + // Output the sample data. for (TrackOutput emsgTrackOutput : emsgTrackOutputs) { atom.setPosition(Atom.FULL_HEADER_SIZE); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java index 7d70d9de1c0..8a3467e2eda 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java @@ -44,13 +44,6 @@ public final class EventMessage implements Metadata.Entry { */ public final long durationMs; - /** - * The presentation time value of this event message in microseconds. - *
- * Except in special cases, application code should not use this field. - */ - public final long presentationTimeUs; - /** * The instance identifier. */ @@ -70,22 +63,19 @@ public final class EventMessage implements Metadata.Entry { * @param durationMs The duration of the event in milliseconds. * @param id The instance identifier. * @param messageData The body of the message. - * @param presentationTimeUs The presentation time value of this event message in microseconds. */ - public EventMessage(String schemeIdUri, String value, long durationMs, long id, - byte[] messageData, long presentationTimeUs) { + public EventMessage( + String schemeIdUri, String value, long durationMs, long id, byte[] messageData) { this.schemeIdUri = schemeIdUri; this.value = value; this.durationMs = durationMs; this.id = id; this.messageData = messageData; - this.presentationTimeUs = presentationTimeUs; } /* package */ EventMessage(Parcel in) { schemeIdUri = castNonNull(in.readString()); value = castNonNull(in.readString()); - presentationTimeUs = in.readLong(); durationMs = in.readLong(); id = in.readLong(); messageData = castNonNull(in.createByteArray()); @@ -97,7 +87,6 @@ public int hashCode() { int result = 17; result = 31 * result + (schemeIdUri != null ? schemeIdUri.hashCode() : 0); result = 31 * result + (value != null ? value.hashCode() : 0); - result = 31 * result + (int) (presentationTimeUs ^ (presentationTimeUs >>> 32)); result = 31 * result + (int) (durationMs ^ (durationMs >>> 32)); result = 31 * result + (int) (id ^ (id >>> 32)); result = 31 * result + Arrays.hashCode(messageData); @@ -115,9 +104,11 @@ public boolean equals(@Nullable Object obj) { return false; } EventMessage other = (EventMessage) obj; - return presentationTimeUs == other.presentationTimeUs && durationMs == other.durationMs - && id == other.id && Util.areEqual(schemeIdUri, other.schemeIdUri) - && Util.areEqual(value, other.value) && Arrays.equals(messageData, other.messageData); + return durationMs == other.durationMs + && id == other.id + && Util.areEqual(schemeIdUri, other.schemeIdUri) + && Util.areEqual(value, other.value) + && Arrays.equals(messageData, other.messageData); } @Override @@ -136,7 +127,6 @@ public int describeContents() { public void writeToParcel(Parcel dest, int flags) { dest.writeString(schemeIdUri); dest.writeString(value); - dest.writeLong(presentationTimeUs); dest.writeLong(durationMs); dest.writeLong(id); dest.writeByteArray(messageData); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java index 14f678374c9..33d79917ebc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoder.java @@ -15,11 +15,11 @@ */ package com.google.android.exoplayer2.metadata.emsg; -import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataDecoder; import com.google.android.exoplayer2.metadata.MetadataInputBuffer; import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.ParsableByteArray; import com.google.android.exoplayer2.util.Util; import java.nio.ByteBuffer; @@ -27,12 +27,15 @@ /** * Decodes Event Message (emsg) atoms, as defined in ISO/IEC 23009-1:2014, Section 5.10.3.3. - *
- * Atom data should be provided to the decoder without the full atom header (i.e. starting from the - * first byte of the scheme_id_uri field). + * + *
Atom data should be provided to the decoder without the full atom header (i.e. starting from
+ * the first byte of the scheme_id_uri field). It is expected that the presentation_time_delta field
+ * should be 0, having already been accounted for by adjusting the sample timestamp.
*/
public final class EventMessageDecoder implements MetadataDecoder {
+ private static final String TAG = "EventMessageDecoder";
+
@SuppressWarnings("ByteBufferBackingArray")
@Override
public Metadata decode(MetadataInputBuffer inputBuffer) {
@@ -43,13 +46,16 @@ public Metadata decode(MetadataInputBuffer inputBuffer) {
String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString());
String value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
long timescale = emsgData.readUnsignedInt();
- long presentationTimeUs = Util.scaleLargeTimestamp(emsgData.readUnsignedInt(),
- C.MICROS_PER_SECOND, timescale);
+ long presentationTimeDelta = emsgData.readUnsignedInt();
+ if (presentationTimeDelta != 0) {
+ // We expect the source to have accounted for presentation_time_delta by adjusting the sample
+ // timestamp and zeroing the field in the sample data. Log a warning if the field is non-zero.
+ Log.w(TAG, "Ignoring non-zero presentation_time_delta: " + presentationTimeDelta);
+ }
long durationMs = Util.scaleLargeTimestamp(emsgData.readUnsignedInt(), 1000, timescale);
long id = emsgData.readUnsignedInt();
byte[] messageData = Arrays.copyOfRange(data, emsgData.getPosition(), size);
- return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData,
- presentationTimeUs));
+ return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData));
}
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java
index eca498a6df4..22708a8448f 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoder.java
@@ -16,9 +16,6 @@
package com.google.android.exoplayer2.metadata.emsg;
import android.support.annotation.Nullable;
-import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.util.Assertions;
-import com.google.android.exoplayer2.util.Util;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -37,27 +34,22 @@ public EventMessageEncoder() {
}
/**
- * Encodes an {@link EventMessage} to a byte array that can be decoded by
- * {@link EventMessageDecoder}.
+ * Encodes an {@link EventMessage} to a byte array that can be decoded by {@link
+ * EventMessageDecoder}.
*
* @param eventMessage The event message to be encoded.
- * @param timescale Timescale of the event message, in units per second.
* @return The serialized byte array.
*/
@Nullable
- public byte[] encode(EventMessage eventMessage, long timescale) {
- Assertions.checkArgument(timescale >= 0);
+ public byte[] encode(EventMessage eventMessage) {
byteArrayOutputStream.reset();
try {
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
writeNullTerminatedString(dataOutputStream, nonNullValue);
- writeUnsignedInt(dataOutputStream, timescale);
- long presentationTime = Util.scaleLargeTimestamp(eventMessage.presentationTimeUs,
- timescale, C.MICROS_PER_SECOND);
- writeUnsignedInt(dataOutputStream, presentationTime);
- long duration = Util.scaleLargeTimestamp(eventMessage.durationMs, timescale, 1000);
- writeUnsignedInt(dataOutputStream, duration);
+ writeUnsignedInt(dataOutputStream, 1000); // timescale
+ writeUnsignedInt(dataOutputStream, 0); // presentation_time_delta
+ writeUnsignedInt(dataOutputStream, eventMessage.durationMs);
writeUnsignedInt(dataOutputStream, eventMessage.id);
dataOutputStream.write(eventMessage.messageData);
dataOutputStream.flush();
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java
index c6558e3fc97..85d336b439d 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageDecoderTest.java
@@ -51,7 +51,6 @@ public void testDecodeEventMessage() {
assertThat(eventMessage.durationMs).isEqualTo(3000);
assertThat(eventMessage.id).isEqualTo(1000403);
assertThat(eventMessage.messageData).isEqualTo(new byte[]{0, 1, 2, 3, 4});
- assertThat(eventMessage.presentationTimeUs).isEqualTo(1000000);
}
}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java
index 7195548fbf2..28696922729 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageEncoderTest.java
@@ -33,25 +33,27 @@ public final class EventMessageEncoderTest {
@Test
public void testEncodeEventStream() throws IOException {
- EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
- new byte[] {0, 1, 2, 3, 4}, 1000000);
- byte[] expectedEmsgBody = new byte[] {
- 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
- 49, 50, 51, 0, // value = "123"
- 0, 0, -69, -128, // timescale = 48000
- 0, 0, -69, -128, // presentation_time_delta = 48000
- 0, 2, 50, -128, // event_duration = 144000
- 0, 15, 67, -45, // id = 1000403
- 0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
- byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage, 48000);
+ EventMessage eventMessage =
+ new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
+ byte[] expectedEmsgBody =
+ new byte[] {
+ 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
+ 49, 50, 51, 0, // value = "123"
+ 0, 0, 3, -24, // timescale = 1000
+ 0, 0, 0, 0, // presentation_time_delta = 0
+ 0, 0, 11, -72, // event_duration = 3000
+ 0, 15, 67, -45, // id = 1000403
+ 0, 1, 2, 3, 4
+ }; // message_data = {0, 1, 2, 3, 4}
+ byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
}
@Test
public void testEncodeDecodeEventStream() throws IOException {
- EventMessage expectedEmsg = new EventMessage("urn:test", "123", 3000, 1000403,
- new byte[] {0, 1, 2, 3, 4}, 1000000);
- byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg, 48000);
+ EventMessage expectedEmsg =
+ new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
+ byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg);
MetadataInputBuffer buffer = new MetadataInputBuffer();
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
@@ -63,30 +65,34 @@ public void testEncodeDecodeEventStream() throws IOException {
@Test
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
- EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
- new byte[] {0, 1, 2, 3, 4}, 1000000);
- byte[] expectedEmsgBody = new byte[] {
- 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
- 49, 50, 51, 0, // value = "123"
- 0, 0, -69, -128, // timescale = 48000
- 0, 0, -69, -128, // presentation_time_delta = 48000
- 0, 2, 50, -128, // event_duration = 144000
- 0, 15, 67, -45, // id = 1000403
- 0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
- EventMessage eventMessage1 = new EventMessage("urn:test", "123", 3000, 1000402,
- new byte[] {4, 3, 2, 1, 0}, 1000000);
- byte[] expectedEmsgBody1 = new byte[] {
- 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
- 49, 50, 51, 0, // value = "123"
- 0, 0, -69, -128, // timescale = 48000
- 0, 0, -69, -128, // presentation_time_delta = 48000
- 0, 2, 50, -128, // event_duration = 144000
- 0, 15, 67, -46, // id = 1000402
- 4, 3, 2, 1, 0}; // message_data = {4, 3, 2, 1, 0}
+ EventMessage eventMessage =
+ new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
+ byte[] expectedEmsgBody =
+ new byte[] {
+ 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
+ 49, 50, 51, 0, // value = "123"
+ 0, 0, 3, -24, // timescale = 1000
+ 0, 0, 0, 0, // presentation_time_delta = 0
+ 0, 0, 11, -72, // event_duration = 3000
+ 0, 15, 67, -45, // id = 1000403
+ 0, 1, 2, 3, 4
+ }; // message_data = {0, 1, 2, 3, 4}
+ EventMessage eventMessage1 =
+ new EventMessage("urn:test", "123", 3000, 1000402, new byte[] {4, 3, 2, 1, 0});
+ byte[] expectedEmsgBody1 =
+ new byte[] {
+ 117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
+ 49, 50, 51, 0, // value = "123"
+ 0, 0, 3, -24, // timescale = 1000
+ 0, 0, 0, 0, // presentation_time_delta = 0
+ 0, 0, 11, -72, // event_duration = 3000
+ 0, 15, 67, -46, // id = 1000402
+ 4, 3, 2, 1, 0
+ }; // message_data = {4, 3, 2, 1, 0}
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
- byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage, 48000);
+ byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
- byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1, 48000);
+ byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1);
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
}
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageTest.java
index 30e1cd6c1f4..f7970d1a165 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/emsg/EventMessageTest.java
@@ -30,8 +30,8 @@ public final class EventMessageTest {
@Test
public void testEventMessageParcelable() {
- EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
- new byte[] {0, 1, 2, 3, 4}, 1000);
+ EventMessage eventMessage =
+ new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
// Write to parcel.
Parcel parcel = Parcel.obtain();
eventMessage.writeToParcel(parcel, 0);
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java
index 9f812b8e841..f06a709960d 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/EventSampleStream.java
@@ -112,8 +112,7 @@ public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
}
}
int sampleIndex = currentIndex++;
- byte[] serializedEvent = eventMessageEncoder.encode(eventStream.events[sampleIndex],
- eventStream.timescale);
+ byte[] serializedEvent = eventMessageEncoder.encode(eventStream.events[sampleIndex]);
if (serializedEvent != null) {
buffer.ensureSpaceForWrite(serializedEvent.length);
buffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);
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 f017ae64add..f34127273dd 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
@@ -834,13 +834,13 @@ protected EventStream parseEventStream(XmlPullParser xpp)
String schemeIdUri = parseString(xpp, "schemeIdUri", "");
String value = parseString(xpp, "value", "");
long timescale = parseLong(xpp, "timescale", 1);
- List