From patchwork Tue Jul 10 21:52:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Keroulas X-Patchwork-Id: 9666 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:104:0:0:0:0:0 with SMTP id c4-v6csp4140248jad; Tue, 10 Jul 2018 14:52:24 -0700 (PDT) X-Google-Smtp-Source: AAOMgpe6+kbt6Plxgk2WFmRZrxbxPGlmaG2p1jnXxWoeSOcYpAnIk6zaR9VUqls5XQhNLXgmbHhX X-Received: by 2002:adf:c684:: with SMTP id j4-v6mr13563826wrg.243.1531259544441; Tue, 10 Jul 2018 14:52:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531259544; cv=none; d=google.com; s=arc-20160816; b=0dixtUiWlDiPuFeCwqQIG9hKX5BTT8e8QbueTkCkgJwHx7jlaE9mBmb7vFDY/Ya0pV XDu9VVE3Li/Ln/69E91rISp9hMalHzkWXx1vsTMcnRPvEoY2XosdFe5j1P42GFe4loBx I1+GbeQTxwZHjtWKsT1mfig4R5iZlxNwm0LgSysIvPfLU6uYgN3podKRV4NceIkaZmy2 uYIs5v9qD/HzPVN4XRjnU3fecnNuYKbh6QqeBlSk6g5BPIyt9fnxQfeBRqY39aBN/Url zpQw0p5SxE5qAPOnlknXWwOXCnjMsu3YRjfba3sToDpiZeA8vU9PppVNnOO8RB3d7he6 SdtQ== 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=eHwIghqr58XPedkN168bL80OcklZzA6JeD5bK78gBvo=; b=t0fVBgpirsDhH7/Hl2seyqZ/bLUpY8tNITQHy7ApMxm2zp3J7ixXo818NZKD8uopT5 bK101M/XGjIuTKEky66pTlUZ0kQjltA2ER/rjhlgl2RBgDtc1ZOn7OEBRQgDZdXA3Qyy 9YBusuhJpRKgA/97X9tTTPp7JuUTaQw1BiRbFiNl8JTeynZjLO/DU5lHXQ15T6jMbYHm 43WGKyJx266/UUEoXhqg7XphNt2M7Zmi6ecCkddTTXNXnszsP9d3UiF8szsQOHJOv2LV +gGH4TBmfymqCFEgKhBflrbpKJISy9+elYwmi+oJ4VRLd2iuqTk090lasKn1MyDVZeS6 +i6w== 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 j16-v6si240634wmj.207.2018.07.10.14.52.24; Tue, 10 Jul 2018 14:52:24 -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 764E968A47D; Wed, 11 Jul 2018 00:52:05 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail.savoirfairelinux.com (mail.savoirfairelinux.com [208.88.110.44]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3064C68A03A for ; Wed, 11 Jul 2018 00:51:58 +0300 (EEST) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id DAB4C9C3054 for ; Tue, 10 Jul 2018 17:52:04 -0400 (EDT) Received: from mail.savoirfairelinux.com ([127.0.0.1]) by localhost (mail.savoirfairelinux.com [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id yo68xQFaavoc; Tue, 10 Jul 2018 17:52:04 -0400 (EDT) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id 3020E9C218B; Tue, 10 Jul 2018 17:52:04 -0400 (EDT) X-Virus-Scanned: amavisd-new at mail.savoirfairelinux.com Received: from mail.savoirfairelinux.com ([127.0.0.1]) by localhost (mail.savoirfairelinux.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id f_1_5kcz8v4i; Tue, 10 Jul 2018 17:52:04 -0400 (EDT) Received: from pkeroulas.cbc-rc.ca (unknown [192.168.50.171]) by mail.savoirfairelinux.com (Postfix) with ESMTPSA id 02F8E9C316B; Tue, 10 Jul 2018 17:52:04 -0400 (EDT) From: Patrick Keroulas To: ffmpeg-devel@ffmpeg.org Date: Tue, 10 Jul 2018 17:52:00 -0400 Message-Id: <1531259521-19421-2-git-send-email-patrick.keroulas@savoirfairelinux.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1531259521-19421-1-git-send-email-patrick.keroulas@savoirfairelinux.com> References: <1531259521-19421-1-git-send-email-patrick.keroulas@savoirfairelinux.com> Subject: [FFmpeg-devel] [PATCH v8 2/3] avcodec/bitpacked: add interlace support 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: Damien Riegel , Patrick Keroulas MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This codec is already capable of depacking some combinations of pixel formats and depth as defined in the RFC4175. The only difference between progressive and interlace is that either a packet will contain the whole frame, or only a field of the frame. There is no mechanism for interlaced frames reconstruction at the rtp demux level, so it has to be handled by the codec which needs to partially recompose an AVFrame with every incoming field AVPacket. A frame is ouput only when the frame is completed with the 2nd field (bottom). The AVAncillary Data carried by AVPacket side data allows the decoder to dynamically determine the frame format, i.e. progressive or interlaced. Signed-off-by: Patrick Keroulas Signed-off-by: Damien Riegel --- Changes v7 -> v8: style --- --- libavcodec/bitpacked.c | 140 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 23 deletions(-) diff --git a/libavcodec/bitpacked.c b/libavcodec/bitpacked.c index f0b417d..e71593c 100644 --- a/libavcodec/bitpacked.c +++ b/libavcodec/bitpacked.c @@ -29,16 +29,18 @@ #include "avcodec.h" #include "internal.h" #include "get_bits.h" +#include "libavutil/ancillary_data.h" #include "libavutil/imgutils.h" struct BitpackedContext { - int (*decode)(AVCodecContext *avctx, AVFrame *frame, - AVPacket *pkt); + int (*decode)(AVCodecContext *avctx, AVFrame *frame, AVPacket *pkt, uint8_t field); + AVFrame *cur_interlaced_frame; + int prev_top_field; }; /* For this format, it's a simple passthrough */ static int bitpacked_decode_uyvy422(AVCodecContext *avctx, AVFrame *frame, - AVPacket *avpkt) + AVPacket *avpkt, uint8_t field) { int ret; @@ -56,29 +58,43 @@ static int bitpacked_decode_uyvy422(AVCodecContext *avctx, AVFrame *frame, } static int bitpacked_decode_yuv422p10(AVCodecContext *avctx, AVFrame *frame, - AVPacket *avpkt) + AVPacket *avpkt, uint8_t field) { - uint64_t frame_size = (uint64_t)avctx->width * (uint64_t)avctx->height * 20; + uint64_t frame_size = avctx->width * avctx->height * 20LL; uint64_t packet_size = (uint64_t)avpkt->size * 8; + int interlaced = frame->interlaced_frame; + int top_field = (field & AV_ANCILLARY_DATA_FIELD_TOP_FIELD) ? 1 : 0; GetBitContext bc; uint16_t *y, *u, *v; int ret, i, j; - ret = ff_get_buffer(avctx, frame, 0); - if (ret < 0) - return ret; + if ((avctx->width % 2 ) || (avctx->height % 2)) + return AVERROR_PATCHWELCOME; - if (frame_size > packet_size) + /* check packet size depending on the interlaced/progressive format */ + if (interlaced) { + if ((frame_size / 2) > packet_size) + return AVERROR_INVALIDDATA; + } else if (frame_size > packet_size) { return AVERROR_INVALIDDATA; + } - if (avctx->width % 2) - return AVERROR_PATCHWELCOME; + /* + * if the frame is interlaced, the avpkt we are getting is either the top + * or the bottom field. If it's the bottom field, it contains all the odd + * lines of the recomposed frame, so we start at offset 1. + */ + i = (interlaced && !top_field) ? 1 : 0; - ret = init_get_bits(&bc, avpkt->data, avctx->width * avctx->height * 20); + ret = init_get_bits(&bc, avpkt->data, frame_size); if (ret) return ret; - for (i = 0; i < avctx->height; i++) { + /* + * Packets from interlaced frames contain either even lines, or odd + * lines, so increment by two in that case. + */ + for (; i < avctx->height; i += 1 + interlaced) { y = (uint16_t*)(frame->data[0] + i * frame->linesize[0]); u = (uint16_t*)(frame->data[1] + i * frame->linesize[1]); v = (uint16_t*)(frame->data[2] + i * frame->linesize[2]); @@ -103,17 +119,35 @@ static av_cold int bitpacked_init_decoder(AVCodecContext *avctx) if (avctx->codec_tag == MKTAG('U', 'Y', 'V', 'Y')) { if (avctx->bits_per_coded_sample == 16 && - avctx->pix_fmt == AV_PIX_FMT_UYVY422) + avctx->pix_fmt == AV_PIX_FMT_UYVY422) { + + if (avctx->field_order > AV_FIELD_PROGRESSIVE) { + av_log(avctx, AV_LOG_ERROR, "interlaced not yet supported for 8-bit\n"); + return AVERROR_PATCHWELCOME; + } + bc->decode = bitpacked_decode_uyvy422; - else if (avctx->bits_per_coded_sample == 20 && - avctx->pix_fmt == AV_PIX_FMT_YUV422P10) + } else if (avctx->bits_per_coded_sample == 20 && + avctx->pix_fmt == AV_PIX_FMT_YUV422P10) { bc->decode = bitpacked_decode_yuv422p10; - else + } else { return AVERROR_INVALIDDATA; + } } else { return AVERROR_INVALIDDATA; } + bc->cur_interlaced_frame = av_frame_alloc(); + + return 0; +} + +static av_cold int bitpacked_end_decoder(AVCodecContext *avctx) +{ + struct BitpackedContext *bc = avctx->priv_data; + + av_frame_free(&bc->cur_interlaced_frame); + return 0; } @@ -121,20 +155,79 @@ static int bitpacked_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { struct BitpackedContext *bc = avctx->priv_data; + AVAncillaryData *ancillary; int buf_size = avpkt->size; AVFrame *frame = data; - int res; + int res, size; + uint8_t *side_data; + uint8_t field = AV_ANCILLARY_DATA_FIELD_NONE; frame->pict_type = AV_PICTURE_TYPE_I; frame->key_frame = 1; - res = bc->decode(avctx, frame, avpkt); - if (res) - return res; + side_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_ANCILLARY, &size); + if (side_data) { + ancillary = (AVAncillaryData*)(side_data); + field = ancillary->field; + } - *got_frame = 1; - return buf_size; + if ((field & AV_ANCILLARY_DATA_FIELD_TOP_FIELD) && + (field & AV_ANCILLARY_DATA_FIELD_BOTTOM_FIELD)) { + av_log(avctx, AV_LOG_WARNING, "Invalid field flags.\n"); + return AVERROR_INVALIDDATA; + } else if (field & AV_ANCILLARY_DATA_FIELD_TOP_FIELD) { + frame->interlaced_frame = 1; + frame->top_field_first = 1; + + if((res = ff_get_buffer(avctx, frame, 0)) < 0) + return res; + + /* always decode the top (1st) field and ref the result frame + * but don't output anything */ + if ((res = bc->decode(avctx, frame, avpkt, field)) < 0) + return res; + + av_frame_unref(bc->cur_interlaced_frame); + if ((res = av_frame_ref(bc->cur_interlaced_frame, frame)) < 0) + return res; + + bc->prev_top_field = 1; + + return 0; + } else if (field & AV_ANCILLARY_DATA_FIELD_BOTTOM_FIELD) { + if (!bc->prev_top_field) { + av_log(avctx, AV_LOG_ERROR, "Top field missing.\n"); + return AVERROR_INVALIDDATA; + } + frame->interlaced_frame = 1; + frame->top_field_first = 1; + + /* complete the ref'd frame with bottom field and output the + * result */ + if ((res = bc->decode(avctx, bc->cur_interlaced_frame, avpkt, field)) < 0) + return res; + + if ((res = av_frame_ref(frame, bc->cur_interlaced_frame)) < 0) + return res; + + bc->prev_top_field = 0; + *got_frame = 1; + return buf_size; + } else { + /* No field: the frame is progressive. */ + if (bc->prev_top_field) + av_frame_unref(bc->cur_interlaced_frame); + + if((res = ff_get_buffer(avctx, frame, 0)) < 0) + return res; + + if ((res = bc->decode(avctx, frame, avpkt, field)) < 0) + return res; + + *got_frame = 1; + return buf_size; + } } AVCodec ff_bitpacked_decoder = { @@ -144,6 +237,7 @@ AVCodec ff_bitpacked_decoder = { .id = AV_CODEC_ID_BITPACKED, .priv_data_size = sizeof(struct BitpackedContext), .init = bitpacked_init_decoder, + .close = bitpacked_end_decoder, .decode = bitpacked_decode, .capabilities = AV_CODEC_CAP_EXPERIMENTAL, };