LCOV - code coverage report
Current view: top level - libavfilter - vf_displace.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 209 0.0 %
Date: 2017-12-14 08:27:08 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Paul B Mahol
       3             :  *
       4             :  * This file is part of FFmpeg.
       5             :  *
       6             :  * FFmpeg is free software; you can redistribute it and/or
       7             :  * modify it under the terms of the GNU Lesser General Public
       8             :  * License as published by the Free Software Foundation; either
       9             :  * version 2.1 of the License, or (at your option) any later version.
      10             :  *
      11             :  * FFmpeg is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * Lesser General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public
      17             :  * License along with FFmpeg; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include "libavutil/imgutils.h"
      22             : #include "libavutil/pixdesc.h"
      23             : #include "libavutil/opt.h"
      24             : #include "avfilter.h"
      25             : #include "formats.h"
      26             : #include "framesync.h"
      27             : #include "internal.h"
      28             : #include "video.h"
      29             : 
      30             : enum EdgeMode {
      31             :     EDGE_BLANK,
      32             :     EDGE_SMEAR,
      33             :     EDGE_WRAP,
      34             :     EDGE_MIRROR,
      35             :     EDGE_NB
      36             : };
      37             : 
      38             : typedef struct DisplaceContext {
      39             :     const AVClass *class;
      40             :     int width[4], height[4];
      41             :     enum EdgeMode edge;
      42             :     int nb_planes;
      43             :     int nb_components;
      44             :     int step;
      45             :     uint8_t blank[4];
      46             :     FFFrameSync fs;
      47             : 
      48             :     void (*displace)(struct DisplaceContext *s, const AVFrame *in,
      49             :                      const AVFrame *xpic, const AVFrame *ypic, AVFrame *out);
      50             : } DisplaceContext;
      51             : 
      52             : #define OFFSET(x) offsetof(DisplaceContext, x)
      53             : #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
      54             : 
      55             : static const AVOption displace_options[] = {
      56             :     { "edge", "set edge mode", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=EDGE_SMEAR}, 0, EDGE_NB-1, FLAGS, "edge" },
      57             :     {   "blank",   "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_BLANK},  0, 0, FLAGS, "edge" },
      58             :     {   "smear",   "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_SMEAR},  0, 0, FLAGS, "edge" },
      59             :     {   "wrap" ,   "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_WRAP},   0, 0, FLAGS, "edge" },
      60             :     {   "mirror" , "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_MIRROR}, 0, 0, FLAGS, "edge" },
      61             :     { NULL }
      62             : };
      63             : 
      64             : AVFILTER_DEFINE_CLASS(displace);
      65             : 
      66           0 : static int query_formats(AVFilterContext *ctx)
      67             : {
      68             :     static const enum AVPixelFormat pix_fmts[] = {
      69             :         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
      70             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
      71             :         AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
      72             :         AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
      73             :         AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
      74             :         AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
      75             :         AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
      76             :         AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
      77             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
      78             :         AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
      79             :     };
      80             : 
      81           0 :     return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
      82             : }
      83             : 
      84           0 : static void displace_planar(DisplaceContext *s, const AVFrame *in,
      85             :                             const AVFrame *xpic, const AVFrame *ypic,
      86             :                             AVFrame *out)
      87             : {
      88             :     int plane, x, y;
      89             : 
      90           0 :     for (plane = 0; plane < s->nb_planes; plane++) {
      91           0 :         const int h = s->height[plane];
      92           0 :         const int w = s->width[plane];
      93           0 :         const int dlinesize = out->linesize[plane];
      94           0 :         const int slinesize = in->linesize[plane];
      95           0 :         const int xlinesize = xpic->linesize[plane];
      96           0 :         const int ylinesize = ypic->linesize[plane];
      97           0 :         const uint8_t *src = in->data[plane];
      98           0 :         const uint8_t *ysrc = ypic->data[plane];
      99           0 :         const uint8_t *xsrc = xpic->data[plane];
     100           0 :         uint8_t *dst = out->data[plane];
     101           0 :         const uint8_t blank = s->blank[plane];
     102             : 
     103           0 :         for (y = 0; y < h; y++) {
     104           0 :             switch (s->edge) {
     105           0 :             case EDGE_BLANK:
     106           0 :                 for (x = 0; x < w; x++) {
     107           0 :                     int Y = y + ysrc[x] - 128;
     108           0 :                     int X = x + xsrc[x] - 128;
     109             : 
     110           0 :                     if (Y < 0 || Y >= h || X < 0 || X >= w)
     111           0 :                         dst[x] = blank;
     112             :                     else
     113           0 :                         dst[x] = src[Y * slinesize + X];
     114             :                 }
     115           0 :                 break;
     116           0 :             case EDGE_SMEAR:
     117           0 :                 for (x = 0; x < w; x++) {
     118           0 :                     int Y = av_clip(y + ysrc[x] - 128, 0, h - 1);
     119           0 :                     int X = av_clip(x + xsrc[x] - 128, 0, w - 1);
     120           0 :                     dst[x] = src[Y * slinesize + X];
     121             :                 }
     122           0 :                 break;
     123           0 :             case EDGE_WRAP:
     124           0 :                 for (x = 0; x < w; x++) {
     125           0 :                     int Y = (y + ysrc[x] - 128) % h;
     126           0 :                     int X = (x + xsrc[x] - 128) % w;
     127             : 
     128           0 :                     if (Y < 0)
     129           0 :                         Y += h;
     130           0 :                     if (X < 0)
     131           0 :                         X += w;
     132           0 :                     dst[x] = src[Y * slinesize + X];
     133             :                 }
     134           0 :                 break;
     135           0 :             case EDGE_MIRROR:
     136           0 :                 for (x = 0; x < w; x++) {
     137           0 :                     int Y = y + ysrc[x] - 128;
     138           0 :                     int X = x + xsrc[x] - 128;
     139             : 
     140           0 :                     if (Y < 0)
     141           0 :                         Y = (-Y) % h;
     142           0 :                     if (X < 0)
     143           0 :                         X = (-X) % w;
     144           0 :                     if (Y >= h)
     145           0 :                         Y = h - (Y % h) - 1;
     146           0 :                     if (X >= w)
     147           0 :                         X = w - (X % w) - 1;
     148           0 :                     dst[x] = src[Y * slinesize + X];
     149             :                 }
     150           0 :                 break;
     151             :             }
     152             : 
     153           0 :             ysrc += ylinesize;
     154           0 :             xsrc += xlinesize;
     155           0 :             dst  += dlinesize;
     156             :         }
     157             :     }
     158           0 : }
     159             : 
     160           0 : static void displace_packed(DisplaceContext *s, const AVFrame *in,
     161             :                             const AVFrame *xpic, const AVFrame *ypic,
     162             :                             AVFrame *out)
     163             : {
     164           0 :     const int step = s->step;
     165           0 :     const int h = s->height[0];
     166           0 :     const int w = s->width[0];
     167           0 :     const int dlinesize = out->linesize[0];
     168           0 :     const int slinesize = in->linesize[0];
     169           0 :     const int xlinesize = xpic->linesize[0];
     170           0 :     const int ylinesize = ypic->linesize[0];
     171           0 :     const uint8_t *src = in->data[0];
     172           0 :     const uint8_t *ysrc = ypic->data[0];
     173           0 :     const uint8_t *xsrc = xpic->data[0];
     174           0 :     const uint8_t *blank = s->blank;
     175           0 :     uint8_t *dst = out->data[0];
     176             :     int c, x, y;
     177             : 
     178           0 :     for (y = 0; y < h; y++) {
     179           0 :         switch (s->edge) {
     180           0 :         case EDGE_BLANK:
     181           0 :             for (x = 0; x < w; x++) {
     182           0 :                 for (c = 0; c < s->nb_components; c++) {
     183           0 :                     int Y = y + (ysrc[x * step + c] - 128);
     184           0 :                     int X = x + (xsrc[x * step + c] - 128);
     185             : 
     186           0 :                     if (Y < 0 || Y >= h || X < 0 || X >= w)
     187           0 :                         dst[x * step + c] = blank[c];
     188             :                     else
     189           0 :                         dst[x * step + c] = src[Y * slinesize + X * step + c];
     190             :                 }
     191             :             }
     192           0 :             break;
     193           0 :         case EDGE_SMEAR:
     194           0 :             for (x = 0; x < w; x++) {
     195           0 :                 for (c = 0; c < s->nb_components; c++) {
     196           0 :                     int Y = av_clip(y + (ysrc[x * step + c] - 128), 0, h - 1);
     197           0 :                     int X = av_clip(x + (xsrc[x * step + c] - 128), 0, w - 1);
     198             : 
     199           0 :                     dst[x * step + c] = src[Y * slinesize + X * step + c];
     200             :                 }
     201             :             }
     202           0 :             break;
     203           0 :         case EDGE_WRAP:
     204           0 :             for (x = 0; x < w; x++) {
     205           0 :                 for (c = 0; c < s->nb_components; c++) {
     206           0 :                     int Y = (y + (ysrc[x * step + c] - 128)) % h;
     207           0 :                     int X = (x + (xsrc[x * step + c] - 128)) % w;
     208             : 
     209           0 :                     if (Y < 0)
     210           0 :                         Y += h;
     211           0 :                     if (X < 0)
     212           0 :                         X += w;
     213           0 :                     dst[x * step + c] = src[Y * slinesize + X * step + c];
     214             :                 }
     215             :             }
     216           0 :             break;
     217           0 :         case EDGE_MIRROR:
     218           0 :             for (x = 0; x < w; x++) {
     219           0 :                 for (c = 0; c < s->nb_components; c++) {
     220           0 :                     int Y = y + ysrc[x * step + c] - 128;
     221           0 :                     int X = x + xsrc[x * step + c] - 128;
     222             : 
     223           0 :                     if (Y < 0)
     224           0 :                         Y = (-Y) % h;
     225           0 :                     if (X < 0)
     226           0 :                         X = (-X) % w;
     227           0 :                     if (Y >= h)
     228           0 :                         Y = h - (Y % h) - 1;
     229           0 :                     if (X >= w)
     230           0 :                         X = w - (X % w) - 1;
     231           0 :                     dst[x * step + c] = src[Y * slinesize + X * step + c];
     232             :                 }
     233             :             }
     234           0 :             break;
     235             :         }
     236             : 
     237           0 :         ysrc += ylinesize;
     238           0 :         xsrc += xlinesize;
     239           0 :         dst  += dlinesize;
     240             :     }
     241           0 : }
     242             : 
     243           0 : static int process_frame(FFFrameSync *fs)
     244             : {
     245           0 :     AVFilterContext *ctx = fs->parent;
     246           0 :     DisplaceContext *s = fs->opaque;
     247           0 :     AVFilterLink *outlink = ctx->outputs[0];
     248             :     AVFrame *out, *in, *xpic, *ypic;
     249             :     int ret;
     250             : 
     251           0 :     if ((ret = ff_framesync_get_frame(&s->fs, 0, &in,   0)) < 0 ||
     252           0 :         (ret = ff_framesync_get_frame(&s->fs, 1, &xpic, 0)) < 0 ||
     253           0 :         (ret = ff_framesync_get_frame(&s->fs, 2, &ypic, 0)) < 0)
     254           0 :         return ret;
     255             : 
     256           0 :     if (ctx->is_disabled) {
     257           0 :         out = av_frame_clone(in);
     258           0 :         if (!out)
     259           0 :             return AVERROR(ENOMEM);
     260             :     } else {
     261           0 :         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     262           0 :         if (!out)
     263           0 :             return AVERROR(ENOMEM);
     264           0 :         av_frame_copy_props(out, in);
     265             : 
     266           0 :         s->displace(s, in, xpic, ypic, out);
     267             :     }
     268           0 :     out->pts = av_rescale_q(in->pts, s->fs.time_base, outlink->time_base);
     269             : 
     270           0 :     return ff_filter_frame(outlink, out);
     271             : }
     272             : 
     273           0 : static int config_input(AVFilterLink *inlink)
     274             : {
     275           0 :     AVFilterContext *ctx = inlink->dst;
     276           0 :     DisplaceContext *s = ctx->priv;
     277           0 :     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
     278             :     int vsub, hsub;
     279             : 
     280           0 :     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
     281           0 :     s->nb_components = desc->nb_components;
     282             : 
     283           0 :     if (s->nb_planes > 1 || s->nb_components == 1)
     284           0 :         s->displace = displace_planar;
     285             :     else
     286           0 :         s->displace = displace_packed;
     287             : 
     288           0 :     if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) {
     289           0 :         s->blank[1] = s->blank[2] = 128;
     290           0 :         s->blank[0] = 16;
     291             :     }
     292             : 
     293           0 :     s->step = av_get_padded_bits_per_pixel(desc) >> 3;
     294           0 :     hsub = desc->log2_chroma_w;
     295           0 :     vsub = desc->log2_chroma_h;
     296           0 :     s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub);
     297           0 :     s->height[0] = s->height[3] = inlink->h;
     298           0 :     s->width[1]  = s->width[2]  = AV_CEIL_RSHIFT(inlink->w, hsub);
     299           0 :     s->width[0]  = s->width[3]  = inlink->w;
     300             : 
     301           0 :     return 0;
     302             : }
     303             : 
     304           0 : static int config_output(AVFilterLink *outlink)
     305             : {
     306           0 :     AVFilterContext *ctx = outlink->src;
     307           0 :     DisplaceContext *s = ctx->priv;
     308           0 :     AVFilterLink *srclink = ctx->inputs[0];
     309           0 :     AVFilterLink *xlink = ctx->inputs[1];
     310           0 :     AVFilterLink *ylink = ctx->inputs[2];
     311             :     FFFrameSyncIn *in;
     312             :     int ret;
     313             : 
     314           0 :     if (srclink->format != xlink->format ||
     315           0 :         srclink->format != ylink->format) {
     316           0 :         av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
     317           0 :         return AVERROR(EINVAL);
     318             :     }
     319           0 :     if (srclink->w != xlink->w ||
     320           0 :         srclink->h != xlink->h ||
     321           0 :         srclink->w != ylink->w ||
     322           0 :         srclink->h != ylink->h) {
     323           0 :         av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
     324             :                "(size %dx%d) do not match the corresponding "
     325             :                "second input link %s parameters (%dx%d) "
     326             :                "and/or third input link %s parameters (%dx%d)\n",
     327           0 :                ctx->input_pads[0].name, srclink->w, srclink->h,
     328           0 :                ctx->input_pads[1].name, xlink->w, xlink->h,
     329           0 :                ctx->input_pads[2].name, ylink->w, ylink->h);
     330           0 :         return AVERROR(EINVAL);
     331             :     }
     332             : 
     333           0 :     outlink->w = srclink->w;
     334           0 :     outlink->h = srclink->h;
     335           0 :     outlink->time_base = srclink->time_base;
     336           0 :     outlink->sample_aspect_ratio = srclink->sample_aspect_ratio;
     337           0 :     outlink->frame_rate = srclink->frame_rate;
     338             : 
     339           0 :     ret = ff_framesync_init(&s->fs, ctx, 3);
     340           0 :     if (ret < 0)
     341           0 :         return ret;
     342             : 
     343           0 :     in = s->fs.in;
     344           0 :     in[0].time_base = srclink->time_base;
     345           0 :     in[1].time_base = xlink->time_base;
     346           0 :     in[2].time_base = ylink->time_base;
     347           0 :     in[0].sync   = 2;
     348           0 :     in[0].before = EXT_STOP;
     349           0 :     in[0].after  = EXT_STOP;
     350           0 :     in[1].sync   = 1;
     351           0 :     in[1].before = EXT_NULL;
     352           0 :     in[1].after  = EXT_INFINITY;
     353           0 :     in[2].sync   = 1;
     354           0 :     in[2].before = EXT_NULL;
     355           0 :     in[2].after  = EXT_INFINITY;
     356           0 :     s->fs.opaque   = s;
     357           0 :     s->fs.on_event = process_frame;
     358             : 
     359           0 :     return ff_framesync_configure(&s->fs);
     360             : }
     361             : 
     362           0 : static int activate(AVFilterContext *ctx)
     363             : {
     364           0 :     DisplaceContext *s = ctx->priv;
     365           0 :     return ff_framesync_activate(&s->fs);
     366             : }
     367             : 
     368           0 : static av_cold void uninit(AVFilterContext *ctx)
     369             : {
     370           0 :     DisplaceContext *s = ctx->priv;
     371             : 
     372           0 :     ff_framesync_uninit(&s->fs);
     373           0 : }
     374             : 
     375             : static const AVFilterPad displace_inputs[] = {
     376             :     {
     377             :         .name         = "source",
     378             :         .type         = AVMEDIA_TYPE_VIDEO,
     379             :         .config_props = config_input,
     380             :     },
     381             :     {
     382             :         .name         = "xmap",
     383             :         .type         = AVMEDIA_TYPE_VIDEO,
     384             :     },
     385             :     {
     386             :         .name         = "ymap",
     387             :         .type         = AVMEDIA_TYPE_VIDEO,
     388             :     },
     389             :     { NULL }
     390             : };
     391             : 
     392             : static const AVFilterPad displace_outputs[] = {
     393             :     {
     394             :         .name          = "default",
     395             :         .type          = AVMEDIA_TYPE_VIDEO,
     396             :         .config_props  = config_output,
     397             :     },
     398             :     { NULL }
     399             : };
     400             : 
     401             : AVFilter ff_vf_displace = {
     402             :     .name          = "displace",
     403             :     .description   = NULL_IF_CONFIG_SMALL("Displace pixels."),
     404             :     .priv_size     = sizeof(DisplaceContext),
     405             :     .uninit        = uninit,
     406             :     .query_formats = query_formats,
     407             :     .activate      = activate,
     408             :     .inputs        = displace_inputs,
     409             :     .outputs       = displace_outputs,
     410             :     .priv_class    = &displace_class,
     411             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
     412             : };

Generated by: LCOV version 1.13