Merge pull request #942 from datdoantelus:CC_708_parser_fix

PiperOrigin-RevId: 596836615
This commit is contained in:
Copybara-Service 2024-01-09 00:25:58 -08:00
commit 6f8249184b
3 changed files with 47 additions and 16 deletions

View File

@ -93,6 +93,10 @@
that contained Binder objects` error when using that contained Binder objects` error when using
`DefaultExtractorsFactory.setTextTrackTranscodingEnabled` `DefaultExtractorsFactory.setTextTrackTranscodingEnabled`
([#836](https://github.com/androidx/media/issues/836)). ([#836](https://github.com/androidx/media/issues/836)).
* CEA-708: Ignore `rowLock` value. The CEA-708-E S-2023 spec states that
`rowLock` and `columnLock` should both be assumed to be true, regardless
of the values present in the stream (`columnLock` support is not
implemented, so it's effectively assumed to always be false).
* Metadata: * Metadata:
* Fix bug where `MediaMetadata` was only populated from Vorbis comments * Fix bug where `MediaMetadata` was only populated from Vorbis comments
with upper-case keys with upper-case keys

View File

@ -786,8 +786,11 @@ public final class Cea708Parser implements SubtitleParser {
// first byte // first byte
captionChannelPacketData.skipBits(2); // null padding captionChannelPacketData.skipBits(2); // null padding
boolean visible = captionChannelPacketData.readBit(); boolean visible = captionChannelPacketData.readBit();
boolean rowLock = captionChannelPacketData.readBit();
boolean columnLock = captionChannelPacketData.readBit(); // ANSI/CTA-708-E S-2023 spec (Section 8.4.7) indicates that rowLock and columnLock values in
// the media should be ignored and assumed to be true.
captionChannelPacketData.skipBits(2);
int priority = captionChannelPacketData.readBits(3); int priority = captionChannelPacketData.readBits(3);
// second byte // second byte
boolean relativePositioning = captionChannelPacketData.readBit(); boolean relativePositioning = captionChannelPacketData.readBit();
@ -799,7 +802,8 @@ public final class Cea708Parser implements SubtitleParser {
int rowCount = captionChannelPacketData.readBits(4); int rowCount = captionChannelPacketData.readBits(4);
// fifth byte // fifth byte
captionChannelPacketData.skipBits(2); // null padding captionChannelPacketData.skipBits(2); // null padding
int columnCount = captionChannelPacketData.readBits(6); // TODO: Add support for column count.
captionChannelPacketData.skipBits(6); // column count
// sixth byte // sixth byte
captionChannelPacketData.skipBits(2); // null padding captionChannelPacketData.skipBits(2); // null padding
int windowStyle = captionChannelPacketData.readBits(3); int windowStyle = captionChannelPacketData.readBits(3);
@ -807,14 +811,11 @@ public final class Cea708Parser implements SubtitleParser {
cueInfoBuilder.defineWindow( cueInfoBuilder.defineWindow(
visible, visible,
rowLock,
columnLock,
priority, priority,
relativePositioning, relativePositioning,
verticalAnchor, verticalAnchor,
horizontalAnchor, horizontalAnchor,
rowCount, rowCount,
columnCount,
anchorId, anchorId,
windowStyle, windowStyle,
penStyle); penStyle);
@ -975,7 +976,6 @@ public final class Cea708Parser implements SubtitleParser {
private int horizontalAnchor; private int horizontalAnchor;
private int anchorId; private int anchorId;
private int rowCount; private int rowCount;
private boolean rowLock;
private int justification; private int justification;
private int windowStyleId; private int windowStyleId;
private int penStyleId; private int penStyleId;
@ -1011,7 +1011,6 @@ public final class Cea708Parser implements SubtitleParser {
horizontalAnchor = 0; horizontalAnchor = 0;
anchorId = 0; anchorId = 0;
rowCount = MAXIMUM_ROW_COUNT; rowCount = MAXIMUM_ROW_COUNT;
rowLock = true;
justification = JUSTIFICATION_LEFT; justification = JUSTIFICATION_LEFT;
windowStyleId = 0; windowStyleId = 0;
penStyleId = 0; penStyleId = 0;
@ -1045,20 +1044,16 @@ public final class Cea708Parser implements SubtitleParser {
public void defineWindow( public void defineWindow(
boolean visible, boolean visible,
boolean rowLock,
boolean columnLock,
int priority, int priority,
boolean relativePositioning, boolean relativePositioning,
int verticalAnchor, int verticalAnchor,
int horizontalAnchor, int horizontalAnchor,
int rowCount, int rowCount,
int columnCount,
int anchorId, int anchorId,
int windowStyleId, int windowStyleId,
int penStyleId) { int penStyleId) {
this.defined = true; this.defined = true;
this.visible = visible; this.visible = visible;
this.rowLock = rowLock;
this.priority = priority; this.priority = priority;
this.relativePositioning = relativePositioning; this.relativePositioning = relativePositioning;
this.verticalAnchor = verticalAnchor; this.verticalAnchor = verticalAnchor;
@ -1070,14 +1065,12 @@ public final class Cea708Parser implements SubtitleParser {
this.rowCount = rowCount + 1; this.rowCount = rowCount + 1;
// Trim any rolled up captions that are no longer valid, if applicable. // Trim any rolled up captions that are no longer valid, if applicable.
while ((rowLock && (rolledUpCaptions.size() >= this.rowCount)) while ((rolledUpCaptions.size() >= this.rowCount)
|| (rolledUpCaptions.size() >= MAXIMUM_ROW_COUNT)) { || (rolledUpCaptions.size() >= MAXIMUM_ROW_COUNT)) {
rolledUpCaptions.remove(0); rolledUpCaptions.remove(0);
} }
} }
// TODO: Add support for column lock and count.
if (windowStyleId != 0 && this.windowStyleId != windowStyleId) { if (windowStyleId != 0 && this.windowStyleId != windowStyleId) {
this.windowStyleId = windowStyleId; this.windowStyleId = windowStyleId;
// windowStyleId is 1-based. // windowStyleId is 1-based.
@ -1239,7 +1232,7 @@ public final class Cea708Parser implements SubtitleParser {
backgroundColorStartPosition = 0; backgroundColorStartPosition = 0;
} }
while ((rowLock && (rolledUpCaptions.size() >= rowCount)) while ((rolledUpCaptions.size() >= rowCount)
|| (rolledUpCaptions.size() >= MAXIMUM_ROW_COUNT)) { || (rolledUpCaptions.size() >= MAXIMUM_ROW_COUNT)) {
rolledUpCaptions.remove(0); rolledUpCaptions.remove(0);
} }

View File

@ -115,6 +115,40 @@ public class Cea708ParserTest {
.isEqualTo("test subtitle"); .isEqualTo("test subtitle");
} }
@Test
public void singleServiceAndWindowDefinition_ignoreRowLock() throws Exception {
Cea708Parser cea708Parser =
new Cea708Parser(
/* accessibilityChannel= */ Format.NO_VALUE, /* initializationData= */ null);
byte[] windowDefinition =
TestUtil.createByteArray(
0x98, // DF0 command (define window 0)
0b0010_0000, // visible=true, row lock and column lock disabled, priority=0
0xF0 | 50, // relative positioning, anchor vertical
50, // anchor horizontal
1, // anchor point = 0, row count = 1
30, // column count = 30
0b0000_1001); // window style = 1, pen style = 1
byte[] setCurrentWindow = TestUtil.createByteArray(0x80); // CW0 (set current window to 0)
byte[] subtitleData =
encodePacketIntoBytePairs(
createPacket(
/* sequenceNumber= */ 0,
createServiceBlock(
Bytes.concat(
windowDefinition,
setCurrentWindow,
"row1\r\nrow2\r\nrow3\r\nrow4".getBytes(Charsets.UTF_8)))));
List<CuesWithTiming> result = new ArrayList<>();
cea708Parser.parse(subtitleData, SubtitleParser.OutputOptions.allCues(), result::add);
// Row count is 1 (which means 2 rows should be kept). Row lock is disabled in the media,
// but this is ignored and the result is still truncated to only the last two rows.
assertThat(Iterables.getOnlyElement(Iterables.getOnlyElement(result).cues).text.toString())
.isEqualTo("row3\nrow4");
}
/** See section 4.4.1 of the CEA-708-B spec. */ /** See section 4.4.1 of the CEA-708-B spec. */
private static byte[] encodePacketIntoBytePairs(byte[] packet) { private static byte[] encodePacketIntoBytePairs(byte[] packet) {
checkState(packet.length % 2 == 0); checkState(packet.length % 2 == 0);