From 14f77cb8b133fe3e6807542827fc3990e798c79b Mon Sep 17 00:00:00 2001 From: ibaker Date: Fri, 16 Aug 2019 15:40:43 +0100 Subject: [PATCH] Unwrap SCTE-35 messages in emsg boxes PiperOrigin-RevId: 263768428 --- .../metadata/emsg/EventMessage.java | 25 ++++++++--- .../metadata/MetadataRendererTest.java | 43 ++++++++++++++++++- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java index 7d35a15e311..6e0b0b40f2b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/metadata/emsg/EventMessage.java @@ -35,13 +35,21 @@ public final class EventMessage implements Metadata.Entry { @VisibleForTesting public static final String ID3_SCHEME_ID = "https://developer.apple.com/streaming/emsg-id3"; + /** + * scheme_id_uri from section 7.3.2 of SCTE 214-3 + * 2015. + */ + @VisibleForTesting public static final String SCTE35_SCHEME_ID = "urn:scte:scte35:2014:bin"; + private static final Format ID3_FORMAT = Format.createSampleFormat( /* 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; /** @@ -94,13 +102,20 @@ public EventMessage( @Override @Nullable 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 @Nullable public byte[] getWrappedMetadataBytes() { - return ID3_SCHEME_ID.equals(schemeIdUri) ? messageData : null; + return getWrappedMetadataFormat() != null ? messageData : null; } @Override diff --git a/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java b/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java index 26dcefc6110..af6489f7263 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/metadata/MetadataRendererTest.java @@ -26,6 +26,7 @@ import com.google.android.exoplayer2.metadata.emsg.EventMessage; import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder; 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.TestUtil; import com.google.android.exoplayer2.util.Assertions; @@ -40,6 +41,28 @@ @RunWith(AndroidJUnit4.class) 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 = Format.createSampleFormat(null, MimeTypes.APPLICATION_EMSG, Format.OFFSET_SAMPLE_RELATIVE); @@ -70,7 +93,7 @@ public void decodeMetadata_skipsMalformed() throws Exception { } @Test - public void decodeMetadata_handlesWrappedMetadata() throws Exception { + public void decodeMetadata_handlesId3WrappedInEmsg() throws Exception { EventMessage emsg = new EventMessage( EventMessage.ID3_SCHEME_ID, @@ -88,6 +111,24 @@ public void decodeMetadata_handlesWrappedMetadata() throws Exception { assertThat(metadata.get(0).get(0)).isEqualTo(expectedId3Frame); } + @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 = 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 { EventMessage emsg =