+ videoFrame->GetStreamTime(&stream_time, &frame_duration, CLOCK_FREQ);
+ video_frame->i_flags = BLOCK_FLAG_TYPE_I | sys->dominance_flags;
+ video_frame->i_pts = video_frame->i_dts = VLC_TS_0 + stream_time;
+
+ if (sys->tenbits) {
+ v210_convert((uint16_t*)video_frame->p_buffer, frame_bytes, width, height);
+ IDeckLinkVideoFrameAncillary *vanc;
+ if (videoFrame->GetAncillaryData(&vanc) == S_OK) {
+ for (int i = 1; i < 21; i++) {
+ uint32_t *buf;
+ if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) != S_OK)
+ break;
+ uint16_t dec[width * 2];
+ v210_convert(&dec[0], buf, width, 1);
+ static const uint16_t vanc_header[3] = { 0, 0x3ff, 0x3ff };
+ if (!memcmp(vanc_header, dec, sizeof(vanc_header))) {
+ int len = (dec[5] & 0xff) + 6 + 1;
+ uint16_t vanc_sum = 0;
+ bool parity_ok = true;
+ for (int i = 3; i < len - 1; i++) {
+ uint16_t v = dec[i];
+ int np = v >> 8;
+ int p = parity(v & 0xff);
+ if ((!!p ^ !!(v & 0x100)) || (np != 1 && np != 2)) {
+ parity_ok = false;
+ break;
+ }
+ vanc_sum += v;
+ vanc_sum &= 0x1ff;
+ dec[i] &= 0xff;
+ }
+
+ if (!parity_ok)
+ continue;
+
+ vanc_sum |= ((~vanc_sum & 0x100) << 1);
+ if (dec[len - 1] != vanc_sum)
+ continue;
+
+ if (dec[3] != 0x61 /* DID */ ||
+ dec[4] != 0x01 /* SDID = CEA-708 */)
+ continue;
+
+ /* CDP follows */
+ uint16_t *cdp = &dec[6];
+ if (cdp[0] != 0x96 || cdp[1] != 0x69)
+ continue;
+
+ len -= 7; // remove VANC header and checksum
+
+ if (cdp[2] != len)
+ continue;
+
+ uint8_t cdp_sum = 0;
+ for (int i = 0; i < len - 1; i++)
+ cdp_sum += cdp[i];
+ cdp_sum = cdp_sum ? 256 - cdp_sum : 0;
+ if (cdp[len - 1] != cdp_sum)
+ continue;
+
+ uint8_t rate = cdp[3];
+ if (!(rate & 0x0f))
+ continue;
+ rate >>= 4;
+ if (rate > 8)
+ continue;
+
+ if (!(cdp[4] & 0x43)) /* ccdata_present | caption_service_active | reserved */
+ continue;
+
+ uint16_t hdr = (cdp[5] << 8) | cdp[6];
+ if (cdp[7] != 0x72) /* ccdata_id */
+ continue;
+
+ int cc_count = cdp[8];
+ if (!(cc_count & 0xe0))
+ continue;
+ cc_count &= 0x1f;
+
+ /* FIXME: parse additional data (CC language?) */
+ if ((len - 13) < cc_count * 3)
+ continue;
+
+ if (cdp[len - 4] != 0x74) /* footer id */
+ continue;
+
+ uint16_t ftr = (cdp[len - 3] << 8) | cdp[len - 2];
+ if (ftr != hdr)
+ continue;
+
+ block_t *cc = block_Alloc(cc_count * 3);
+
+ for (int i = 0; i < cc_count; i++) {
+ cc->p_buffer[3*i+0] = cdp[9 + 3*i+0] & 3;
+ cc->p_buffer[3*i+1] = cdp[9 + 3*i+1];
+ cc->p_buffer[3*i+2] = cdp[9 + 3*i+2];
+ }
+
+ cc->i_pts = cc->i_dts = VLC_TS_0 + stream_time;
+
+ if (!sys->cc_es) {
+ es_format_t fmt;
+
+ es_format_Init( &fmt, SPU_ES, VLC_FOURCC('c', 'c', '1' , ' ') );
+ fmt.psz_description = strdup("Closed captions 1");
+ if (fmt.psz_description) {
+ sys->cc_es = es_out_Add(demux_->out, &fmt);
+ msg_Dbg(demux_, "Adding Closed captions stream");
+ }
+ }
+ if (sys->cc_es)
+ es_out_Send(demux_->out, sys->cc_es, cc);
+ else
+ block_Release(cc);
+ break; // we found the line with Closed Caption data
+ }
+ }
+ vanc->Release();
+ }
+ } else {
+ for (int y = 0; y < height; ++y) {
+ const uint8_t *src = (const uint8_t *)frame_bytes + stride * y;
+ uint8_t *dst = video_frame->p_buffer + width * 2 * y;
+ memcpy(dst, src, width * 2);
+ }
+ }