From 9f07863f288ad7bbd27f4761bbf9ebeff7bf4801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Tue, 2 Dec 2014 18:32:09 +0100 Subject: [PATCH] avfilter/tinterlace: merge code with interlace --- libavfilter/Makefile | 2 +- libavfilter/interlace.h | 58 --------- libavfilter/tinterlace.h | 5 +- libavfilter/vf_interlace.c | 248 ------------------------------------ libavfilter/vf_tinterlace.c | 44 +++++++ libavfilter/x86/Makefile | 2 +- libavfilter/x86/vf_interlace_init.c | 47 ------- 7 files changed, 49 insertions(+), 357 deletions(-) delete mode 100644 libavfilter/interlace.h delete mode 100644 libavfilter/vf_interlace.c delete mode 100644 libavfilter/x86/vf_interlace_init.c diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 2c56e38..36676aa 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -136,7 +136,7 @@ OBJS-$(CONFIG_HQX_FILTER) += vf_hqx.o OBJS-$(CONFIG_HUE_FILTER) += vf_hue.o OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o -OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o +OBJS-$(CONFIG_INTERLACE_FILTER) += vf_tinterlace.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/interlace.h b/libavfilter/interlace.h deleted file mode 100644 index 44f1e06..0000000 --- a/libavfilter/interlace.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ - -/** - * @file - * progressive to interlaced content filter, inspired by heavy debugging of - * tinterlace filter. - */ - -#ifndef AVFILTER_INTERLACE_H -#define AVFILTER_INTERLACE_H - -#include "libavutil/common.h" -#include "libavutil/imgutils.h" -#include "libavutil/opt.h" - -#include "avfilter.h" -#include "formats.h" -#include "internal.h" -#include "video.h" - -enum ScanMode { - MODE_TFF = 0, - MODE_BFF = 1, -}; - -enum FieldType { - FIELD_UPPER = 0, - FIELD_LOWER = 1, -}; - -typedef struct InterlaceContext { - const AVClass *class; - enum ScanMode scan; // top or bottom field first scanning - int lowpass; // enable or disable low pass filterning - AVFrame *cur, *next; // the two frames from which the new one is obtained - void (*lowpass_line)(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, - const uint8_t *srcp_above, const uint8_t *srcp_below); -} InterlaceContext; - -void ff_interlace_init_x86(InterlaceContext *interlace); - -#endif /* AVFILTER_INTERLACE_H */ diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h index fa0a83a..846c426 100644 --- a/libavfilter/tinterlace.h +++ b/libavfilter/tinterlace.h @@ -44,12 +44,13 @@ enum TInterlaceMode { typedef struct { const AVClass *class; enum TInterlaceMode mode; ///< interlace mode selected + int scan; ///< top (0) or bottom (1) field first scanning 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; + int lowpass; ///< enable or disable low pass filterning + AVFrame *cur, *next; ///< the two frames from which the new one is obtained uint8_t *black_data[4]; ///< buffer used to fill padded lines int black_linesize[4]; void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, diff --git a/libavfilter/vf_interlace.c b/libavfilter/vf_interlace.c deleted file mode 100644 index a63f915..0000000 --- a/libavfilter/vf_interlace.c +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (c) 2003 Michael Zucchi - * Copyright (c) 2010 Baptiste Coudurier - * Copyright (c) 2011 Stefano Sabatini - * Copyright (c) 2013 Vittorio Giovara - * - * 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. - */ - -/** - * @file - * progressive to interlaced content filter, inspired by heavy debugging of tinterlace filter - */ - -#include "libavutil/common.h" -#include "libavutil/opt.h" -#include "libavutil/imgutils.h" -#include "libavutil/avassert.h" - -#include "formats.h" -#include "avfilter.h" -#include "interlace.h" -#include "internal.h" -#include "video.h" - -#define OFFSET(x) offsetof(InterlaceContext, x) -#define V AV_OPT_FLAG_VIDEO_PARAM -static const AVOption interlace_options[] = { - { "scan", "scanning mode", OFFSET(scan), - AV_OPT_TYPE_INT, {.i64 = MODE_TFF }, 0, 1, .flags = V, .unit = "scan" }, - { "tff", "top field first", 0, - AV_OPT_TYPE_CONST, {.i64 = MODE_TFF }, INT_MIN, INT_MAX, .flags = V, .unit = "scan" }, - { "bff", "bottom field first", 0, - AV_OPT_TYPE_CONST, {.i64 = MODE_BFF }, INT_MIN, INT_MAX, .flags = V, .unit = "scan" }, - { "lowpass", "enable vertical low-pass filter", OFFSET(lowpass), - AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 1, .flags = V }, - { NULL } -}; - -AVFILTER_DEFINE_CLASS(interlace); - -static void lowpass_line_c(uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, - const uint8_t *srcp_above, - const uint8_t *srcp_below) -{ - int i; - for (i = 0; i < linesize; 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 const enum AVPixelFormat formats_supported[] = { - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA420P, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, - AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_NONE -}; - -static int query_formats(AVFilterContext *ctx) -{ - ff_set_common_formats(ctx, ff_make_format_list(formats_supported)); - return 0; -} - -static av_cold void uninit(AVFilterContext *ctx) -{ - InterlaceContext *s = ctx->priv; - - av_frame_free(&s->cur); - av_frame_free(&s->next); -} - -static int config_out_props(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - AVFilterLink *inlink = outlink->src->inputs[0]; - InterlaceContext *s = ctx->priv; - - if (inlink->h < 2) { - av_log(ctx, AV_LOG_ERROR, "input video height is too small\n"); - return AVERROR_INVALIDDATA; - } - - if (!s->lowpass) - av_log(ctx, AV_LOG_WARNING, "***warning*** Lowpass filter is disabled, " - "the resulting video will be aliased rather than interlaced.\n"); - - // same input size - outlink->w = inlink->w; - outlink->h = inlink->h; - outlink->time_base = inlink->time_base; - outlink->frame_rate = inlink->frame_rate; - // half framerate - outlink->frame_rate.den *= 2; - outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; - - - if (s->lowpass) { - s->lowpass_line = lowpass_line_c; - if (ARCH_X86) - ff_interlace_init_x86(s); - } - - av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n", - s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without"); - - return 0; -} - -static void copy_picture_field(InterlaceContext *s, - AVFrame *src_frame, AVFrame *dst_frame, - AVFilterLink *inlink, enum FieldType field_type, - int lowpass) -{ - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); - int vsub = desc->log2_chroma_h; - int plane, j; - - for (plane = 0; plane < desc->nb_components; plane++) { - int lines = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->h, vsub) : inlink->h; - ptrdiff_t linesize = av_image_get_linesize(inlink->format, inlink->w, plane); - uint8_t *dstp = dst_frame->data[plane]; - const uint8_t *srcp = src_frame->data[plane]; - - av_assert0(linesize >= 0); - - lines = (lines + (field_type == FIELD_UPPER)) / 2; - if (field_type == FIELD_LOWER) - srcp += src_frame->linesize[plane]; - if (field_type == FIELD_LOWER) - dstp += dst_frame->linesize[plane]; - if (lowpass) { - int srcp_linesize = src_frame->linesize[plane] * 2; - int dstp_linesize = dst_frame->linesize[plane] * 2; - for (j = lines; j > 0; j--) { - const uint8_t *srcp_above = srcp - src_frame->linesize[plane]; - const uint8_t *srcp_below = srcp + src_frame->linesize[plane]; - if (j == lines) - srcp_above = srcp; // there is no line above - if (j == 1) - srcp_below = srcp; // there is no line below - s->lowpass_line(dstp, linesize, srcp, srcp_above, srcp_below); - dstp += dstp_linesize; - srcp += srcp_linesize; - } - } else { - av_image_copy_plane(dstp, dst_frame->linesize[plane] * 2, - srcp, src_frame->linesize[plane] * 2, - linesize, lines); - } - } -} - -static int filter_frame(AVFilterLink *inlink, AVFrame *buf) -{ - AVFilterContext *ctx = inlink->dst; - AVFilterLink *outlink = ctx->outputs[0]; - InterlaceContext *s = ctx->priv; - AVFrame *out; - int tff, ret; - - av_frame_free(&s->cur); - s->cur = s->next; - s->next = buf; - - /* we need at least two frames */ - if (!s->cur || !s->next) - return 0; - - if (s->cur->interlaced_frame) { - av_log(ctx, AV_LOG_WARNING, - "video is already interlaced, adjusting framerate only\n"); - out = av_frame_clone(s->cur); - if (!out) - return AVERROR(ENOMEM); - out->pts /= 2; // adjust pts to new framerate - ret = ff_filter_frame(outlink, out); - return ret; - } - - tff = (s->scan == MODE_TFF); - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - if (!out) - return AVERROR(ENOMEM); - - av_frame_copy_props(out, s->cur); - out->interlaced_frame = 1; - out->top_field_first = tff; - - /* copy upper/lower field from cur */ - copy_picture_field(s, s->cur, out, inlink, tff ? FIELD_UPPER : FIELD_LOWER, s->lowpass); - av_frame_free(&s->cur); - - /* copy lower/upper field from next */ - copy_picture_field(s, s->next, out, inlink, tff ? FIELD_LOWER : FIELD_UPPER, s->lowpass); - av_frame_free(&s->next); - - ret = ff_filter_frame(outlink, out); - - return ret; -} - -static const AVFilterPad inputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, - }, - { NULL } -}; - -static const AVFilterPad outputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .config_props = config_out_props, - }, - { NULL } -}; - -AVFilter ff_vf_interlace = { - .name = "interlace", - .description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."), - .uninit = uninit, - .priv_class = &interlace_class, - .priv_size = sizeof(InterlaceContext), - .query_formats = query_formats, - .inputs = inputs, - .outputs = outputs, -}; diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c index c644895..f8f865a 100644 --- a/libavfilter/vf_tinterlace.c +++ b/libavfilter/vf_tinterlace.c @@ -2,6 +2,7 @@ * Copyright (c) 2011 Stefano Sabatini * Copyright (c) 2010 Baptiste Coudurier * Copyright (c) 2003 Michael Zucchi + * Copyright (c) 2013 Vittorio Giovara * * This file is part of FFmpeg. * @@ -57,6 +58,16 @@ static const AVOption tinterlace_options[] = { AVFILTER_DEFINE_CLASS(tinterlace); +static const AVOption interlace_options[] = { + {"scan", "scanning mode", OFFSET(scan), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS, "scan"}, + { "tff", "top field first", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "scan"}, + { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, FLAGS, "scan"}, + {"lowpass", "enable vertical low-pass filter", OFFSET(lowpass), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, 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 @@ -114,6 +125,11 @@ static int config_out_props(AVFilterLink *outlink) TInterlaceContext *tinterlace = ctx->priv; int i; + if (inlink->h < 2) { + av_log(ctx, AV_LOG_ERROR, "input video height is too small\n"); + return AVERROR_INVALIDDATA; + } + tinterlace->vsub = desc->log2_chroma_h; outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; outlink->w = inlink->w; @@ -162,6 +178,13 @@ static int config_out_props(AVFilterLink *outlink) (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB)) outlink->time_base = tinterlace->preout_time_base; + if (tinterlace->mode == MODE_INTERLEAVE_TOP || + tinterlace->mode == MODE_INTERLEAVE_BOTTOM) { + if (!(tinterlace->flags & TINTERLACE_FLAG_VLPF)) + av_log(ctx, AV_LOG_WARNING, "Vertical lowpass filter is disabled, " + "the resulting video will be aliased rather than interlaced.\n"); + } + if (tinterlace->flags & TINTERLACE_FLAG_VLPF) { tinterlace->lowpass_line = lowpass_line_c; if (ARCH_X86) @@ -414,3 +437,24 @@ AVFilter ff_vf_tinterlace = { .outputs = tinterlace_outputs, .priv_class = &tinterlace_class, }; + +static av_cold int interlace_init(AVFilterContext *ctx) +{ + TInterlaceContext *s = ctx->priv; + + s->mode = MODE_INTERLEAVE_TOP + s->scan; + s->flags |= s->lowpass ? TINTERLACE_FLAG_VLPF : 0; + return 0; +} + +AVFilter ff_vf_interlace = { + .name = "interlace", + .description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."), + .priv_size = sizeof(TInterlaceContext), + .init = interlace_init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = tinterlace_inputs, + .outputs = tinterlace_outputs, + .priv_class = &interlace_class, +}; diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index 44765d2..d77c420 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -1,7 +1,7 @@ OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_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_interlace_init.o +OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_tinterlace_init.o OBJS-$(CONFIG_NOISE_FILTER) += x86/vf_noise.o OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup_init.o OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o diff --git a/libavfilter/x86/vf_interlace_init.c b/libavfilter/x86/vf_interlace_init.c deleted file mode 100644 index 68ee47d..0000000 --- a/libavfilter/x86/vf_interlace_init.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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/interlace.h" - -void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, - const uint8_t *srcp_above, - const uint8_t *srcp_below); -void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, - const uint8_t *srcp, - const uint8_t *srcp_above, - const uint8_t *srcp_below); - -av_cold void ff_interlace_init_x86(InterlaceContext *s) -{ - int cpu_flags = av_get_cpu_flags(); - - if (EXTERNAL_SSE2(cpu_flags)) - s->lowpass_line = ff_lowpass_line_sse2; - if (EXTERNAL_AVX(cpu_flags)) - s->lowpass_line = ff_lowpass_line_avx; -} -- 2.1.3