From patchwork Fri Jul 7 23:24:24 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marton Balint X-Patchwork-Id: 4263 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.1.76 with SMTP id 73csp776118vsb; Fri, 7 Jul 2017 16:24:39 -0700 (PDT) X-Received: by 10.223.135.154 with SMTP id b26mr2086018wrb.48.1499469879871; Fri, 07 Jul 2017 16:24:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1499469879; cv=none; d=google.com; s=arc-20160816; b=J8Ljr30AhGfLL2zmgaO3d7ygyZPWcAd+d1OT/kdTfnouWF1TxzCNjlbrP8jhonCb9E 5km4nVQpEjYVgZt7R2kCN96jKSElg87ITQQeEZ+eNXVY8KuzAjMjNKPTMRLK8CFoIzcy lG/gkQTLLuuWaKYGMsczywDRJj0hkBLL6WsWNcRml2YEpe1kKT7Obm9QwIVl0HPbw3Oz p8RfoSEIKL9cue+Igm08WO/jXgP1Ja7cV/dmfIYnZ47OWFcNXE1wQNetoALrKnnxIIId sQ1c8UbLd8WLizrnpxSyikRfM8LIGgGQ/nC5ervt7iefR7iz0OacRCSB7aWbI+IMOTQP tNxQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:delivered-to:arc-authentication-results; bh=Ioo6bGg0oK1Ogibpic8w1uhuCP5GPdLeKFGURyki0No=; b=vJaOh1Q3oEi14hwJMJA0Z/3eaCQiiop2j0hC4r9avvygXOk5wsQpzuUn/YeVAvjiIz A6dEtIQQBzmisupTRi/3WeB48oF20nDsBCoxKK5Wo8yny/1ZCvEDfVh5p+ioRT0gr46Q 6N50SfcpDU9+j8CwVbfX+ri5OAyxYwqzcR6nweEO6kD2lHDq2wLEK/sSgGI+AIWBnJc6 yWClOzII0EP+V61DG9gY4oqVwMBQYwRua/GXmWB7pyYa9Qy9Rpgr0CCzaaUekII+znYL EOabhPscKzI2Mz7GHw0cu9qTWuGko8QC6NbPG+sEBr3OrLeYQMCUXASJjMjSC5I9WYpG cL4Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id z9si632440wmg.26.2017.07.07.16.24.39; Fri, 07 Jul 2017 16:24:39 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 66A2B689B73; Sat, 8 Jul 2017 02:24:34 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from iq.passwd.hu (iq.passwd.hu [217.27.212.140]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id DCE07689B4B for ; Sat, 8 Jul 2017 02:24:27 +0300 (EEST) Received: from localhost (localhost [127.0.0.1]) by iq.passwd.hu (Postfix) with ESMTP id 0E600102F74; Sat, 8 Jul 2017 01:24:31 +0200 (CEST) X-Virus-Scanned: amavisd-new at passwd.hu Received: from iq.passwd.hu ([127.0.0.1]) by localhost (iq.passwd.hu [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VjbD6g7vuHzn; Sat, 8 Jul 2017 01:24:29 +0200 (CEST) Received: from bluegene.passwd.hu (localhost [127.0.0.1]) by iq.passwd.hu (Postfix) with ESMTP id 635EF1021E6; Sat, 8 Jul 2017 01:24:29 +0200 (CEST) From: Marton Balint To: ffmpeg-devel@ffmpeg.org Date: Sat, 8 Jul 2017 01:24:24 +0200 Message-Id: <20170707232424.5458-1-cus@passwd.hu> X-Mailer: git-send-email 2.12.3 In-Reply-To: References: Subject: [FFmpeg-devel] [PATCHv2 2/2] avdevice/decklink_dec: add support for receiving op47 teletext X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Marton Balint MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 --- doc/indevs.texi | 20 ++++--- libavdevice/decklink_dec.cpp | 127 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 129 insertions(+), 18 deletions(-) diff --git a/doc/indevs.texi b/doc/indevs.texi index 330617a7c9..09e33216dc 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -245,13 +245,19 @@ of uyvy422. Not all Blackmagic devices support this option. @item teletext_lines If set to nonzero, an additional teletext stream will be captured from the -vertical ancillary data. This option is a bitmask of the VBI lines checked, -specifically lines 6 to 22, and lines 318 to 335. Line 6 is the LSB in the mask. -Selected lines which do not contain teletext information will be ignored. You -can use the special @option{all} constant to select all possible lines, or -@option{standard} to skip lines 6, 318 and 319, which are not compatible with all -receivers. Capturing teletext only works for SD PAL sources. To use this -option, ffmpeg needs to be compiled with @code{--enable-libzvbi}. +vertical ancillary data. Both SD PAL (576i) and HD (1080i or 1080p) +sources are supported. In case of HD sources, OP47 packets are decoded. + +This option is a bitmask of the SD PAL VBI lines captured, specifically lines 6 +to 22, and lines 318 to 335. Line 6 is the LSB in the mask. Selected lines +which do not contain teletext information will be ignored. You can use the +special @option{all} constant to select all possible lines, or +@option{standard} to skip lines 6, 318 and 319, which are not compatible with +all receivers. + +For SD sources, ffmpeg needs to be compiled with @code{--enable-libzvbi}. For +HD sources, on older (pre-4K) DeckLink card models you have to capture in 10 +bit mode. @item channels Defines number of audio channels to capture. Must be @samp{2}, @samp{8} or @samp{16}. 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) {