From patchwork Thu Aug 16 11:56:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasile Toncu X-Patchwork-Id: 10005 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:104:0:0:0:0:0 with SMTP id c4-v6csp1942839jad; Thu, 16 Aug 2018 05:02:17 -0700 (PDT) X-Google-Smtp-Source: AA+uWPz3uxOiwplE54DItfxkmAXf/GzkfQfcjmsYUg1eGDCcu0u9UPngaSAirHyiNDrnCiA26eae X-Received: by 2002:adf:94c6:: with SMTP id 64-v6mr14287437wrr.99.1534420937160; Thu, 16 Aug 2018 05:02:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1534420937; cv=none; d=google.com; s=arc-20160816; b=wtKzsq5g6X0Z7O2mH7u9uX8+mYHoENNUWHtw+Kj8EC1EXgNOpuI/0gK/T684wUCh9S PzGVTpd94r+/+qHniAnxco/0+zn30hcBeyhRC2iRWHNDN2Ipv/t+9Wq4IeLoFEIu1Soc rNoljrpwl/Dp8HwlUoacWJ5sUj2zeTblebnY0DNpQYQlVdH6VMFquXaJk9QWG7lLKdmA xhUL0FypsKUMyNRt/3XwjV63B1/e1KW4edmGH+4SpXO5ecdTzjCyYIfPtkz/texFP0zn M234yDEaLWf1H7ZnK4nOs1YBsfAMJnvZV4tCtbm88qLen4z8lR0cXeecsBXvN7nJ7ngP +a4A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to :message-id:date:from:references:in-reply-to:mime-version :dkim-signature:delivered-to:arc-authentication-results; bh=VxX98GO6mf9415z017wAwaXYDJV3fczG2BcMRpDe2gg=; b=MNvmltvcaFGguII09Q5+5Yw9XxGSxrxZp8/LvhPdXwOHPOJ+qw+iw8M5yN8fI8Qewz Wg1ECNn51pkETrWA3H7Tx4k07sZPsjUkJaMMSExAN/hkwAQTO1r8Z543N39IWT8matDI UDCm6/HDBlcMYMptAMUL0G4WUJdpll4a5vbWWCOixIzudDNCII3wVKGxC5YnIor/VrM4 osOYCbXN1mbDSWM8h0FHJnWYhkKcUVATb7pjJ96fILKxOrHWTZxeuJDg0/OTRFULzvTT lIzBVrs1az9OKBsPAnOKgqtqUQuuaCsRq4wApabIGI1/+uh6UYhAhAA8LUtT9hhTpWIP Gb/w== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@tremend-com.20150623.gappssmtp.com header.s=20150623 header.b=WWQDhIJR; 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 v21-v6si21150474wrc.122.2018.08.16.05.02.15; Thu, 16 Aug 2018 05:02:17 -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; dkim=neutral (body hash did not verify) header.i=@tremend-com.20150623.gappssmtp.com header.s=20150623 header.b=WWQDhIJR; 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 D816868A73F; Thu, 16 Aug 2018 15:01:48 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f54.google.com (mail-wm0-f54.google.com [74.125.82.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C79FA68A426 for ; Thu, 16 Aug 2018 15:01:42 +0300 (EEST) Received: by mail-wm0-f54.google.com with SMTP id w24-v6so4099690wmc.1 for ; Thu, 16 Aug 2018 05:02:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tremend-com.20150623.gappssmtp.com; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to; bh=fV0ncdYXtskRR1+j5Olp1c/GMllcfFbNIuRTKYe0nk4=; b=WWQDhIJR7255wcNe+1w8Xx8vKCQNl2Oh5T0JG3hPlfn3ZnAzFnTo7wkene5a21b0Ho IZJrEYN6hhbPKPMmlShn6QbHTMz3BDgjcYAhSoxw07Pq+CXZ1l9cEPAa+4CGLSvNtSC9 tDK/wQnCWjybMYZyIM514ob5cwjs5ukQSsgp0yt+/4+OgTIcGWPfo6i5b8rKH6YawHpg IeYkqr9AzJqYpfqdyKA4GOTXR99R3hTPYfYiYYBQQFFcPKV5K/+Z+Mwiw9JLnaY/bj1u 81SA9BQ6e4C/M5XBCXk2yJRZBFE3xdrwjJHnGNyiiuEQd7r0YnHe2EAiT6KqZCKY1BR3 EvNQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=fV0ncdYXtskRR1+j5Olp1c/GMllcfFbNIuRTKYe0nk4=; b=q+g8K6yT9Xl83VlvKgJ2RLKGtjtzUlP9mprBYVe47Juj9IMZlrrf8AoPja8MT0a7Og 9dTGIP2NLgPwZQWExZvmGv7/Tqb0dNv1B8nxDM9WhlaSKQkiJQefXaQPRN8HK9fjUJYz SSGMae3FQxJ8kMMjx3HGpX6X4mNqoKBMQOL1yAqwKNjqhL6HANH/zk75p638ZgoR4SFY KdctWOuxz4pTVND4erdWN33Gd8dPGw/cGaL38vBWLqRzHFuGXmsqnZZoDENsnILFdxFT cFfhyIB4facu0mkKifs/qgl/dNNLUNHknF6SP7voRSQsYA/29R2/lxF0ykvGpd/5xkdl 7l4w== X-Gm-Message-State: AOUpUlHTlmJoODKpOApbPjkFREvDVJwLw7HTYzZCj2nv5jtPiuD/gwdn jek17r/ydDeeLw6XVld5WQc642c+F4GfpSEwAw8AWTh3uEw= X-Received: by 2002:a1c:8f0e:: with SMTP id r14-v6mr17018651wmd.79.1534420611542; Thu, 16 Aug 2018 04:56:51 -0700 (PDT) MIME-Version: 1.0 Received: by 2002:a1c:1d86:0:0:0:0:0 with HTTP; Thu, 16 Aug 2018 04:56:50 -0700 (PDT) In-Reply-To: References: <2e625e61-7c13-3f0b-4013-b093aaf711ce@tremend.com> From: Vasile Toncu Date: Thu, 16 Aug 2018 13:56:50 +0200 Message-ID: To: FFmpeg development discussions and patches X-Content-Filtered-By: Mailman/MimeDel 2.1.20 Subject: Re: [FFmpeg-devel] [PATCH 3/5] Renamed reinterlace to tinterlace 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Hi, Thank you for the additional testing effort. Fixed the issue. On Tue, Aug 14, 2018 at 10:25 PM, Thomas Mundt wrote: > Hi, > > 2018-08-14 18:53 GMT+02:00 Vasile Toncu : > > > Hi Thomas, > > > > I added the log messages. > > > > Thanks for the review. > > > > I found some more time for testing this evening. Unfortunately there are > still issues. > I get half green pictures with some modes at high bit depth. > But the fix is easy. > The bytewidth in all av_image_copy_plane functions need to be adapted for > high bit depths. > > {....} > > const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out-> > format); > > int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1); > > > > You used the calculated "mult" in the av_image_copy_plane functions of > MODE_MERGE and MODE_PAD only. > And forgot the others: > > > > {....} > > > + case MODE_INTERLEAVE_BOTTOM: > > + case MODE_INTERLEAVE_TOP: > > + y = y * 2; > > + > > + if (tinterlace->flags & FLAG_VLPF || tinterlace->flags & > > FLAG_CVLPF) { > > + int clip_max = (1 << fmt_desc->comp[plane].depth) - 1; > > + > > + interleave_filter_frame(tinterlace, first, out, plane, > > !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == > MODE_INTERLEAVE_TOP, > > x, y, clip_max); > > + interleave_filter_frame(tinterlace, second, out, plane, > > !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == > > MODE_INTERLEAVE_BOTTOM, x, y, clip_max); > > } else { > > - if (tinterlace->csp->comp[plane].depth > 8) > > - cols *= 2; > > - av_image_copy_plane(dstp, dstp_linesize, srcp, > srcp_linesize, > > cols, lines); > > + offset1 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : > > out->linesize[plane]; > > + offset2 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : > > first->linesize[plane]; > > + offset3 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? > > out->linesize[plane] : 0; > > + offset4 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? > > second->linesize[plane] : 0; > > + > > + av_image_copy_plane(out->data[plane] + offset1, 2 * > > out->linesize[plane], > > + first->data[plane] + offset2, 2 * > first->linesize[plane], > > + first->width / x, first->height / y); > > + av_image_copy_plane(out->data[plane] + offset3, 2 * > > out->linesize[plane], > > + second->data[plane] + offset4, 2 * > > second->linesize[plane], > > + second->width / x, second->height / y); > > > > Here > > } > > + break; > > + > > + case MODE_INTERLACE_X2: > > + y = y * 2; > > + > > + offset1 = 0; offset2 = 0; > > + offset3 = out->linesize[plane]; > > + offset4 = second->linesize[plane]; > > + > > + if (second->interlaced_frame && second->top_field_first) { > > + offset1 = out->linesize[plane]; > > + offset2 = first->linesize[plane]; > > + offset3 = 0; offset4 = 0; > > + } > > + > > + av_image_copy_plane(out->data[plane] + offset1, 2 * > > out->linesize[plane], > > + first->data[plane] + offset2, 2 * first->linesize[plane], > > + first->width / x, first->height / y); > > + av_image_copy_plane(out->data[plane] + offset3, 2 * > > out->linesize[plane], > > + second->data[plane] + offset4, 2 * second->linesize[plane], > > + second->width / x, second->height / y); > > > > Here > > + break; > > + > > + case MODE_MERGE_X2: > > + if (IS_ODD(tinterlace->current_frame_index - 1)) { > > + av_image_copy_plane(out->data[plane], 2 * > > out->linesize[plane], > > + second->data[plane], second->linesize[plane], > > second->width / x, second->height / y); > > + av_image_copy_plane(out->data[plane] + > out->linesize[plane], > > 2 * out->linesize[plane], > > + first->data[plane], first->linesize[plane], first->width > > / x, first->height / y); > > + } else { > > + av_image_copy_plane(out->data[plane], 2 * > > out->linesize[plane], > > + first->data[plane], first->linesize[plane], first->width > > / x, first->height / y); > > + av_image_copy_plane(out->data[plane] + > out->linesize[plane], > > 2 * out->linesize[plane], > > + second->data[plane], second->linesize[plane], > > second->width / x, second->height / y); > > > > Here. > > Sorry for the piecemeal. > > Regards, > Thomas > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > http://ffmpeg.org/mailman/listinfo/ffmpeg-devel > From c00141a51b3ddbb24080fb8fdf1a056af528856f Mon Sep 17 00:00:00 2001 From: Vasile Toncu Date: Tue, 24 Jul 2018 12:02:16 +0200 Subject: [PATCH] Patch 3 - Move reinterlace to tinterlace --- configure | 1 - libavfilter/Makefile | 1 - libavfilter/allfilters.c | 1 - libavfilter/reinterlace.h | 105 ---- libavfilter/tinterlace.h | 96 ++-- libavfilter/vf_reinterlace.c | 775 -------------------------- libavfilter/vf_tinterlace.c | 697 +++++++++++++---------- libavfilter/x86/Makefile | 1 - libavfilter/x86/vf_reinterlace_init.c | 102 ---- libavfilter/x86/vf_tinterlace_init.c | 41 +- 10 files changed, 492 insertions(+), 1328 deletions(-) delete mode 100644 libavfilter/reinterlace.h delete mode 100644 libavfilter/vf_reinterlace.c delete mode 100644 libavfilter/x86/vf_reinterlace_init.c diff --git a/configure b/configure index e718c1531c..8f42a86f8f 100755 --- a/configure +++ b/configure @@ -3420,7 +3420,6 @@ stereo3d_filter_deps="gpl" subtitles_filter_deps="avformat avcodec libass" super2xsai_filter_deps="gpl" pixfmts_super2xsai_test_deps="super2xsai_filter" -tinterlace_filter_deps="gpl" tinterlace_merge_test_deps="tinterlace_filter" tinterlace_pad_test_deps="tinterlace_filter" tonemap_filter_deps="const_nan" diff --git a/libavfilter/Makefile b/libavfilter/Makefile index c8ba079750..245302bbe8 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -246,7 +246,6 @@ OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o OBJS-$(CONFIG_INFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_INTERLACE_FILTER) += vf_tinterlace.o -OBJS-$(CONFIG_REINTERLACE_FILTER) += vf_reinterlace.o OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o OBJS-$(CONFIG_LENSCORRECTION_FILTER) += vf_lenscorrection.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9956776938..2d19929bdc 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -348,7 +348,6 @@ extern AVFilter ff_vf_thumbnail; extern AVFilter ff_vf_thumbnail_cuda; extern AVFilter ff_vf_tile; extern AVFilter ff_vf_tinterlace; -extern AVFilter ff_vf_reinterlace; extern AVFilter ff_vf_tlut2; extern AVFilter ff_vf_tmix; extern AVFilter ff_vf_tonemap; diff --git a/libavfilter/reinterlace.h b/libavfilter/reinterlace.h deleted file mode 100644 index cb512c7639..0000000000 --- a/libavfilter/reinterlace.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2017 Vasile Toncu - * Copyright (c) 2017 Thomas Mundt - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Reinterlace filter - */ - -#ifndef AVFILTER_REINTERLACE_H -#define AVFILTER_REINTERLACE_H - -#include "avfilter.h" -#include "formats.h" -#include "internal.h" -#include "video.h" -#include "libavutil/avassert.h" -#include "libavutil/imgutils.h" -#include "libavutil/opt.h" -#include "libavutil/pixdesc.h" -#include "libavutil/bswap.h" - -enum FilterMode { - MODE_MERGE, - MODE_DROP_EVEN, - MODE_DROP_ODD, - MODE_PAD, - MODE_INTERLEAVE_TOP, - MODE_INTERLEAVE_BOTTOM, - MODE_INTERLACE_X2, - MODE_MERGE_X2, - MODE_MERGE_TFF, - MODE_MERGE_BFF, - MODE_NB, - }; - -enum FilterFlags { - FLAG_NOTHING = 0x00, - FLAG_VLPF = 0x01, - FLAG_EXACT_TB = 0x02, - FLAG_CVLPF = 0x04, - FLAG_NB -}; - -typedef struct { - const AVClass *class; - int mode; - int flags; - - AVFrame *prev_frame, *current_frame; - int64_t current_frame_index; - - uint8_t *black_vec[4]; - int black_linesize[4]; - - int skip_next_frame; - - void *thread_data; - - uint8_t bit_depth; - - void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, - ptrdiff_t mref, ptrdiff_t pref, int clip_max); - - AVRational preout_time_base; - - } ReInterlaceContext; - -#if CONFIG_GPL -void ff_reinterlace_init_x86(ReInterlaceContext *reinterlace); -#endif - -#define OFFSET(x) offsetof(ReInterlaceContext, x) -#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM - -#define IS_ODD(value) (value & 1) - -typedef struct ReInterlaceThreadData { - AVFrame *out, *first, *second; - int plane; - ReInterlaceContext *reinterlace; - - int scale_w_plane12_factor; - int scale_h_plane12_factor; - -} ReInterlaceThreadData; - -#endif /* AVFILTER_REINTERLACE_H */ diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h index b5c39aac52..19381985a3 100644 --- a/libavfilter/tinterlace.h +++ b/libavfilter/tinterlace.h @@ -1,72 +1,90 @@ /* - * Copyright (c) 2011 Stefano Sabatini - * Copyright (c) 2010 Baptiste Coudurier - * Copyright (c) 2003 Michael Zucchi + * Copyright (c) 2017 Vasile Toncu + * Copyright (c) 2017 Thomas Mundt * * This file is part of FFmpeg. * - * FFmpeg is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with FFmpeg; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file - * temporal field interlace filter, ported from MPlayer/libmpcodecs + * TInterlace filter */ + #ifndef AVFILTER_TINTERLACE_H #define AVFILTER_TINTERLACE_H -#include "libavutil/bswap.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "drawutils.h" -#include "avfilter.h" - -#define TINTERLACE_FLAG_VLPF 01 -#define TINTERLACE_FLAG_EXACT_TB 2 -#define TINTERLACE_FLAG_CVLPF 4 +#include "libavutil/bswap.h" -enum TInterlaceMode { - MODE_MERGE = 0, +enum FilterMode { + MODE_MERGE, MODE_DROP_EVEN, MODE_DROP_ODD, MODE_PAD, MODE_INTERLEAVE_TOP, MODE_INTERLEAVE_BOTTOM, - MODE_INTERLACEX2, - MODE_MERGEX2, + MODE_INTERLACE_X2, + MODE_MERGE_X2, MODE_NB, + }; + +enum FilterFlags { + FLAG_NOTHING = 0x00, + FLAG_VLPF = 0x01, + FLAG_EXACT_TB = 0x02, + FLAG_CVLPF = 0x04, + FLAG_NB }; -typedef struct TInterlaceContext { +typedef struct { const AVClass *class; - int mode; ///< TInterlaceMode, interlace mode selected - AVRational preout_time_base; - int flags; ///< flags affecting interlacing algorithm - int frame; ///< number of the output frame - int vsub; ///< chroma vertical subsampling - AVFrame *cur; - AVFrame *next; - uint8_t *black_data[4]; ///< buffer used to fill padded lines + int mode; + int flags; + + AVFrame *prev_frame, *current_frame; + int64_t current_frame_index; + + uint8_t *black_vec[4]; int black_linesize[4]; - FFDrawContext draw; - FFDrawColor color; - const AVPixFmtDescriptor *csp; + + int skip_next_frame; + + uint8_t bit_depth; + void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, - ptrdiff_t mref, ptrdiff_t pref, int clip_max); -} TInterlaceContext; + ptrdiff_t mref, ptrdiff_t pref, int clip_max); + + AVRational preout_time_base; + + } TInterlaceContext; + +#if CONFIG_GPL +void ff_tinterlace_init_x86(TInterlaceContext *tinterlace); +#endif -void ff_tinterlace_init_x86(TInterlaceContext *interlace); +#define IS_ODD(value) (value & 1) +#define OFFSET(x) offsetof(TInterlaceContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM #endif /* AVFILTER_TINTERLACE_H */ diff --git a/libavfilter/vf_reinterlace.c b/libavfilter/vf_reinterlace.c deleted file mode 100644 index d3f8f374ae..0000000000 --- a/libavfilter/vf_reinterlace.c +++ /dev/null @@ -1,775 +0,0 @@ -/* - * Copyright (c) 2018 Vasile Toncu - * Copyright (c) 2017 Thomas Mundt - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * Reinterlace filter - */ - -#include "libavutil/pixdesc.h" -#include "libavutil/imgutils.h" -#include "drawutils.h" -#include "reinterlace.h" - -static const AVRational standard_tbs[] = { - {1, 25}, - {1, 30}, - {1001, 30000}, -}; - -static const AVOption reinterlace_options[] = { - { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB - 1, FLAGS, "mode" }, - { "merge", "merge frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "drop_even", "drop even frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "drop_odd", "drop odd frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "pad", "pad lines of a frame with black lines", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "interleave_top", "interleave top and bottom frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "interleave_bottom", "interleave bottom and top frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "interlacex2", "interlace consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACE_X2}, INT_MIN, INT_MAX, FLAGS, "mode"}, - { "mergex2", "just like merge, but at the same frame rate", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE_X2}, INT_MIN, INT_MAX, FLAGS, "mode"}, - - { "flags", "add flag for reinterlace", OFFSET(flags), AV_OPT_TYPE_INT, {.i64=FLAG_NOTHING}, 0, 0xFF, FLAGS, "flags" }, - { "low_pass_filter", "low pass fitler", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"}, - { "vlpf", "low pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"}, - { "complex_filter", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, - { "cvlpf", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, - { "exact_tb", "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" }, - { NULL } -}; - -AVFILTER_DEFINE_CLASS(reinterlace); - -static av_cold int init(AVFilterContext *ctx) -{ - ReInterlaceContext *reinterlace = ctx->priv; - int i; - - for (i = 0; i < 4; i++) - reinterlace->black_vec[i] = NULL; - - reinterlace->thread_data = av_malloc(4 * sizeof(ReInterlaceThreadData)); - if (!reinterlace->thread_data) - return AVERROR(ENOMEM); - - return 0; -} - -static int query_formats(AVFilterContext *ctx) -{ - static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, - AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE, - AV_PIX_FMT_YUV440P10LE, AV_PIX_FMT_YUV444P10LE, - AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV422P12LE, - AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE, - AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, - AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, - AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_NONE - }; - - AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); - - if (!fmts_list) - return AVERROR(ENOMEM); - - return ff_set_common_formats(ctx, fmts_list); -} - -static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, - ptrdiff_t mref, ptrdiff_t pref, int clip_max) -{ - const uint8_t *srcp_above = srcp + mref; - const uint8_t *srcp_below = srcp + pref; - int i; - for (i = 0; i < width; i++) { - // this calculation is an integer representation of - // '0.5 * current + 0.25 * above + 0.25 * below' - // '1 +' is for rounding. - dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2; - } -} - -static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, - ptrdiff_t mref, ptrdiff_t pref, int clip_max) -{ - uint16_t *dstp = (uint16_t *)dst8; - const uint16_t *srcp = (const uint16_t *)src8; - const uint16_t *srcp_above = srcp + mref / 2; - const uint16_t *srcp_below = srcp + pref / 2; - int i, src_x; - for (i = 0; i < width; i++) { - // this calculation is an integer representation of - // '0.5 * current + 0.25 * above + 0.25 * below' - // '1 +' is for rounding. - src_x = av_le2ne16(srcp[i]) << 1; - dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i]) - + av_le2ne16(srcp_below[i])) >> 2); - } -} - -static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, - ptrdiff_t mref, ptrdiff_t pref, int clip_max) -{ - const uint8_t *srcp_above = srcp + mref; - const uint8_t *srcp_below = srcp + pref; - const uint8_t *srcp_above2 = srcp + mref * 2; - const uint8_t *srcp_below2 = srcp + pref * 2; - int i, src_x, src_ab; - for (i = 0; i < width; i++) { - // this calculation is an integer representation of - // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2' - // '4 +' is for rounding. - src_x = srcp[i] << 1; - src_ab = srcp_above[i] + srcp_below[i]; - dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1) - - srcp_above2[i] - srcp_below2[i]) >> 3); - // Prevent over-sharpening: - // dst must not exceed src when the average of above and below - // is less than src. And the other way around. - if (src_ab > src_x) { - if (dstp[i] < srcp[i]) - dstp[i] = srcp[i]; - } else if (dstp[i] > srcp[i]) - dstp[i] = srcp[i]; - } -} - -static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, - ptrdiff_t mref, ptrdiff_t pref, int clip_max) -{ - uint16_t *dstp = (uint16_t *)dst8; - const uint16_t *srcp = (const uint16_t *)src8; - const uint16_t *srcp_above = srcp + mref / 2; - const uint16_t *srcp_below = srcp + pref / 2; - const uint16_t *srcp_above2 = srcp + mref; - const uint16_t *srcp_below2 = srcp + pref; - int i, dst_le, src_le, src_x, src_ab; - for (i = 0; i < width; i++) { - // this calculation is an integer representation of - // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2' - // '4 +' is for rounding. - src_le = av_le2ne16(srcp[i]); - src_x = src_le << 1; - src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]); - dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1) - - av_le2ne16(srcp_above2[i]) - - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max); - // Prevent over-sharpening: - // dst must not exceed src when the average of above and below - // is less than src. And the other way around. - if (src_ab > src_x) { - if (dst_le < src_le) - dstp[i] = av_le2ne16(src_le); - else - dstp[i] = av_le2ne16(dst_le); - } else if (dst_le > src_le) { - dstp[i] = av_le2ne16(src_le); - } else - dstp[i] = av_le2ne16(dst_le); - } -} - -/** - * alocate memory for a black frame - */ -static int init_black_buffers(ReInterlaceContext *reinterlace, AVFilterLink *outlink) -{ - FFDrawContext ctx; - FFDrawColor color; - int ret; - int format = outlink->format; - - if ((ret = av_image_alloc(reinterlace->black_vec, reinterlace->black_linesize, - outlink->w, outlink->h, outlink->format, 16)) < 0) - return ret; - - ff_draw_init(&ctx, outlink->format, 0); - ff_draw_color(&ctx, &color, (uint8_t[]){0, 0, 0, 16}); - if (format == AV_PIX_FMT_YUVJ420P || - format == AV_PIX_FMT_YUVJ422P || - format == AV_PIX_FMT_YUVJ440P || - format == AV_PIX_FMT_YUVJ444P) - color.comp[0].u8[0] = 0; - ff_fill_rectangle(&ctx, &color, reinterlace->black_vec, - reinterlace->black_linesize, 0, 0, outlink->w, outlink->h); - - return 0; -} - -static int config_out_props(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - AVFilterLink *inlink = outlink->src->inputs[0]; - ReInterlaceContext *reinterlace = ctx->priv; - const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(outlink->format); - int reinterlace_mode = reinterlace->mode; - int ret, i; - - reinterlace->bit_depth = fmt_desc->comp[0].depth; - reinterlace->preout_time_base = inlink->time_base; - - switch (reinterlace_mode) { - case MODE_PAD: - outlink->w = inlink->w; - outlink->h = 2 * inlink->h; - outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1)); - - ret = init_black_buffers(reinterlace, outlink); - if (ret < 0) - return ret; - break; - - case MODE_DROP_EVEN: - case MODE_DROP_ODD: - outlink->w = inlink->w; - outlink->h = inlink->h; - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); - outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); - break; - - case MODE_INTERLEAVE_TOP: - case MODE_INTERLEAVE_BOTTOM: - outlink->w = inlink->w; - outlink->h = inlink->h; - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); - outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); - break; - - case MODE_INTERLACE_X2: - outlink->w = inlink->w; - outlink->h = inlink->h; - reinterlace->preout_time_base.den *= 2; - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1}); - outlink->time_base = av_mul_q(inlink->time_base , (AVRational){1,2}); - break; - - case MODE_MERGE_X2: - outlink->w = inlink->w; - outlink->h = 2 * inlink->h; - outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1)); - outlink->frame_rate = inlink->frame_rate; - outlink->time_base = inlink->time_base; - break; - - case MODE_MERGE: - case MODE_MERGE_BFF: - case MODE_MERGE_TFF: - outlink->w = inlink->w; - outlink->h = 2 * inlink->h; - outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1)); - outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); - outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); - break; - - default: - av_log(ctx, AV_LOG_VERBOSE, "invalid value for mode"); - av_assert0(0); - - } - - for (i = 0; i < FF_ARRAY_ELEMS(standard_tbs); i++) { - if (!av_cmp_q(standard_tbs[i], outlink->time_base)) - break; - } - if (i == FF_ARRAY_ELEMS(standard_tbs) || (reinterlace->flags & FLAG_EXACT_TB) ) - outlink->time_base = reinterlace->preout_time_base; - - if (reinterlace->flags & FLAG_VLPF || reinterlace->flags & FLAG_CVLPF) { - - if (reinterlace_mode != MODE_INTERLEAVE_TOP && reinterlace_mode != MODE_INTERLEAVE_BOTTOM) { - reinterlace->flags &= ~(FLAG_VLPF | FLAG_CVLPF); - } else { - reinterlace->lowpass_line = (reinterlace->flags & FLAG_VLPF) ? lowpass_line_c : lowpass_line_complex_c; - - if (reinterlace->bit_depth > 8) { - reinterlace->lowpass_line = (reinterlace->flags & FLAG_VLPF) ? lowpass_line_c_16 : lowpass_line_complex_c_16; - } - -#if CONFIG_GPL - if (ARCH_X86) { - ff_reinterlace_init_x86(reinterlace); - } -#endif - } - - } - - return 0; -} - -static int filter_frame_plane(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - // jobnr is usualy plane number - ReInterlaceThreadData *rtd = arg; - ReInterlaceContext *reinterlace = rtd->reinterlace; - AVFrame *first = rtd->first; - AVFrame *second = rtd->second; - AVFrame *out = rtd->out; - - int plane = rtd->plane; - int reinterlace_mode = reinterlace->mode; - - int x = (plane == 1 || plane == 2) ? rtd->scale_w_plane12_factor : 1; - int y = (plane == 1 || plane == 2) ? rtd->scale_h_plane12_factor : 1; - int i, ls_offset; - int offset1, offset2, offset3, offset4; - - const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out->format); - int clip_max = (1 << fmt_desc->comp[plane].depth) - 1; - int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1); - - switch (reinterlace_mode) { - case MODE_MERGE: - av_image_copy_plane(out->data[plane], 2 * out->linesize[plane], - first->data[plane], first->linesize[plane], mult * first->width / x, first->height / y); - av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane], - second->data[plane], second->linesize[plane], mult * second->width / x, second->height / y); - break; - - case MODE_PAD: - ls_offset = (reinterlace->current_frame_index & 1) ? 0 : out->linesize[plane]; - av_image_copy_plane(out->data[plane] + ls_offset, 2 * out->linesize[plane], - second->data[plane], second->linesize[plane], mult * second->width / x, second->height / y); - av_image_copy_plane(out->data[plane] + out->linesize[plane] - ls_offset, 2 * out->linesize[plane], - reinterlace->black_vec[plane], reinterlace->black_linesize[plane], mult * second->width / x, second->height / y); - break; - - case MODE_INTERLEAVE_BOTTOM: - case MODE_INTERLEAVE_TOP: - y = y * 2; - - if (reinterlace->flags & FLAG_VLPF || reinterlace->flags & FLAG_CVLPF) { - - int lines, cols, cvlfp; - AVFrame *from_frame; - uint8_t *from, *to; - int from_step, to_step; - - lines = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? (2 * out->height / y + 1) / 2 : (2 * out->height / y + 0) / 2; - cols = out->width / x; - from_frame = first; - from = from_frame->data[plane]; - to = out->data[plane]; - - if (reinterlace_mode == MODE_INTERLEAVE_BOTTOM) { - from = from + from_frame->linesize[plane]; - to = to + out->linesize[plane]; - } - - from_step = 2 * from_frame->linesize[plane]; - to_step = 2 * out->linesize[plane]; - - // when i = lines - aka first line - reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max); - to += to_step; - from += from_step; - - cvlfp = !!(reinterlace->flags & FLAG_CVLPF); - if (cvlfp) { - reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max); - to += to_step; - from += from_step; - } - - for (i = lines - 2 - 2 * cvlfp; i; i--) { - reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], -from_frame->linesize[plane], clip_max); - to += to_step; - from += from_step; - } - - // when i == 1 - aka last line - reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max); - to += to_step; - from += from_step; - - if (cvlfp) { - reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max); - to += to_step; - from += from_step; - } - - - lines = (reinterlace_mode == MODE_INTERLEAVE_BOTTOM) ? ((2 * out->height / y) + 1) / 2 : (2 * out->height / y + 0) / 2; - cols = out->width / x; - from_frame = second; - from = from_frame->data[plane]; - to = out->data[plane]; - - if (reinterlace_mode == MODE_INTERLEAVE_TOP) { - from = from + from_frame->linesize[plane]; - to = to + out->linesize[plane]; - } - - from_step = 2 * from_frame->linesize[plane]; - to_step = 2 * out->linesize[plane]; - - // when i = lines - reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max); - to += to_step; - from += from_step; - - if (cvlfp) { - reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max); - to += to_step; - from += from_step; - } - - - for (i = lines - 2 - 2 * cvlfp; i; i--) { - reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], -from_frame->linesize[plane], clip_max); - to += to_step; - from += from_step; - } - - // when i == 1 - reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max); - to += to_step; - from += from_step; - - if (cvlfp) { - reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max); - to += to_step; - from += from_step; - } - - } else { - offset1 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : out->linesize[plane]; - offset2 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : first->linesize[plane]; - offset3 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? out->linesize[plane] : 0; - offset4 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? second->linesize[plane] : 0; - - av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane], - first->data[plane] + offset2, 2 * first->linesize[plane], - first->width / x, first->height / y); - av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane], - second->data[plane] + offset4, 2 * second->linesize[plane], - second->width / x, second->height / y); - } - break; - - case MODE_INTERLACE_X2: - y = y * 2; - - offset1 = 0; offset2 = 0; - offset3 = out->linesize[plane]; - offset4 = second->linesize[plane]; - - if (second->interlaced_frame && second->top_field_first) { - offset1 = out->linesize[plane]; - offset2 = first->linesize[plane]; - offset3 = 0; offset4 = 0; - } - - av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane], - first->data[plane] + offset2, 2 * first->linesize[plane], - first->width / x, first->height / y); - av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane], - second->data[plane] + offset4, 2 * second->linesize[plane], - second->width / x, second->height / y); - break; - - case MODE_MERGE_X2: - if (IS_ODD(reinterlace->current_frame_index - 1)) { - av_image_copy_plane(out->data[plane], 2 * out->linesize[plane], - second->data[plane], second->linesize[plane], second->width / x, second->height / y); - av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane], - first->data[plane], first->linesize[plane], first->width / x, first->height / y); - } else { - av_image_copy_plane(out->data[plane], 2 * out->linesize[plane], - first->data[plane], first->linesize[plane], first->width / x, first->height / y); - av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane], - second->data[plane], second->linesize[plane], second->width / x, second->height / y); - } - break; - - case MODE_MERGE_TFF: - case MODE_MERGE_BFF: - offset1 = (reinterlace_mode == MODE_MERGE_TFF) ? 0 : out->linesize[plane]; - offset2 = (reinterlace_mode == MODE_MERGE_TFF) ? out->linesize[plane] : 0; - - av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane], - first->data[plane], first->linesize[plane], first->width / x, first->height / y); - av_image_copy_plane(out->data[plane] + offset2, 2 * out->linesize[plane], - second->data[plane], second->linesize[plane], second->width / x, second->height / y); - break; - - default: - break; - } - - return 0; -} - -static ReInterlaceThreadData *get_ReInterlaceThreadData(AVFrame *out, AVFrame *first, AVFrame *second, - int plane, ReInterlaceContext *reinterlace, - int scale_w_plane12_factor, - int scale_h_plane12_factor) -{ - ReInterlaceThreadData *rtd = &((ReInterlaceThreadData *)reinterlace->thread_data)[plane]; - - if (!rtd) - return rtd; - - rtd->out = out; - rtd->first = first; - rtd->second = second; - rtd->plane = plane; - rtd->reinterlace = reinterlace; - rtd->scale_h_plane12_factor = scale_h_plane12_factor; - rtd->scale_w_plane12_factor = scale_w_plane12_factor; - - return rtd; -} - -static void copy_all_planes(AVFilterContext *ctx, - ReInterlaceContext *reinterlace, - const AVPixFmtDescriptor *desc, - AVFrame *out, AVFrame *first, AVFrame *second) -{ - int scale_w_plane12_factor = 1 << desc->log2_chroma_w; - int scale_h_plane12_factor = 1 << desc->log2_chroma_h; - int plane; - - for (plane = 0; plane < desc->nb_components; plane++) { - - ReInterlaceThreadData *rtd = get_ReInterlaceThreadData(out, first, second, - plane, reinterlace, scale_w_plane12_factor, scale_h_plane12_factor); - - ctx->internal->execute(ctx, filter_frame_plane, rtd, NULL, FFMIN(desc->nb_components, ctx->graph->nb_threads)); - } -} - -static int filter_frame(AVFilterLink *inlink, AVFrame *in) -{ - AVFilterContext *ctx = inlink->dst; - ReInterlaceContext *reinterlace = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); - AVFrame *out, *first, *second; - int ret; - - int reinterlace_mode = reinterlace->mode; - - av_frame_free(&(reinterlace->prev_frame)); - reinterlace->prev_frame = reinterlace->current_frame; - reinterlace->current_frame = in; - reinterlace->current_frame_index++; - - // we process two frames at a time, thus only even frame indexes are considered - if (IS_ODD(reinterlace->current_frame_index)) { - if (reinterlace_mode == MODE_PAD || reinterlace_mode == MODE_MERGE_X2 - || reinterlace_mode == MODE_INTERLACE_X2 || reinterlace_mode == MODE_MERGE_BFF - || reinterlace_mode == MODE_MERGE_TFF) { - // continue - } else { - return 0; - } - } - - first = reinterlace->prev_frame; - second = reinterlace->current_frame; - - switch (reinterlace_mode) { - case MODE_DROP_EVEN: - case MODE_DROP_ODD: - out = (reinterlace_mode == MODE_DROP_ODD) ? reinterlace->current_frame : reinterlace->prev_frame; - out = av_frame_clone(out); - - if (!out) - return AVERROR(ENOMEM); - - out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - break; - - case MODE_MERGE: - case MODE_MERGE_X2: - case MODE_MERGE_TFF: - case MODE_MERGE_BFF: - if (reinterlace_mode == MODE_MERGE_X2 && reinterlace->current_frame_index == 1) - return 0; - - if (reinterlace_mode == MODE_MERGE_BFF || reinterlace_mode == MODE_MERGE_TFF) { - if (!first) - return 0; - - if (reinterlace->skip_next_frame) { - reinterlace->skip_next_frame = 0; - return 0; - } - - if (first->interlaced_frame == 1 && second->interlaced_frame == 1) - { - if (first->top_field_first == second->top_field_first) - return 0; - else if (reinterlace->mode == MODE_MERGE_BFF && first->top_field_first != 0) - return 0; - else if (reinterlace->mode == MODE_MERGE_TFF && first->top_field_first != 1) - return 0; - } - } - - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - - if (!out) - return AVERROR(ENOMEM); - - av_frame_copy_props(out, first); - out->sample_aspect_ratio = av_mul_q(first->sample_aspect_ratio, av_make_q(2, 1)); - out->interlaced_frame = 1; - out->top_field_first = reinterlace_mode == MODE_MERGE_BFF ? 0 : 1; - out->height = outlink->h; - - copy_all_planes(ctx, reinterlace, desc, out, first, second); - - if (reinterlace_mode == MODE_MERGE_BFF || reinterlace_mode == MODE_MERGE_TFF) - reinterlace->skip_next_frame = 1; - - out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - break; - - case MODE_PAD: - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - - if (!out) - return AVERROR(ENOMEM); - - av_frame_copy_props(out, second); - out->sample_aspect_ratio = av_mul_q(second->sample_aspect_ratio, av_make_q(2, 1)); - out->height = outlink->h; - - copy_all_planes(ctx, reinterlace, desc, out, first, second); - - out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - break; - - case MODE_INTERLEAVE_BOTTOM: - case MODE_INTERLEAVE_TOP: - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - - if (!out) - return AVERROR(ENOMEM); - - av_frame_copy_props(out, first); - - copy_all_planes(ctx, reinterlace, desc, out, first, second); - - out->interlaced_frame = 1; - out->top_field_first = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? 1 : 0; - - out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - break; - - case MODE_INTERLACE_X2: - if (reinterlace->current_frame_index == 1) - return 0; - - out = av_frame_clone(first); - - if (!out) - return AVERROR(ENOMEM); - - // output first frame - out->pts = (AV_NOPTS_VALUE != first->pts ) ? first->pts * 2 : AV_NOPTS_VALUE; - out->interlaced_frame = 1; - out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - - if (ret < 0) - return ret; - - // output the second frame interlaced with first frame - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - - if (!out) - return AVERROR(ENOMEM); - - av_frame_copy_props(out, second); - out->interlaced_frame = 1; - out->top_field_first = !out->top_field_first; - out->pts = first->pts + second->pts; - out->pts = ( first->pts == AV_NOPTS_VALUE || second->pts == AV_NOPTS_VALUE) ? AV_NOPTS_VALUE : out->pts; - - copy_all_planes(ctx, reinterlace, desc, out, first, second); - - out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - break; - - default: - av_assert0(0); - } - - return ret; -} - -static av_cold void uninit(AVFilterContext *ctx) -{ - ReInterlaceContext *reinterlace = ctx->priv; - - av_frame_free(&reinterlace->prev_frame); - av_frame_free(&reinterlace->current_frame); - - if (reinterlace->black_vec[0] != NULL) - { - av_freep(&reinterlace->black_vec[0]); - } - - av_free(reinterlace->thread_data); -} - -static const AVFilterPad reinterlace_inputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, - }, - { NULL } -}; - -static const AVFilterPad reinterlace_outputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .config_props = config_out_props, - }, - { NULL } -}; - -AVFilter ff_vf_reinterlace = { - .name = "reinterlace", - .description = NULL_IF_CONFIG_SMALL("Various interlace frame manipulations"), - .priv_size = sizeof(ReInterlaceContext), - .init = init, - .uninit = uninit, - .query_formats = query_formats, - .inputs = reinterlace_inputs, - .outputs = reinterlace_outputs, - .priv_class = &reinterlace_class, - .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, -}; diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c index 4f5c10d7ac..155dff0ef6 100644 --- a/libavfilter/vf_tinterlace.c +++ b/libavfilter/vf_tinterlace.c @@ -1,60 +1,58 @@ /* + * Copyright (c) 2018 Vasile Toncu * Copyright (c) 2017 Thomas Mundt - * Copyright (c) 2011 Stefano Sabatini - * Copyright (c) 2010 Baptiste Coudurier - * Copyright (c) 2003 Michael Zucchi * * This file is part of FFmpeg. * - * FFmpeg is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with FFmpeg if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file - * temporal field interlace filter, ported from MPlayer/libmpcodecs + * TInterlace filter */ -#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" -#include "libavutil/avassert.h" -#include "avfilter.h" -#include "internal.h" +#include "drawutils.h" #include "tinterlace.h" -#define OFFSET(x) offsetof(TInterlaceContext, x) -#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVRational standard_tbs[] = { + {1, 25}, + {1, 30}, + {1001, 30000}, +}; static const AVOption tinterlace_options[] = { - {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"}, - {"merge", "merge fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"drop_even", "drop even fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"drop_odd", "drop odd fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"pad", "pad alternate lines with black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"interleave_top", "interleave top and bottom fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"interleave_bottom", "interleave bottom and top fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"interlacex2", "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2}, INT_MIN, INT_MAX, FLAGS, "mode"}, - {"mergex2", "merge fields keeping same frame rate", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGEX2}, INT_MIN, INT_MAX, FLAGS, "mode"}, - - {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" }, - {"low_pass_filter", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" }, - {"vlpf", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" }, - {"complex_filter", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, - {"cvlpf", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, - {"exact_tb", "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" }, - - {NULL} + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB - 1, FLAGS, "mode" }, + { "merge", "merge frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "drop_even", "drop even frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "drop_odd", "drop odd frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "pad", "pad lines of a frame with black lines", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "interleave_top", "interleave top and bottom frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "interleave_bottom", "interleave bottom and top frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "interlacex2", "interlace consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACE_X2}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "mergex2", "just like merge, but at the same frame rate", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE_X2}, INT_MIN, INT_MAX, FLAGS, "mode"}, + + { "flags", "add flag for tinterlace", OFFSET(flags), AV_OPT_TYPE_INT, {.i64=FLAG_NOTHING}, 0, 0xFF, FLAGS, "flags" }, + { "low_pass_filter", "low pass fitler", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"}, + { "vlpf", "low pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"}, + { "complex_filter", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, + { "cvlpf", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, + { "exact_tb", "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" }, + { NULL } }; AVFILTER_DEFINE_CLASS(tinterlace); @@ -63,28 +61,26 @@ static const AVOption interlace_options[] = { { "scan", "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_INTERLEAVE_TOP}, 0, MODE_NB-1, FLAGS, "mode"}, { "tff", "top field first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, .unit = "mode" }, { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, - { "lowpass", "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = TINTERLACE_FLAG_VLPF}, 0,INT_MAX, 0, "flags" }, + { "lowpass", "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = FLAG_VLPF}, 0,INT_MAX, 0, "flags" }, { "off", "disable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "flags" }, - { "linear", "linear vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" }, - { "complex", "complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, + { "linear", "linear vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" }, + { "complex", "complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, { NULL } }; AVFILTER_DEFINE_CLASS(interlace); -#define FULL_SCALE_YUVJ_FORMATS \ - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P +static av_cold int init(AVFilterContext *ctx) +{ + TInterlaceContext *tinterlace = ctx->priv; + int i; -static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = { - FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE -}; + for (i = 0; i < 4; i++) + tinterlace->black_vec[i] = NULL; -static const AVRational standard_tbs[] = { - {1, 25}, - {1, 30}, - {1001, 30000}, -}; + return 0; +} static int query_formats(AVFilterContext *ctx) { @@ -98,13 +94,16 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE, - AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); } @@ -202,315 +201,436 @@ static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint } } -static av_cold void uninit(AVFilterContext *ctx) +/** + * alocate memory for a black frame + */ +static int init_black_buffers(TInterlaceContext *tinterlace, AVFilterLink *outlink) { - TInterlaceContext *tinterlace = ctx->priv; + FFDrawContext ctx; + FFDrawColor color; + int ret; + int format = outlink->format; + + if ((ret = av_image_alloc(tinterlace->black_vec, tinterlace->black_linesize, + outlink->w, outlink->h, format, 16)) < 0) + return ret; + + ff_draw_init(&ctx, outlink->format, 0); + ff_draw_color(&ctx, &color, (uint8_t[]){0, 0, 0, 16}); + if (format == AV_PIX_FMT_YUVJ420P || + format == AV_PIX_FMT_YUVJ422P || + format == AV_PIX_FMT_YUVJ440P || + format == AV_PIX_FMT_YUVJ444P) + color.comp[0].u8[0] = 0; + ff_fill_rectangle(&ctx, &color, tinterlace->black_vec, + tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); - av_frame_free(&tinterlace->cur ); - av_frame_free(&tinterlace->next); - av_freep(&tinterlace->black_data[0]); + return 0; } static int config_out_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = outlink->src->inputs[0]; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); TInterlaceContext *tinterlace = ctx->priv; - int i; + const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(outlink->format); + int tinterlace_mode = tinterlace->mode; + int ret, i; - tinterlace->vsub = desc->log2_chroma_h; - outlink->w = inlink->w; - outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2? - inlink->h*2 : inlink->h; - if (tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2) - outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, - av_make_q(2, 1)); - - if (tinterlace->mode == MODE_PAD) { - uint8_t black[4] = { 0, 0, 0, 16 }; - int ret; - ff_draw_init(&tinterlace->draw, outlink->format, 0); - ff_draw_color(&tinterlace->draw, &tinterlace->color, black); - if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts)) - tinterlace->color.comp[0].u8[0] = 0; - ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize, - outlink->w, outlink->h, outlink->format, 16); + tinterlace->bit_depth = fmt_desc->comp[0].depth; + tinterlace->preout_time_base = inlink->time_base; + + switch (tinterlace_mode) { + case MODE_PAD: + outlink->w = inlink->w; + outlink->h = 2 * inlink->h; + outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1)); + + ret = init_black_buffers(tinterlace, outlink); if (ret < 0) return ret; + break; - ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data, - tinterlace->black_linesize, 0, 0, outlink->w, outlink->h); - } - if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF) - && !(tinterlace->mode == MODE_INTERLEAVE_TOP - || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) { - av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n", - tinterlace->mode); - tinterlace->flags &= ~(TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF); - } - tinterlace->preout_time_base = inlink->time_base; - if (tinterlace->mode == MODE_INTERLACEX2) { + case MODE_DROP_EVEN: + case MODE_DROP_ODD: + outlink->w = inlink->w; + outlink->h = inlink->h; + outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); + outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); + break; + + case MODE_INTERLEAVE_TOP: + case MODE_INTERLEAVE_BOTTOM: + outlink->w = inlink->w; + outlink->h = inlink->h; + outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); + outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); + break; + + case MODE_INTERLACE_X2: + outlink->w = inlink->w; + outlink->h = inlink->h; tinterlace->preout_time_base.den *= 2; outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1}); outlink->time_base = av_mul_q(inlink->time_base , (AVRational){1,2}); - } else if (tinterlace->mode == MODE_MERGEX2) { + break; + + case MODE_MERGE_X2: + outlink->w = inlink->w; + outlink->h = 2 * inlink->h; + outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1)); outlink->frame_rate = inlink->frame_rate; outlink->time_base = inlink->time_base; - } else if (tinterlace->mode != MODE_PAD) { + break; + + case MODE_MERGE: + outlink->w = inlink->w; + outlink->h = 2 * inlink->h; + outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1)); outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); + break; + + default: + av_log(ctx, AV_LOG_VERBOSE, "invalid value for mode"); + av_assert0(0); + } - for (i = 0; itime_base)) break; } - if (i == FF_ARRAY_ELEMS(standard_tbs) || - (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB)) + if (i == FF_ARRAY_ELEMS(standard_tbs) || (tinterlace->flags & FLAG_EXACT_TB) ) outlink->time_base = tinterlace->preout_time_base; - tinterlace->csp = av_pix_fmt_desc_get(outlink->format); - if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) { - if (tinterlace->csp->comp[0].depth > 8) - tinterlace->lowpass_line = lowpass_line_complex_c_16; - else - tinterlace->lowpass_line = lowpass_line_complex_c; - if (ARCH_X86) - ff_tinterlace_init_x86(tinterlace); - } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) { - if (tinterlace->csp->comp[0].depth > 8) - tinterlace->lowpass_line = lowpass_line_c_16; - else - tinterlace->lowpass_line = lowpass_line_c; - if (ARCH_X86) - ff_tinterlace_init_x86(tinterlace); + if (tinterlace->flags & FLAG_VLPF || tinterlace->flags & FLAG_CVLPF) { + + if (tinterlace_mode != MODE_INTERLEAVE_TOP && tinterlace_mode != MODE_INTERLEAVE_BOTTOM) { + av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n", tinterlace_mode); + tinterlace->flags &= ~(FLAG_VLPF | FLAG_CVLPF); + } else { + tinterlace->lowpass_line = (tinterlace->flags & FLAG_VLPF) ? lowpass_line_c : lowpass_line_complex_c; + + if (tinterlace->bit_depth > 8) { + tinterlace->lowpass_line = (tinterlace->flags & FLAG_VLPF) ? lowpass_line_c_16 : lowpass_line_complex_c_16; + } + +#if CONFIG_GPL + if (ARCH_X86) { + ff_tinterlace_init_x86(tinterlace); + } +#endif + } + } - av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode, - (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" : - (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off", - inlink->h, outlink->h); + av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace_mode, + (tinterlace->flags & FLAG_CVLPF) ? "complex" : + (tinterlace->flags & FLAG_VLPF) ? "linear" : "off", + inlink->h, outlink->h); return 0; } -#define FIELD_UPPER 0 -#define FIELD_LOWER 1 -#define FIELD_UPPER_AND_LOWER 2 - -/** - * Copy picture field from src to dst. - * - * @param src_field copy from upper, lower field or both - * @param interleave leave a padding line between each copied line - * @param dst_field copy to upper or lower field, - * only meaningful when interleave is selected - * @param flags context flags - */ static inline -void copy_picture_field(TInterlaceContext *tinterlace, - uint8_t *dst[4], int dst_linesize[4], - const uint8_t *src[4], int src_linesize[4], - enum AVPixelFormat format, int w, int src_h, - int src_field, int interleave, int dst_field, - int flags) +void interleave_filter_frame(TInterlaceContext *tinterlace, AVFrame *from_frame, AVFrame *out, + int plane, int cvlfp, int mode, int x, int y, int clip_max) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format); - int hsub = desc->log2_chroma_w; - int plane, vsub = desc->log2_chroma_h; - int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2; - int h; + int lines = mode ? (2 * out->height / y + 1) / 2 : (2 * out->height / y) / 2; + int i = lines; + int cols = out->width / x; + uint8_t *from = from_frame->data[plane]; + uint8_t *to = out->data[plane]; + int from_step = 2 * from_frame->linesize[plane]; + int to_step = 2 * out->linesize[plane]; + + if (!mode) { + from = from + from_frame->linesize[plane]; + to = to + out->linesize[plane]; + } - for (plane = 0; plane < desc->nb_components; plane++) { - int lines = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(src_h, vsub) : src_h; - int cols = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT( w, hsub) : w; - uint8_t *dstp = dst[plane]; - const uint8_t *srcp = src[plane]; - int srcp_linesize = src_linesize[plane] * k; - int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1); - int clip_max = (1 << tinterlace->csp->comp[plane].depth) - 1; - - lines = (lines + (src_field == FIELD_UPPER)) / k; - if (src_field == FIELD_LOWER) - srcp += src_linesize[plane]; - if (interleave && dst_field == FIELD_LOWER) - dstp += dst_linesize[plane]; - // Low-pass filtering is required when creating an interlaced destination from - // a progressive source which contains high-frequency vertical detail. - // Filtering will reduce interlace 'twitter' and Moire patterning. - if (flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)) { - int x = !!(flags & TINTERLACE_FLAG_CVLPF); - for (h = lines; h > 0; h--) { - ptrdiff_t pref = src_linesize[plane]; - ptrdiff_t mref = -pref; - if (h >= (lines - x)) mref = 0; // there is no line above - else if (h <= (1 + x)) pref = 0; // there is no line below - - tinterlace->lowpass_line(dstp, cols, srcp, mref, pref, clip_max); - dstp += dstp_linesize; - srcp += srcp_linesize; - } + for (; i >= (lines - cvlfp); --i, from += from_step, to += to_step) + tinterlace->lowpass_line(to, cols, from, 0, from_frame->linesize[plane], clip_max); + + for (; i > (1 + cvlfp); --i, from += from_step, to += to_step) + tinterlace->lowpass_line(to, cols, from, -from_frame->linesize[plane], from_frame->linesize[plane], clip_max); + + for (; i > 0; --i, from += from_step, to += to_step) + tinterlace->lowpass_line(to, cols, from, -from_frame->linesize[plane], 0, clip_max); +} + +static int filter_frame_plane(TInterlaceContext *tinterlace, AVFrame *first, AVFrame *second, AVFrame *out, + int plane, int scale_w_plane12_factor, int scale_h_plane12_factor) +{ + int tinterlace_mode = tinterlace->mode; + + int x = (plane == 1 || plane == 2) ? scale_w_plane12_factor : 1; + int y = (plane == 1 || plane == 2) ? scale_h_plane12_factor : 1; + int ls_offset, offset1, offset2, offset3, offset4; + + const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out->format); + int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1); + + switch (tinterlace_mode) { + case MODE_MERGE: + av_image_copy_plane(out->data[plane], 2 * out->linesize[plane], + first->data[plane], first->linesize[plane], + mult * first->width / x, first->height / y); + av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane], + second->data[plane], second->linesize[plane], + mult * second->width / x, second->height / y); + break; + + case MODE_PAD: + ls_offset = (tinterlace->current_frame_index & 1) ? 0 : out->linesize[plane]; + av_image_copy_plane(out->data[plane] + ls_offset, 2 * out->linesize[plane], + second->data[plane], second->linesize[plane], + mult * second->width / x, second->height / y); + av_image_copy_plane(out->data[plane] + out->linesize[plane] - ls_offset, 2 * out->linesize[plane], + tinterlace->black_vec[plane], tinterlace->black_linesize[plane], + mult * second->width / x, second->height / y); + break; + + case MODE_INTERLEAVE_BOTTOM: + case MODE_INTERLEAVE_TOP: + y = y * 2; + + if (tinterlace->flags & FLAG_VLPF || tinterlace->flags & FLAG_CVLPF) { + int clip_max = (1 << fmt_desc->comp[plane].depth) - 1; + + interleave_filter_frame(tinterlace, first, out, plane, !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == MODE_INTERLEAVE_TOP, x, y, clip_max); + interleave_filter_frame(tinterlace, second, out, plane, !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == MODE_INTERLEAVE_BOTTOM, x, y, clip_max); + } else { + offset1 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : out->linesize[plane]; + offset2 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : first->linesize[plane]; + offset3 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? out->linesize[plane] : 0; + offset4 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? second->linesize[plane] : 0; + + av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane], + first->data[plane] + offset2, 2 * first->linesize[plane], + mult * first->width / x, first->height / y); + av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane], + second->data[plane] + offset4, 2 * second->linesize[plane], + mult * second->width / x, second->height / y); + } + break; + + case MODE_INTERLACE_X2: + y = y * 2; + + offset1 = 0; offset2 = 0; + offset3 = out->linesize[plane]; + offset4 = second->linesize[plane]; + + if (second->interlaced_frame && second->top_field_first) { + offset1 = out->linesize[plane]; + offset2 = first->linesize[plane]; + offset3 = 0; offset4 = 0; + } + + av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane], + first->data[plane] + offset2, 2 * first->linesize[plane], + mult * first->width / x, first->height / y); + av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane], + second->data[plane] + offset4, 2 * second->linesize[plane], + mult * second->width / x, second->height / y); + break; + + case MODE_MERGE_X2: + if (IS_ODD(tinterlace->current_frame_index - 1)) { + av_image_copy_plane(out->data[plane], 2 * out->linesize[plane], + second->data[plane], second->linesize[plane], + mult * second->width / x, second->height / y); + av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane], + first->data[plane], first->linesize[plane], + mult * first->width / x, first->height / y); } else { - if (tinterlace->csp->comp[plane].depth > 8) - cols *= 2; - av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines); + av_image_copy_plane(out->data[plane], 2 * out->linesize[plane], + first->data[plane], first->linesize[plane], + mult * first->width / x, first->height / y); + av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane], + second->data[plane], second->linesize[plane], + mult * second->width / x, second->height / y); } + break; + + default: + break; } + + return 0; } -static int filter_frame(AVFilterLink *inlink, AVFrame *picref) +static void copy_all_planes(AVFilterContext *ctx, + TInterlaceContext *tinterlace, + const AVPixFmtDescriptor *desc, + AVFrame *out, AVFrame *first, AVFrame *second) { - AVFilterContext *ctx = inlink->dst; - AVFilterLink *outlink = ctx->outputs[0]; - TInterlaceContext *tinterlace = ctx->priv; - AVFrame *cur, *next, *out; - int field, tff, ret; - - av_frame_free(&tinterlace->cur); - tinterlace->cur = tinterlace->next; - tinterlace->next = picref; - - cur = tinterlace->cur; - next = tinterlace->next; - /* we need at least two frames */ - if (!tinterlace->cur) - return 0; - - switch (tinterlace->mode) { - case MODE_MERGEX2: /* move the odd frame into the upper field of the new image, even into - * the lower field, generating a double-height video at same framerate */ - case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into - * the lower field, generating a double-height video at half framerate */ - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + int scale_w_plane12_factor = 1 << desc->log2_chroma_w; + int scale_h_plane12_factor = 1 << desc->log2_chroma_h; + int plane; + + for (plane = 0; plane < desc->nb_components; plane++) { + filter_frame_plane(tinterlace, first, second, out, plane, + scale_w_plane12_factor, scale_h_plane12_factor); + } +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + TInterlaceContext *tinterlace = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); + AVFrame *out, *first, *second; + int ret; + + int tinterlace_mode = tinterlace->mode; + + av_frame_free(&(tinterlace->prev_frame)); + tinterlace->prev_frame = tinterlace->current_frame; + tinterlace->current_frame = in; + tinterlace->current_frame_index++; + + // we process two frames at a time, thus only even frame indexes are considered + if (IS_ODD(tinterlace->current_frame_index)) { + if (tinterlace_mode == MODE_PAD || tinterlace_mode == MODE_MERGE_X2 + || tinterlace_mode == MODE_INTERLACE_X2) { + // continue + } else { + return 0; + } + } + + first = tinterlace->prev_frame; + second = tinterlace->current_frame; + + switch (tinterlace_mode) { + case MODE_DROP_EVEN: + case MODE_DROP_ODD: + out = (tinterlace_mode == MODE_DROP_ODD) ? tinterlace->current_frame : tinterlace->prev_frame; + out = av_frame_clone(out); + if (!out) return AVERROR(ENOMEM); - av_frame_copy_props(out, cur); - out->height = outlink->h; - out->interlaced_frame = 1; - out->top_field_first = 1; - out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); - - /* write odd frame lines into the upper field of the new frame */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)cur->data, cur->linesize, - inlink->format, inlink->w, inlink->h, - FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags); - /* write even frame lines into the lower field of the new frame */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)next->data, next->linesize, - inlink->format, inlink->w, inlink->h, - FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags); - if (tinterlace->mode != MODE_MERGEX2) - av_frame_free(&tinterlace->next); + + out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); + ret = ff_filter_frame(outlink, out); break; - case MODE_DROP_ODD: /* only output even frames, odd frames are dropped; height unchanged, half framerate */ - case MODE_DROP_EVEN: /* only output odd frames, even frames are dropped; height unchanged, half framerate */ - out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next); + case MODE_MERGE: + case MODE_MERGE_X2: + if (tinterlace_mode == MODE_MERGE_X2 && tinterlace->current_frame_index == 1) + return 0; + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) return AVERROR(ENOMEM); - av_frame_free(&tinterlace->next); + + av_frame_copy_props(out, first); + out->sample_aspect_ratio = av_mul_q(first->sample_aspect_ratio, av_make_q(2, 1)); + out->interlaced_frame = 1; + out->top_field_first = 1; + out->height = outlink->h; + + copy_all_planes(ctx, tinterlace, desc, out, first, second); + + out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); + ret = ff_filter_frame(outlink, out); break; - case MODE_PAD: /* expand each frame to double height, but pad alternate - * lines with black; framerate unchanged */ + case MODE_PAD: out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) return AVERROR(ENOMEM); - av_frame_copy_props(out, cur); + + av_frame_copy_props(out, second); + out->sample_aspect_ratio = av_mul_q(second->sample_aspect_ratio, av_make_q(2, 1)); out->height = outlink->h; - out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1)); - - field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER; - /* copy upper and lower fields */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)cur->data, cur->linesize, - inlink->format, inlink->w, inlink->h, - FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags); - /* pad with black the other field */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize, - inlink->format, inlink->w, inlink->h, - FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags); + + copy_all_planes(ctx, tinterlace, desc, out, first, second); + + out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); + ret = ff_filter_frame(outlink, out); break; - /* interleave upper/lower lines from odd frames with lower/upper lines from even frames, - * halving the frame rate and preserving image height */ - case MODE_INTERLEAVE_TOP: /* top field first */ - case MODE_INTERLEAVE_BOTTOM: /* bottom field first */ - tff = tinterlace->mode == MODE_INTERLEAVE_TOP; - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + case MODE_INTERLEAVE_BOTTOM: + case MODE_INTERLEAVE_TOP: + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) return AVERROR(ENOMEM); - av_frame_copy_props(out, cur); + + av_frame_copy_props(out, first); + + copy_all_planes(ctx, tinterlace, desc, out, first, second); + out->interlaced_frame = 1; - out->top_field_first = tff; - - /* copy upper/lower field from cur */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)cur->data, cur->linesize, - inlink->format, inlink->w, inlink->h, - tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER, - tinterlace->flags); - /* copy lower/upper field from next */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)next->data, next->linesize, - inlink->format, inlink->w, inlink->h, - tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER, - tinterlace->flags); - av_frame_free(&tinterlace->next); + out->top_field_first = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 1 : 0; + + out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); + ret = ff_filter_frame(outlink, out); break; - case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */ - /* output current frame first */ - out = av_frame_clone(cur); + + case MODE_INTERLACE_X2: + if (tinterlace->current_frame_index == 1) + return 0; + + out = av_frame_clone(first); + if (!out) return AVERROR(ENOMEM); - out->interlaced_frame = 1; - if (cur->pts != AV_NOPTS_VALUE) - out->pts = cur->pts*2; + // output first frame + out->pts = (AV_NOPTS_VALUE != first->pts ) ? first->pts * 2 : AV_NOPTS_VALUE; + out->interlaced_frame = 1; out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); - if ((ret = ff_filter_frame(outlink, out)) < 0) + ret = ff_filter_frame(outlink, out); + + if (ret < 0) return ret; - /* output mix of current and next frame */ - tff = next->top_field_first; + // output the second frame interlaced with first frame out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) return AVERROR(ENOMEM); - av_frame_copy_props(out, next); + + av_frame_copy_props(out, second); out->interlaced_frame = 1; - out->top_field_first = !tff; - - if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE) - out->pts = cur->pts + next->pts; - else - out->pts = AV_NOPTS_VALUE; - /* write current frame second field lines into the second field of the new frame */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)cur->data, cur->linesize, - inlink->format, inlink->w, inlink->h, - tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER, - tinterlace->flags); - /* write next frame first field lines into the first field of the new frame */ - copy_picture_field(tinterlace, out->data, out->linesize, - (const uint8_t **)next->data, next->linesize, - inlink->format, inlink->w, inlink->h, - tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER, - tinterlace->flags); + out->top_field_first = !out->top_field_first; + out->pts = first->pts + second->pts; + out->pts = ( first->pts == AV_NOPTS_VALUE || second->pts == AV_NOPTS_VALUE) ? AV_NOPTS_VALUE : out->pts; + + copy_all_planes(ctx, tinterlace, desc, out, first, second); + + out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); + ret = ff_filter_frame(outlink, out); break; + default: av_assert0(0); } - out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base); - ret = ff_filter_frame(outlink, out); - tinterlace->frame++; - return ret; } +static av_cold void uninit(AVFilterContext *ctx) +{ + TInterlaceContext *tinterlace = ctx->priv; + + av_frame_free(&tinterlace->prev_frame); + av_frame_free(&tinterlace->current_frame); + + if (tinterlace->black_vec[0] != NULL) + { + av_freep(&tinterlace->black_vec[0]); + } +} + static const AVFilterPad tinterlace_inputs[] = { { .name = "default", @@ -522,32 +642,35 @@ static const AVFilterPad tinterlace_inputs[] = { static const AVFilterPad tinterlace_outputs[] = { { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .config_props = config_out_props, + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_out_props, }, { NULL } }; AVFilter ff_vf_tinterlace = { .name = "tinterlace", - .description = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."), + .description = NULL_IF_CONFIG_SMALL("Various interlace frame manipulations"), .priv_size = sizeof(TInterlaceContext), + .init = init, .uninit = uninit, .query_formats = query_formats, .inputs = tinterlace_inputs, .outputs = tinterlace_outputs, .priv_class = &tinterlace_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; - AVFilter ff_vf_interlace = { .name = "interlace", .description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."), .priv_size = sizeof(TInterlaceContext), + .init = init, .uninit = uninit, .query_formats = query_formats, .inputs = tinterlace_inputs, .outputs = tinterlace_outputs, .priv_class = &interlace_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index e31884aec0..b484c8bd1c 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -10,7 +10,6 @@ OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip_init.o OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet_init.o OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_tinterlace_init.o -OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_reinterlace_init.o OBJS-$(CONFIG_LIMITER_FILTER) += x86/vf_limiter_init.o OBJS-$(CONFIG_MASKEDMERGE_FILTER) += x86/vf_maskedmerge_init.o OBJS-$(CONFIG_NOISE_FILTER) += x86/vf_noise.o diff --git a/libavfilter/x86/vf_reinterlace_init.c b/libavfilter/x86/vf_reinterlace_init.c deleted file mode 100644 index 144db23beb..0000000000 --- a/libavfilter/x86/vf_reinterlace_init.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2018 Vasile Toncu - * Copyright (C) 2014 Kieran Kunhya - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with FFmpeg; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "libavutil/attributes.h" -#include "libavutil/cpu.h" -#include "libavutil/internal.h" -#include "libavutil/mem.h" -#include "libavutil/x86/asm.h" -#include "libavutil/x86/cpu.h" - -#include "libavfilter/reinterlace.h" - -#if CONFIG_GPL - -void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); -void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); -void ff_lowpass_line_avx2 (uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); - -void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); -void ff_lowpass_line_16_avx (uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); -void ff_lowpass_line_16_avx2 (uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); - -void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); - -void ff_lowpass_line_complex_12_sse2(uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, ptrdiff_t mref, - ptrdiff_t pref, int clip_max); - -av_cold void ff_reinterlace_init_x86(ReInterlaceContext *reinterlace) -{ - int cpu_flags = av_get_cpu_flags(); - - if (reinterlace->bit_depth > 8) { - if (EXTERNAL_SSE2(cpu_flags)) { - if (!(reinterlace->flags & FLAG_CVLPF)) - reinterlace->lowpass_line = ff_lowpass_line_16_sse2; - else - reinterlace->lowpass_line = ff_lowpass_line_complex_12_sse2; - } - if (EXTERNAL_AVX(cpu_flags)) - if (!(reinterlace->flags & FLAG_CVLPF)) - reinterlace->lowpass_line = ff_lowpass_line_16_avx; - if (EXTERNAL_AVX2_FAST(cpu_flags)) { - if (!(reinterlace->flags & FLAG_CVLPF)) { - reinterlace->lowpass_line = ff_lowpass_line_16_avx2; - } - } - } else { - if (EXTERNAL_SSE2(cpu_flags)) { - if (!(reinterlace->flags & FLAG_CVLPF)) - reinterlace->lowpass_line = ff_lowpass_line_sse2; - else - reinterlace->lowpass_line = ff_lowpass_line_complex_sse2; - } - if (EXTERNAL_AVX(cpu_flags)) - if (!(reinterlace->flags & FLAG_CVLPF)) - reinterlace->lowpass_line = ff_lowpass_line_avx; - if (EXTERNAL_AVX2_FAST(cpu_flags)) { - if (!(reinterlace->flags & FLAG_CVLPF)) { - reinterlace->lowpass_line = ff_lowpass_line_avx2; - } - } - } -} - -#elif /* CONFIG_GPL */ - -av_cold void ff_reinterlace_init_x86(ReInterlaceContext *s) {} - -#endif /* CONFIG_GPL */ diff --git a/libavfilter/x86/vf_tinterlace_init.c b/libavfilter/x86/vf_tinterlace_init.c index 2c9b1de581..c14f62991d 100644 --- a/libavfilter/x86/vf_tinterlace_init.c +++ b/libavfilter/x86/vf_tinterlace_init.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018 Vasile Toncu * Copyright (C) 2014 Kieran Kunhya * * This file is part of FFmpeg. @@ -27,6 +28,8 @@ #include "libavfilter/tinterlace.h" +#if CONFIG_GPL + void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); @@ -55,39 +58,45 @@ void ff_lowpass_line_complex_12_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); -av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) +av_cold void ff_tinterlace_init_x86(TInterlaceContext *tinterlace) { int cpu_flags = av_get_cpu_flags(); - if (s->csp->comp[0].depth > 8) { + if (tinterlace->bit_depth > 8) { if (EXTERNAL_SSE2(cpu_flags)) { - if (!(s->flags & TINTERLACE_FLAG_CVLPF)) - s->lowpass_line = ff_lowpass_line_16_sse2; + if (!(tinterlace->flags & FLAG_CVLPF)) + tinterlace->lowpass_line = ff_lowpass_line_16_sse2; else - s->lowpass_line = ff_lowpass_line_complex_12_sse2; + tinterlace->lowpass_line = ff_lowpass_line_complex_12_sse2; } if (EXTERNAL_AVX(cpu_flags)) - if (!(s->flags & TINTERLACE_FLAG_CVLPF)) - s->lowpass_line = ff_lowpass_line_16_avx; + if (!(tinterlace->flags & FLAG_CVLPF)) + tinterlace->lowpass_line = ff_lowpass_line_16_avx; if (EXTERNAL_AVX2_FAST(cpu_flags)) { - if (!(s->flags & TINTERLACE_FLAG_CVLPF)) { - s->lowpass_line = ff_lowpass_line_16_avx2; + if (!(tinterlace->flags & FLAG_CVLPF)) { + tinterlace->lowpass_line = ff_lowpass_line_16_avx2; } } } else { if (EXTERNAL_SSE2(cpu_flags)) { - if (!(s->flags & TINTERLACE_FLAG_CVLPF)) - s->lowpass_line = ff_lowpass_line_sse2; + if (!(tinterlace->flags & FLAG_CVLPF)) + tinterlace->lowpass_line = ff_lowpass_line_sse2; else - s->lowpass_line = ff_lowpass_line_complex_sse2; + tinterlace->lowpass_line = ff_lowpass_line_complex_sse2; } if (EXTERNAL_AVX(cpu_flags)) - if (!(s->flags & TINTERLACE_FLAG_CVLPF)) - s->lowpass_line = ff_lowpass_line_avx; + if (!(tinterlace->flags & FLAG_CVLPF)) + tinterlace->lowpass_line = ff_lowpass_line_avx; if (EXTERNAL_AVX2_FAST(cpu_flags)) { - if (!(s->flags & TINTERLACE_FLAG_CVLPF)) { - s->lowpass_line = ff_lowpass_line_avx2; + if (!(tinterlace->flags & FLAG_CVLPF)) { + tinterlace->lowpass_line = ff_lowpass_line_avx2; } } } } + +#elif /* CONFIG_GPL */ + +av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) {} + +#endif /* CONFIG_GPL */ -- 2.17.1