LCOV - code coverage report
Current view: top level - libavfilter - vf_interlace.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 110 158 69.6 %
Date: 2017-12-16 13:57:32 Functions: 7 9 77.8 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
       3             :  * Copyright (c) 2010 Baptiste Coudurier
       4             :  * Copyright (c) 2011 Stefano Sabatini
       5             :  * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara@gmail.com>
       6             :  * Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
       7             :  *
       8             :  * This file is part of FFmpeg.
       9             :  *
      10             :  * FFmpeg is free software; you can redistribute it and/or modify
      11             :  * it under the terms of the GNU General Public License as published by
      12             :  * the Free Software Foundation; either version 2 of the License, or
      13             :  * (at your option) any later version.
      14             :  *
      15             :  * FFmpeg is distributed in the hope that it will be useful,
      16             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  * GNU General Public License for more details.
      19             :  *
      20             :  * You should have received a copy of the GNU General Public License along
      21             :  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
      22             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      23             :  */
      24             : 
      25             : /**
      26             :  * @file
      27             :  * progressive to interlaced content filter, inspired by heavy debugging of tinterlace filter
      28             :  */
      29             : 
      30             : #include "libavutil/common.h"
      31             : #include "libavutil/opt.h"
      32             : #include "libavutil/imgutils.h"
      33             : #include "libavutil/avassert.h"
      34             : 
      35             : #include "formats.h"
      36             : #include "avfilter.h"
      37             : #include "interlace.h"
      38             : #include "internal.h"
      39             : #include "video.h"
      40             : 
      41             : #define OFFSET(x) offsetof(InterlaceContext, x)
      42             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      43             : static const AVOption interlace_options[] = {
      44             :     { "scan", "scanning mode", OFFSET(scan),
      45             :         AV_OPT_TYPE_INT,   {.i64 = MODE_TFF }, 0, 1, .flags = FLAGS, .unit = "scan" },
      46             :     { "tff", "top field first", 0,
      47             :         AV_OPT_TYPE_CONST, {.i64 = MODE_TFF }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "scan" },
      48             :     { "bff", "bottom field first", 0,
      49             :         AV_OPT_TYPE_CONST, {.i64 = MODE_BFF }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "scan" },
      50             :     { "lowpass", "set vertical low-pass filter", OFFSET(lowpass),
      51             :         AV_OPT_TYPE_INT,   {.i64 = VLPF_LIN }, 0, 2, .flags = FLAGS, .unit = "lowpass" },
      52             :     { "off",     "disable vertical low-pass filter", 0,
      53             :         AV_OPT_TYPE_CONST, {.i64 = VLPF_OFF }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "lowpass" },
      54             :     { "linear",  "linear vertical low-pass filter",  0,
      55             :         AV_OPT_TYPE_CONST, {.i64 = VLPF_LIN }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "lowpass" },
      56             :     { "complex", "complex vertical low-pass filter", 0,
      57             :         AV_OPT_TYPE_CONST, {.i64 = VLPF_CMP }, INT_MIN, INT_MAX, .flags = FLAGS, .unit = "lowpass" },
      58             :     { NULL }
      59             : };
      60             : 
      61             : AVFILTER_DEFINE_CLASS(interlace);
      62             : 
      63       28800 : static void lowpass_line_c(uint8_t *dstp, ptrdiff_t linesize,
      64             :                            const uint8_t *srcp, ptrdiff_t mref,
      65             :                            ptrdiff_t pref, int clip_max)
      66             : {
      67       28800 :     const uint8_t *srcp_above = srcp + mref;
      68       28800 :     const uint8_t *srcp_below = srcp + pref;
      69             :     int i;
      70     7632000 :     for (i = 0; i < linesize; i++) {
      71             :         // this calculation is an integer representation of
      72             :         // '0.5 * current + 0.25 * above + 0.25 * below'
      73             :         // '1 +' is for rounding.
      74     7603200 :         dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
      75             :     }
      76       28800 : }
      77             : 
      78           0 : static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t linesize,
      79             :                               const uint8_t *src8, ptrdiff_t mref,
      80             :                               ptrdiff_t pref, int clip_max)
      81             : {
      82           0 :     uint16_t *dstp = (uint16_t *)dst8;
      83           0 :     const uint16_t *srcp = (const uint16_t *)src8;
      84           0 :     const uint16_t *srcp_above = srcp + mref / 2;
      85           0 :     const uint16_t *srcp_below = srcp + pref / 2;
      86             :     int i, src_x;
      87           0 :     for (i = 0; i < linesize; i++) {
      88             :         // this calculation is an integer representation of
      89             :         // '0.5 * current + 0.25 * above + 0.25 * below'
      90             :         // '1 +' is for rounding.
      91           0 :         src_x   = av_le2ne16(srcp[i]) << 1;
      92           0 :         dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i])
      93             :                              + av_le2ne16(srcp_below[i])) >> 2);
      94             :     }
      95           0 : }
      96             : 
      97       14400 : static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t linesize,
      98             :                                    const uint8_t *srcp, ptrdiff_t mref,
      99             :                                    ptrdiff_t pref, int clip_max)
     100             : {
     101       14400 :     const uint8_t *srcp_above = srcp + mref;
     102       14400 :     const uint8_t *srcp_below = srcp + pref;
     103       14400 :     const uint8_t *srcp_above2 = srcp + mref * 2;
     104       14400 :     const uint8_t *srcp_below2 = srcp + pref * 2;
     105             :     int i, src_x, src_ab;
     106     3816000 :     for (i = 0; i < linesize; i++) {
     107             :         // this calculation is an integer representation of
     108             :         // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
     109             :         // '4 +' is for rounding.
     110     3801600 :         src_x   = srcp[i] << 1;
     111     3801600 :         src_ab  = srcp_above[i] + srcp_below[i];
     112     7603200 :         dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1)
     113     3801600 :                                 - srcp_above2[i] - srcp_below2[i]) >> 3);
     114             :         // Prevent over-sharpening:
     115             :         // dst must not exceed src when the average of above and below
     116             :         // is less than src. And the other way around.
     117     3801600 :         if (src_ab > src_x) {
     118     1629394 :             if (dstp[i] < srcp[i])
     119      175930 :                 dstp[i] = srcp[i];
     120     2172206 :         } else if (dstp[i] > srcp[i])
     121      227655 :             dstp[i] = srcp[i];
     122             :     }
     123       14400 : }
     124             : 
     125           0 : static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t linesize,
     126             :                                       const uint8_t *src8, ptrdiff_t mref,
     127             :                                       ptrdiff_t pref, int clip_max)
     128             : {
     129           0 :     uint16_t *dstp = (uint16_t *)dst8;
     130           0 :     const uint16_t *srcp = (const uint16_t *)src8;
     131           0 :     const uint16_t *srcp_above = srcp + mref / 2;
     132           0 :     const uint16_t *srcp_below = srcp + pref / 2;
     133           0 :     const uint16_t *srcp_above2 = srcp + mref;
     134           0 :     const uint16_t *srcp_below2 = srcp + pref;
     135             :     int i, dst_le, src_le, src_x, src_ab;
     136           0 :     for (i = 0; i < linesize; i++) {
     137             :         // this calculation is an integer representation of
     138             :         // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
     139             :         // '4 +' is for rounding.
     140           0 :         src_le = av_le2ne16(srcp[i]);
     141           0 :         src_x  = src_le << 1;
     142           0 :         src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]);
     143           0 :         dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1)
     144           0 :                          - av_le2ne16(srcp_above2[i])
     145           0 :                          - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max);
     146             :         // Prevent over-sharpening:
     147             :         // dst must not exceed src when the average of above and below
     148             :         // is less than src. And the other way around.
     149           0 :         if (src_ab > src_x) {
     150           0 :             if (dst_le < src_le)
     151           0 :                 dstp[i] = av_le2ne16(src_le);
     152             :             else
     153           0 :                 dstp[i] = av_le2ne16(dst_le);
     154           0 :         } else if (dst_le > src_le) {
     155           0 :             dstp[i] = av_le2ne16(src_le);
     156             :         } else
     157           0 :             dstp[i] = av_le2ne16(dst_le);
     158             :     }
     159           0 : }
     160             : 
     161             : static const enum AVPixelFormat formats_supported[] = {
     162             :     AV_PIX_FMT_YUV410P,      AV_PIX_FMT_YUV411P,
     163             :     AV_PIX_FMT_YUV420P,      AV_PIX_FMT_YUV422P,      AV_PIX_FMT_YUV444P,
     164             :     AV_PIX_FMT_YUV420P10LE,  AV_PIX_FMT_YUV422P10LE,  AV_PIX_FMT_YUV444P10LE,
     165             :     AV_PIX_FMT_YUV420P12LE,  AV_PIX_FMT_YUV422P12LE,  AV_PIX_FMT_YUV444P12LE,
     166             :     AV_PIX_FMT_YUVA420P,     AV_PIX_FMT_YUVA422P,     AV_PIX_FMT_YUVA444P,
     167             :     AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE,
     168             :     AV_PIX_FMT_GRAY8,        AV_PIX_FMT_YUVJ420P,     AV_PIX_FMT_YUVJ422P,
     169             :     AV_PIX_FMT_YUVJ444P,     AV_PIX_FMT_YUVJ440P,     AV_PIX_FMT_NONE
     170             : };
     171             : 
     172           3 : static int query_formats(AVFilterContext *ctx)
     173             : {
     174           3 :     AVFilterFormats *fmts_list = ff_make_format_list(formats_supported);
     175           3 :     if (!fmts_list)
     176           0 :         return AVERROR(ENOMEM);
     177           3 :     return ff_set_common_formats(ctx, fmts_list);
     178             : }
     179             : 
     180           3 : static av_cold void uninit(AVFilterContext *ctx)
     181             : {
     182           3 :     InterlaceContext *s = ctx->priv;
     183             : 
     184           3 :     av_frame_free(&s->cur);
     185           3 :     av_frame_free(&s->next);
     186           3 : }
     187             : 
     188           3 : static int config_out_props(AVFilterLink *outlink)
     189             : {
     190           3 :     AVFilterContext *ctx = outlink->src;
     191           3 :     AVFilterLink *inlink = outlink->src->inputs[0];
     192           3 :     InterlaceContext *s = ctx->priv;
     193             : 
     194           3 :     if (inlink->h < 2) {
     195           0 :         av_log(ctx, AV_LOG_ERROR, "input video height is too small\n");
     196           0 :         return AVERROR_INVALIDDATA;
     197             :     }
     198             : 
     199           3 :     if (!s->lowpass)
     200           0 :         av_log(ctx, AV_LOG_WARNING, "Lowpass filter is disabled, "
     201             :                "the resulting video will be aliased rather than interlaced.\n");
     202             : 
     203             :     // same input size
     204           3 :     outlink->w = inlink->w;
     205           3 :     outlink->h = inlink->h;
     206           3 :     outlink->time_base = inlink->time_base;
     207           3 :     outlink->frame_rate = inlink->frame_rate;
     208             :     // half framerate
     209           3 :     outlink->time_base.num *= 2;
     210           3 :     outlink->frame_rate.den *= 2;
     211             : 
     212           3 :     s->csp = av_pix_fmt_desc_get(outlink->format);
     213           3 :     if (s->lowpass) {
     214           3 :         if (s->lowpass == VLPF_LIN) {
     215           2 :             if (s->csp->comp[0].depth > 8)
     216           0 :                 s->lowpass_line = lowpass_line_c_16;
     217             :             else
     218           2 :                 s->lowpass_line = lowpass_line_c;
     219           1 :         } else if (s->lowpass == VLPF_CMP) {
     220           1 :             if (s->csp->comp[0].depth > 8)
     221           0 :                 s->lowpass_line = lowpass_line_complex_c_16;
     222             :             else
     223           1 :                 s->lowpass_line = lowpass_line_complex_c;
     224             :         }
     225             :         if (ARCH_X86)
     226           3 :             ff_interlace_init_x86(s);
     227             :     }
     228             : 
     229           6 :     av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n",
     230           6 :            s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without");
     231             : 
     232           3 :     return 0;
     233             : }
     234             : 
     235         150 : static void copy_picture_field(InterlaceContext *s,
     236             :                                AVFrame *src_frame, AVFrame *dst_frame,
     237             :                                AVFilterLink *inlink, enum FieldType field_type,
     238             :                                int lowpass)
     239             : {
     240         150 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     241         150 :     int hsub = desc->log2_chroma_w;
     242         150 :     int vsub = desc->log2_chroma_h;
     243             :     int plane, j;
     244             : 
     245         600 :     for (plane = 0; plane < desc->nb_components; plane++) {
     246         450 :         int cols  = (plane == 1 || plane == 2) ? -(-inlink->w) >> hsub : inlink->w;
     247         450 :         int lines = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->h, vsub) : inlink->h;
     248         450 :         uint8_t *dstp = dst_frame->data[plane];
     249         450 :         const uint8_t *srcp = src_frame->data[plane];
     250         450 :         int srcp_linesize = src_frame->linesize[plane] * 2;
     251         450 :         int dstp_linesize = dst_frame->linesize[plane] * 2;
     252         450 :         int clip_max = (1 << s->csp->comp[plane].depth) - 1;
     253             : 
     254         450 :         av_assert0(cols >= 0 || lines >= 0);
     255             : 
     256         450 :         lines = (lines + (field_type == FIELD_UPPER)) / 2;
     257         450 :         if (field_type == FIELD_LOWER) {
     258         225 :             srcp += src_frame->linesize[plane];
     259         225 :             dstp += dst_frame->linesize[plane];
     260             :         }
     261         450 :         if (lowpass) {
     262         450 :             int x = 0;
     263         450 :             if (lowpass == VLPF_CMP)
     264         150 :                 x = 1;
     265       43650 :             for (j = lines; j > 0; j--) {
     266       43200 :                 ptrdiff_t pref = src_frame->linesize[plane];
     267       43200 :                 ptrdiff_t mref = -pref;
     268       43200 :                 if (j >= (lines - x))
     269         600 :                     mref = 0;
     270       42600 :                 else if (j <= (1 + x))
     271         600 :                     pref = 0;
     272       43200 :                 s->lowpass_line(dstp, cols, srcp, mref, pref, clip_max);
     273       43200 :                 dstp += dstp_linesize;
     274       43200 :                 srcp += srcp_linesize;
     275             :             }
     276             :         } else {
     277           0 :             if (s->csp->comp[plane].depth > 8)
     278           0 :                 cols *= 2;
     279           0 :             av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines);
     280             :         }
     281             :     }
     282         150 : }
     283             : 
     284         150 : static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
     285             : {
     286         150 :     AVFilterContext *ctx = inlink->dst;
     287         150 :     AVFilterLink *outlink = ctx->outputs[0];
     288         150 :     InterlaceContext *s = ctx->priv;
     289             :     AVFrame *out;
     290             :     int tff, ret;
     291             : 
     292         150 :     av_frame_free(&s->cur);
     293         150 :     s->cur  = s->next;
     294         150 :     s->next = buf;
     295             : 
     296             :     /* we need at least two frames */
     297         150 :     if (!s->cur || !s->next)
     298          75 :         return 0;
     299             : 
     300          75 :     if (s->cur->interlaced_frame) {
     301           0 :         av_log(ctx, AV_LOG_WARNING,
     302             :                "video is already interlaced, adjusting framerate only\n");
     303           0 :         out = av_frame_clone(s->cur);
     304           0 :         if (!out)
     305           0 :             return AVERROR(ENOMEM);
     306           0 :         out->pts /= 2;  // adjust pts to new framerate
     307           0 :         ret = ff_filter_frame(outlink, out);
     308           0 :         return ret;
     309             :     }
     310             : 
     311          75 :     tff = (s->scan == MODE_TFF);
     312          75 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     313          75 :     if (!out)
     314           0 :         return AVERROR(ENOMEM);
     315             : 
     316          75 :     av_frame_copy_props(out, s->cur);
     317          75 :     out->interlaced_frame = 1;
     318          75 :     out->top_field_first  = tff;
     319          75 :     out->pts             /= 2;  // adjust pts to new framerate
     320             : 
     321             :     /* copy upper/lower field from cur */
     322          75 :     copy_picture_field(s, s->cur, out, inlink, tff ? FIELD_UPPER : FIELD_LOWER, s->lowpass);
     323          75 :     av_frame_free(&s->cur);
     324             : 
     325             :     /* copy lower/upper field from next */
     326          75 :     copy_picture_field(s, s->next, out, inlink, tff ? FIELD_LOWER : FIELD_UPPER, s->lowpass);
     327          75 :     av_frame_free(&s->next);
     328             : 
     329          75 :     ret = ff_filter_frame(outlink, out);
     330             : 
     331          75 :     return ret;
     332             : }
     333             : 
     334             : static const AVFilterPad inputs[] = {
     335             :     {
     336             :         .name         = "default",
     337             :         .type         = AVMEDIA_TYPE_VIDEO,
     338             :         .filter_frame = filter_frame,
     339             :     },
     340             :     { NULL }
     341             : };
     342             : 
     343             : static const AVFilterPad outputs[] = {
     344             :     {
     345             :         .name         = "default",
     346             :         .type         = AVMEDIA_TYPE_VIDEO,
     347             :         .config_props = config_out_props,
     348             :     },
     349             :     { NULL }
     350             : };
     351             : 
     352             : AVFilter ff_vf_interlace = {
     353             :     .name          = "interlace",
     354             :     .description   = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
     355             :     .uninit        = uninit,
     356             :     .priv_class    = &interlace_class,
     357             :     .priv_size     = sizeof(InterlaceContext),
     358             :     .query_formats = query_formats,
     359             :     .inputs        = inputs,
     360             :     .outputs       = outputs,
     361             : };

Generated by: LCOV version 1.13