Skip to content

Commit

Permalink
CEA608: Limiting duplicated command checks to immediate frames
Browse files Browse the repository at this point in the history
Reported in google#3860
For failing examples see the github link above.

[Problem]
We drop matching control codes even if they are not received on
consecutive frames.

The specification says
"(4) If the first transmission of a control code pair passes parity,
it is acted upon within one video frame. If the NEXT frame contains
a perfect repeat of the same pair, the redundant code is ignored."

Keyword is the NEXT. The frames must arrive immediately after
each other.

See https://www.law.cornell.edu/cfr/text/47/79.101

[Solution]
Set an additional flag when any data is processed. Control code
duplication checks should be limited only for the first control
byte pairs processed after any control code.

[Test]
Sarnoff tests have equivalent CEA708 and CEA608 Streams.
  • Loading branch information
zsmatyas committed Jan 10, 2019
1 parent e0c6f53 commit fff6023
Showing 1 changed file with 9 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ protected Subtitle createSubtitle() {
protected void decode(SubtitleInputBuffer inputBuffer) {
ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
boolean captionDataProcessed = false;
boolean isRepeatableControl = false;
while (ccData.bytesLeft() >= packetLength) {
byte ccHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
: (byte) ccData.readUnsignedByte();
Expand Down Expand Up @@ -337,6 +336,9 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
// If we've reached this point then there is data to process; flag that work has been done.
captionDataProcessed = true;

boolean repeatedControlPossible = repeatableControlSet;
repeatableControlSet = false;

if (!ODD_PARITY_BYTE_TABLE[ccByte1] || !ODD_PARITY_BYTE_TABLE[ccByte2]) {
// The data is invalid.
resetCueBuilders();
Expand Down Expand Up @@ -372,7 +374,7 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
// Control character.
// ccData1 - 0|0|0|X|X|X|X|X
if ((ccData1 & 0xE0) == 0x00) {
isRepeatableControl = handleCtrl(ccData1, ccData2);
handleCtrl(ccData1, ccData2, repeatedControlPossible);
continue;
}

Expand All @@ -384,30 +386,26 @@ protected void decode(SubtitleInputBuffer inputBuffer) {
}

if (captionDataProcessed) {
if (!isRepeatableControl) {
repeatableControlSet = false;
}
if (captionMode == CC_MODE_ROLL_UP || captionMode == CC_MODE_PAINT_ON) {
cues = getDisplayCues();
}
}
}

private boolean handleCtrl(byte cc1, byte cc2) {
private void handleCtrl(byte cc1, byte cc2, boolean repeatedControlPossible) {
boolean isRepeatableControl = isRepeatable(cc1);

// Most control commands are sent twice in succession to ensure they are received properly.
// We don't want to process duplicate commands, so if we see the same repeatable command twice
// in a row, ignore the second one.
if (isRepeatableControl) {
if (repeatableControlSet
if (repeatedControlPossible
&& repeatableControlCc1 == cc1
&& repeatableControlCc2 == cc2) {
// This is a duplicate. Clear the repeatable control flag and return.
repeatableControlSet = false;
return true;
// This is a duplicate. Repeatable control flag should be already cleared, let's return.
return;
} else {
// This is a repeatable command, but we haven't see it yet, so set the repeatable control
// This is a repeatable command, but we haven't seen it yet, so set the repeatable control
// flag (to ensure we ignore the next one should it be a duplicate) and continue processing
// the command.
repeatableControlSet = true;
Expand All @@ -425,8 +423,6 @@ private boolean handleCtrl(byte cc1, byte cc2) {
} else if (isMiscCode(cc1, cc2)) {
handleMiscCode(cc2);
}

return isRepeatableControl;
}

private void handleMidrowCtrl(byte cc2) {
Expand Down

0 comments on commit fff6023

Please sign in to comment.