mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Unwrap SCTE-35 messages in emsg boxes
PiperOrigin-RevId: 263768428
This commit is contained in:
parent
424f991079
commit
14f77cb8b1
2 changed files with 62 additions and 6 deletions
|
|
@ -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 {
|
||||||
@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;
|
||||||
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;
|
||||||
@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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@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,
|
||||||
|
|
@ -88,6 +111,24 @@ public class MetadataRendererTest {
|
||||||
assertThat(metadata.get(0).get(0)).isEqualTo(expectedId3Frame);
|
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> 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
|
@Test
|
||||||
public void decodeMetadata_skipsMalformedWrappedMetadata() throws Exception {
|
public void decodeMetadata_skipsMalformedWrappedMetadata() throws Exception {
|
||||||
EventMessage emsg =
|
EventMessage emsg =
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue