+ len -= 7; // remove VANC header and checksum
+
+ if (cdp[2] != len) {
+ av_log(avctx, AV_LOG_WARNING, "CDP len %d != %zu\n", cdp[2], len);
+ return NULL;
+ }
+
+ cdp_sum = 0;
+ for (i = 0; i < len - 1; i++)
+ cdp_sum += cdp[i];
+ cdp_sum = cdp_sum ? 256 - cdp_sum : 0;
+ if (cdp[len - 1] != cdp_sum) {
+ av_log(avctx, AV_LOG_WARNING, "CDP checksum invalid 0x%.4x != 0x%.4x\n", cdp_sum, cdp[len-1]);
+ return NULL;
+ }
+
+ rate = cdp[3];
+ if (!(rate & 0x0f)) {
+ av_log(avctx, AV_LOG_WARNING, "CDP frame rate invalid (0x%.2x)\n", rate);
+ return NULL;
+ }
+ rate >>= 4;
+ if (rate > 8) {
+ av_log(avctx, AV_LOG_WARNING, "CDP frame rate invalid (0x%.2x)\n", rate);
+ return NULL;
+ }
+
+ if (!(cdp[4] & 0x43)) /* ccdata_present | caption_service_active | reserved */ {
+ av_log(avctx, AV_LOG_WARNING, "CDP flags invalid (0x%.2x)\n", cdp[4]);
+ return NULL;
+ }
+
+ hdr = (cdp[5] << 8) | cdp[6];
+ if (cdp[7] != 0x72) /* ccdata_id */ {
+ av_log(avctx, AV_LOG_WARNING, "Invalid ccdata_id 0x%.2x\n", cdp[7]);
+ return NULL;
+ }
+
+ cc_count = cdp[8];
+ if (!(cc_count & 0xe0)) {
+ av_log(avctx, AV_LOG_WARNING, "Invalid cc_count 0x%.2x\n", cc_count);
+ return NULL;
+ }
+
+ cc_count &= 0x1f;
+ if ((len - 13) < cc_count * 3) {
+ av_log(avctx, AV_LOG_WARNING, "Invalid cc_count %d (> %zu)\n", cc_count * 3, len - 13);
+ return NULL;
+ }
+
+ if (cdp[len - 4] != 0x74) /* footer id */ {
+ av_log(avctx, AV_LOG_WARNING, "Invalid footer id 0x%.2x\n", cdp[len-4]);
+ return NULL;
+ }
+
+ ftr = (cdp[len - 3] << 8) | cdp[len - 2];
+ if (ftr != hdr) {
+ av_log(avctx, AV_LOG_WARNING, "Header 0x%.4x != Footer 0x%.4x\n", hdr, ftr);
+ return NULL;
+ }
+
+ cc = (uint8_t *)av_malloc(cc_count * 3);
+ if (cc == NULL) {
+ av_log(avctx, AV_LOG_WARNING, "CC - av_malloc failed for cc_count = %d\n", cc_count);
+ return NULL;
+ }
+
+ for (size_t i = 0; i < cc_count; i++) {
+ cc[3*i + 0] = cdp[9 + 3*i+0] /* & 3 */;
+ cc[3*i + 1] = cdp[9 + 3*i+1];
+ cc[3*i + 2] = cdp[9 + 3*i+2];
+ }
+
+ cc_count *= 3;
+ return cc;
+}
+
+uint8_t *get_metadata(AVFormatContext *avctx, uint16_t *buf, size_t width,
+ uint8_t *tgt, size_t tgt_size, AVPacket *pkt)
+{
+ decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;
+ uint16_t *max_buf = buf + width;
+
+ while (buf < max_buf - 6) {
+ int len;
+ uint16_t did = buf[3] & 0xFF; // data id
+ uint16_t sdid = buf[4] & 0xFF; // secondary data id
+ /* Check for VANC header */
+ if (buf[0] != 0 || buf[1] != 0x3ff || buf[2] != 0x3ff) {
+ return tgt;
+ }
+
+ len = (buf[5] & 0xff) + 6 + 1;
+ if (len > max_buf - buf) {
+ av_log(avctx, AV_LOG_WARNING, "Data Count (%d) > data left (%zu)\n",
+ len, max_buf - buf);
+ return tgt;
+ }
+
+ if (did == 0x43 && (sdid == 0x02 || sdid == 0x03) && cctx->teletext_lines &&
+ width == 1920 && tgt_size >= 1920) {
+ if (check_vanc_parity_checksum(buf, len, buf[len - 1]) < 0) {
+ av_log(avctx, AV_LOG_WARNING, "VANC parity or checksum incorrect\n");
+ goto skip_packet;
+ }
+ tgt = teletext_data_unit_from_ancillary_packet(buf + 3, buf + len, tgt, cctx->teletext_lines, 0);
+ } else if (did == 0x61 && sdid == 0x01) {
+ unsigned int data_len;
+ uint8_t *data;
+ if (check_vanc_parity_checksum(buf, len, buf[len - 1]) < 0) {
+ av_log(avctx, AV_LOG_WARNING, "VANC parity or checksum incorrect\n");
+ goto skip_packet;
+ }
+ clear_parity_bits(buf, len);
+ data = vanc_to_cc(avctx, buf, width, data_len);
+ if (data) {
+ uint8_t *pkt_cc = av_packet_new_side_data(pkt, AV_PKT_DATA_A53_CC, data_len);
+ if (pkt_cc)
+ memcpy(pkt_cc, data, data_len);
+ av_free(data);
+ }