2 * Copyright (c) 2013 Paul B Mahol
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/eval.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/pixdesc.h"
28 #include "libswscale/swscale.h"
30 static const char *const var_names
[] = {
76 typedef struct ZPcontext
{
81 char *duration_expr_str
;
86 struct SwsContext
*sws
;
90 #define OFFSET(x) offsetof(ZPContext, x)
91 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
92 static const AVOption zoompan_options
[] = {
93 { "zoom", "set the zoom expression", OFFSET(zoom_expr_str
), AV_OPT_TYPE_STRING
, {.str
= "1" }, .flags
= FLAGS
},
94 { "z", "set the zoom expression", OFFSET(zoom_expr_str
), AV_OPT_TYPE_STRING
, {.str
= "1" }, .flags
= FLAGS
},
95 { "x", "set the x expression", OFFSET(x_expr_str
), AV_OPT_TYPE_STRING
, {.str
="0"}, .flags
= FLAGS
},
96 { "y", "set the y expression", OFFSET(y_expr_str
), AV_OPT_TYPE_STRING
, {.str
="0"}, .flags
= FLAGS
},
97 { "d", "set the duration expression", OFFSET(duration_expr_str
), AV_OPT_TYPE_STRING
, {.str
="90"}, .flags
= FLAGS
},
98 { "s", "set the output image size", OFFSET(w
), AV_OPT_TYPE_IMAGE_SIZE
, {.str
="hd720"}, .flags
= FLAGS
},
102 AVFILTER_DEFINE_CLASS(zoompan
);
104 static av_cold
int init(AVFilterContext
*ctx
)
106 ZPContext
*s
= ctx
->priv
;
112 static int config_output(AVFilterLink
*outlink
)
114 AVFilterContext
*ctx
= outlink
->src
;
115 ZPContext
*s
= ctx
->priv
;
123 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
125 AVFilterContext
*ctx
= inlink
->dst
;
126 AVFilterLink
*outlink
= ctx
->outputs
[0];
127 ZPContext
*s
= ctx
->priv
;
128 double var_values
[VARS_NB
], nb_frames
, zoom
, dx
, dy
;
129 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(in
->format
);
131 int i
, k
, x
, y
, w
, h
, ret
= 0;
133 var_values
[VAR_IN_W
] = var_values
[VAR_IW
] = in
->width
;
134 var_values
[VAR_IN_H
] = var_values
[VAR_IH
] = in
->height
;
135 var_values
[VAR_OUT_W
] = var_values
[VAR_OW
] = s
->w
;
136 var_values
[VAR_OUT_H
] = var_values
[VAR_OH
] = s
->h
;
137 var_values
[VAR_IN
] = inlink
->frame_count
+ 1;
138 var_values
[VAR_ON
] = outlink
->frame_count
+ 1;
139 var_values
[VAR_PX
] = s
->x
;
140 var_values
[VAR_PY
] = s
->y
;
141 var_values
[VAR_X
] = 0;
142 var_values
[VAR_Y
] = 0;
143 var_values
[VAR_PZOOM
] = s
->prev_zoom
;
144 var_values
[VAR_ZOOM
] = 1;
145 var_values
[VAR_PDURATION
] = s
->prev_nb_frames
;
146 var_values
[VAR_A
] = (double) in
->width
/ in
->height
;
147 var_values
[VAR_SAR
] = inlink
->sample_aspect_ratio
.num
?
148 (double) inlink
->sample_aspect_ratio
.num
/ inlink
->sample_aspect_ratio
.den
: 1;
149 var_values
[VAR_DAR
] = var_values
[VAR_A
] * var_values
[VAR_SAR
];
150 var_values
[VAR_HSUB
] = 1 << desc
->log2_chroma_w
;
151 var_values
[VAR_VSUB
] = 1 << desc
->log2_chroma_h
;
153 if ((ret
= av_expr_parse_and_eval(&nb_frames
, s
->duration_expr_str
,
154 var_names
, var_values
,
155 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
)) < 0)
158 var_values
[VAR_DURATION
] = nb_frames
;
159 for (i
= 0; i
< nb_frames
; i
++) {
163 int64_t pts
= av_rescale_q(in
->pts
, inlink
->time_base
,
164 outlink
->time_base
) + s
->frame_count
;
166 var_values
[VAR_TIME
] = pts
* av_q2d(outlink
->time_base
);
167 var_values
[VAR_FRAME
] = i
;
168 var_values
[VAR_ON
] = outlink
->frame_count
+ 1;
169 if ((ret
= av_expr_parse_and_eval(&zoom
, s
->zoom_expr_str
,
170 var_names
, var_values
,
171 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
)) < 0)
174 zoom
= av_clipd(zoom
, 1, 10);
175 var_values
[VAR_ZOOM
] = zoom
;
176 w
= in
->width
* (1.0 / zoom
);
177 h
= in
->height
* (1.0 / zoom
);
179 if ((ret
= av_expr_parse_and_eval(&dx
, s
->x_expr_str
,
180 var_names
, var_values
,
181 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
)) < 0)
183 x
= dx
= av_clipd(dx
, 0, FFMAX(in
->width
- w
, 0));
184 var_values
[VAR_X
] = dx
;
185 x
&= ~((1 << desc
->log2_chroma_w
) - 1);
187 if ((ret
= av_expr_parse_and_eval(&dy
, s
->y_expr_str
,
188 var_names
, var_values
,
189 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
)) < 0)
191 y
= dy
= av_clipd(dy
, 0, FFMAX(in
->height
- h
, 0));
192 var_values
[VAR_Y
] = dy
;
193 y
&= ~((1 << desc
->log2_chroma_h
) - 1);
195 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
197 ret
= AVERROR(ENOMEM
);
201 px
[1] = px
[2] = FF_CEIL_RSHIFT(x
, desc
->log2_chroma_w
);
204 py
[1] = py
[2] = FF_CEIL_RSHIFT(y
, desc
->log2_chroma_h
);
207 s
->sws
= sws_alloc_context();
209 ret
= AVERROR(ENOMEM
);
213 for (k
= 0; in
->data
[k
]; k
++)
214 input
[k
] = in
->data
[k
] + py
[k
] * in
->linesize
[k
] + px
[k
];
216 av_opt_set_int(s
->sws
, "srcw", w
, 0);
217 av_opt_set_int(s
->sws
, "srch", h
, 0);
218 av_opt_set_int(s
->sws
, "src_format", in
->format
, 0);
219 av_opt_set_int(s
->sws
, "dstw", outlink
->w
, 0);
220 av_opt_set_int(s
->sws
, "dsth", outlink
->h
, 0);
221 av_opt_set_int(s
->sws
, "dst_format", outlink
->format
, 0);
222 av_opt_set_int(s
->sws
, "sws_flags", SWS_BICUBIC
, 0);
224 if ((ret
= sws_init_context(s
->sws
, NULL
, NULL
)) < 0)
227 sws_scale(s
->sws
, (const uint8_t *const *)&input
, in
->linesize
, 0, h
, out
->data
, out
->linesize
);
232 ret
= ff_filter_frame(outlink
, out
);
236 sws_freeContext(s
->sws
);
243 s
->prev_nb_frames
= nb_frames
;
246 sws_freeContext(s
->sws
);
252 static int query_formats(AVFilterContext
*ctx
)
254 static const enum AVPixelFormat pix_fmts
[] = {
255 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUV422P
,
256 AV_PIX_FMT_YUV420P
, AV_PIX_FMT_YUV411P
,
257 AV_PIX_FMT_YUV410P
, AV_PIX_FMT_YUV440P
,
258 AV_PIX_FMT_YUVA444P
, AV_PIX_FMT_YUVA422P
,
260 AV_PIX_FMT_YUVJ444P
, AV_PIX_FMT_YUVJ440P
,
261 AV_PIX_FMT_YUVJ422P
, AV_PIX_FMT_YUVJ420P
,
268 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
272 static av_cold
void uninit(AVFilterContext
*ctx
)
274 ZPContext
*s
= ctx
->priv
;
276 sws_freeContext(s
->sws
);
280 static const AVFilterPad inputs
[] = {
283 .type
= AVMEDIA_TYPE_VIDEO
,
284 .filter_frame
= filter_frame
,
289 static const AVFilterPad outputs
[] = {
292 .type
= AVMEDIA_TYPE_VIDEO
,
293 .config_props
= config_output
,
298 AVFilter ff_vf_zoompan
= {
300 .description
= NULL_IF_CONFIG_SMALL("Apply Zoom & Pan effect."),
301 .priv_size
= sizeof(ZPContext
),
302 .priv_class
= &zoompan_class
,
305 .query_formats
= query_formats
,
308 .flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,