LCOV - code coverage report
Current view: top level - libavfilter - vf_zoompan.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 152 0.0 %
Date: 2017-12-15 02:19:58 Functions: 0 6 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/avassert.h"
      22             : #include "libavutil/eval.h"
      23             : #include "libavutil/opt.h"
      24             : #include "libavutil/pixdesc.h"
      25             : #include "avfilter.h"
      26             : #include "filters.h"
      27             : #include "formats.h"
      28             : #include "internal.h"
      29             : #include "video.h"
      30             : #include "libswscale/swscale.h"
      31             : 
      32             : static const char *const var_names[] = {
      33             :     "in_w",   "iw",
      34             :     "in_h",   "ih",
      35             :     "out_w",  "ow",
      36             :     "out_h",  "oh",
      37             :     "in",
      38             :     "on",
      39             :     "duration",
      40             :     "pduration",
      41             :     "time",
      42             :     "frame",
      43             :     "zoom",
      44             :     "pzoom",
      45             :     "x", "px",
      46             :     "y", "py",
      47             :     "a",
      48             :     "sar",
      49             :     "dar",
      50             :     "hsub",
      51             :     "vsub",
      52             :     NULL
      53             : };
      54             : 
      55             : enum var_name {
      56             :     VAR_IN_W,   VAR_IW,
      57             :     VAR_IN_H,   VAR_IH,
      58             :     VAR_OUT_W,  VAR_OW,
      59             :     VAR_OUT_H,  VAR_OH,
      60             :     VAR_IN,
      61             :     VAR_ON,
      62             :     VAR_DURATION,
      63             :     VAR_PDURATION,
      64             :     VAR_TIME,
      65             :     VAR_FRAME,
      66             :     VAR_ZOOM,
      67             :     VAR_PZOOM,
      68             :     VAR_X, VAR_PX,
      69             :     VAR_Y, VAR_PY,
      70             :     VAR_A,
      71             :     VAR_SAR,
      72             :     VAR_DAR,
      73             :     VAR_HSUB,
      74             :     VAR_VSUB,
      75             :     VARS_NB
      76             : };
      77             : 
      78             : typedef struct ZPcontext {
      79             :     const AVClass *class;
      80             :     char *zoom_expr_str;
      81             :     char *x_expr_str;
      82             :     char *y_expr_str;
      83             :     char *duration_expr_str;
      84             : 
      85             :     AVExpr *zoom_expr, *x_expr, *y_expr;
      86             : 
      87             :     int w, h;
      88             :     double x, y;
      89             :     double prev_zoom;
      90             :     int prev_nb_frames;
      91             :     struct SwsContext *sws;
      92             :     int64_t frame_count;
      93             :     const AVPixFmtDescriptor *desc;
      94             :     AVFrame *in;
      95             :     double var_values[VARS_NB];
      96             :     int nb_frames;
      97             :     int current_frame;
      98             :     int finished;
      99             :     AVRational framerate;
     100             : } ZPContext;
     101             : 
     102             : #define OFFSET(x) offsetof(ZPContext, x)
     103             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
     104             : static const AVOption zoompan_options[] = {
     105             :     { "zoom", "set the zoom expression", OFFSET(zoom_expr_str), AV_OPT_TYPE_STRING, {.str = "1" }, .flags = FLAGS },
     106             :     { "z", "set the zoom expression", OFFSET(zoom_expr_str), AV_OPT_TYPE_STRING, {.str = "1" }, .flags = FLAGS },
     107             :     { "x", "set the x expression", OFFSET(x_expr_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags = FLAGS },
     108             :     { "y", "set the y expression", OFFSET(y_expr_str), AV_OPT_TYPE_STRING, {.str="0"}, .flags = FLAGS },
     109             :     { "d", "set the duration expression", OFFSET(duration_expr_str), AV_OPT_TYPE_STRING, {.str="90"}, .flags = FLAGS },
     110             :     { "s", "set the output image size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, .flags = FLAGS },
     111             :     { "fps", "set the output framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, .flags = FLAGS },
     112             :     { NULL }
     113             : };
     114             : 
     115             : AVFILTER_DEFINE_CLASS(zoompan);
     116             : 
     117           0 : static av_cold int init(AVFilterContext *ctx)
     118             : {
     119           0 :     ZPContext *s = ctx->priv;
     120             : 
     121           0 :     s->prev_zoom = 1;
     122           0 :     return 0;
     123             : }
     124             : 
     125           0 : static int config_output(AVFilterLink *outlink)
     126             : {
     127           0 :     AVFilterContext *ctx = outlink->src;
     128           0 :     ZPContext *s = ctx->priv;
     129             :     int ret;
     130             : 
     131           0 :     outlink->w = s->w;
     132           0 :     outlink->h = s->h;
     133           0 :     outlink->time_base = av_inv_q(s->framerate);
     134           0 :     outlink->frame_rate = s->framerate;
     135           0 :     s->desc = av_pix_fmt_desc_get(outlink->format);
     136           0 :     s->finished = 1;
     137             : 
     138           0 :     ret = av_expr_parse(&s->zoom_expr, s->zoom_expr_str, var_names, NULL, NULL, NULL, NULL, 0, ctx);
     139           0 :     if (ret < 0)
     140           0 :         return ret;
     141             : 
     142           0 :     ret = av_expr_parse(&s->x_expr, s->x_expr_str, var_names, NULL, NULL, NULL, NULL, 0, ctx);
     143           0 :     if (ret < 0)
     144           0 :         return ret;
     145             : 
     146           0 :     ret = av_expr_parse(&s->y_expr, s->y_expr_str, var_names, NULL, NULL, NULL, NULL, 0, ctx);
     147           0 :     if (ret < 0)
     148           0 :         return ret;
     149             : 
     150           0 :     return 0;
     151             : }
     152             : 
     153           0 : static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_values, int i,
     154             :                                double *zoom, double *dx, double *dy)
     155             : {
     156           0 :     ZPContext *s = ctx->priv;
     157           0 :     AVFilterLink *outlink = ctx->outputs[0];
     158           0 :     int64_t pts = s->frame_count;
     159           0 :     int k, x, y, w, h, ret = 0;
     160             :     uint8_t *input[4];
     161             :     int px[4], py[4];
     162             :     AVFrame *out;
     163             : 
     164           0 :     var_values[VAR_PX]    = s->x;
     165           0 :     var_values[VAR_PY]    = s->y;
     166           0 :     var_values[VAR_PZOOM] = s->prev_zoom;
     167           0 :     var_values[VAR_PDURATION] = s->prev_nb_frames;
     168           0 :     var_values[VAR_TIME] = pts * av_q2d(outlink->time_base);
     169           0 :     var_values[VAR_FRAME] = i;
     170           0 :     var_values[VAR_ON] = outlink->frame_count_in + 1;
     171             : 
     172           0 :     *zoom = av_expr_eval(s->zoom_expr, var_values, NULL);
     173             : 
     174           0 :     *zoom = av_clipd(*zoom, 1, 10);
     175           0 :     var_values[VAR_ZOOM] = *zoom;
     176           0 :     w = in->width * (1.0 / *zoom);
     177           0 :     h = in->height * (1.0 / *zoom);
     178             : 
     179           0 :     *dx = av_expr_eval(s->x_expr, var_values, NULL);
     180             : 
     181           0 :     x = *dx = av_clipd(*dx, 0, FFMAX(in->width - w, 0));
     182           0 :     var_values[VAR_X] = *dx;
     183           0 :     x &= ~((1 << s->desc->log2_chroma_w) - 1);
     184             : 
     185           0 :     *dy = av_expr_eval(s->y_expr, var_values, NULL);
     186             : 
     187           0 :     y = *dy = av_clipd(*dy, 0, FFMAX(in->height - h, 0));
     188           0 :     var_values[VAR_Y] = *dy;
     189           0 :     y &= ~((1 << s->desc->log2_chroma_h) - 1);
     190             : 
     191           0 :     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     192           0 :     if (!out) {
     193           0 :         ret = AVERROR(ENOMEM);
     194           0 :         return ret;
     195             :     }
     196             : 
     197           0 :     px[1] = px[2] = AV_CEIL_RSHIFT(x, s->desc->log2_chroma_w);
     198           0 :     px[0] = px[3] = x;
     199             : 
     200           0 :     py[1] = py[2] = AV_CEIL_RSHIFT(y, s->desc->log2_chroma_h);
     201           0 :     py[0] = py[3] = y;
     202             : 
     203           0 :     s->sws = sws_alloc_context();
     204           0 :     if (!s->sws) {
     205           0 :         ret = AVERROR(ENOMEM);
     206           0 :         goto error;
     207             :     }
     208             : 
     209           0 :     for (k = 0; in->data[k]; k++)
     210           0 :         input[k] = in->data[k] + py[k] * in->linesize[k] + px[k];
     211             : 
     212           0 :     av_opt_set_int(s->sws, "srcw", w, 0);
     213           0 :     av_opt_set_int(s->sws, "srch", h, 0);
     214           0 :     av_opt_set_int(s->sws, "src_format", in->format, 0);
     215           0 :     av_opt_set_int(s->sws, "dstw", outlink->w, 0);
     216           0 :     av_opt_set_int(s->sws, "dsth", outlink->h, 0);
     217           0 :     av_opt_set_int(s->sws, "dst_format", outlink->format, 0);
     218           0 :     av_opt_set_int(s->sws, "sws_flags", SWS_BICUBIC, 0);
     219             : 
     220           0 :     if ((ret = sws_init_context(s->sws, NULL, NULL)) < 0)
     221           0 :         goto error;
     222             : 
     223           0 :     sws_scale(s->sws, (const uint8_t *const *)&input, in->linesize, 0, h, out->data, out->linesize);
     224             : 
     225           0 :     out->pts = pts;
     226           0 :     s->frame_count++;
     227             : 
     228           0 :     ret = ff_filter_frame(outlink, out);
     229           0 :     sws_freeContext(s->sws);
     230           0 :     s->sws = NULL;
     231           0 :     s->current_frame++;
     232             : 
     233           0 :     if (s->current_frame >= s->nb_frames) {
     234           0 :         if (*dx != -1)
     235           0 :             s->x = *dx;
     236           0 :         if (*dy != -1)
     237           0 :             s->y = *dy;
     238           0 :         if (*zoom != -1)
     239           0 :             s->prev_zoom = *zoom;
     240           0 :         s->prev_nb_frames = s->nb_frames;
     241           0 :         s->nb_frames = 0;
     242           0 :         s->current_frame = 0;
     243           0 :         av_frame_free(&s->in);
     244           0 :         s->finished = 1;
     245             :     }
     246           0 :     return ret;
     247           0 : error:
     248           0 :     av_frame_free(&out);
     249           0 :     return ret;
     250             : }
     251             : 
     252           0 : static int activate(AVFilterContext *ctx)
     253             : {
     254           0 :     ZPContext *s = ctx->priv;
     255           0 :     AVFilterLink *inlink = ctx->inputs[0];
     256           0 :     AVFilterLink *outlink = ctx->outputs[0];
     257           0 :     int status, ret = 0;
     258             :     int64_t pts;
     259             : 
     260           0 :     if (s->in && ff_outlink_frame_wanted(outlink)) {
     261           0 :         double zoom = -1, dx = -1, dy = -1;
     262             : 
     263           0 :         ret = output_single_frame(ctx, s->in, s->var_values, s->current_frame,
     264             :                                   &zoom, &dx, &dy);
     265           0 :         if (ret < 0)
     266           0 :             return ret;
     267             :     }
     268             : 
     269           0 :     if (!s->in && (ret = ff_inlink_consume_frame(inlink, &s->in)) > 0) {
     270           0 :         double zoom = -1, dx = -1, dy = -1, nb_frames;
     271             : 
     272           0 :         s->finished = 0;
     273           0 :         s->var_values[VAR_IN_W]  = s->var_values[VAR_IW] = s->in->width;
     274           0 :         s->var_values[VAR_IN_H]  = s->var_values[VAR_IH] = s->in->height;
     275           0 :         s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = s->w;
     276           0 :         s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = s->h;
     277           0 :         s->var_values[VAR_IN]    = inlink->frame_count_out + 1;
     278           0 :         s->var_values[VAR_ON]    = outlink->frame_count_in + 1;
     279           0 :         s->var_values[VAR_PX]    = s->x;
     280           0 :         s->var_values[VAR_PY]    = s->y;
     281           0 :         s->var_values[VAR_X]     = 0;
     282           0 :         s->var_values[VAR_Y]     = 0;
     283           0 :         s->var_values[VAR_PZOOM] = s->prev_zoom;
     284           0 :         s->var_values[VAR_ZOOM]  = 1;
     285           0 :         s->var_values[VAR_PDURATION] = s->prev_nb_frames;
     286           0 :         s->var_values[VAR_A]     = (double) s->in->width / s->in->height;
     287           0 :         s->var_values[VAR_SAR]   = inlink->sample_aspect_ratio.num ?
     288           0 :             (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
     289           0 :         s->var_values[VAR_DAR]   = s->var_values[VAR_A] * s->var_values[VAR_SAR];
     290           0 :         s->var_values[VAR_HSUB]  = 1 << s->desc->log2_chroma_w;
     291           0 :         s->var_values[VAR_VSUB]  = 1 << s->desc->log2_chroma_h;
     292             : 
     293           0 :         if ((ret = av_expr_parse_and_eval(&nb_frames, s->duration_expr_str,
     294           0 :                                           var_names, s->var_values,
     295             :                                           NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) {
     296           0 :             av_frame_free(&s->in);
     297           0 :             return ret;
     298             :         }
     299             : 
     300           0 :         s->var_values[VAR_DURATION] = s->nb_frames = nb_frames;
     301             : 
     302           0 :         ret = output_single_frame(ctx, s->in, s->var_values, s->current_frame,
     303             :                                   &zoom, &dx, &dy);
     304           0 :         if (ret < 0)
     305           0 :             return ret;
     306             :     }
     307           0 :     if (ret < 0) {
     308           0 :         return ret;
     309           0 :     } else if (s->finished && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
     310           0 :         ff_outlink_set_status(outlink, status, pts);
     311           0 :         return 0;
     312             :     } else {
     313           0 :         if (ff_outlink_frame_wanted(outlink) && s->finished)
     314           0 :             ff_inlink_request_frame(inlink);
     315           0 :         return 0;
     316             :     }
     317             : }
     318             : 
     319           0 : static int query_formats(AVFilterContext *ctx)
     320             : {
     321             :     static const enum AVPixelFormat pix_fmts[] = {
     322             :         AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,
     323             :         AV_PIX_FMT_YUV420P,  AV_PIX_FMT_YUV411P,
     324             :         AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUV440P,
     325             :         AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P,
     326             :         AV_PIX_FMT_YUVA420P,
     327             :         AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
     328             :         AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
     329             :         AV_PIX_FMT_YUVJ411P,
     330             :         AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
     331             :         AV_PIX_FMT_GRAY8,
     332             :         AV_PIX_FMT_NONE
     333             :     };
     334             : 
     335           0 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     336           0 :     if (!fmts_list)
     337           0 :         return AVERROR(ENOMEM);
     338           0 :     return ff_set_common_formats(ctx, fmts_list);
     339             : }
     340             : 
     341           0 : static av_cold void uninit(AVFilterContext *ctx)
     342             : {
     343           0 :     ZPContext *s = ctx->priv;
     344             : 
     345           0 :     sws_freeContext(s->sws);
     346           0 :     s->sws = NULL;
     347           0 : }
     348             : 
     349             : static const AVFilterPad inputs[] = {
     350             :     {
     351             :         .name         = "default",
     352             :         .type         = AVMEDIA_TYPE_VIDEO,
     353             :     },
     354             :     { NULL }
     355             : };
     356             : 
     357             : static const AVFilterPad outputs[] = {
     358             :     {
     359             :         .name          = "default",
     360             :         .type          = AVMEDIA_TYPE_VIDEO,
     361             :         .config_props  = config_output,
     362             :     },
     363             :     { NULL }
     364             : };
     365             : 
     366             : AVFilter ff_vf_zoompan = {
     367             :     .name          = "zoompan",
     368             :     .description   = NULL_IF_CONFIG_SMALL("Apply Zoom & Pan effect."),
     369             :     .priv_size     = sizeof(ZPContext),
     370             :     .priv_class    = &zoompan_class,
     371             :     .init          = init,
     372             :     .uninit        = uninit,
     373             :     .query_formats = query_formats,
     374             :     .activate      = activate,
     375             :     .inputs        = inputs,
     376             :     .outputs       = outputs,
     377             : };

Generated by: LCOV version 1.13