LCOV - code coverage report
Current view: top level - libavfilter - vf_kerndeint.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 107 139 77.0 %
Date: 2017-12-16 13:57:32 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012 Jeremy Tran
       3             :  * Copyright (c) 2004 Tobias Diedrich
       4             :  * Copyright (c) 2003 Donald A. Graft
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU General Public License as published by
      10             :  * the Free Software Foundation; either version 2 of the License, or
      11             :  * (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License along
      19             :  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
      20             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      21             :  */
      22             : 
      23             : /**
      24             :  * @file
      25             :  * Kernel Deinterlacer
      26             :  * Ported from MPlayer libmpcodecs/vf_kerndeint.c.
      27             :  */
      28             : 
      29             : #include "libavutil/imgutils.h"
      30             : #include "libavutil/intreadwrite.h"
      31             : #include "libavutil/opt.h"
      32             : #include "libavutil/pixdesc.h"
      33             : 
      34             : #include "avfilter.h"
      35             : #include "formats.h"
      36             : #include "internal.h"
      37             : 
      38             : typedef struct KerndeintContext {
      39             :     const AVClass *class;
      40             :     int           frame; ///< frame count, starting from 0
      41             :     int           thresh, map, order, sharp, twoway;
      42             :     int           vsub;
      43             :     int           is_packed_rgb;
      44             :     uint8_t       *tmp_data    [4];  ///< temporary plane data buffer
      45             :     int            tmp_linesize[4];  ///< temporary plane byte linesize
      46             :     int            tmp_bwidth  [4];  ///< temporary plane byte width
      47             : } KerndeintContext;
      48             : 
      49             : #define OFFSET(x) offsetof(KerndeintContext, x)
      50             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      51             : static const AVOption kerndeint_options[] = {
      52             :     { "thresh", "set the threshold", OFFSET(thresh), AV_OPT_TYPE_INT, {.i64=10}, 0, 255, FLAGS },
      53             :     { "map",    "set the map",    OFFSET(map),    AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
      54             :     { "order",  "set the order",  OFFSET(order),  AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
      55             :     { "sharp",  "set sharpening", OFFSET(sharp),  AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
      56             :     { "twoway", "set twoway",     OFFSET(twoway), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
      57             :     { NULL }
      58             : };
      59             : 
      60             : AVFILTER_DEFINE_CLASS(kerndeint);
      61             : 
      62          11 : static av_cold void uninit(AVFilterContext *ctx)
      63             : {
      64          11 :     KerndeintContext *kerndeint = ctx->priv;
      65             : 
      66          11 :     av_freep(&kerndeint->tmp_data[0]);
      67          11 : }
      68             : 
      69          11 : static int query_formats(AVFilterContext *ctx)
      70             : {
      71             :     static const enum AVPixelFormat pix_fmts[] = {
      72             :         AV_PIX_FMT_YUV420P,
      73             :         AV_PIX_FMT_YUYV422,
      74             :         AV_PIX_FMT_ARGB, AV_PIX_FMT_0RGB,
      75             :         AV_PIX_FMT_ABGR, AV_PIX_FMT_0BGR,
      76             :         AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB0,
      77             :         AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR0,
      78             :         AV_PIX_FMT_NONE
      79             :     };
      80             : 
      81          11 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
      82          11 :     if (!fmts_list)
      83           0 :         return AVERROR(ENOMEM);
      84          11 :     return ff_set_common_formats(ctx, fmts_list);
      85             : }
      86             : 
      87          10 : static int config_props(AVFilterLink *inlink)
      88             : {
      89          10 :     KerndeintContext *kerndeint = inlink->dst->priv;
      90          10 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
      91             :     int ret;
      92             : 
      93          10 :     kerndeint->is_packed_rgb = av_pix_fmt_desc_get(inlink->format)->flags & AV_PIX_FMT_FLAG_RGB;
      94          10 :     kerndeint->vsub = desc->log2_chroma_h;
      95             : 
      96          10 :     ret = av_image_alloc(kerndeint->tmp_data, kerndeint->tmp_linesize,
      97          10 :                          inlink->w, inlink->h, inlink->format, 16);
      98          10 :     if (ret < 0)
      99           0 :         return ret;
     100          10 :     memset(kerndeint->tmp_data[0], 0, ret);
     101             : 
     102          10 :     if ((ret = av_image_fill_linesizes(kerndeint->tmp_bwidth, inlink->format, inlink->w)) < 0)
     103           0 :         return ret;
     104             : 
     105          10 :     return 0;
     106             : }
     107             : 
     108          10 : static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
     109             : {
     110          10 :     KerndeintContext *kerndeint = inlink->dst->priv;
     111          10 :     AVFilterLink *outlink = inlink->dst->outputs[0];
     112             :     AVFrame *outpic;
     113             :     const uint8_t *prvp;   ///< Previous field's pixel line number n
     114             :     const uint8_t *prvpp;  ///< Previous field's pixel line number (n - 1)
     115             :     const uint8_t *prvpn;  ///< Previous field's pixel line number (n + 1)
     116             :     const uint8_t *prvppp; ///< Previous field's pixel line number (n - 2)
     117             :     const uint8_t *prvpnn; ///< Previous field's pixel line number (n + 2)
     118             :     const uint8_t *prvp4p; ///< Previous field's pixel line number (n - 4)
     119             :     const uint8_t *prvp4n; ///< Previous field's pixel line number (n + 4)
     120             : 
     121             :     const uint8_t *srcp;   ///< Current field's pixel line number n
     122             :     const uint8_t *srcpp;  ///< Current field's pixel line number (n - 1)
     123             :     const uint8_t *srcpn;  ///< Current field's pixel line number (n + 1)
     124             :     const uint8_t *srcppp; ///< Current field's pixel line number (n - 2)
     125             :     const uint8_t *srcpnn; ///< Current field's pixel line number (n + 2)
     126             :     const uint8_t *srcp3p; ///< Current field's pixel line number (n - 3)
     127             :     const uint8_t *srcp3n; ///< Current field's pixel line number (n + 3)
     128             :     const uint8_t *srcp4p; ///< Current field's pixel line number (n - 4)
     129             :     const uint8_t *srcp4n; ///< Current field's pixel line number (n + 4)
     130             : 
     131             :     uint8_t *dstp, *dstp_saved;
     132             :     const uint8_t *srcp_saved;
     133             : 
     134             :     int src_linesize, psrc_linesize, dst_linesize, bwidth;
     135          10 :     int x, y, plane, val, hi, lo, g, h, n = kerndeint->frame++;
     136             :     double valf;
     137             : 
     138          10 :     const int thresh = kerndeint->thresh;
     139          10 :     const int order  = kerndeint->order;
     140          10 :     const int map    = kerndeint->map;
     141          10 :     const int sharp  = kerndeint->sharp;
     142          10 :     const int twoway = kerndeint->twoway;
     143             : 
     144          10 :     const int is_packed_rgb = kerndeint->is_packed_rgb;
     145             : 
     146          10 :     outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     147          10 :     if (!outpic) {
     148           0 :         av_frame_free(&inpic);
     149           0 :         return AVERROR(ENOMEM);
     150             :     }
     151          10 :     av_frame_copy_props(outpic, inpic);
     152          10 :     outpic->interlaced_frame = 0;
     153             : 
     154          22 :     for (plane = 0; plane < 4 && inpic->data[plane] && inpic->linesize[plane]; plane++) {
     155          12 :         h = plane == 0 ? inlink->h : AV_CEIL_RSHIFT(inlink->h, kerndeint->vsub);
     156          12 :         bwidth = kerndeint->tmp_bwidth[plane];
     157             : 
     158          12 :         srcp_saved        = inpic->data[plane];
     159          12 :         src_linesize      = inpic->linesize[plane];
     160          12 :         psrc_linesize     = kerndeint->tmp_linesize[plane];
     161          12 :         dstp_saved        = outpic->data[plane];
     162          12 :         dst_linesize      = outpic->linesize[plane];
     163          12 :         srcp              = srcp_saved + (1 - order) * src_linesize;
     164          12 :         dstp              = dstp_saved + (1 - order) * dst_linesize;
     165             : 
     166        1596 :         for (y = 0; y < h; y += 2) {
     167        1584 :             memcpy(dstp, srcp, bwidth);
     168        1584 :             srcp += 2 * src_linesize;
     169        1584 :             dstp += 2 * dst_linesize;
     170             :         }
     171             : 
     172             :         // Copy through the lines that will be missed below.
     173          12 :         memcpy(dstp_saved + order            * dst_linesize, srcp_saved + (1 -     order) * src_linesize, bwidth);
     174          12 :         memcpy(dstp_saved + (2 + order    )  * dst_linesize, srcp_saved + (3 -     order) * src_linesize, bwidth);
     175          12 :         memcpy(dstp_saved + (h - 2 + order)  * dst_linesize, srcp_saved + (h - 1 - order) * src_linesize, bwidth);
     176          12 :         memcpy(dstp_saved + (h - 4 + order)  * dst_linesize, srcp_saved + (h - 3 - order) * src_linesize, bwidth);
     177             : 
     178             :         /* For the other field choose adaptively between using the previous field
     179             :            or the interpolant from the current field. */
     180          12 :         prvp   = kerndeint->tmp_data[plane] + 5 * psrc_linesize - (1 - order) * psrc_linesize;
     181          12 :         prvpp  = prvp - psrc_linesize;
     182          12 :         prvppp = prvp - 2 * psrc_linesize;
     183          12 :         prvp4p = prvp - 4 * psrc_linesize;
     184          12 :         prvpn  = prvp + psrc_linesize;
     185          12 :         prvpnn = prvp + 2 * psrc_linesize;
     186          12 :         prvp4n = prvp + 4 * psrc_linesize;
     187             : 
     188          12 :         srcp   = srcp_saved + 5 * src_linesize - (1 - order) * src_linesize;
     189          12 :         srcpp  = srcp - src_linesize;
     190          12 :         srcppp = srcp - 2 * src_linesize;
     191          12 :         srcp3p = srcp - 3 * src_linesize;
     192          12 :         srcp4p = srcp - 4 * src_linesize;
     193             : 
     194          12 :         srcpn  = srcp + src_linesize;
     195          12 :         srcpnn = srcp + 2 * src_linesize;
     196          12 :         srcp3n = srcp + 3 * src_linesize;
     197          12 :         srcp4n = srcp + 4 * src_linesize;
     198             : 
     199          12 :         dstp   = dstp_saved + 5 * dst_linesize - (1 - order) * dst_linesize;
     200             : 
     201        1548 :         for (y = 5 - (1 - order); y <= h - 5 - (1 - order); y += 2) {
     202     1750272 :             for (x = 0; x < bwidth; x++) {
     203     1748736 :                 if (thresh == 0 || n == 0 ||
     204           0 :                     (abs((int)prvp[x]  - (int)srcp[x])  > thresh) ||
     205           0 :                     (abs((int)prvpp[x] - (int)srcpp[x]) > thresh) ||
     206           0 :                     (abs((int)prvpn[x] - (int)srcpn[x]) > thresh)) {
     207     3497472 :                     if (map) {
     208           0 :                         g = x & ~3;
     209             : 
     210           0 :                         if (is_packed_rgb) {
     211           0 :                             AV_WB32(dstp + g, 0xffffffff);
     212           0 :                             x = g + 3;
     213           0 :                         } else if (inlink->format == AV_PIX_FMT_YUYV422) {
     214             :                             // y <- 235, u <- 128, y <- 235, v <- 128
     215           0 :                             AV_WB32(dstp + g, 0xeb80eb80);
     216           0 :                             x = g + 3;
     217             :                         } else {
     218           0 :                             dstp[x] = plane == 0 ? 235 : 128;
     219             :                         }
     220             :                     } else {
     221     1748736 :                         if (is_packed_rgb) {
     222     1576960 :                             hi = 255;
     223     1576960 :                             lo = 0;
     224      171776 :                         } else if (inlink->format == AV_PIX_FMT_YUYV422) {
     225       98560 :                             hi = x & 1 ? 240 : 235;
     226       98560 :                             lo = 16;
     227             :                         } else {
     228       73216 :                             hi = plane == 0 ? 235 : 240;
     229       73216 :                             lo = 16;
     230             :                         }
     231             : 
     232     1748736 :                         if (sharp) {
     233           0 :                             if (twoway) {
     234           0 :                                 valf = + 0.526 * ((int)srcpp[x] + (int)srcpn[x])
     235           0 :                                     + 0.170 * ((int)srcp[x] + (int)prvp[x])
     236           0 :                                     - 0.116 * ((int)srcppp[x] + (int)srcpnn[x] + (int)prvppp[x] + (int)prvpnn[x])
     237           0 :                                     - 0.026 * ((int)srcp3p[x] + (int)srcp3n[x])
     238           0 :                                     + 0.031 * ((int)srcp4p[x] + (int)srcp4n[x] + (int)prvp4p[x] + (int)prvp4n[x]);
     239             :                             } else {
     240           0 :                                 valf = + 0.526 * ((int)srcpp[x] + (int)srcpn[x])
     241           0 :                                     + 0.170 * ((int)prvp[x])
     242           0 :                                     - 0.116 * ((int)prvppp[x] + (int)prvpnn[x])
     243           0 :                                     - 0.026 * ((int)srcp3p[x] + (int)srcp3n[x])
     244           0 :                                     + 0.031 * ((int)prvp4p[x] + (int)prvp4p[x]);
     245             :                             }
     246           0 :                             dstp[x] = av_clip(valf, lo, hi);
     247             :                         } else {
     248     1748736 :                             if (twoway) {
     249           0 :                                 val = (8 * ((int)srcpp[x] + (int)srcpn[x]) + 2 * ((int)srcp[x] + (int)prvp[x])
     250           0 :                                        - (int)(srcppp[x]) - (int)(srcpnn[x])
     251           0 :                                        - (int)(prvppp[x]) - (int)(prvpnn[x])) >> 4;
     252             :                             } else {
     253     3497472 :                                 val = (8 * ((int)srcpp[x] + (int)srcpn[x]) + 2 * ((int)prvp[x])
     254     1748736 :                                        - (int)(prvppp[x]) - (int)(prvpnn[x])) >> 4;
     255             :                             }
     256     1748736 :                             dstp[x] = av_clip(val, lo, hi);
     257             :                         }
     258             :                     }
     259             :                 } else {
     260           0 :                     dstp[x] = srcp[x];
     261             :                 }
     262             :             }
     263        1536 :             prvp   += 2 * psrc_linesize;
     264        1536 :             prvpp  += 2 * psrc_linesize;
     265        1536 :             prvppp += 2 * psrc_linesize;
     266        1536 :             prvpn  += 2 * psrc_linesize;
     267        1536 :             prvpnn += 2 * psrc_linesize;
     268        1536 :             prvp4p += 2 * psrc_linesize;
     269        1536 :             prvp4n += 2 * psrc_linesize;
     270        1536 :             srcp   += 2 * src_linesize;
     271        1536 :             srcpp  += 2 * src_linesize;
     272        1536 :             srcppp += 2 * src_linesize;
     273        1536 :             srcp3p += 2 * src_linesize;
     274        1536 :             srcp4p += 2 * src_linesize;
     275        1536 :             srcpn  += 2 * src_linesize;
     276        1536 :             srcpnn += 2 * src_linesize;
     277        1536 :             srcp3n += 2 * src_linesize;
     278        1536 :             srcp4n += 2 * src_linesize;
     279        1536 :             dstp   += 2 * dst_linesize;
     280             :         }
     281             : 
     282          12 :         srcp = inpic->data[plane];
     283          12 :         dstp = kerndeint->tmp_data[plane];
     284          12 :         av_image_copy_plane(dstp, psrc_linesize, srcp, src_linesize, bwidth, h);
     285             :     }
     286             : 
     287          10 :     av_frame_free(&inpic);
     288          10 :     return ff_filter_frame(outlink, outpic);
     289             : }
     290             : 
     291             : static const AVFilterPad kerndeint_inputs[] = {
     292             :     {
     293             :         .name         = "default",
     294             :         .type         = AVMEDIA_TYPE_VIDEO,
     295             :         .filter_frame = filter_frame,
     296             :         .config_props = config_props,
     297             :     },
     298             :     { NULL }
     299             : };
     300             : 
     301             : static const AVFilterPad kerndeint_outputs[] = {
     302             :     {
     303             :         .name = "default",
     304             :         .type = AVMEDIA_TYPE_VIDEO,
     305             :     },
     306             :     { NULL }
     307             : };
     308             : 
     309             : 
     310             : AVFilter ff_vf_kerndeint = {
     311             :     .name          = "kerndeint",
     312             :     .description   = NULL_IF_CONFIG_SMALL("Apply kernel deinterlacing to the input."),
     313             :     .priv_size     = sizeof(KerndeintContext),
     314             :     .priv_class    = &kerndeint_class,
     315             :     .uninit        = uninit,
     316             :     .query_formats = query_formats,
     317             :     .inputs        = kerndeint_inputs,
     318             :     .outputs       = kerndeint_outputs,
     319             : };

Generated by: LCOV version 1.13