video-anc: Add support for parsing composite ADF and check the packets' checksum

And add the checksum to the data we test in the unit test.
This commit is contained in:
Sebastian Dröge 2018-11-08 18:15:58 +02:00 committed by Nicolas Dufresne
parent ca702a9190
commit 932e9f5eee
2 changed files with 123 additions and 38 deletions

View file

@ -84,40 +84,60 @@ gst_video_vbi_parser_copy (const GstVideoVBIParser * parser)
return res;
}
/* Smallest ANC size (which would have a size Data Count of 0 though) */
#define SMALLEST_ANC_SIZE 7
/* See SMPTE S291 */
static GstVideoVBIParserResult
get_ancillary_16 (GstVideoVBIParser * parser, GstVideoAncillary * anc)
{
gboolean found = FALSE;
guint16 *data = (guint16 *) parser->work_data;
const guint16 *data = (const guint16 *) parser->work_data;
g_return_val_if_fail (parser != NULL, GST_VIDEO_VBI_PARSER_RESULT_ERROR);
g_return_val_if_fail (anc != NULL, GST_VIDEO_VBI_PARSER_RESULT_ERROR);
while (parser->offset + SMALLEST_ANC_SIZE < parser->work_data_size) {
/* 3 words are needed at least to detect what kind of packet we look at
*
* - ADF (SMPTE S291 3.2.1) in case of component ancillary format:
* 0x000 0x3ff 0x3ff (followed by DID, SDID)
* - ADF (SMPTE S291 3.2.2) in case of composite ancillary format:
* 0x3fc DID SDID
*/
while (parser->offset + 3 < parser->work_data_size) {
guint8 DID, SDID, DC;
guint i;
guint i = 0, j;
guint checksum = 0;
gboolean composite;
/* Look for ADF
* FIXME : This assumes 10bit data with parity ! */
if (data[parser->offset] != 0x000 ||
data[parser->offset + 1] != 0x3ff ||
data[parser->offset + 2] != 0x3ff) {
/* Look for ADF */
if (data[parser->offset] == 0x3fc) {
/* composite */
i += 1;
composite = TRUE;
} else if (data[parser->offset] == 0x000 &&
data[parser->offset + 1] == 0x3ff &&
data[parser->offset + 1] == 0x3ff) {
/* component */
i += 3;
composite = FALSE;
} else {
parser->offset += 1;
continue;
}
/* FIXME : Add parity and checksum checks at some point if using
* 10bit data */
/* TODO: Might want to check parity bits here but the checksum in
* the end should really be enough */
/* 4 words: DID, SDID, DC, [DATA], checksum */
if (parser->offset + i + 4 >= parser->work_data_size)
goto not_enough_data;
/* We have a valid ADF */
DID = data[parser->offset + 3] & 0xff;
SDID = data[parser->offset + 4] & 0xff;
DC = data[parser->offset + 5] & 0xff;
/* Check if we have enough room to get the User Data */
if (parser->offset + SMALLEST_ANC_SIZE + DC >= parser->work_data_size)
DID = data[parser->offset + i] & 0xff;
SDID = data[parser->offset + i + 1] & 0xff;
DC = data[parser->offset + i + 2] & 0xff;
i += 3;
/* Check if we have enough room to get the User Data and checksum */
if (parser->offset + i + DC + 1 >= parser->work_data_size)
goto not_enough_data;
/* We found a valid ANC \o/ */
@ -125,10 +145,29 @@ get_ancillary_16 (GstVideoVBIParser * parser, GstVideoAncillary * anc)
anc->SDID_block_number = SDID;
anc->data_count = DC;
memset (anc->data, 0, 256);
for (i = 0; i < anc->data_count; i++)
anc->data[i] = data[parser->offset + 6 + i] & 0xff;
/* i is at the beginning of the user data now */
for (j = 0; j < anc->data_count; j++)
anc->data[j] = data[parser->offset + i + j] & 0xff;
i += DC;
/* Checksum calculation SMPTE S291 3.2.1 */
for (j = (composite ? 1 : 3); j < i; j++)
checksum += data[parser->offset + j] & 0x1ff;
checksum &= 0x1ff;
checksum |= (!(checksum >> 8)) << 9;
if (checksum != (data[parser->offset + i] & 0x3ff)) {
GST_WARNING ("ADF checksum mismatch: expected 0x%03x, got 0x%03x",
checksum, (data[parser->offset + i] & 0x3ff));
parser->offset += 1;
continue;
}
i += 1;
found = TRUE;
parser->offset += SMALLEST_ANC_SIZE + DC;
parser->offset += i;
break;
}
@ -140,39 +179,63 @@ get_ancillary_16 (GstVideoVBIParser * parser, GstVideoAncillary * anc)
/* ERRORS */
not_enough_data:
{
GST_WARNING ("ANC requires more User Data that available line size");
GST_WARNING ("ANC requires more User Data than available line size");
/* Avoid further calls to go in the same error */
parser->offset = parser->work_data_size;
return GST_VIDEO_VBI_PARSER_RESULT_ERROR;
}
}
/* See SMPTE S291 */
static GstVideoVBIParserResult
get_ancillary_8 (GstVideoVBIParser * parser, GstVideoAncillary * anc)
{
gboolean found = FALSE;
guint8 *data = parser->work_data;
const guint8 *data = parser->work_data;
g_return_val_if_fail (parser != NULL, GST_VIDEO_VBI_PARSER_RESULT_ERROR);
g_return_val_if_fail (anc != NULL, GST_VIDEO_VBI_PARSER_RESULT_ERROR);
while (parser->offset + SMALLEST_ANC_SIZE < parser->work_data_size) {
/* 3 words are needed at least to detect what kind of packet we look at
*
* - ADF (SMPTE S291 3.2.1) in case of component ancillary format:
* 0x000 0x3ff 0x3ff (followed by DID, SDID)
* - ADF (SMPTE S291 3.2.2) in case of composite ancillary format:
* 0x3fc DID SDID
*/
while (parser->offset + 3 < parser->work_data_size) {
guint8 DID, SDID, DC;
guint i;
guint i = 0, j;
gboolean composite;
guint checksum = 0;
/* Look for 8bit ADF (0x00 0xff 0xff) */
if (data[parser->offset] != 0x00 ||
data[parser->offset + 1] != 0xff || data[parser->offset + 2] != 0xff) {
/* Look for ADF */
if (data[parser->offset] == 0xfc) {
/* composite */
composite = TRUE;
i += 1;
} else if (data[parser->offset] == 0x00 &&
data[parser->offset + 1] == 0xff && data[parser->offset + 1] == 0xff) {
/* component */
composite = FALSE;
i += 3;
} else {
parser->offset += 1;
continue;
}
/* 4 words: DID, SDID, DC, [DATA], checksum */
if (parser->offset + i + 4 >= parser->work_data_size)
goto not_enough_data;
/* We have a valid ADF */
DID = data[parser->offset + 3];
SDID = data[parser->offset + 4];
DC = data[parser->offset + 5];
/* Check if we have enough room to get the User Data */
if (parser->offset + SMALLEST_ANC_SIZE + DC >= parser->work_data_size)
DID = data[parser->offset + i];
SDID = data[parser->offset + i + 1];
DC = data[parser->offset + i + 2];
i += 3;
/* Check if we have enough room to get the User Data and checksum */
if (parser->offset + i + DC + 1 >= parser->work_data_size)
goto not_enough_data;
/* We found a valid ANC \o/ */
@ -180,10 +243,28 @@ get_ancillary_8 (GstVideoVBIParser * parser, GstVideoAncillary * anc)
anc->SDID_block_number = SDID;
anc->data_count = DC;
memset (anc->data, 0, 256);
for (i = 0; i < anc->data_count; i++)
anc->data[i] = data[parser->offset + 6 + i];
/* i is at the beginning of the user data now */
for (j = 0; j < anc->data_count; j++)
anc->data[j] = data[parser->offset + i + j] & 0xff;
i += DC;
/* Checksum calculation SMPTE S291 3.2.1 */
for (j = (composite ? 1 : 3); j < i; j++)
checksum += data[parser->offset + j];
checksum &= 0xff;
if (checksum != data[parser->offset + i]) {
GST_WARNING ("ADF checksum mismatch: expected 0x%02x, got 0x%02x",
checksum, data[parser->offset + i]);
parser->offset += 1;
continue;
}
i += 1;
found = TRUE;
parser->offset += SMALLEST_ANC_SIZE + DC;
parser->offset += i;
break;
}
@ -195,7 +276,7 @@ get_ancillary_8 (GstVideoVBIParser * parser, GstVideoAncillary * anc)
/* ERRORS */
not_enough_data:
{
GST_WARNING ("ANC requires more User Data that available line size");
GST_WARNING ("ANC requires more User Data than available line size");
/* Avoid further calls to go in the same error */
parser->offset = parser->work_data_size;
return GST_VIDEO_VBI_PARSER_RESULT_ERROR;

View file

@ -54,6 +54,7 @@ GST_START_TEST (parse_8bit)
line[38] = 0x60;
line[40] = 0x70;
line[42] = 0x80;
line[44] = 0xf9; /* checksum */
gst_video_vbi_parser_add_line (parser, line);
@ -84,6 +85,7 @@ GST_START_TEST (parse_8bit)
line[31] = 0x03;
line[33] = 0x02;
line[35] = 0x01;
line[37] = 0x75; /* checksum */
gst_video_vbi_parser_add_line (parser, line);
@ -146,6 +148,7 @@ GST_START_TEST (parse_10bit)
GST_WRITE_UINT32_LE (line + 44, (0x260 << 10));
GST_WRITE_UINT32_LE (line + 48, (0x170 << 0) | (0x180 << 20));
GST_WRITE_UINT32_LE (line + 52, (0x2f9 << 10));
gst_video_vbi_parser_add_line (parser, line);
@ -174,9 +177,10 @@ GST_START_TEST (parse_10bit)
GST_WRITE_UINT32_LE (line + 32, (0x101 << 0) | (0x102 << 20) | (0x104 << 10));
GST_WRITE_UINT32_LE (line + 36, (0x203 << 10) | (0x203 << 0) | (0x102 << 20));
GST_WRITE_UINT32_LE (line + 40, (0x104 << 0) | (0x250 << 20) | (0x101 << 10));
GST_WRITE_UINT32_LE (line + 44, (0x260 << 10));
GST_WRITE_UINT32_LE (line + 44, (0x275 << 0) | (0x260 << 10));
GST_WRITE_UINT32_LE (line + 48, (0x170 << 0) | (0x180 << 20));
GST_WRITE_UINT32_LE (line + 52, (0x2f9 << 10));
gst_video_vbi_parser_add_line (parser, line);