mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Fix EventMessage timestamp issue
Stop encoding/decoding presentation time as part of the message. What's actually in emsg boxes is a presentation time delta, which is why it's only 32 bits, and hence why it doesn't handle large absolute timestamps. We were using this field to hold absolute timestamps only for the purpose of passing presentation times from DashManifestParser.parseEvent back to the calling method. After this change, we return Pair<Long, EventMessage> instead. Issue: #5490 PiperOrigin-RevId: 233561731
This commit is contained in:
parent
ad69a93708
commit
c66d26b601
@ -8,6 +8,9 @@
|
|||||||
Cast demo app to work with `ExoCastPlayer`.
|
Cast demo app to work with `ExoCastPlayer`.
|
||||||
* HLS:
|
* HLS:
|
||||||
* Form an adaptive track group out of audio renditions with matching name.
|
* Form an adaptive track group out of audio renditions with matching name.
|
||||||
|
* DASH:
|
||||||
|
* Fix issue handling large `EventStream` presentation timestamps
|
||||||
|
([#5490](https://github.com/google/ExoPlayer/issues/5490)).
|
||||||
* `ExtractorMediaSource` renamed to `ProgressiveMediaSource`.
|
* `ExtractorMediaSource` renamed to `ProgressiveMediaSource`.
|
||||||
* Support for playing spherical videos on Daydream.
|
* Support for playing spherical videos on Daydream.
|
||||||
* Improve decoder re-use between playbacks. TODO: Write and link a blog post
|
* Improve decoder re-use between playbacks. TODO: Write and link a blog post
|
||||||
|
@ -601,6 +601,14 @@ public class FragmentedMp4Extractor implements Extractor {
|
|||||||
long presentationTimeDeltaUs =
|
long presentationTimeDeltaUs =
|
||||||
Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MICROS_PER_SECOND, timescale);
|
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.
|
// Output the sample data.
|
||||||
for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
|
for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
|
||||||
atom.setPosition(Atom.FULL_HEADER_SIZE);
|
atom.setPosition(Atom.FULL_HEADER_SIZE);
|
||||||
|
@ -44,13 +44,6 @@ public final class EventMessage implements Metadata.Entry {
|
|||||||
*/
|
*/
|
||||||
public final long durationMs;
|
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.
|
* The instance identifier.
|
||||||
*/
|
*/
|
||||||
@ -70,22 +63,19 @@ public final class EventMessage implements Metadata.Entry {
|
|||||||
* @param durationMs The duration of the event in milliseconds.
|
* @param durationMs The duration of the event in milliseconds.
|
||||||
* @param id The instance identifier.
|
* @param id The instance identifier.
|
||||||
* @param messageData The body of the message.
|
* @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,
|
public EventMessage(
|
||||||
byte[] messageData, long presentationTimeUs) {
|
String schemeIdUri, String value, long durationMs, long id, byte[] messageData) {
|
||||||
this.schemeIdUri = schemeIdUri;
|
this.schemeIdUri = schemeIdUri;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.durationMs = durationMs;
|
this.durationMs = durationMs;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.messageData = messageData;
|
this.messageData = messageData;
|
||||||
this.presentationTimeUs = presentationTimeUs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ EventMessage(Parcel in) {
|
/* package */ EventMessage(Parcel in) {
|
||||||
schemeIdUri = castNonNull(in.readString());
|
schemeIdUri = castNonNull(in.readString());
|
||||||
value = castNonNull(in.readString());
|
value = castNonNull(in.readString());
|
||||||
presentationTimeUs = in.readLong();
|
|
||||||
durationMs = in.readLong();
|
durationMs = in.readLong();
|
||||||
id = in.readLong();
|
id = in.readLong();
|
||||||
messageData = castNonNull(in.createByteArray());
|
messageData = castNonNull(in.createByteArray());
|
||||||
@ -97,7 +87,6 @@ public final class EventMessage implements Metadata.Entry {
|
|||||||
int result = 17;
|
int result = 17;
|
||||||
result = 31 * result + (schemeIdUri != null ? schemeIdUri.hashCode() : 0);
|
result = 31 * result + (schemeIdUri != null ? schemeIdUri.hashCode() : 0);
|
||||||
result = 31 * result + (value != null ? value.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) (durationMs ^ (durationMs >>> 32));
|
||||||
result = 31 * result + (int) (id ^ (id >>> 32));
|
result = 31 * result + (int) (id ^ (id >>> 32));
|
||||||
result = 31 * result + Arrays.hashCode(messageData);
|
result = 31 * result + Arrays.hashCode(messageData);
|
||||||
@ -115,9 +104,11 @@ public final class EventMessage implements Metadata.Entry {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EventMessage other = (EventMessage) obj;
|
EventMessage other = (EventMessage) obj;
|
||||||
return presentationTimeUs == other.presentationTimeUs && durationMs == other.durationMs
|
return durationMs == other.durationMs
|
||||||
&& id == other.id && Util.areEqual(schemeIdUri, other.schemeIdUri)
|
&& id == other.id
|
||||||
&& Util.areEqual(value, other.value) && Arrays.equals(messageData, other.messageData);
|
&& Util.areEqual(schemeIdUri, other.schemeIdUri)
|
||||||
|
&& Util.areEqual(value, other.value)
|
||||||
|
&& Arrays.equals(messageData, other.messageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -136,7 +127,6 @@ public final class EventMessage implements Metadata.Entry {
|
|||||||
public void writeToParcel(Parcel dest, int flags) {
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
dest.writeString(schemeIdUri);
|
dest.writeString(schemeIdUri);
|
||||||
dest.writeString(value);
|
dest.writeString(value);
|
||||||
dest.writeLong(presentationTimeUs);
|
|
||||||
dest.writeLong(durationMs);
|
dest.writeLong(durationMs);
|
||||||
dest.writeLong(id);
|
dest.writeLong(id);
|
||||||
dest.writeByteArray(messageData);
|
dest.writeByteArray(messageData);
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.metadata.emsg;
|
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.Metadata;
|
||||||
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
||||||
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
|
import com.google.android.exoplayer2.metadata.MetadataInputBuffer;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
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.ParsableByteArray;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -27,12 +27,15 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Decodes Event Message (emsg) atoms, as defined in ISO/IEC 23009-1:2014, Section 5.10.3.3.
|
* 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
|
* <p>Atom data should be provided to the decoder without the full atom header (i.e. starting from
|
||||||
* first byte of the scheme_id_uri field).
|
* 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 {
|
public final class EventMessageDecoder implements MetadataDecoder {
|
||||||
|
|
||||||
|
private static final String TAG = "EventMessageDecoder";
|
||||||
|
|
||||||
@SuppressWarnings("ByteBufferBackingArray")
|
@SuppressWarnings("ByteBufferBackingArray")
|
||||||
@Override
|
@Override
|
||||||
public Metadata decode(MetadataInputBuffer inputBuffer) {
|
public Metadata decode(MetadataInputBuffer inputBuffer) {
|
||||||
@ -43,13 +46,16 @@ public final class EventMessageDecoder implements MetadataDecoder {
|
|||||||
String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
String schemeIdUri = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
||||||
String value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
String value = Assertions.checkNotNull(emsgData.readNullTerminatedString());
|
||||||
long timescale = emsgData.readUnsignedInt();
|
long timescale = emsgData.readUnsignedInt();
|
||||||
long presentationTimeUs = Util.scaleLargeTimestamp(emsgData.readUnsignedInt(),
|
long presentationTimeDelta = emsgData.readUnsignedInt();
|
||||||
C.MICROS_PER_SECOND, timescale);
|
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 durationMs = Util.scaleLargeTimestamp(emsgData.readUnsignedInt(), 1000, timescale);
|
||||||
long id = emsgData.readUnsignedInt();
|
long id = emsgData.readUnsignedInt();
|
||||||
byte[] messageData = Arrays.copyOfRange(data, emsgData.getPosition(), size);
|
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,6 @@
|
|||||||
package com.google.android.exoplayer2.metadata.emsg;
|
package com.google.android.exoplayer2.metadata.emsg;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
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.ByteArrayOutputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -37,27 +34,22 @@ public final class EventMessageEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes an {@link EventMessage} to a byte array that can be decoded by
|
* Encodes an {@link EventMessage} to a byte array that can be decoded by {@link
|
||||||
* {@link EventMessageDecoder}.
|
* EventMessageDecoder}.
|
||||||
*
|
*
|
||||||
* @param eventMessage The event message to be encoded.
|
* @param eventMessage The event message to be encoded.
|
||||||
* @param timescale Timescale of the event message, in units per second.
|
|
||||||
* @return The serialized byte array.
|
* @return The serialized byte array.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public byte[] encode(EventMessage eventMessage, long timescale) {
|
public byte[] encode(EventMessage eventMessage) {
|
||||||
Assertions.checkArgument(timescale >= 0);
|
|
||||||
byteArrayOutputStream.reset();
|
byteArrayOutputStream.reset();
|
||||||
try {
|
try {
|
||||||
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
|
writeNullTerminatedString(dataOutputStream, eventMessage.schemeIdUri);
|
||||||
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
|
String nonNullValue = eventMessage.value != null ? eventMessage.value : "";
|
||||||
writeNullTerminatedString(dataOutputStream, nonNullValue);
|
writeNullTerminatedString(dataOutputStream, nonNullValue);
|
||||||
writeUnsignedInt(dataOutputStream, timescale);
|
writeUnsignedInt(dataOutputStream, 1000); // timescale
|
||||||
long presentationTime = Util.scaleLargeTimestamp(eventMessage.presentationTimeUs,
|
writeUnsignedInt(dataOutputStream, 0); // presentation_time_delta
|
||||||
timescale, C.MICROS_PER_SECOND);
|
writeUnsignedInt(dataOutputStream, eventMessage.durationMs);
|
||||||
writeUnsignedInt(dataOutputStream, presentationTime);
|
|
||||||
long duration = Util.scaleLargeTimestamp(eventMessage.durationMs, timescale, 1000);
|
|
||||||
writeUnsignedInt(dataOutputStream, duration);
|
|
||||||
writeUnsignedInt(dataOutputStream, eventMessage.id);
|
writeUnsignedInt(dataOutputStream, eventMessage.id);
|
||||||
dataOutputStream.write(eventMessage.messageData);
|
dataOutputStream.write(eventMessage.messageData);
|
||||||
dataOutputStream.flush();
|
dataOutputStream.flush();
|
||||||
|
@ -51,7 +51,6 @@ public final class EventMessageDecoderTest {
|
|||||||
assertThat(eventMessage.durationMs).isEqualTo(3000);
|
assertThat(eventMessage.durationMs).isEqualTo(3000);
|
||||||
assertThat(eventMessage.id).isEqualTo(1000403);
|
assertThat(eventMessage.id).isEqualTo(1000403);
|
||||||
assertThat(eventMessage.messageData).isEqualTo(new byte[]{0, 1, 2, 3, 4});
|
assertThat(eventMessage.messageData).isEqualTo(new byte[]{0, 1, 2, 3, 4});
|
||||||
assertThat(eventMessage.presentationTimeUs).isEqualTo(1000000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,25 +33,27 @@ public final class EventMessageEncoderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeEventStream() throws IOException {
|
public void testEncodeEventStream() throws IOException {
|
||||||
EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
|
EventMessage eventMessage =
|
||||||
new byte[] {0, 1, 2, 3, 4}, 1000000);
|
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
||||||
byte[] expectedEmsgBody = new byte[] {
|
byte[] expectedEmsgBody =
|
||||||
|
new byte[] {
|
||||||
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
||||||
49, 50, 51, 0, // value = "123"
|
49, 50, 51, 0, // value = "123"
|
||||||
0, 0, -69, -128, // timescale = 48000
|
0, 0, 3, -24, // timescale = 1000
|
||||||
0, 0, -69, -128, // presentation_time_delta = 48000
|
0, 0, 0, 0, // presentation_time_delta = 0
|
||||||
0, 2, 50, -128, // event_duration = 144000
|
0, 0, 11, -72, // event_duration = 3000
|
||||||
0, 15, 67, -45, // id = 1000403
|
0, 15, 67, -45, // id = 1000403
|
||||||
0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
|
0, 1, 2, 3, 4
|
||||||
byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage, 48000);
|
}; // message_data = {0, 1, 2, 3, 4}
|
||||||
|
byte[] encodedByteArray = new EventMessageEncoder().encode(eventMessage);
|
||||||
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
|
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeDecodeEventStream() throws IOException {
|
public void testEncodeDecodeEventStream() throws IOException {
|
||||||
EventMessage expectedEmsg = new EventMessage("urn:test", "123", 3000, 1000403,
|
EventMessage expectedEmsg =
|
||||||
new byte[] {0, 1, 2, 3, 4}, 1000000);
|
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
||||||
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg, 48000);
|
byte[] encodedByteArray = new EventMessageEncoder().encode(expectedEmsg);
|
||||||
MetadataInputBuffer buffer = new MetadataInputBuffer();
|
MetadataInputBuffer buffer = new MetadataInputBuffer();
|
||||||
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
|
buffer.data = ByteBuffer.allocate(encodedByteArray.length).put(encodedByteArray);
|
||||||
|
|
||||||
@ -63,30 +65,34 @@ public final class EventMessageEncoderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
|
public void testEncodeEventStreamMultipleTimesWorkingCorrectly() throws IOException {
|
||||||
EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
|
EventMessage eventMessage =
|
||||||
new byte[] {0, 1, 2, 3, 4}, 1000000);
|
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
||||||
byte[] expectedEmsgBody = new byte[] {
|
byte[] expectedEmsgBody =
|
||||||
|
new byte[] {
|
||||||
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
||||||
49, 50, 51, 0, // value = "123"
|
49, 50, 51, 0, // value = "123"
|
||||||
0, 0, -69, -128, // timescale = 48000
|
0, 0, 3, -24, // timescale = 1000
|
||||||
0, 0, -69, -128, // presentation_time_delta = 48000
|
0, 0, 0, 0, // presentation_time_delta = 0
|
||||||
0, 2, 50, -128, // event_duration = 144000
|
0, 0, 11, -72, // event_duration = 3000
|
||||||
0, 15, 67, -45, // id = 1000403
|
0, 15, 67, -45, // id = 1000403
|
||||||
0, 1, 2, 3, 4}; // message_data = {0, 1, 2, 3, 4}
|
0, 1, 2, 3, 4
|
||||||
EventMessage eventMessage1 = new EventMessage("urn:test", "123", 3000, 1000402,
|
}; // message_data = {0, 1, 2, 3, 4}
|
||||||
new byte[] {4, 3, 2, 1, 0}, 1000000);
|
EventMessage eventMessage1 =
|
||||||
byte[] expectedEmsgBody1 = new byte[] {
|
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"
|
117, 114, 110, 58, 116, 101, 115, 116, 0, // scheme_id_uri = "urn:test"
|
||||||
49, 50, 51, 0, // value = "123"
|
49, 50, 51, 0, // value = "123"
|
||||||
0, 0, -69, -128, // timescale = 48000
|
0, 0, 3, -24, // timescale = 1000
|
||||||
0, 0, -69, -128, // presentation_time_delta = 48000
|
0, 0, 0, 0, // presentation_time_delta = 0
|
||||||
0, 2, 50, -128, // event_duration = 144000
|
0, 0, 11, -72, // event_duration = 3000
|
||||||
0, 15, 67, -46, // id = 1000402
|
0, 15, 67, -46, // id = 1000402
|
||||||
4, 3, 2, 1, 0}; // message_data = {4, 3, 2, 1, 0}
|
4, 3, 2, 1, 0
|
||||||
|
}; // message_data = {4, 3, 2, 1, 0}
|
||||||
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
|
EventMessageEncoder eventMessageEncoder = new EventMessageEncoder();
|
||||||
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage, 48000);
|
byte[] encodedByteArray = eventMessageEncoder.encode(eventMessage);
|
||||||
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
|
assertThat(encodedByteArray).isEqualTo(expectedEmsgBody);
|
||||||
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1, 48000);
|
byte[] encodedByteArray1 = eventMessageEncoder.encode(eventMessage1);
|
||||||
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
|
assertThat(encodedByteArray1).isEqualTo(expectedEmsgBody1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ public final class EventMessageTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEventMessageParcelable() {
|
public void testEventMessageParcelable() {
|
||||||
EventMessage eventMessage = new EventMessage("urn:test", "123", 3000, 1000403,
|
EventMessage eventMessage =
|
||||||
new byte[] {0, 1, 2, 3, 4}, 1000);
|
new EventMessage("urn:test", "123", 3000, 1000403, new byte[] {0, 1, 2, 3, 4});
|
||||||
// Write to parcel.
|
// Write to parcel.
|
||||||
Parcel parcel = Parcel.obtain();
|
Parcel parcel = Parcel.obtain();
|
||||||
eventMessage.writeToParcel(parcel, 0);
|
eventMessage.writeToParcel(parcel, 0);
|
||||||
|
@ -112,8 +112,7 @@ import java.io.IOException;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int sampleIndex = currentIndex++;
|
int sampleIndex = currentIndex++;
|
||||||
byte[] serializedEvent = eventMessageEncoder.encode(eventStream.events[sampleIndex],
|
byte[] serializedEvent = eventMessageEncoder.encode(eventStream.events[sampleIndex]);
|
||||||
eventStream.timescale);
|
|
||||||
if (serializedEvent != null) {
|
if (serializedEvent != null) {
|
||||||
buffer.ensureSpaceForWrite(serializedEvent.length);
|
buffer.ensureSpaceForWrite(serializedEvent.length);
|
||||||
buffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);
|
buffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);
|
||||||
|
@ -829,13 +829,13 @@ 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);
|
||||||
List<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")) {
|
||||||
EventMessage event = parseEvent(xpp, schemeIdUri, value, timescale,
|
Pair<Long, EventMessage> event =
|
||||||
scratchOutputStream);
|
parseEvent(xpp, schemeIdUri, value, timescale, scratchOutputStream);
|
||||||
eventMessages.add(event);
|
eventMessages.add(event);
|
||||||
} else {
|
} else {
|
||||||
maybeSkipTag(xpp);
|
maybeSkipTag(xpp);
|
||||||
@ -845,9 +845,9 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
long[] presentationTimesUs = new long[eventMessages.size()];
|
long[] presentationTimesUs = new long[eventMessages.size()];
|
||||||
EventMessage[] events = new EventMessage[eventMessages.size()];
|
EventMessage[] events = new EventMessage[eventMessages.size()];
|
||||||
for (int i = 0; i < eventMessages.size(); i++) {
|
for (int i = 0; i < eventMessages.size(); i++) {
|
||||||
EventMessage event = eventMessages.get(i);
|
Pair<Long, EventMessage> event = eventMessages.get(i);
|
||||||
presentationTimesUs[i] = event.presentationTimeUs;
|
presentationTimesUs[i] = event.first;
|
||||||
events[i] = event;
|
events[i] = event.second;
|
||||||
}
|
}
|
||||||
return buildEventStream(schemeIdUri, value, timescale, presentationTimesUs, events);
|
return buildEventStream(schemeIdUri, value, timescale, presentationTimesUs, events);
|
||||||
}
|
}
|
||||||
@ -866,11 +866,12 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
* @param timescale The timescale of the parent EventStream.
|
* @param timescale The timescale 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 The {@link EventMessage} parsed from this EventStream node.
|
* @return A pair containing the node's presentation timestamp in microseconds and the parsed
|
||||||
|
* {@link EventMessage}.
|
||||||
* @throws XmlPullParserException If there is any error parsing this node.
|
* @throws XmlPullParserException If there is any error parsing this node.
|
||||||
* @throws IOException If there is any error reading from the underlying input stream.
|
* @throws IOException If there is any error reading from the underlying input stream.
|
||||||
*/
|
*/
|
||||||
protected EventMessage parseEvent(
|
protected Pair<Long, EventMessage> parseEvent(
|
||||||
XmlPullParser xpp,
|
XmlPullParser xpp,
|
||||||
String schemeIdUri,
|
String schemeIdUri,
|
||||||
String value,
|
String value,
|
||||||
@ -885,13 +886,14 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
timescale);
|
timescale);
|
||||||
String messageData = parseString(xpp, "messageData", null);
|
String messageData = parseString(xpp, "messageData", null);
|
||||||
byte[] eventObject = parseEventObject(xpp, scratchOutputStream);
|
byte[] eventObject = parseEventObject(xpp, scratchOutputStream);
|
||||||
return buildEvent(
|
return Pair.create(
|
||||||
|
presentationTimesUs,
|
||||||
|
buildEvent(
|
||||||
schemeIdUri,
|
schemeIdUri,
|
||||||
value,
|
value,
|
||||||
id,
|
id,
|
||||||
durationMs,
|
durationMs,
|
||||||
messageData == null ? eventObject : Util.getUtf8Bytes(messageData),
|
messageData == null ? eventObject : Util.getUtf8Bytes(messageData)));
|
||||||
presentationTimesUs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -958,9 +960,9 @@ public class DashManifestParser extends DefaultHandler
|
|||||||
return scratchOutputStream.toByteArray();
|
return scratchOutputStream.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected EventMessage buildEvent(String schemeIdUri, String value, long id,
|
protected EventMessage buildEvent(
|
||||||
long durationMs, byte[] messageData, long presentationTimeUs) {
|
String schemeIdUri, String value, long id, long durationMs, byte[] messageData) {
|
||||||
return new EventMessage(schemeIdUri, value, durationMs, id, messageData, presentationTimeUs);
|
return new EventMessage(schemeIdUri, value, durationMs, id, messageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)
|
protected List<SegmentTimelineElement> parseSegmentTimeline(XmlPullParser xpp)
|
||||||
|
@ -111,7 +111,7 @@ public final class EventSampleStreamTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadDataReturnDataAfterFormat() {
|
public void testReadDataReturnDataAfterFormat() {
|
||||||
long presentationTimeUs = 1000000;
|
long presentationTimeUs = 1000000;
|
||||||
EventMessage eventMessage = newEventMessageWithIdAndTime(1, presentationTimeUs);
|
EventMessage eventMessage = newEventMessageWithId(1);
|
||||||
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs}, new EventMessage[] {eventMessage});
|
new long[] {presentationTimeUs}, new EventMessage[] {eventMessage});
|
||||||
EventSampleStream sampleStream = new EventSampleStream(eventStream, FORMAT, false);
|
EventSampleStream sampleStream = new EventSampleStream(eventStream, FORMAT, false);
|
||||||
@ -133,8 +133,8 @@ public final class EventSampleStreamTest {
|
|||||||
public void testSkipDataThenReadDataReturnDataFromSkippedPosition() {
|
public void testSkipDataThenReadDataReturnDataFromSkippedPosition() {
|
||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1, presentationTimeUs2},
|
new long[] {presentationTimeUs1, presentationTimeUs2},
|
||||||
new EventMessage[] {eventMessage1, eventMessage2});
|
new EventMessage[] {eventMessage1, eventMessage2});
|
||||||
@ -159,8 +159,8 @@ public final class EventSampleStreamTest {
|
|||||||
public void testSeekToUsThenReadDataReturnDataFromSeekPosition() {
|
public void testSeekToUsThenReadDataReturnDataFromSeekPosition() {
|
||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1, presentationTimeUs2},
|
new long[] {presentationTimeUs1, presentationTimeUs2},
|
||||||
new EventMessage[] {eventMessage1, eventMessage2});
|
new EventMessage[] {eventMessage1, eventMessage2});
|
||||||
@ -186,9 +186,9 @@ public final class EventSampleStreamTest {
|
|||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
long presentationTimeUs3 = 3000000;
|
long presentationTimeUs3 = 3000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventMessage eventMessage3 = newEventMessageWithIdAndTime(3, presentationTimeUs3);
|
EventMessage eventMessage3 = newEventMessageWithId(3);
|
||||||
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1, presentationTimeUs2},
|
new long[] {presentationTimeUs1, presentationTimeUs2},
|
||||||
new EventMessage[] {eventMessage1, eventMessage2});
|
new EventMessage[] {eventMessage1, eventMessage2});
|
||||||
@ -220,9 +220,9 @@ public final class EventSampleStreamTest {
|
|||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
long presentationTimeUs3 = 3000000;
|
long presentationTimeUs3 = 3000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventMessage eventMessage3 = newEventMessageWithIdAndTime(3, presentationTimeUs3);
|
EventMessage eventMessage3 = newEventMessageWithId(3);
|
||||||
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1, presentationTimeUs2},
|
new long[] {presentationTimeUs1, presentationTimeUs2},
|
||||||
new EventMessage[] {eventMessage1, eventMessage2});
|
new EventMessage[] {eventMessage1, eventMessage2});
|
||||||
@ -253,9 +253,9 @@ public final class EventSampleStreamTest {
|
|||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
long presentationTimeUs3 = 3000000;
|
long presentationTimeUs3 = 3000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventMessage eventMessage3 = newEventMessageWithIdAndTime(3, presentationTimeUs3);
|
EventMessage eventMessage3 = newEventMessageWithId(3);
|
||||||
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1},
|
new long[] {presentationTimeUs1},
|
||||||
new EventMessage[] {eventMessage1});
|
new EventMessage[] {eventMessage1});
|
||||||
@ -287,9 +287,9 @@ public final class EventSampleStreamTest {
|
|||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
long presentationTimeUs3 = 3000000;
|
long presentationTimeUs3 = 3000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventMessage eventMessage3 = newEventMessageWithIdAndTime(3, presentationTimeUs3);
|
EventMessage eventMessage3 = newEventMessageWithId(3);
|
||||||
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1, presentationTimeUs2},
|
new long[] {presentationTimeUs1, presentationTimeUs2},
|
||||||
new EventMessage[] {eventMessage1, eventMessage2});
|
new EventMessage[] {eventMessage1, eventMessage2});
|
||||||
@ -319,9 +319,9 @@ public final class EventSampleStreamTest {
|
|||||||
long presentationTimeUs1 = 1000000;
|
long presentationTimeUs1 = 1000000;
|
||||||
long presentationTimeUs2 = 2000000;
|
long presentationTimeUs2 = 2000000;
|
||||||
long presentationTimeUs3 = 3000000;
|
long presentationTimeUs3 = 3000000;
|
||||||
EventMessage eventMessage1 = newEventMessageWithIdAndTime(1, presentationTimeUs1);
|
EventMessage eventMessage1 = newEventMessageWithId(1);
|
||||||
EventMessage eventMessage2 = newEventMessageWithIdAndTime(2, presentationTimeUs2);
|
EventMessage eventMessage2 = newEventMessageWithId(2);
|
||||||
EventMessage eventMessage3 = newEventMessageWithIdAndTime(3, presentationTimeUs3);
|
EventMessage eventMessage3 = newEventMessageWithId(3);
|
||||||
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
EventStream eventStream1 = new EventStream(SCHEME_ID, VALUE, TIME_SCALE,
|
||||||
new long[] {presentationTimeUs1},
|
new long[] {presentationTimeUs1},
|
||||||
new EventMessage[] {eventMessage1});
|
new EventMessage[] {eventMessage1});
|
||||||
@ -345,12 +345,12 @@ public final class EventSampleStreamTest {
|
|||||||
return sampleStream.readData(formatHolder, inputBuffer, false);
|
return sampleStream.readData(formatHolder, inputBuffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventMessage newEventMessageWithIdAndTime(int id, long presentationTimeUs) {
|
private EventMessage newEventMessageWithId(int id) {
|
||||||
return new EventMessage(SCHEME_ID, VALUE, DURATION_MS, id, MESSAGE_DATA, presentationTimeUs);
|
return new EventMessage(SCHEME_ID, VALUE, DURATION_MS, id, MESSAGE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getEncodedMessage(EventMessage eventMessage) {
|
private byte[] getEncodedMessage(EventMessage eventMessage) {
|
||||||
return eventMessageEncoder.encode(eventMessage, TIME_SCALE);
|
return eventMessageEncoder.encode(eventMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -104,15 +104,14 @@ public class DashManifestParserTest {
|
|||||||
"call",
|
"call",
|
||||||
10000,
|
10000,
|
||||||
0,
|
0,
|
||||||
"+ 1 800 10101010".getBytes(Charset.forName(C.UTF8_NAME)),
|
"+ 1 800 10101010".getBytes(Charset.forName(C.UTF8_NAME)));
|
||||||
0);
|
|
||||||
assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1);
|
assertThat(eventStream1.events[0]).isEqualTo(expectedEvent1);
|
||||||
|
assertThat(eventStream1.presentationTimesUs[0]).isEqualTo(0);
|
||||||
|
|
||||||
// assert CData-structured event stream
|
// assert CData-structured event stream
|
||||||
EventStream eventStream2 = period.eventStreams.get(1);
|
EventStream eventStream2 = period.eventStreams.get(1);
|
||||||
assertThat(eventStream2.events.length).isEqualTo(1);
|
assertThat(eventStream2.events.length).isEqualTo(1);
|
||||||
assertThat(eventStream2.events[0])
|
EventMessage expectedEvent2 =
|
||||||
.isEqualTo(
|
|
||||||
new EventMessage(
|
new EventMessage(
|
||||||
"urn:dvb:iptv:cpm:2014",
|
"urn:dvb:iptv:cpm:2014",
|
||||||
"",
|
"",
|
||||||
@ -130,14 +129,15 @@ public class DashManifestParserTest {
|
|||||||
+ " <mpeg7:Region>GB</mpeg7:Region>\n"
|
+ " <mpeg7:Region>GB</mpeg7:Region>\n"
|
||||||
+ " </ParentalGuidance>\n"
|
+ " </ParentalGuidance>\n"
|
||||||
+ " </InstanceDescription>\n"
|
+ " </InstanceDescription>\n"
|
||||||
+ " </BroadcastEvent>]]>"),
|
+ " </BroadcastEvent>]]>"));
|
||||||
300000000));
|
|
||||||
|
assertThat(eventStream2.events[0]).isEqualTo(expectedEvent2);
|
||||||
|
assertThat(eventStream2.presentationTimesUs[0]).isEqualTo(300000000);
|
||||||
|
|
||||||
// assert xml-structured event stream
|
// assert xml-structured event stream
|
||||||
EventStream eventStream3 = period.eventStreams.get(2);
|
EventStream eventStream3 = period.eventStreams.get(2);
|
||||||
assertThat(eventStream3.events.length).isEqualTo(1);
|
assertThat(eventStream3.events.length).isEqualTo(1);
|
||||||
assertThat(eventStream3.events[0])
|
EventMessage expectedEvent3 =
|
||||||
.isEqualTo(
|
|
||||||
new EventMessage(
|
new EventMessage(
|
||||||
"urn:scte:scte35:2014:xml+bin",
|
"urn:scte:scte35:2014:xml+bin",
|
||||||
"",
|
"",
|
||||||
@ -148,8 +148,9 @@ public class DashManifestParserTest {
|
|||||||
+ " <scte35:Binary>\n"
|
+ " <scte35:Binary>\n"
|
||||||
+ " /DAIAAAAAAAAAAAQAAZ/I0VniQAQAgBDVUVJQAAAAH+cAAAAAA==\n"
|
+ " /DAIAAAAAAAAAAAQAAZ/I0VniQAQAgBDVUVJQAAAAH+cAAAAAA==\n"
|
||||||
+ " </scte35:Binary>\n"
|
+ " </scte35:Binary>\n"
|
||||||
+ " </scte35:Signal>"),
|
+ " </scte35:Signal>"));
|
||||||
1000000000));
|
assertThat(eventStream3.events[0]).isEqualTo(expectedEvent3);
|
||||||
|
assertThat(eventStream3.presentationTimesUs[0]).isEqualTo(1000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user