Support emsg metadata decoding
Note: End to end emsg support is still non-functional. There's some additional plumbing that still needs to be done. Issue: #2176 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=143775147
This commit is contained in:
parent
9d5c750fe9
commit
f2634d11f5
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.metadata.emsg;
|
||||
|
||||
import android.test.MoreAsserts;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test for {@link EventMessageDecoder}.
|
||||
*/
|
||||
public final class EventMessageDecoderTest extends TestCase {
|
||||
|
||||
public void testDecodeEventMessage() {
|
||||
byte[] rawEmsgBody = 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, 0, 0, // presentation_time_delta (ignored) = 0
|
||||
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}
|
||||
EventMessageDecoder decoder = new EventMessageDecoder();
|
||||
Metadata metadata = decoder.decode(rawEmsgBody, rawEmsgBody.length);
|
||||
assertEquals(1, metadata.length());
|
||||
EventMessage eventMessage = (EventMessage) metadata.get(0);
|
||||
assertEquals("urn:test", eventMessage.schemeIdUri);
|
||||
assertEquals("123", eventMessage.value);
|
||||
assertEquals(3000, eventMessage.durationMs);
|
||||
assertEquals(1000403, eventMessage.id);
|
||||
MoreAsserts.assertEquals(new byte[] {0, 1, 2, 3, 4}, eventMessage.messageData);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.metadata.emsg;
|
||||
|
||||
import android.os.Parcel;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test for {@link EventMessage}.
|
||||
*/
|
||||
public final class EventMessageTest extends TestCase {
|
||||
|
||||
public void testEventMessageParcelable() {
|
||||
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);
|
||||
// Create from parcel.
|
||||
parcel.setDataPosition(0);
|
||||
EventMessage fromParcelEventMessage = EventMessage.CREATOR.createFromParcel(parcel);
|
||||
// Assert equals.
|
||||
assertEquals(eventMessage, fromParcelEventMessage);
|
||||
}
|
||||
|
||||
}
|
@ -21,9 +21,9 @@ import com.google.android.exoplayer2.metadata.MetadataDecoderException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Test for {@link Id3Decoder}
|
||||
* Test for {@link Id3Decoder}.
|
||||
*/
|
||||
public class Id3DecoderTest extends TestCase {
|
||||
public final class Id3DecoderTest extends TestCase {
|
||||
|
||||
public void testDecodeTxxxFrame() throws MetadataDecoderException {
|
||||
byte[] rawId3 = new byte[] {73, 68, 51, 4, 0, 0, 0, 0, 0, 41, 84, 88, 88, 88, 0, 0, 0, 31, 0, 0,
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.metadata.emsg;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* An Event Message (emsg) as defined in ISO 23009-1.
|
||||
*/
|
||||
public final class EventMessage implements Metadata.Entry {
|
||||
|
||||
/**
|
||||
* The message scheme.
|
||||
*/
|
||||
public final String schemeIdUri;
|
||||
|
||||
/**
|
||||
* The value for the event.
|
||||
*/
|
||||
public final String value;
|
||||
|
||||
/**
|
||||
* The duration of the event in milliseconds.
|
||||
*/
|
||||
public final long durationMs;
|
||||
|
||||
/**
|
||||
* The instance identifier.
|
||||
*/
|
||||
public final long id;
|
||||
|
||||
/**
|
||||
* The body of the message.
|
||||
*/
|
||||
public final byte[] messageData;
|
||||
|
||||
// Lazily initialized hashcode.
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* package */ EventMessage(Parcel in) {
|
||||
schemeIdUri = in.readString();
|
||||
value = in.readString();
|
||||
durationMs = in.readLong();
|
||||
id = in.readLong();
|
||||
messageData = in.createByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode == 0) {
|
||||
int result = 17;
|
||||
result = 31 * result + (schemeIdUri != null ? schemeIdUri.hashCode() : 0);
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
result = 31 * result + (int) (durationMs ^ (durationMs >>> 32));
|
||||
result = 31 * result + (int) (id ^ (id >>> 32));
|
||||
result = 31 * result + Arrays.hashCode(messageData);
|
||||
hashCode = result;
|
||||
}
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Parcelable implementation.
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(schemeIdUri);
|
||||
dest.writeString(value);
|
||||
dest.writeLong(durationMs);
|
||||
dest.writeLong(id);
|
||||
dest.writeByteArray(messageData);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<EventMessage> CREATOR =
|
||||
new Parcelable.Creator<EventMessage>() {
|
||||
|
||||
@Override
|
||||
public EventMessage createFromParcel(Parcel in) {
|
||||
return new EventMessage(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventMessage[] newArray(int size) {
|
||||
return new EventMessage[size];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.metadata.emsg;
|
||||
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.MetadataDecoder;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Decodes Event Message (emsg) atoms, as defined in ISO 23009-1.
|
||||
* <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).
|
||||
*/
|
||||
public final class EventMessageDecoder implements MetadataDecoder {
|
||||
|
||||
@Override
|
||||
public boolean canDecode(String mimeType) {
|
||||
return MimeTypes.APPLICATION_EMSG.equals(mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metadata decode(byte[] data, int size) {
|
||||
ParsableByteArray emsgData = new ParsableByteArray(data, size);
|
||||
String schemeIdUri = emsgData.readNullTerminatedString();
|
||||
String value = emsgData.readNullTerminatedString();
|
||||
long timescale = emsgData.readUnsignedInt();
|
||||
emsgData.skipBytes(4); // presentation_time_delta
|
||||
long durationMs = (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));
|
||||
}
|
||||
|
||||
}
|
@ -79,6 +79,7 @@ public final class MimeTypes {
|
||||
public static final String APPLICATION_PGS = BASE_TYPE_APPLICATION + "/pgs";
|
||||
public static final String APPLICATION_SCTE35 = BASE_TYPE_APPLICATION + "/x-scte35";
|
||||
public static final String APPLICATION_CAMERA_MOTION = BASE_TYPE_APPLICATION + "/x-camera-motion";
|
||||
public static final String APPLICATION_EMSG = BASE_TYPE_APPLICATION + "/x-emsg";
|
||||
|
||||
private MimeTypes() {}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user