From patchwork Mon May 14 22:26:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Keroulas X-Patchwork-Id: 8968 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:155:0:0:0:0:0 with SMTP id c82-v6csp648610jad; Mon, 14 May 2018 15:27:03 -0700 (PDT) X-Google-Smtp-Source: AB8JxZohTwxY/lsSqbqBjx6WcWVG2bJN+ow3YFoOSPbF0GK2Uw4KbOZIVAEXVhN7veZ1eeiBnWf+ X-Received: by 2002:a1c:4406:: with SMTP id r6-v6mr5774112wma.99.1526336823852; Mon, 14 May 2018 15:27:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526336823; cv=none; d=google.com; s=arc-20160816; b=tKO5KDSmUo7sFLkSlAEbgs/zNjbrf3oV5fhYJlSuOOfL/lrOk3WVFgPSYPJBGF5JI3 UrMzstoDSjMrry/ecGN39jgcPkVNAG8Dtbzg/TyazSWGqQy9MGXK4cFzRqVB8uPeEg3x oR7xXTlW7Rf1wdQhHvi+Bnomz8fW380x81pn9Jsr93nJaOJOKqmb+ibI6OWUNThekM39 vnC81LM90jRgfOR+TmUNmC8gHGgZx+0mic7Czyvrgp7LaWvyUzS4HgHqpN2yP45DI12+ EoRrETW/mQLwt2+6NA5LT+GJWkd9N6V4I8zh4PuJwUXs2iV96qHiE0StOsxCSK8J1+9k okzw== 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=usnady4LTUADqV3hodKcUvNAp/1cP5mRhzbYE9GBNrU=; b=UjrfsypLuKxBdNHGET7gQvL+Py/xjyfGx8OKinarOSaxVl6aIv9uPHBqLnQxfSTbDK sd8X8DG7w1vqi4Or+9AEJq1hQyLltDOBerRYGSs0BX1aYLapAnKAlFnSJkOADQDhjVUe zislre9jviaMr+kzcn8xkO/yrw8lbIKsILkikGudzuqTx9GJKh+UqSC85PoqGJ6VIrqG W4mw80JLfrKG71XEBvkpr4Jd52w0Xccm2JwsS0mvnPkCOCXXxkNRiBGVjy5CWR+dAW+K Nrgay2a/Hh1OlU5WDWjeq0Lb/1KI3sCuWDKNtiw4Tpv9Bd+ekGSRlheJqwJmFAh42AOm 0biQ== 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 l4-v6si8506062wrn.212.2018.05.14.15.27.03; Mon, 14 May 2018 15:27:03 -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 6CE10689E84; Tue, 15 May 2018 01:26:13 +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 A419C689A52 for ; Tue, 15 May 2018 01:26:05 +0300 (EEST) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id EB7F09C34F4 for ; Mon, 14 May 2018 18:26:42 -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 NLLLwaz9LTSx; Mon, 14 May 2018 18:26:42 -0400 (EDT) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id 49D2E9C34F7; Mon, 14 May 2018 18:26:42 -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 k_x6pJPuFhCD; Mon, 14 May 2018 18:26:42 -0400 (EDT) Received: from pkeroulas.media.in.cbcsrc.ca (unknown [192.168.50.171]) by mail.savoirfairelinux.com (Postfix) with ESMTPSA id 1D4659C34F4; Mon, 14 May 2018 18:26:42 -0400 (EDT) From: Patrick Keroulas To: ffmpeg-devel@ffmpeg.org Date: Mon, 14 May 2018 18:26:36 -0400 Message-Id: <1526336797-21703-2-git-send-email-patrick.keroulas@savoirfairelinux.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1526336797-21703-1-git-send-email-patrick.keroulas@savoirfairelinux.com> References: <1526336797-21703-1-git-send-email-patrick.keroulas@savoirfairelinux.com> Subject: [FFmpeg-devel] [PATCH v6 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" From: Damien Riegel 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 additionnal field flags in AVPacket allow the decoder to dynamically determine the frame format, i.e. progressive or interlaced. Signed-off-by: Patrick Keroulas Signed-off-by: Damien Riegel --- Changes v5 -> v6: * cleanup * move the packet flags in a separate patch * bump lavc minor version in this new patch --- libavcodec/bitpacked.c | 122 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 19 deletions(-) diff --git a/libavcodec/bitpacked.c b/libavcodec/bitpacked.c index f0b417d..4157876 100644 --- a/libavcodec/bitpacked.c +++ b/libavcodec/bitpacked.c @@ -32,8 +32,9 @@ #include "libavutil/imgutils.h" struct BitpackedContext { - int (*decode)(AVCodecContext *avctx, AVFrame *frame, - AVPacket *pkt); + int (*decode)(AVCodecContext *avctx, AVFrame *frame, AVPacket *pkt); + AVFrame *cur_interlaced_frame; + int prev_top_field; }; /* For this format, it's a simple passthrough */ @@ -58,27 +59,41 @@ static int bitpacked_decode_uyvy422(AVCodecContext *avctx, AVFrame *frame, static int bitpacked_decode_yuv422p10(AVCodecContext *avctx, AVFrame *frame, AVPacket *avpkt) { - 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 = (avpkt->flags & AV_PKT_FLAG_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 (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; - ret = init_get_bits(&bc, avpkt->data, avctx->width * avctx->height * 20); + /* + * 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, 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 +118,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; } @@ -128,13 +161,63 @@ static int bitpacked_decode(AVCodecContext *avctx, void *data, int *got_frame, frame->pict_type = AV_PICTURE_TYPE_I; frame->key_frame = 1; - res = bc->decode(avctx, frame, avpkt); - if (res) - return res; + if ((avpkt->flags & AV_PKT_FLAG_TOP_FIELD) && + (avpkt->flags & AV_PKT_FLAG_BOTTOM_FIELD)) { + av_log(avctx, AV_LOG_WARNING, "Invalid field flags.\n"); + return AVERROR_INVALIDDATA; + } else if (avpkt->flags & AV_PKT_FLAG_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)) < 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 (avpkt->flags & AV_PKT_FLAG_BOTTOM_FIELD) { + if (!bc->prev_top_field) { + av_log(avctx, AV_LOG_ERROR, "Top field missing.\n"); + return AVERROR_INVALIDDATA; + } - *got_frame = 1; - return buf_size; + 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)) < 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)) < 0) + return res; + + *got_frame = 1; + return buf_size; + } } AVCodec ff_bitpacked_decoder = { @@ -144,6 +227,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, };