LCOV - code coverage report
Current view: top level - libavfilter - vf_tinterlace.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 208 258 80.6 %
Date: 2018-05-20 11:54:08 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
       3             :  * Copyright (c) 2011 Stefano Sabatini
       4             :  * Copyright (c) 2010 Baptiste Coudurier
       5             :  * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
       6             :  *
       7             :  * This file is part of FFmpeg.
       8             :  *
       9             :  * FFmpeg is free software; you can redistribute it and/or modify
      10             :  * it under the terms of the GNU General Public License as published by
      11             :  * the Free Software Foundation; either version 2 of the License, or
      12             :  * (at your option) any later version.
      13             :  *
      14             :  * FFmpeg is distributed in the hope that it will be useful,
      15             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :  * GNU General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU General Public License along
      20             :  * with FFmpeg if not, write to the Free Software Foundation, Inc.,
      21             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      22             :  */
      23             : 
      24             : /**
      25             :  * @file
      26             :  * temporal field interlace filter, ported from MPlayer/libmpcodecs
      27             :  */
      28             : 
      29             : #include "libavutil/opt.h"
      30             : #include "libavutil/imgutils.h"
      31             : #include "libavutil/avassert.h"
      32             : #include "avfilter.h"
      33             : #include "internal.h"
      34             : #include "tinterlace.h"
      35             : 
      36             : #define OFFSET(x) offsetof(TInterlaceContext, x)
      37             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      38             : 
      39             : static const AVOption tinterlace_options[] = {
      40             :     {"mode",              "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"},
      41             :     {"merge",             "merge fields",                                 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE},             INT_MIN, INT_MAX, FLAGS, "mode"},
      42             :     {"drop_even",         "drop even fields",                             0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN},         INT_MIN, INT_MAX, FLAGS, "mode"},
      43             :     {"drop_odd",          "drop odd fields",                              0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD},          INT_MIN, INT_MAX, FLAGS, "mode"},
      44             :     {"pad",               "pad alternate lines with black",               0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD},               INT_MIN, INT_MAX, FLAGS, "mode"},
      45             :     {"interleave_top",    "interleave top and bottom fields",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},    INT_MIN, INT_MAX, FLAGS, "mode"},
      46             :     {"interleave_bottom", "interleave bottom and top fields",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"},
      47             :     {"interlacex2",       "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2},       INT_MIN, INT_MAX, FLAGS, "mode"},
      48             :     {"mergex2",           "merge fields keeping same frame rate",         0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGEX2},           INT_MIN, INT_MAX, FLAGS, "mode"},
      49             : 
      50             :     {"flags",             "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
      51             :     {"low_pass_filter",   "enable vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
      52             :     {"vlpf",              "enable vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
      53             :     {"complex_filter",    "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
      54             :     {"cvlpf",             "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
      55             :     {"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" },
      56             : 
      57             :     {NULL}
      58             : };
      59             : 
      60             : AVFILTER_DEFINE_CLASS(tinterlace);
      61             : 
      62             : static const AVOption interlace_options[] = {
      63             :    { "scan",              "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_INTERLEAVE_TOP}, 0, MODE_NB-1, FLAGS, "mode"},
      64             :    { "tff",               "top field first",                              0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},    INT_MIN, INT_MAX, FLAGS, .unit = "mode" },
      65             :    { "bff",               "bottom field first",                           0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"},
      66             :    { "lowpass",           "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS,   {.i64 = TINTERLACE_FLAG_VLPF}, 0,INT_MAX, 0, "flags" },
      67             :    { "off",               "disable vertical low-pass filter",             0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "flags" },
      68             :    { "linear",            "linear vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
      69             :    { "complex",           "complex vertical low-pass filter",             0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
      70             : 
      71             :    { NULL }
      72             : };
      73             : 
      74             : AVFILTER_DEFINE_CLASS(interlace);
      75             : 
      76             : #define FULL_SCALE_YUVJ_FORMATS \
      77             :     AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
      78             : 
      79             : static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
      80             :     FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE
      81             : };
      82             : 
      83             : static const AVRational standard_tbs[] = {
      84             :     {1, 25},
      85             :     {1, 30},
      86             :     {1001, 30000},
      87             : };
      88             : 
      89         117 : static int query_formats(AVFilterContext *ctx)
      90             : {
      91             :     static const enum AVPixelFormat pix_fmts[] = {
      92             :         AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
      93             :         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
      94             :         AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
      95             :         AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE,
      96             :         AV_PIX_FMT_YUV440P10LE, AV_PIX_FMT_YUV444P10LE,
      97             :         AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV422P12LE,
      98             :         AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE,
      99             :         AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
     100             :         AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE,
     101             :         AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS,
     102             :         AV_PIX_FMT_NONE
     103             :     };
     104             : 
     105         117 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     106         117 :     if (!fmts_list)
     107           0 :         return AVERROR(ENOMEM);
     108         117 :     return ff_set_common_formats(ctx, fmts_list);
     109             : }
     110             : 
     111       39312 : static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
     112             :                            ptrdiff_t mref, ptrdiff_t pref, int clip_max)
     113             : {
     114       39312 :     const uint8_t *srcp_above = srcp + mref;
     115       39312 :     const uint8_t *srcp_below = srcp + pref;
     116             :     int i;
     117    10696464 :     for (i = 0; i < width; i++) {
     118             :         // this calculation is an integer representation of
     119             :         // '0.5 * current + 0.25 * above + 0.25 * below'
     120             :         // '1 +' is for rounding.
     121    10657152 :         dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
     122             :     }
     123       39312 : }
     124             : 
     125        8928 : static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
     126             :                               ptrdiff_t mref, ptrdiff_t pref, int clip_max)
     127             : {
     128        8928 :     uint16_t *dstp = (uint16_t *)dst8;
     129        8928 :     const uint16_t *srcp = (const uint16_t *)src8;
     130        8928 :     const uint16_t *srcp_above = srcp + mref / 2;
     131        8928 :     const uint16_t *srcp_below = srcp + pref / 2;
     132             :     int i, src_x;
     133     2695392 :     for (i = 0; i < width; i++) {
     134             :         // this calculation is an integer representation of
     135             :         // '0.5 * current + 0.25 * above + 0.25 * below'
     136             :         // '1 +' is for rounding.
     137     2686464 :         src_x   = av_le2ne16(srcp[i]) << 1;
     138     2686464 :         dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i])
     139             :                              + av_le2ne16(srcp_below[i])) >> 2);
     140             :     }
     141        8928 : }
     142             : 
     143       24912 : static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
     144             :                                    ptrdiff_t mref, ptrdiff_t pref, int clip_max)
     145             : {
     146       24912 :     const uint8_t *srcp_above = srcp + mref;
     147       24912 :     const uint8_t *srcp_below = srcp + pref;
     148       24912 :     const uint8_t *srcp_above2 = srcp + mref * 2;
     149       24912 :     const uint8_t *srcp_below2 = srcp + pref * 2;
     150             :     int i, src_x, src_ab;
     151     6880464 :     for (i = 0; i < width; i++) {
     152             :         // this calculation is an integer representation of
     153             :         // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
     154             :         // '4 +' is for rounding.
     155     6855552 :         src_x   = srcp[i] << 1;
     156     6855552 :         src_ab  = srcp_above[i] + srcp_below[i];
     157    13711104 :         dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1)
     158     6855552 :                                 - srcp_above2[i] - srcp_below2[i]) >> 3);
     159             :         // Prevent over-sharpening:
     160             :         // dst must not exceed src when the average of above and below
     161             :         // is less than src. And the other way around.
     162     6855552 :         if (src_ab > src_x) {
     163     2774592 :             if (dstp[i] < srcp[i])
     164      384549 :                 dstp[i] = srcp[i];
     165     4080960 :         } else if (dstp[i] > srcp[i])
     166      487484 :             dstp[i] = srcp[i];
     167             :     }
     168       24912 : }
     169             : 
     170        8928 : static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
     171             :                                       ptrdiff_t mref, ptrdiff_t pref, int clip_max)
     172             : {
     173        8928 :     uint16_t *dstp = (uint16_t *)dst8;
     174        8928 :     const uint16_t *srcp = (const uint16_t *)src8;
     175        8928 :     const uint16_t *srcp_above = srcp + mref / 2;
     176        8928 :     const uint16_t *srcp_below = srcp + pref / 2;
     177        8928 :     const uint16_t *srcp_above2 = srcp + mref;
     178        8928 :     const uint16_t *srcp_below2 = srcp + pref;
     179             :     int i, dst_le, src_le, src_x, src_ab;
     180     2695392 :     for (i = 0; i < width; i++) {
     181             :         // this calculation is an integer representation of
     182             :         // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
     183             :         // '4 +' is for rounding.
     184     2686464 :         src_le = av_le2ne16(srcp[i]);
     185     2686464 :         src_x  = src_le << 1;
     186     2686464 :         src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]);
     187     5372928 :         dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1)
     188     2686464 :                          - av_le2ne16(srcp_above2[i])
     189     2686464 :                          - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max);
     190             :         // Prevent over-sharpening:
     191             :         // dst must not exceed src when the average of above and below
     192             :         // is less than src. And the other way around.
     193     2686464 :         if (src_ab > src_x) {
     194     1072111 :             if (dst_le < src_le)
     195      270609 :                 dstp[i] = av_le2ne16(src_le);
     196             :             else
     197      801502 :                 dstp[i] = av_le2ne16(dst_le);
     198     1614353 :         } else if (dst_le > src_le) {
     199      306777 :             dstp[i] = av_le2ne16(src_le);
     200             :         } else
     201     1307576 :             dstp[i] = av_le2ne16(dst_le);
     202             :     }
     203        8928 : }
     204             : 
     205         117 : static av_cold void uninit(AVFilterContext *ctx)
     206             : {
     207         117 :     TInterlaceContext *tinterlace = ctx->priv;
     208             : 
     209         117 :     av_frame_free(&tinterlace->cur );
     210         117 :     av_frame_free(&tinterlace->next);
     211         117 :     av_freep(&tinterlace->black_data[0]);
     212         117 : }
     213             : 
     214         113 : static int config_out_props(AVFilterLink *outlink)
     215             : {
     216         113 :     AVFilterContext *ctx = outlink->src;
     217         113 :     AVFilterLink *inlink = outlink->src->inputs[0];
     218         113 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     219         113 :     TInterlaceContext *tinterlace = ctx->priv;
     220             :     int i;
     221             : 
     222         113 :     tinterlace->vsub = desc->log2_chroma_h;
     223         113 :     outlink->w = inlink->w;
     224         314 :     outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2?
     225         163 :         inlink->h*2 : inlink->h;
     226         113 :     if (tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2)
     227          50 :         outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio,
     228             :                                                 av_make_q(2, 1));
     229             : 
     230         113 :     if (tinterlace->mode == MODE_PAD) {
     231          25 :         uint8_t black[4] = { 0, 0, 0, 16 };
     232             :         int ret;
     233          25 :         ff_draw_init(&tinterlace->draw, outlink->format, 0);
     234          25 :         ff_draw_color(&tinterlace->draw, &tinterlace->color, black);
     235          25 :         if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
     236           4 :             tinterlace->color.comp[0].u8[0] = 0;
     237          25 :         ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
     238          25 :                              outlink->w, outlink->h, outlink->format, 16);
     239          25 :         if (ret < 0)
     240           0 :             return ret;
     241             : 
     242          50 :         ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data,
     243          25 :                           tinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
     244             :     }
     245         113 :     if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)
     246          53 :             && !(tinterlace->mode == MODE_INTERLEAVE_TOP
     247           0 :               || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
     248           0 :         av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n",
     249             :                 tinterlace->mode);
     250           0 :         tinterlace->flags &= ~(TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF);
     251             :     }
     252         113 :     tinterlace->preout_time_base = inlink->time_base;
     253         113 :     if (tinterlace->mode == MODE_INTERLACEX2) {
     254           0 :         tinterlace->preout_time_base.den *= 2;
     255           0 :         outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
     256           0 :         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){1,2});
     257         113 :     } else if (tinterlace->mode == MODE_MERGEX2) {
     258           0 :         outlink->frame_rate = inlink->frame_rate;
     259           0 :         outlink->time_base  = inlink->time_base;
     260         113 :     } else if (tinterlace->mode != MODE_PAD) {
     261          88 :         outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
     262          88 :         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
     263             :     }
     264             : 
     265         452 :     for (i = 0; i<FF_ARRAY_ELEMS(standard_tbs); i++){
     266         339 :         if (!av_cmp_q(standard_tbs[i], outlink->time_base))
     267           0 :             break;
     268             :     }
     269         113 :     if (i == FF_ARRAY_ELEMS(standard_tbs) ||
     270           0 :         (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
     271         113 :         outlink->time_base = tinterlace->preout_time_base;
     272             : 
     273         113 :     tinterlace->csp = av_pix_fmt_desc_get(outlink->format);
     274         113 :     if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) {
     275          26 :         if (tinterlace->csp->comp[0].depth > 8)
     276          11 :             tinterlace->lowpass_line = lowpass_line_complex_c_16;
     277             :         else
     278          15 :             tinterlace->lowpass_line = lowpass_line_complex_c;
     279             :         if (ARCH_X86)
     280          26 :             ff_tinterlace_init_x86(tinterlace);
     281          87 :     } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
     282          27 :         if (tinterlace->csp->comp[0].depth > 8)
     283          11 :             tinterlace->lowpass_line = lowpass_line_c_16;
     284             :         else
     285          16 :             tinterlace->lowpass_line = lowpass_line_c;
     286             :         if (ARCH_X86)
     287          27 :             ff_tinterlace_init_x86(tinterlace);
     288             :     }
     289             : 
     290         313 :     av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode,
     291         113 :            (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
     292          87 :            (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off",
     293             :            inlink->h, outlink->h);
     294             : 
     295         113 :     return 0;
     296             : }
     297             : 
     298             : #define FIELD_UPPER           0
     299             : #define FIELD_LOWER           1
     300             : #define FIELD_UPPER_AND_LOWER 2
     301             : 
     302             : /**
     303             :  * Copy picture field from src to dst.
     304             :  *
     305             :  * @param src_field copy from upper, lower field or both
     306             :  * @param interleave leave a padding line between each copied line
     307             :  * @param dst_field copy to upper or lower field,
     308             :  *        only meaningful when interleave is selected
     309             :  * @param flags context flags
     310             :  */
     311             : static inline
     312         370 : void copy_picture_field(TInterlaceContext *tinterlace,
     313             :                         uint8_t *dst[4], int dst_linesize[4],
     314             :                         const uint8_t *src[4], int src_linesize[4],
     315             :                         enum AVPixelFormat format, int w, int src_h,
     316             :                         int src_field, int interleave, int dst_field,
     317             :                         int flags)
     318             : {
     319         370 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
     320         370 :     int hsub = desc->log2_chroma_w;
     321         370 :     int plane, vsub = desc->log2_chroma_h;
     322         370 :     int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
     323             :     int h;
     324             : 
     325        1512 :     for (plane = 0; plane < desc->nb_components; plane++) {
     326        1142 :         int lines = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(src_h, vsub) : src_h;
     327        1142 :         int cols  = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(    w, hsub) : w;
     328        1142 :         uint8_t *dstp = dst[plane];
     329        1142 :         const uint8_t *srcp = src[plane];
     330        1142 :         int srcp_linesize = src_linesize[plane] * k;
     331        1142 :         int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
     332        1142 :         int clip_max = (1 << tinterlace->csp->comp[plane].depth) - 1;
     333             : 
     334        1142 :         lines = (lines + (src_field == FIELD_UPPER)) / k;
     335        1142 :         if (src_field == FIELD_LOWER)
     336         413 :             srcp += src_linesize[plane];
     337        1142 :         if (interleave && dst_field == FIELD_LOWER)
     338         571 :             dstp += dst_linesize[plane];
     339             :         // Low-pass filtering is required when creating an interlaced destination from
     340             :         // a progressive source which contains high-frequency vertical detail.
     341             :         // Filtering will reduce interlace 'twitter' and Moire patterning.
     342        1142 :         if (flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)) {
     343         766 :             int x = !!(flags & TINTERLACE_FLAG_CVLPF);
     344       82846 :             for (h = lines; h > 0; h--) {
     345       82080 :                 ptrdiff_t pref = src_linesize[plane];
     346       82080 :                 ptrdiff_t mref = -pref;
     347       82080 :                 if (h >= (lines - x))  mref = 0; // there is no line above
     348       81006 :                 else if (h <= (1 + x)) pref = 0; // there is no line below
     349             : 
     350       82080 :                 tinterlace->lowpass_line(dstp, cols, srcp, mref, pref, clip_max);
     351       82080 :                 dstp += dstp_linesize;
     352       82080 :                 srcp += srcp_linesize;
     353             :             }
     354             :         } else {
     355         376 :             if (tinterlace->csp->comp[plane].depth > 8)
     356         144 :                 cols *= 2;
     357         376 :             av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines);
     358             :         }
     359             :     }
     360         370 : }
     361             : 
     362         370 : static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
     363             : {
     364         370 :     AVFilterContext *ctx = inlink->dst;
     365         370 :     AVFilterLink *outlink = ctx->outputs[0];
     366         370 :     TInterlaceContext *tinterlace = ctx->priv;
     367             :     AVFrame *cur, *next, *out;
     368             :     int field, tff, ret;
     369             : 
     370         370 :     av_frame_free(&tinterlace->cur);
     371         370 :     tinterlace->cur  = tinterlace->next;
     372         370 :     tinterlace->next = picref;
     373             : 
     374         370 :     cur = tinterlace->cur;
     375         370 :     next = tinterlace->next;
     376             :     /* we need at least two frames */
     377         370 :     if (!tinterlace->cur)
     378         185 :         return 0;
     379             : 
     380         185 :     switch (tinterlace->mode) {
     381          25 :     case MODE_MERGEX2: /* move the odd frame into the upper field of the new image, even into
     382             :                         * the lower field, generating a double-height video at same framerate */
     383             :     case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
     384             :              * the lower field, generating a double-height video at half framerate */
     385          25 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     386          25 :         if (!out)
     387           0 :             return AVERROR(ENOMEM);
     388          25 :         av_frame_copy_props(out, cur);
     389          25 :         out->height = outlink->h;
     390          25 :         out->interlaced_frame = 1;
     391          25 :         out->top_field_first = 1;
     392          25 :         out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
     393             : 
     394             :         /* write odd frame lines into the upper field of the new frame */
     395          75 :         copy_picture_field(tinterlace, out->data, out->linesize,
     396          25 :                            (const uint8_t **)cur->data, cur->linesize,
     397          25 :                            inlink->format, inlink->w, inlink->h,
     398          25 :                            FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags);
     399             :         /* write even frame lines into the lower field of the new frame */
     400          75 :         copy_picture_field(tinterlace, out->data, out->linesize,
     401          25 :                            (const uint8_t **)next->data, next->linesize,
     402          25 :                            inlink->format, inlink->w, inlink->h,
     403          25 :                            FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags);
     404          25 :         if (tinterlace->mode != MODE_MERGEX2)
     405          25 :             av_frame_free(&tinterlace->next);
     406          25 :         break;
     407             : 
     408           0 :     case MODE_DROP_ODD:  /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
     409             :     case MODE_DROP_EVEN: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
     410           0 :         out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next);
     411           0 :         if (!out)
     412           0 :             return AVERROR(ENOMEM);
     413           0 :         av_frame_free(&tinterlace->next);
     414           0 :         break;
     415             : 
     416          25 :     case MODE_PAD: /* expand each frame to double height, but pad alternate
     417             :                     * lines with black; framerate unchanged */
     418          25 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     419          25 :         if (!out)
     420           0 :             return AVERROR(ENOMEM);
     421          25 :         av_frame_copy_props(out, cur);
     422          25 :         out->height = outlink->h;
     423          25 :         out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
     424             : 
     425          25 :         field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
     426             :         /* copy upper and lower fields */
     427          50 :         copy_picture_field(tinterlace, out->data, out->linesize,
     428          25 :                            (const uint8_t **)cur->data, cur->linesize,
     429          25 :                            inlink->format, inlink->w, inlink->h,
     430             :                            FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags);
     431             :         /* pad with black the other field */
     432          50 :         copy_picture_field(tinterlace, out->data, out->linesize,
     433          25 :                            (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
     434          25 :                            inlink->format, inlink->w, inlink->h,
     435             :                            FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags);
     436          25 :         break;
     437             : 
     438             :         /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
     439             :          * halving the frame rate and preserving image height */
     440         135 :     case MODE_INTERLEAVE_TOP:    /* top    field first */
     441             :     case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
     442         135 :         tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
     443         135 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     444         135 :         if (!out)
     445           0 :             return AVERROR(ENOMEM);
     446         135 :         av_frame_copy_props(out, cur);
     447         135 :         out->interlaced_frame = 1;
     448         135 :         out->top_field_first = tff;
     449             : 
     450             :         /* copy upper/lower field from cur */
     451         270 :         copy_picture_field(tinterlace, out->data, out->linesize,
     452         135 :                            (const uint8_t **)cur->data, cur->linesize,
     453         135 :                            inlink->format, inlink->w, inlink->h,
     454             :                            tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
     455             :                            tinterlace->flags);
     456             :         /* copy lower/upper field from next */
     457         270 :         copy_picture_field(tinterlace, out->data, out->linesize,
     458         135 :                            (const uint8_t **)next->data, next->linesize,
     459         135 :                            inlink->format, inlink->w, inlink->h,
     460             :                            tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
     461             :                            tinterlace->flags);
     462         135 :         av_frame_free(&tinterlace->next);
     463         135 :         break;
     464           0 :     case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
     465             :         /* output current frame first */
     466           0 :         out = av_frame_clone(cur);
     467           0 :         if (!out)
     468           0 :             return AVERROR(ENOMEM);
     469           0 :         out->interlaced_frame = 1;
     470           0 :         if (cur->pts != AV_NOPTS_VALUE)
     471           0 :             out->pts = cur->pts*2;
     472             : 
     473           0 :         out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
     474           0 :         if ((ret = ff_filter_frame(outlink, out)) < 0)
     475           0 :             return ret;
     476             : 
     477             :         /* output mix of current and next frame */
     478           0 :         tff = next->top_field_first;
     479           0 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     480           0 :         if (!out)
     481           0 :             return AVERROR(ENOMEM);
     482           0 :         av_frame_copy_props(out, next);
     483           0 :         out->interlaced_frame = 1;
     484           0 :         out->top_field_first = !tff;
     485             : 
     486           0 :         if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE)
     487           0 :             out->pts = cur->pts + next->pts;
     488             :         else
     489           0 :             out->pts = AV_NOPTS_VALUE;
     490             :         /* write current frame second field lines into the second field of the new frame */
     491           0 :         copy_picture_field(tinterlace, out->data, out->linesize,
     492           0 :                            (const uint8_t **)cur->data, cur->linesize,
     493           0 :                            inlink->format, inlink->w, inlink->h,
     494             :                            tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
     495             :                            tinterlace->flags);
     496             :         /* write next frame first field lines into the first field of the new frame */
     497           0 :         copy_picture_field(tinterlace, out->data, out->linesize,
     498           0 :                            (const uint8_t **)next->data, next->linesize,
     499           0 :                            inlink->format, inlink->w, inlink->h,
     500             :                            tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
     501             :                            tinterlace->flags);
     502           0 :         break;
     503           0 :     default:
     504           0 :         av_assert0(0);
     505             :     }
     506             : 
     507         185 :     out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
     508         185 :     ret = ff_filter_frame(outlink, out);
     509         185 :     tinterlace->frame++;
     510             : 
     511         185 :     return ret;
     512             : }
     513             : 
     514             : static const AVFilterPad tinterlace_inputs[] = {
     515             :     {
     516             :         .name         = "default",
     517             :         .type         = AVMEDIA_TYPE_VIDEO,
     518             :         .filter_frame = filter_frame,
     519             :     },
     520             :     { NULL }
     521             : };
     522             : 
     523             : static const AVFilterPad tinterlace_outputs[] = {
     524             :     {
     525             :         .name         = "default",
     526             :         .type         = AVMEDIA_TYPE_VIDEO,
     527             :         .config_props = config_out_props,
     528             :     },
     529             :     { NULL }
     530             : };
     531             : 
     532             : AVFilter ff_vf_tinterlace = {
     533             :     .name          = "tinterlace",
     534             :     .description   = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
     535             :     .priv_size     = sizeof(TInterlaceContext),
     536             :     .uninit        = uninit,
     537             :     .query_formats = query_formats,
     538             :     .inputs        = tinterlace_inputs,
     539             :     .outputs       = tinterlace_outputs,
     540             :     .priv_class    = &tinterlace_class,
     541             : };
     542             : 
     543             : 
     544             : AVFilter ff_vf_interlace = {
     545             :     .name          = "interlace",
     546             :     .description   = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
     547             :     .priv_size     = sizeof(TInterlaceContext),
     548             :     .uninit        = uninit,
     549             :     .query_formats = query_formats,
     550             :     .inputs        = tinterlace_inputs,
     551             :     .outputs       = tinterlace_outputs,
     552             :     .priv_class    = &interlace_class,
     553             : };

Generated by: LCOV version 1.13