Commit e2e1c459 by Oliver Woodman

Merge #5140: Cea608 - Check parity and valid bits

Imported from GitHub PR https://github.com/google/ExoPlayer/pull/5140

https://github.com/google/ExoPlayer/pull/5086 moved onto the right branch.
Merge 8822e188d24c1d9b3ed101918763b16e46c8debc into 0c385a85

PiperOrigin-RevId: 222633340
parent 0c385a85
...@@ -46,7 +46,6 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -46,7 +46,6 @@ public final class Cea608Decoder extends CeaDecoder {
private static final int NTSC_CC_FIELD_1 = 0x00; private static final int NTSC_CC_FIELD_1 = 0x00;
private static final int NTSC_CC_FIELD_2 = 0x01; private static final int NTSC_CC_FIELD_2 = 0x01;
private static final int CC_VALID_608_ID = 0x04;
private static final int CC_MODE_UNKNOWN = 0; private static final int CC_MODE_UNKNOWN = 0;
private static final int CC_MODE_ROLL_UP = 1; private static final int CC_MODE_ROLL_UP = 1;
...@@ -179,6 +178,41 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -179,6 +178,41 @@ public final class Cea608Decoder extends CeaDecoder {
0xC5, 0xE5, 0xD8, 0xF8, 0x250C, 0x2510, 0x2514, 0x2518 0xC5, 0xE5, 0xD8, 0xF8, 0x250C, 0x2510, 0x2514, 0x2518
}; };
private static final boolean[] ODD_PARITY_BYTE_TABLE = {
false, true, true, false, true, false, false, true, // 0
true, false, false, true, false, true, true, false, // 8
true, false, false, true, false, true, true, false, // 16
false, true, true, false, true, false, false, true, // 24
true, false, false, true, false, true, true, false, // 32
false, true, true, false, true, false, false, true, // 40
false, true, true, false, true, false, false, true, // 48
true, false, false, true, false, true, true, false, // 56
true, false, false, true, false, true, true, false, // 64
false, true, true, false, true, false, false, true, // 72
false, true, true, false, true, false, false, true, // 80
true, false, false, true, false, true, true, false, // 88
false, true, true, false, true, false, false, true, // 96
true, false, false, true, false, true, true, false, // 104
true, false, false, true, false, true, true, false, // 112
false, true, true, false, true, false, false, true, // 120
true, false, false, true, false, true, true, false, // 128
false, true, true, false, true, false, false, true, // 136
false, true, true, false, true, false, false, true, // 144
true, false, false, true, false, true, true, false, // 152
false, true, true, false, true, false, false, true, // 160
true, false, false, true, false, true, true, false, // 168
true, false, false, true, false, true, true, false, // 176
false, true, true, false, true, false, false, true, // 184
false, true, true, false, true, false, false, true, // 192
true, false, false, true, false, true, true, false, // 200
true, false, false, true, false, true, true, false, // 208
false, true, true, false, true, false, false, true, // 216
true, false, false, true, false, true, true, false, // 224
false, true, true, false, true, false, false, true, // 232
false, true, true, false, true, false, false, true, // 240
true, false, false, true, false, true, true, false, // 248
};
private final ParsableByteArray ccData; private final ParsableByteArray ccData;
private final int packetLength; private final int packetLength;
private final int selectedField; private final int selectedField;
...@@ -191,6 +225,7 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -191,6 +225,7 @@ public final class Cea608Decoder extends CeaDecoder {
private int captionMode; private int captionMode;
private int captionRowCount; private int captionRowCount;
private boolean captionValid;
private boolean repeatableControlSet; private boolean repeatableControlSet;
private byte repeatableControlCc1; private byte repeatableControlCc1;
private byte repeatableControlCc2; private byte repeatableControlCc2;
...@@ -229,6 +264,7 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -229,6 +264,7 @@ public final class Cea608Decoder extends CeaDecoder {
setCaptionMode(CC_MODE_UNKNOWN); setCaptionMode(CC_MODE_UNKNOWN);
setCaptionRowCount(DEFAULT_CAPTIONS_ROW_COUNT); setCaptionRowCount(DEFAULT_CAPTIONS_ROW_COUNT);
resetCueBuilders(); resetCueBuilders();
captionValid = false;
repeatableControlSet = false; repeatableControlSet = false;
repeatableControlCc1 = 0; repeatableControlCc1 = 0;
repeatableControlCc2 = 0; repeatableControlCc2 = 0;
...@@ -259,31 +295,54 @@ public final class Cea608Decoder extends CeaDecoder { ...@@ -259,31 +295,54 @@ public final class Cea608Decoder extends CeaDecoder {
while (ccData.bytesLeft() >= packetLength) { while (ccData.bytesLeft() >= packetLength) {
byte ccDataHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER byte ccDataHeader = packetLength == 2 ? CC_IMPLICIT_DATA_HEADER
: (byte) ccData.readUnsignedByte(); : (byte) ccData.readUnsignedByte();
byte ccData1 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit
byte ccData2 = (byte) (ccData.readUnsignedByte() & 0x7F); // strip the parity bit
// Only examine valid CEA-608 packets // Only examine valid CEA-608 packets
// TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according // TODO: We're currently ignoring the top 5 marker bits, which should all be 1s according
// to the CEA-608 specification. We need to determine if the data should be handled // to the CEA-608 specification. We need to determine if the data should be handled
// differently when that is not the case. // differently when that is not the case.
if ((ccDataHeader & (CC_VALID_FLAG | CC_TYPE_FLAG)) != CC_VALID_608_ID) {
if ((ccDataHeader & CC_TYPE_FLAG) != 0) {
// Do not process anything that is not part of the 608 byte stream.
continue; continue;
} }
// Only examine packets within the selected field
if ((selectedField == 1 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_1) if ((selectedField == 1 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_1)
|| (selectedField == 2 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_2)) { || (selectedField == 2 && (ccDataHeader & CC_FIELD_FLAG) != NTSC_CC_FIELD_2)) {
// Do not process packets not within the selected field.
continue; continue;
} }
// Ignore empty captions. int ccByte1 = ccData.readUnsignedByte();
int ccByte2 = ccData.readUnsignedByte();
// Strip the parity bit from each byte to get CC data.
byte ccData1 = (byte) (ccByte1 & 0x7F);
byte ccData2 = (byte) (ccByte2 & 0x7F);
if (ccData1 == 0 && ccData2 == 0) { if (ccData1 == 0 && ccData2 == 0) {
// Ignore empty captions.
continue;
}
if ((ccDataHeader & CC_VALID_FLAG) != CC_VALID_FLAG) {
if (captionValid) {
// The encoder has flipped the validity bit to indicate closed captions are being turned.
resetCueBuilders();
captionValid = false;
captionDataProcessed = true;
}
continue; continue;
} }
// If we've reached this point then there is data to process; flag that work has been done. // If we've reached this point then there is data to process; flag that work has been done.
captionDataProcessed = true; captionDataProcessed = true;
if (!ODD_PARITY_BYTE_TABLE[ccByte1] || !ODD_PARITY_BYTE_TABLE[ccByte2]) {
// The data is invalid.
resetCueBuilders();
continue;
}
// Special North American character set. // Special North American character set.
// ccData1 - 0|0|0|1|C|0|0|1 // ccData1 - 0|0|0|1|C|0|0|1
// ccData2 - 0|0|1|1|X|X|X|X // ccData2 - 0|0|1|1|X|X|X|X
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment