From patchwork Thu Nov 16 18:34:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Devin Heitmueller X-Patchwork-Id: 6125 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.2.161.94 with SMTP id m30csp6150003jah; Thu, 16 Nov 2017 10:35:23 -0800 (PST) X-Google-Smtp-Source: AGs4zMaBLumIz7Dnpwr3ShRJcKRmZkjDjkTEMNkbgJB4ll36H1y4xigjlCArENhS7tWgqsUq5z39 X-Received: by 10.28.132.19 with SMTP id g19mr2194459wmd.90.1510857323529; Thu, 16 Nov 2017 10:35:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1510857323; cv=none; d=google.com; s=arc-20160816; b=ZpKk9hNOBXtw1Z5v3IuGJK/MoJ1hadjevgjbSiohu89FaHRFbUs4D/Mz1f5fzer6zt i9a8ngQ1Lavf46NUNcKoBVxiXJJ+IxCYyZpPri0FFsHPerouQOyGJ0keTYRwiHVi1u4F YrZqXEb+rmPAdTc64KwXzQmeHIYHSJgC3y3v3BhtI+y8BFiEuYm4KwrMyD+Nar+n9bT/ 9LDvSVUQ+Bzf6+wX9ivR1C9frIhb8P8g0/5+Mpddv3ne0pOcWmIfDXwzaTjlXOVDNGTI 4rdX0+EknaFiVyvocwVEIaQ+YtuvoRdCiSR0y4kIRn82gGUsXyFeWlyhjMdJmxL1APA7 KYLw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:delivered-to:arc-authentication-results; bh=9cWP1uSZHyyr0yJxBC2QkA2yPcSKUAyVzN5GyJps0d8=; b=ibuNCTNEEOB3a3hX6pOZPq5nVWE2+ATdUw+4rTHHFmuEaWsd4bBawaVYJVoTRpmYlL lMnfM3pcC3jluYjXx6sZnijcJhUaJgSLDSFWoBdg059lrLKMP2tfvUUFgTMvV1KDo7PI mG0rY0NqbAY0EkI+vyTzmX4Y8dpoHLP/ui3LytmieBJpksBtSyEmTMwAP6dAF8po79HZ PlEvY1qzXMK00hwb0UkrDzbLS0i/n6Z2kLEs2wf/JBUesYOogfauJ2OgxFmvYsVMsYZz A9tqE0GEwon8B/u2/aExdmjkbydA33ja1UbddyGCfZFyMoS6Wub9MjwfXynjfXRsua6W /VRg== 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 142si1373366wme.138.2017.11.16.10.35.23; Thu, 16 Nov 2017 10:35:23 -0800 (PST) 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 3065B68A064; Thu, 16 Nov 2017 20:34:24 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from was-smtp1.livetimenet.net (50-206-97-56-static.hfc.comcastbusiness.net [50.206.97.56]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9B91C689F79 for ; Thu, 16 Nov 2017 20:34:16 +0200 (EET) Received: by was-smtp1.livetimenet.net with esmtpsa (TLSv1:AES128-SHA:128) (Exim 4.84_2) (envelope-from ) id 1eFOze-0002o7-NC; Thu, 16 Nov 2017 13:34:31 -0500 From: Devin Heitmueller To: ffmpeg-devel@ffmpeg.org Date: Thu, 16 Nov 2017 13:34:16 -0500 Message-Id: <20171116183417.93073-6-dheitmueller@ltnglobal.com> X-Mailer: git-send-email 2.13.2 In-Reply-To: <20171116183417.93073-1-dheitmueller@ltnglobal.com> References: <20171116183417.93073-1-dheitmueller@ltnglobal.com> MIME-Version: 1.0 X-Spam-Score: -1.9 (-) Subject: [FFmpeg-devel] [PATCH 5/6] Add suppoort for using libklvanc from within decklink capture module 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: jgreen@ltnglobal.com, Devin Heitmueller Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Make use of libklvanc from within the decklink capture module, initially for EIA-708 and AFD. Support for other VANC types will come in subsequent patches. Signed-off-by: Devin Heitmueller --- libavdevice/decklink_dec.cpp | 135 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 11b7e60..bea9213 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -3,6 +3,7 @@ * Copyright (c) 2013-2014 Luca Barbato, Deti Fliegl * Copyright (c) 2014 Rafaël Carré * Copyright (c) 2017 Akamai Technologies, Inc. + * Copyright (c) 2017 LTN Global Communications, Inc. * * This file is part of FFmpeg. * @@ -669,10 +670,128 @@ error: return ret; } +#if CONFIG_LIBKLVANC +/* VANC Callbacks */ +struct vanc_cb_ctx { + AVFormatContext *avctx; + AVPacket *pkt; +}; +static int cb_AFD(void *callback_context, struct klvanc_context_s *ctx, + struct klvanc_packet_afd_s *pkt) +{ + struct vanc_cb_ctx *cb_ctx = (struct vanc_cb_ctx *)callback_context; + uint8_t *afd; + + afd = (uint8_t *)av_malloc(1); + if (afd == NULL) + return AVERROR(ENOMEM); + + afd[0] = pkt->hdr.payload[0] >> 3; + if (av_packet_add_side_data(cb_ctx->pkt, AV_PKT_DATA_AFD, afd, 1) < 0) + av_free(afd); + + return 0; +} + +static int cb_EIA_708B(void *callback_context, struct klvanc_context_s *ctx, + struct klvanc_packet_eia_708b_s *pkt) +{ + struct vanc_cb_ctx *cb_ctx = (struct vanc_cb_ctx *)callback_context; + decklink_cctx *cctx = (struct decklink_cctx *)cb_ctx->avctx->priv_data; + struct decklink_ctx *decklink_ctx = (struct decklink_ctx *)cctx->ctx; + + uint16_t expected_cdp; + uint8_t *cc; + + if (!pkt->checksum_valid) + return 0; + + if (!pkt->header.ccdata_present) + return 0; + + expected_cdp = decklink_ctx->cdp_sequence_num + 1; + decklink_ctx->cdp_sequence_num = pkt->header.cdp_hdr_sequence_cntr; + if (pkt->header.cdp_hdr_sequence_cntr != expected_cdp) { + av_log(cb_ctx->avctx, AV_LOG_DEBUG, + "CDP counter inconsistent. Received=0x%04x Expected=%04x\n", + pkt->header.cdp_hdr_sequence_cntr, expected_cdp); + return 0; + } + + cc = (uint8_t *)av_malloc(pkt->ccdata.cc_count * 3); + if (cc == NULL) + return AVERROR(ENOMEM); + + for (int i = 0; i < pkt->ccdata.cc_count; i++) { + cc[3*i] = 0xf8 | (pkt->ccdata.cc[i].cc_valid ? 0x04 : 0x00) | + (pkt->ccdata.cc[i].cc_type & 0x03); + cc[3*i+1] = pkt->ccdata.cc[i].cc_data[0]; + cc[3*i+2] = pkt->ccdata.cc[i].cc_data[1]; + } + + if (av_packet_add_side_data(cb_ctx->pkt, AV_PKT_DATA_A53_CC, cc, pkt->ccdata.cc_count * 3) < 0) + av_free(cc); + + return 0; +} + +static struct klvanc_callbacks_s callbacks = +{ + .afd = cb_AFD, + .eia_708b = cb_EIA_708B, + .eia_608 = NULL, + .scte_104 = NULL, + .all = NULL, + .kl_i64le_counter = NULL, +}; +/* End: VANC Callbacks */ + +/* Take one line of V210 from VANC, colorspace convert and feed it to the + * VANC parser. We'll expect our VANC message callbacks to happen on this + * same calling thread. + */ +static void klvanc_handle_line(AVFormatContext *avctx, struct klvanc_context_s *vanc_ctx, + unsigned char *buf, unsigned int uiWidth, unsigned int lineNr, + AVPacket *pkt) +{ + /* Convert the vanc line from V210 to CrCB422, then vanc parse it */ + + /* We need two kinds of type pointers into the source vbi buffer */ + /* TODO: What the hell is this, two ptrs? */ + const uint32_t *src = (const uint32_t *)buf; + + /* Convert Blackmagic pixel format to nv20. + * src pointer gets mangled during conversion, hence we need its own + * ptr instead of passing vbiBufferPtr. + * decoded_words should be atleast 2 * uiWidth. + */ + uint16_t decoded_words[16384]; + + /* On output each pixel will be decomposed into three 16-bit words (one for Y, U, V) */ + memset(&decoded_words[0], 0, sizeof(decoded_words)); + uint16_t *p_anc = decoded_words; + if (klvanc_v210_line_to_nv20_c(src, p_anc, sizeof(decoded_words), (uiWidth / 6) * 6) < 0) + return; + + if (vanc_ctx) { + struct vanc_cb_ctx cb_ctx = { + .avctx = avctx, + .pkt = pkt + }; + vanc_ctx->callback_context = &cb_ctx; + int ret = klvanc_packet_parse(vanc_ctx, lineNr, decoded_words, sizeof(decoded_words) / (sizeof(unsigned short))); + if (ret < 0) { + /* No VANC on this line */ + } + } +} +#endif + HRESULT decklink_input_callback::VideoInputFrameArrived( IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame) { decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; void *frameBytes; void *audioFrameBytes; BMDTimeValue frameTime; @@ -774,15 +893,21 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( for (i = vanc_line_numbers[idx].vanc_start; i <= vanc_line_numbers[idx].vanc_end; i++) { uint8_t *buf; if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) { +#if CONFIG_LIBKLVANC + klvanc_handle_line(avctx, ctx->vanc_ctx, + buf, videoFrame->GetWidth(), i, &pkt); +#else uint16_t luma_vanc[MAX_WIDTH_VANC]; extract_luma_from_v210(luma_vanc, buf, videoFrame->GetWidth()); txt_buf = get_metadata(avctx, luma_vanc, videoFrame->GetWidth(), txt_buf, sizeof(txt_buf0) - (txt_buf - txt_buf0), &pkt); +#endif } if (i == vanc_line_numbers[idx].field0_vanc_end) i = vanc_line_numbers[idx].field1_vanc_start - 1; } } + vanc->Release(); if (txt_buf - txt_buf0 > 1) { int stuffing_units = (4 - ((45 + txt_buf - txt_buf0) / 46) % 4) % 4; @@ -900,6 +1025,7 @@ av_cold int ff_decklink_read_close(AVFormatContext *avctx) ff_decklink_cleanup(avctx); avpacket_queue_end(&ctx->queue); + klvanc_context_destroy(ctx->vanc_ctx); av_freep(&cctx->ctx); @@ -1128,6 +1254,15 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) avpacket_queue_init (avctx, &ctx->queue); +#if CONFIG_LIBKLVANC + if (klvanc_context_create(&ctx->vanc_ctx) < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot create VANC library context\n"); + } else { + ctx->vanc_ctx->verbose = 0; + ctx->vanc_ctx->callbacks = &callbacks; + } +#endif + if (decklink_start_input (avctx) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Cannot start input stream\n"); ret = AVERROR(EIO);