mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Fix Cea608Decoder handling of service switch commands in field 2
From ANSI-CTA-608-E R-2014 section 8.4:
> When closed captioning is used on line 21, field 2, it shall conform
> to all of the applicable specifications and recommended practices as
> defined for field 1 services with the following differences:
> 1. The non-printing character of the miscellaneous control-character
> pairs that fall in the range of 0x14, 0x20 to 0x14, 0x2F in field 1,
> shall be replaced with 0x15, 0x20 to 0x15, 0x2F when used in field
> 2.
> 2. The non-printing character of the miscellaneous control-character
> pairs that fall in the range of 0x1C, 0x20 to 0x1C, 0x2F in field
> 1, shall be replaced with 0x1D, 0x20 to 0x1D, 0x2F when used in
> field 2.
This basically means that `cc1=0x15` in field 2 should be interpreted as
`cc1=0x14` in field 1, and same for `0x1D -> 0x1C`.
The `isMiscCode` method above already handles this by ignoring the LSB
(the only difference between `0x14` and `0x15`, and `0x1C` and `0x1D`)
by AND-ing with `0xF6` instead of `0xF7`. This change uses the same
trick in `isServiceSwitchCommand`.
Issue: google/ExoPlayer#10666
#minor-release
PiperOrigin-RevId: 483927506
(cherry picked from commit 7c6d492ff1)
This commit is contained in:
parent
fe9bad1119
commit
6b3bec8618
2 changed files with 61 additions and 2 deletions
|
|
@ -872,8 +872,8 @@ public final class Cea608Decoder extends CeaDecoder {
|
|||
}
|
||||
|
||||
private static boolean isServiceSwitchCommand(byte cc1) {
|
||||
// cc1 - 0|0|0|1|C|1|0|0
|
||||
return (cc1 & 0xF7) == 0x14;
|
||||
// cc1 - 0|0|0|1|C|1|0|F
|
||||
return (cc1 & 0xF6) == 0x14;
|
||||
}
|
||||
|
||||
private static final class CueBuilder {
|
||||
|
|
|
|||
|
|
@ -255,6 +255,65 @@ public class Cea608DecoderTest {
|
|||
assertThat(getOnlyCue(fifthSubtitle).text.toString()).isEqualTo("test subtitle");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void serviceSwitchOnField1Handled() throws Exception {
|
||||
Cea608Decoder decoder =
|
||||
new Cea608Decoder(
|
||||
MimeTypes.APPLICATION_CEA608,
|
||||
/* accessibilityChannel= */ 1, // field 1, channel 1
|
||||
Cea608Decoder.MIN_DATA_CHANNEL_TIMEOUT_MS);
|
||||
// field 1 (0xFC header): 'test' then service switch
|
||||
// field 2 (0xFD header): 'wrong!'
|
||||
byte[] sample1 =
|
||||
Bytes.concat(
|
||||
// 'paint on' control character
|
||||
createPacket(0xFC, 0x14, 0x29),
|
||||
createPacket(0xFD, 0x15, 0x29),
|
||||
createPacket(0xFC, 't', 'e'),
|
||||
createPacket(0xFD, 'w', 'r'),
|
||||
createPacket(0xFC, 's', 't'),
|
||||
createPacket(0xFD, 'o', 'n'),
|
||||
// Enter TEXT service
|
||||
createPacket(0xFC, 0x14, 0x2A),
|
||||
createPacket(0xFD, 'g', '!'),
|
||||
createPacket(0xFC, 'X', 'X'),
|
||||
createPacket(0xFD, 0x0, 0x0));
|
||||
|
||||
Subtitle firstSubtitle = checkNotNull(decodeSampleAndCopyResult(decoder, sample1));
|
||||
|
||||
assertThat(getOnlyCue(firstSubtitle).text.toString()).isEqualTo("test");
|
||||
}
|
||||
|
||||
// https://github.com/google/ExoPlayer/issues/10666
|
||||
@Test
|
||||
public void serviceSwitchOnField2Handled() throws Exception {
|
||||
Cea608Decoder decoder =
|
||||
new Cea608Decoder(
|
||||
MimeTypes.APPLICATION_CEA608,
|
||||
/* accessibilityChannel= */ 3, // field 2, channel 1
|
||||
Cea608Decoder.MIN_DATA_CHANNEL_TIMEOUT_MS);
|
||||
// field 1 (0xFC header): 'wrong!'
|
||||
// field 2 (0xFD header): 'test' then service switch
|
||||
byte[] sample1 =
|
||||
Bytes.concat(
|
||||
// 'paint on' control character
|
||||
createPacket(0xFC, 0x14, 0x29),
|
||||
createPacket(0xFD, 0x15, 0x29),
|
||||
createPacket(0xFC, 'w', 'r'),
|
||||
createPacket(0xFD, 't', 'e'),
|
||||
createPacket(0xFC, 'o', 'n'),
|
||||
createPacket(0xFD, 's', 't'),
|
||||
createPacket(0xFC, 'g', '!'),
|
||||
// Enter TEXT service
|
||||
createPacket(0xFD, 0x15, 0x2A),
|
||||
createPacket(0xFC, 0x0, 0x0),
|
||||
createPacket(0xFD, 'X', 'X'));
|
||||
|
||||
Subtitle firstSubtitle = checkNotNull(decodeSampleAndCopyResult(decoder, sample1));
|
||||
|
||||
assertThat(getOnlyCue(firstSubtitle).text.toString()).isEqualTo("test");
|
||||
}
|
||||
|
||||
private static byte[] createPacket(int header, int cc1, int cc2) {
|
||||
return new byte[] {
|
||||
UnsignedBytes.checkedCast(header),
|
||||
|
|
|
|||
Loading…
Reference in a new issue