Commit 47e0580d by ibaker Committed by Oliver Woodman

Unwrap SCTE-35 messages in emsg boxes

PiperOrigin-RevId: 263768428
parent d3d192e3
...@@ -35,13 +35,21 @@ public final class EventMessage implements Metadata.Entry { ...@@ -35,13 +35,21 @@ public final class EventMessage implements Metadata.Entry {
@VisibleForTesting @VisibleForTesting
public static final String ID3_SCHEME_ID = "https://developer.apple.com/streaming/emsg-id3"; public static final String ID3_SCHEME_ID = "https://developer.apple.com/streaming/emsg-id3";
/**
* scheme_id_uri from section 7.3.2 of <a
* href="https://www.scte.org/SCTEDocs/Standards/ANSI_SCTE%20214-3%202015.pdf">SCTE 214-3
* 2015</a>.
*/
@VisibleForTesting public static final String SCTE35_SCHEME_ID = "urn:scte:scte35:2014:bin";
private static final Format ID3_FORMAT = private static final Format ID3_FORMAT =
Format.createSampleFormat( Format.createSampleFormat(
/* id= */ null, MimeTypes.APPLICATION_ID3, Format.OFFSET_SAMPLE_RELATIVE); /* id= */ null, MimeTypes.APPLICATION_ID3, Format.OFFSET_SAMPLE_RELATIVE);
private static final Format SCTE35_FORMAT =
Format.createSampleFormat(
/* id= */ null, MimeTypes.APPLICATION_SCTE35, Format.OFFSET_SAMPLE_RELATIVE);
/** /** The message scheme. */
* The message scheme.
*/
public final String schemeIdUri; public final String schemeIdUri;
/** /**
...@@ -94,13 +102,20 @@ public final class EventMessage implements Metadata.Entry { ...@@ -94,13 +102,20 @@ public final class EventMessage implements Metadata.Entry {
@Override @Override
@Nullable @Nullable
public Format getWrappedMetadataFormat() { public Format getWrappedMetadataFormat() {
return ID3_SCHEME_ID.equals(schemeIdUri) ? ID3_FORMAT : null; switch (schemeIdUri) {
case ID3_SCHEME_ID:
return ID3_FORMAT;
case SCTE35_SCHEME_ID:
return SCTE35_FORMAT;
default:
return null;
}
} }
@Override @Override
@Nullable @Nullable
public byte[] getWrappedMetadataBytes() { public byte[] getWrappedMetadataBytes() {
return ID3_SCHEME_ID.equals(schemeIdUri) ? messageData : null; return getWrappedMetadataFormat() != null ? messageData : null;
} }
@Override @Override
......
...@@ -26,6 +26,7 @@ import com.google.android.exoplayer2.Format; ...@@ -26,6 +26,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.metadata.emsg.EventMessage; import com.google.android.exoplayer2.metadata.emsg.EventMessage;
import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder; import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.metadata.scte35.TimeSignalCommand;
import com.google.android.exoplayer2.testutil.FakeSampleStream; import com.google.android.exoplayer2.testutil.FakeSampleStream;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
...@@ -40,6 +41,28 @@ import org.junit.runner.RunWith; ...@@ -40,6 +41,28 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class MetadataRendererTest { public class MetadataRendererTest {
private static final byte[] SCTE35_TIME_SIGNAL_BYTES =
TestUtil.joinByteArrays(
TestUtil.createByteArray(
0, // table_id.
0x80, // section_syntax_indicator, private_indicator, reserved, section_length(4).
0x14, // section_length(8).
0x00, // protocol_version.
0x00), // encrypted_packet, encryption_algorithm, pts_adjustment(1).
TestUtil.createByteArray(0x00, 0x00, 0x00, 0x00), // pts_adjustment(32).
TestUtil.createByteArray(
0x00, // cw_index.
0x00, // tier(8).
0x00, // tier(4), splice_command_length(4).
0x05, // splice_command_length(8).
0x06, // splice_command_type = time_signal.
// Start of splice_time().
0x80), // time_specified_flag, reserved, pts_time(1).
TestUtil.createByteArray(
0x52, 0x03, 0x02, 0x8f), // pts_time(32). PTS for a second after playback position.
TestUtil.createByteArray(
0x00, 0x00, 0x00, 0x00)); // CRC_32 (ignored, check happens at extraction).
private static final Format EMSG_FORMAT = private static final Format EMSG_FORMAT =
Format.createSampleFormat(null, MimeTypes.APPLICATION_EMSG, Format.OFFSET_SAMPLE_RELATIVE); Format.createSampleFormat(null, MimeTypes.APPLICATION_EMSG, Format.OFFSET_SAMPLE_RELATIVE);
...@@ -70,7 +93,7 @@ public class MetadataRendererTest { ...@@ -70,7 +93,7 @@ public class MetadataRendererTest {
} }
@Test @Test
public void decodeMetadata_handlesWrappedMetadata() throws Exception { public void decodeMetadata_handlesId3WrappedInEmsg() throws Exception {
EventMessage emsg = EventMessage emsg =
new EventMessage( new EventMessage(
EventMessage.ID3_SCHEME_ID, EventMessage.ID3_SCHEME_ID,
...@@ -89,6 +112,24 @@ public class MetadataRendererTest { ...@@ -89,6 +112,24 @@ public class MetadataRendererTest {
} }
@Test @Test
public void decodeMetadata_handlesScte35WrappedInEmsg() throws Exception {
EventMessage emsg =
new EventMessage(
EventMessage.SCTE35_SCHEME_ID,
/* value= */ "",
/* durationMs= */ 1,
/* id= */ 0,
SCTE35_TIME_SIGNAL_BYTES);
List<Metadata> metadata = runRenderer(EMSG_FORMAT, eventMessageEncoder.encode(emsg));
assertThat(metadata).hasSize(1);
assertThat(metadata.get(0).length()).isEqualTo(1);
assertThat(metadata.get(0).get(0)).isInstanceOf(TimeSignalCommand.class);
}
@Test
public void decodeMetadata_skipsMalformedWrappedMetadata() throws Exception { public void decodeMetadata_skipsMalformedWrappedMetadata() throws Exception {
EventMessage emsg = EventMessage emsg =
new EventMessage( new EventMessage(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment