From patchwork Mon May 14 19:29:09 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Keroulas X-Patchwork-Id: 8961 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:155:0:0:0:0:0 with SMTP id c82-v6csp511776jad; Mon, 14 May 2018 12:29:25 -0700 (PDT) X-Google-Smtp-Source: AB8JxZro0EXfM/uULRSPlB683MeV/Fe8CBlC8BxzrTpD0cqWyiJJf6zsgmK+UN71YeGPrLApL/n1 X-Received: by 2002:adf:b246:: with SMTP id y6-v6mr7558397wra.99.1526326165764; Mon, 14 May 2018 12:29:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526326165; cv=none; d=google.com; s=arc-20160816; b=s7xC3K8FdmtcNdWc38O5ulR9hxEfobli5STRhRRHStAFhb0hvG7QVa3HC0ZurFYcom SRM+oZb1j5gWwPegs+hBOynRhdr35s0O262FbXACI61jF46QktgBvUObXrFKCQOIzjJ9 B539FlhO6hM/epVoEQpNBrPvggufVgnTAeGot5oXBbtjUcJn9+i59iGInVMHVg5RQd/R WYFuY4XLYJ3y1kiEviVhvQAlzqJxEWP+AcMmhdIqGvgmwRQc4u4C6zqz0/6hHORI+Lz7 yiuT3X+bD1C1gfAzeL9t6P+TvAplqBN4tVG/fR+OIv0xYeFgNxW1eE3Lf+gYpjG7BT9c pv1w== 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:message-id:date:to:from:delivered-to :arc-authentication-results; bh=56bBl4+28dV/Ispce/oQaAnwtvIncdNROwkCHKmW9t8=; b=unPMGf+OBUGErDpmiCKDT2cVUnI57SDkn0ZDxO4OgtlNFU/x927k+Fm4nPQqX1Ey1i ylF6rMvo8/CQpF5Cu8c0Jg6pjnZhUJK1kkW5cq+CQCdrk5pu56hcDO33QzG2T2jbjpYW PqUGFD2H7Hn2CinY/ti7lqfoL5OqmUtxQKidcUGCD7dsYDxD+jqsPqPYizhUOizVemNx ix6YreNK00MZVpOkYJ6GFp3oMack/lDk0+EvTQ5kfuTpIGPXB4rT0bIHLDN1t7PXZXfg ft+5HUeVVtxMPIb/0erebM9WrlbxNynhYQhcyQ0bGFnaD8Mj5DxohB0us+jTh550+mkz Tsgg== 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 204-v6si5748202wmf.26.2018.05.14.12.29.24; Mon, 14 May 2018 12:29:25 -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 6D84E6809F9; Mon, 14 May 2018 22:28:44 +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 11861680643 for ; Mon, 14 May 2018 22:28:38 +0300 (EEST) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id A470C9C1D15 for ; Mon, 14 May 2018 15:29:14 -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 9qlOccl60d04; Mon, 14 May 2018 15:29:13 -0400 (EDT) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id B008F9C3472; Mon, 14 May 2018 15:29:13 -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 AOCDxRlpdnfJ; Mon, 14 May 2018 15:29:13 -0400 (EDT) Received: from pkeroulas.media.in.cbcsrc.ca (unknown [192.168.50.171]) by mail.savoirfairelinux.com (Postfix) with ESMTPSA id 7F5289C1D15; Mon, 14 May 2018 15:29:13 -0400 (EDT) From: Patrick Keroulas To: ffmpeg-devel@ffmpeg.org Date: Mon, 14 May 2018 15:29:09 -0400 Message-Id: <1526326150-12360-1-git-send-email-patrick.keroulas@savoirfairelinux.com> X-Mailer: git-send-email 2.7.4 Subject: [FFmpeg-devel] [PATCH v5 1/2] 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 --- Change v4 -> v5: Call ff_get_buffer only when necessary. --- libavcodec/avcodec.h | 8 ++++ libavcodec/bitpacked.c | 127 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 118 insertions(+), 17 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index fb0c6fa..14811be 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1480,6 +1480,14 @@ typedef struct AVPacket { */ #define AV_PKT_FLAG_DISPOSABLE 0x0010 +/** + * The packet contains a top field. + */ +#define AV_PKT_FLAG_TOP_FIELD 0x0020 +/** + * The packet contains a bottom field. + */ +#define AV_PKT_FLAG_BOTTOM_FIELD 0x0040 enum AVSideDataParamChangeFlags { AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, diff --git a/libavcodec/bitpacked.c b/libavcodec/bitpacked.c index f0b417d..7c5221d 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 */ @@ -60,25 +61,39 @@ static int bitpacked_decode_yuv422p10(AVCodecContext *avctx, AVFrame *frame, { uint64_t frame_size = (uint64_t)avctx->width * (uint64_t)avctx->height * 20; 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; + /* + * 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); 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,72 @@ 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) { + if (bc->prev_top_field) + av_log(avctx, AV_LOG_WARNING, "Consecutive top field detected.\n"); + + frame->interlaced_frame = 1; + frame->top_field_first = 1; + + if (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) { + res = ff_get_buffer(avctx, frame, 0); + if (res < 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_WARNING, "Top field missing.\n"); + return 0; + } + + 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; - *got_frame = 1; - return buf_size; + 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 (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) { + res = ff_get_buffer(avctx, frame, 0); + if (res < 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 +236,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, };