From 9b937958907daaddade139c36ce33c6eac269631 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sun, 18 Jun 2017 02:34:11 +0200 Subject: avdevice/decklink_dec: add support for receiving op47 teletext v2: - use uint16_t instead of int to store 10-bit ancillary data - fix ancillary line numbers for 1080p - some comments and clarifications as requested by Aaron Levinson Signed-off-by: Marton Balint --- libavdevice/decklink_dec.cpp | 127 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 11 deletions(-) (limited to 'libavdevice/decklink_dec.cpp') diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 6783a0ce77..8b5c1a20c1 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -36,6 +36,7 @@ extern "C" { #include "libavutil/imgutils.h" #include "libavutil/time.h" #include "libavutil/mathematics.h" +#include "libavutil/reverse.h" #if CONFIG_LIBZVBI #include #endif @@ -44,7 +45,6 @@ extern "C" { #include "decklink_common.h" #include "decklink_dec.h" -#if CONFIG_LIBZVBI static uint8_t calc_parity_and_line_offset(int line) { uint8_t ret = (line < 313) << 5; @@ -63,6 +63,7 @@ static void fill_data_unit_head(int line, uint8_t *tgt) tgt[3] = 0xe4; // framing code } +#if CONFIG_LIBZVBI static uint8_t* teletext_data_unit_from_vbi_data(int line, uint8_t *src, uint8_t *tgt, vbi_pixfmt fmt) { vbi_bit_slicer slicer; @@ -95,6 +96,95 @@ static uint8_t* teletext_data_unit_from_vbi_data_10bit(int line, uint8_t *src, u } #endif +static uint8_t* teletext_data_unit_from_op47_vbi_packet(int line, uint16_t *py, uint8_t *tgt) +{ + int i; + + if (py[0] != 0x255 || py[1] != 0x255 || py[2] != 0x227) + return tgt; + + fill_data_unit_head(line, tgt); + + py += 3; + tgt += 4; + + for (i = 0; i < 42; i++) + *tgt++ = ff_reverse[py[i] & 255]; + + return tgt; +} + +static int linemask_matches(int line, int64_t mask) +{ + int shift = -1; + if (line >= 6 && line <= 22) + shift = line - 6; + if (line >= 318 && line <= 335) + shift = line - 318 + 17; + return shift >= 0 && ((1ULL << shift) & mask); +} + +static uint8_t* teletext_data_unit_from_op47_data(uint16_t *py, uint16_t *pend, uint8_t *tgt, int64_t wanted_lines) +{ + if (py < pend - 9) { + if (py[0] == 0x151 && py[1] == 0x115 && py[3] == 0x102) { // identifier, identifier, format code for WST teletext + uint16_t *descriptors = py + 4; + int i; + py += 9; + for (i = 0; i < 5 && py < pend - 45; i++, py += 45) { + int line = (descriptors[i] & 31) + (!(descriptors[i] & 128)) * 313; + if (line && linemask_matches(line, wanted_lines)) + tgt = teletext_data_unit_from_op47_vbi_packet(line, py, tgt); + } + } + } + return tgt; +} + +static uint8_t* teletext_data_unit_from_ancillary_packet(uint16_t *py, uint16_t *pend, uint8_t *tgt, int64_t wanted_lines, int allow_multipacket) +{ + uint16_t did = py[0]; // data id + uint16_t sdid = py[1]; // secondary data id + uint16_t dc = py[2] & 255; // data count + py += 3; + pend = FFMIN(pend, py + dc); + if (did == 0x143 && sdid == 0x102) { // subtitle distribution packet + tgt = teletext_data_unit_from_op47_data(py, pend, tgt, wanted_lines); + } else if (allow_multipacket && did == 0x143 && sdid == 0x203) { // VANC multipacket + py += 2; // priority, line/field + while (py < pend - 3) { + tgt = teletext_data_unit_from_ancillary_packet(py, pend, tgt, wanted_lines, 0); + py += 4 + (py[2] & 255); // ndid, nsdid, ndc, line/field + } + } + return tgt; +} + +static uint8_t* teletext_data_unit_from_vanc_data(uint8_t *src, uint8_t *tgt, int64_t wanted_lines) +{ + uint16_t y[1920]; + uint16_t *py = y; + uint16_t *pend = y + 1920; + /* The 10-bit VANC data is packed in V210, we only need the luma component. */ + while (py < pend) { + *py++ = (src[1] >> 2) + ((src[2] & 15) << 6); + *py++ = src[4] + ((src[5] & 3) << 8); + *py++ = (src[6] >> 4) + ((src[7] & 63) << 4); + src += 8; + } + py = y; + while (py < pend - 6) { + if (py[0] == 0 && py[1] == 0x3ff && py[2] == 0x3ff) { // ancillary data flag + py += 3; + tgt = teletext_data_unit_from_ancillary_packet(py, pend, tgt, wanted_lines, 0); + py += py[2] & 255; + } else { + py++; + } + } + return tgt; +} + static void avpacket_queue_init(AVFormatContext *avctx, AVPacketQueue *q) { memset(q, 0, sizeof(AVPacketQueue)); @@ -381,11 +471,10 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( videoFrame->GetHeight(); //fprintf(stderr,"Video Frame size %d ts %d\n", pkt.size, pkt.pts); -#if CONFIG_LIBZVBI if (!no_video && ctx->teletext_lines) { IDeckLinkVideoFrameAncillary *vanc; AVPacket txt_pkt; - uint8_t txt_buf0[1611]; // max 35 * 46 bytes decoded teletext lines + 1 byte data_identifier + uint8_t txt_buf0[3531]; // 35 * 46 bytes decoded teletext lines + 1 byte data_identifier + 1920 bytes OP47 decode buffer uint8_t *txt_buf = txt_buf0; if (videoFrame->GetAncillaryData(&vanc) == S_OK) { @@ -394,6 +483,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( BMDPixelFormat vanc_format = vanc->GetPixelFormat(); txt_buf[0] = 0x10; // data_identifier - EBU_data txt_buf++; +#if CONFIG_LIBZVBI if (ctx->bmd_mode == bmdModePAL && (vanc_format == bmdFormat8BitYUV || vanc_format == bmdFormat10BitYUV)) { av_assert0(videoFrame->GetWidth() == 720); for (i = 6; i < 336; i++, line_mask <<= 1) { @@ -408,6 +498,21 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( i = 317; } } +#endif + if (videoFrame->GetWidth() == 1920 && vanc_format == bmdFormat10BitYUV) { + int first_active_line = ctx->bmd_field_dominance == bmdProgressiveFrame ? 42 : 584; + for (i = 8; i < first_active_line; i++) { + uint8_t *buf; + if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) + txt_buf = teletext_data_unit_from_vanc_data(buf, txt_buf, ctx->teletext_lines); + if (ctx->bmd_field_dominance != bmdProgressiveFrame && i == 20) // skip field1 active lines + i = 569; + if (txt_buf - txt_buf0 > 1611) { // ensure we still have at least 1920 bytes free in the buffer + av_log(avctx, AV_LOG_ERROR, "Too many OP47 teletext packets.\n"); + break; + } + } + } vanc->Release(); if (txt_buf - txt_buf0 > 1) { int stuffing_units = (4 - ((45 + txt_buf - txt_buf0) / 46) % 4) % 4; @@ -428,7 +533,6 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( } } } -#endif if (avpacket_queue_put(&ctx->queue, &pkt) < 0) { ++ctx->dropped; @@ -527,13 +631,6 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) ctx->draw_bars = cctx->draw_bars; cctx->ctx = ctx; -#if !CONFIG_LIBZVBI - if (ctx->teletext_lines) { - av_log(avctx, AV_LOG_ERROR, "Libzvbi support is needed for capturing teletext, please recompile FFmpeg.\n"); - return AVERROR(ENOSYS); - } -#endif - /* Check audio channel option for valid values: 2, 8 or 16 */ switch (cctx->audio_channels) { case 2: @@ -587,6 +684,14 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) } } +#if !CONFIG_LIBZVBI + if (ctx->teletext_lines && ctx->bmd_mode == bmdModePAL) { + av_log(avctx, AV_LOG_ERROR, "Libzvbi support is needed for capturing SD PAL teletext, please recompile FFmpeg.\n"); + ret = AVERROR(ENOSYS); + goto error; + } +#endif + /* Setup streams. */ st = avformat_new_stream(avctx, NULL); if (!st) { -- cgit v1.2.3