Let EventMessage encloses its presentationTimeMs.

Currently EventMessage's presentationTimeMs is kept separately in
EventSampleStream. However, EventMessage's presentationTimeMs maybe used in
other places besides EventSampleStream, such as when handling `emsg' messages
targeting the player. This CL let EventMessage object to holds its
presentationTimeMs for such use cases.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=176502938
This commit is contained in:
hoangtc 2017-11-21 07:03:55 -08:00 committed by Oliver Woodman
parent 3998ed49ae
commit e619079a0d
9 changed files with 57 additions and 44 deletions

View file

@ -41,6 +41,13 @@ public final class EventMessage implements Metadata.Entry {
*/
public final long durationMs;
/**
* The presentation time value of this event message in microseconds.
* <p>
* Except in special cases, application code should <em>not</em> use this field.
*/
public final long presentationTimeUs;
/**
* The instance identifier.
*/
@ -55,25 +62,27 @@ public final class EventMessage implements Metadata.Entry {
private int hashCode;
/**
*
* @param schemeIdUri The message scheme.
* @param value The value for the event.
* @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) {
byte[] messageData, long presentationTimeUs) {
this.schemeIdUri = schemeIdUri;
this.value = value;
this.durationMs = durationMs;
this.id = id;
this.messageData = messageData;
this.presentationTimeUs = presentationTimeUs;
}
/* package */ EventMessage(Parcel in) {
schemeIdUri = in.readString();
value = in.readString();
presentationTimeUs = in.readLong();
durationMs = in.readLong();
id = in.readLong();
messageData = in.createByteArray();
@ -85,6 +94,7 @@ public final class EventMessage implements Metadata.Entry {
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);
@ -102,9 +112,9 @@ public final class EventMessage implements Metadata.Entry {
return false;
}
EventMessage other = (EventMessage) obj;
return durationMs == other.durationMs && id == other.id
&& Util.areEqual(schemeIdUri, other.schemeIdUri) && Util.areEqual(value, other.value)
&& Arrays.equals(messageData, other.messageData);
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);
}
// Parcelable implementation.
@ -118,6 +128,7 @@ public final class EventMessage implements Metadata.Entry {
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);

View file

@ -15,6 +15,7 @@
*/
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;
@ -24,7 +25,7 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
/**
* Decodes Event Message (emsg) atoms, as defined in ISO 23009-1.
* Decodes Event Message (emsg) atoms, as defined in ISO/IEC 23009-1:2014, Section 5.10.3.3.
* <p>
* 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).
@ -40,11 +41,13 @@ public final class EventMessageDecoder implements MetadataDecoder {
String schemeIdUri = emsgData.readNullTerminatedString();
String value = emsgData.readNullTerminatedString();
long timescale = emsgData.readUnsignedInt();
emsgData.skipBytes(4); // presentation_time_delta
long presentationTimeUs = Util.scaleLargeTimestamp(emsgData.readUnsignedInt(),
C.MICROS_PER_SECOND, timescale);
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));
return new Metadata(new EventMessage(schemeIdUri, value, durationMs, id, messageData,
presentationTimeUs));
}
}

View file

@ -42,11 +42,10 @@ public final class EventMessageEncoder {
*
* @param eventMessage The event message to be encoded.
* @param timescale Timescale of the event message, in units per second.
* @param presentationTimeUs The presentation time of the event message in microseconds.
* @return The serialized byte array.
*/
@Nullable
public byte[] encode(EventMessage eventMessage, long timescale, long presentationTimeUs) {
public byte[] encode(EventMessage eventMessage, long timescale) {
Assertions.checkArgument(timescale >= 0);
byteArrayOutputStream.reset();
try {
@ -54,8 +53,8 @@ public final class EventMessageEncoder {
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
writeNullTerminatedString(dataOutputStream, nonNullValue);
writeUnsignedInt(dataOutputStream, timescale);
long presentationTime = Util.scaleLargeTimestamp(presentationTimeUs, timescale,
C.MICROS_PER_SECOND);
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);

View file

@ -38,7 +38,7 @@ public final class EventMessageDecoderTest {
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, 0, 0, // presentation_time_delta (ignored) = 0
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}
@ -53,6 +53,7 @@ public final class EventMessageDecoderTest {
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);
}
}

View file

@ -36,24 +36,24 @@ 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});
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 = 48
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, 1000000);
byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage, 48000);
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});
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg, 48000, 1);
new byte[] {0, 1, 2, 3, 4}, 1000000);
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg, 48000);
MetadataInputBuffer buffer = new MetadataInputBuffer();
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
@ -66,29 +66,29 @@ public final class EventMessageEncoderTest {
@Test
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
new byte[] {0, 1, 2, 3, 4});
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 = 48
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});
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 = 48
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}
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage, 48000, 1000000);
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage, 48000);
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1, 48000, 1000000);
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1, 48000);
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
}

View file

@ -33,7 +33,7 @@ public final class EventMessageTest {
@Test
public void testEventMessageParcelable() {
EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
new byte[] {0, 1, 2, 3, 4});
new byte[] {0, 1, 2, 3, 4}, 1000);
// Write to parcel.
Parcel parcel = Parcel.obtain();
eventMessage.writeToParcel(parcel, 0);

View file

@ -84,7 +84,7 @@ public class DashManifestParserTest extends InstrumentationTestCase {
EventStream eventStream1 = period.eventStreams.get(0);
assertEquals(1, eventStream1.events.length);
EventMessage expectedEvent1 = new EventMessage("urn:uuid:XYZY", "call", 10000, 0,
"+ 1 800 10101010".getBytes());
"+ 1 800 10101010".getBytes(), 0);
assertEquals(expectedEvent1, eventStream1.events[0]);
// assert CData-structured event stream
@ -102,7 +102,7 @@ public class DashManifestParserTest extends InstrumentationTestCase {
+ " <mpeg7:Region>GB</mpeg7:Region>\n"
+ " </ParentalGuidance>\n"
+ " </InstanceDescription>\n"
+ " </BroadcastEvent>]]>").getBytes()),
+ " </BroadcastEvent>]]>").getBytes(), 300000000),
eventStream2.events[0]);
// assert xml-structured event stream
@ -114,7 +114,7 @@ public class DashManifestParserTest extends InstrumentationTestCase {
+ " <scte35:Binary>\n"
+ " /DAIAAAAAAAAAAAQAAZ/I0VniQAQAgBDVUVJQAAAAH+cAAAAAA==\n"
+ " </scte35:Binary>\n"
+ " </scte35:Signal>").getBytes()),
+ " </scte35:Signal>").getBytes(), 1000000000),
eventStream3.events[0]);
}

View file

@ -95,7 +95,7 @@ import java.io.IOException;
}
int sampleIndex = currentIndex++;
byte[] serializedEvent = eventMessageEncoder.encode(eventStream.events[sampleIndex],
eventStream.timescale, eventTimesUs[sampleIndex]);
eventStream.timescale);
if (serializedEvent != null) {
buffer.ensureSpaceForWrite(serializedEvent.length);
buffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);

View file

@ -688,23 +688,23 @@ public class DashManifestParser extends DefaultHandler
String schemeIdUri = parseString(xpp, "schemeIdUri", "");
String value = parseString(xpp, "value", "");
long timescale = parseLong(xpp, "timescale", 1);
List<Pair<Long, EventMessage>> timedEvents = new ArrayList<>();
List<EventMessage> eventMessages = new ArrayList<>();
ByteArrayOutputStream scratchOutputStream = new ByteArrayOutputStream(512);
do {
xpp.next();
if (XmlPullParserUtil.isStartTag(xpp, "Event")) {
Pair<Long, EventMessage> timedEvent = parseEvent(xpp, schemeIdUri, value, timescale,
EventMessage event = parseEvent(xpp, schemeIdUri, value, timescale,
scratchOutputStream);
timedEvents.add(timedEvent);
eventMessages.add(event);
}
} while (!XmlPullParserUtil.isEndTag(xpp, "EventStream"));
long[] presentationTimesUs = new long[timedEvents.size()];
EventMessage[] events = new EventMessage[timedEvents.size()];
for (int i = 0; i < timedEvents.size(); i++) {
Pair<Long, EventMessage> timedEvent = timedEvents.get(i);
presentationTimesUs[i] = timedEvent.first;
events[i] = timedEvent.second;
long[] presentationTimesUs = new long[eventMessages.size()];
EventMessage[] events = new EventMessage[eventMessages.size()];
for (int i = 0; i < eventMessages.size(); i++) {
EventMessage event = eventMessages.get(i);
presentationTimesUs[i] = event.presentationTimeUs;
events[i] = event;
}
return buildEventStream(schemeIdUri, value, timescale, presentationTimesUs, events);
}
@ -723,11 +723,11 @@ public class DashManifestParser extends DefaultHandler
* @param timescale The timescale of the parent EventStream.
* @param scratchOutputStream A {@link ByteArrayOutputStream} that is used to write serialize data
* in between <Event> and </Event> tags into.
* @return The {@link EventStream} parsed from this EventStream node.
* @return The {@link EventMessage} parsed from this EventStream node.
* @throws XmlPullParserException If there is any error parsing this node.
* @throws IOException If there is any error reading from the underlying input stream.
*/
protected Pair<Long, EventMessage> parseEvent(XmlPullParser xpp, String schemeIdUri, String value,
protected EventMessage parseEvent(XmlPullParser xpp, String schemeIdUri, String value,
long timescale, ByteArrayOutputStream scratchOutputStream)
throws IOException, XmlPullParserException {
long id = parseLong(xpp, "id", 0);
@ -737,8 +737,7 @@ public class DashManifestParser extends DefaultHandler
long presentationTimesUs = Util.scaleLargeTimestamp(presentationTime, C.MICROS_PER_SECOND,
timescale);
byte[] eventObject = parseEventObject(xpp, scratchOutputStream);
return new Pair<>(presentationTimesUs, buildEvent(schemeIdUri, value, id, durationMs,
eventObject));
return buildEvent(schemeIdUri, value, id, durationMs, eventObject, presentationTimesUs);
}
/**
@ -807,8 +806,8 @@ public class DashManifestParser extends DefaultHandler
}
protected EventMessage buildEvent(String schemeIdUri, String value, long id,
long durationMs, byte[] messageData) {
return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
long durationMs, byte[] messageData, long presentationTimeUs) {
return new EventMessage(schemeIdUri, value, durationMs, id, messageData, presentationTimeUs);
}
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)