mirror of
https://github.com/samsonjs/media.git
synced 2026-04-07 11:35:46 +00:00
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:
parent
3998ed49ae
commit
e619079a0d
9 changed files with 57 additions and 44 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue