Imported Debian version 2.4.3~trusty1
[deb_ffmpeg.git] / ffmpeg / libavfilter / vf_aspect.c
CommitLineData
2ba45a60
DM
1/*
2 * Copyright (c) 2010 Bobby Bingham
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/**
22 * @file
23 * aspect ratio modification video filters
24 */
25
26#include <float.h>
27
28#include "libavutil/common.h"
29#include "libavutil/eval.h"
30#include "libavutil/mathematics.h"
31#include "libavutil/opt.h"
32#include "libavutil/parseutils.h"
33#include "libavutil/pixdesc.h"
34
35#include "avfilter.h"
36#include "internal.h"
37#include "video.h"
38
39static const char *const var_names[] = {
40 "w",
41 "h",
42 "a", "dar",
43 "sar",
44 "hsub",
45 "vsub",
46 NULL
47};
48
49enum var_name {
50 VAR_W,
51 VAR_H,
52 VAR_A, VAR_DAR,
53 VAR_SAR,
54 VAR_HSUB,
55 VAR_VSUB,
56 VARS_NB
57};
58
59typedef struct AspectContext {
60 const AVClass *class;
61 AVRational dar;
62 AVRational sar;
63 int max;
64#if FF_API_OLD_FILTER_OPTS
65 float aspect_den;
66#endif
67 char *ratio_expr;
68} AspectContext;
69
70static av_cold int init(AVFilterContext *ctx)
71{
72 AspectContext *s = ctx->priv;
73 int ret;
74
75#if FF_API_OLD_FILTER_OPTS
76 if (s->ratio_expr && s->aspect_den > 0) {
77 double num;
78 av_log(ctx, AV_LOG_WARNING,
79 "num:den syntax is deprecated, please use num/den or named options instead\n");
80 ret = av_expr_parse_and_eval(&num, s->ratio_expr, NULL, NULL,
81 NULL, NULL, NULL, NULL, NULL, 0, ctx);
82 if (ret < 0) {
83 av_log(ctx, AV_LOG_ERROR, "Unable to parse ratio numerator \"%s\"\n", s->ratio_expr);
84 return AVERROR(EINVAL);
85 }
86 s->sar = s->dar = av_d2q(num / s->aspect_den, s->max);
87 }
88#endif
89
90 return 0;
91}
92
93static int filter_frame(AVFilterLink *link, AVFrame *frame)
94{
95 AspectContext *s = link->dst->priv;
96
97 frame->sample_aspect_ratio = s->sar;
98 return ff_filter_frame(link->dst->outputs[0], frame);
99}
100
101#define OFFSET(x) offsetof(AspectContext, x)
102#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
103
104static inline void compute_dar(AVRational *dar, AVRational sar, int w, int h)
105{
106 if (sar.num && sar.den) {
107 av_reduce(&dar->num, &dar->den, sar.num * w, sar.den * h, INT_MAX);
108 } else {
109 av_reduce(&dar->num, &dar->den, w, h, INT_MAX);
110 }
111}
112
113static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio)
114{
115 AVFilterContext *ctx = inlink->dst;
116 AspectContext *s = inlink->dst->priv;
117 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
118 double var_values[VARS_NB], res;
119 int ret;
120
121 var_values[VAR_W] = inlink->w;
122 var_values[VAR_H] = inlink->h;
123 var_values[VAR_A] = (double) inlink->w / inlink->h;
124 var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
125 (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
126 var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
127 var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
128 var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
129
130 /* evaluate new aspect ratio*/
131 ret = av_expr_parse_and_eval(&res, s->ratio_expr,
132 var_names, var_values,
133 NULL, NULL, NULL, NULL, NULL, 0, ctx);
134 if (ret < 0) {
135 ret = av_parse_ratio(aspect_ratio, s->ratio_expr, s->max, 0, ctx);
136 } else
137 *aspect_ratio = av_d2q(res, s->max);
138
139 if (ret < 0) {
140 av_log(ctx, AV_LOG_ERROR,
141 "Error when evaluating the expression '%s'\n", s->ratio_expr);
142 return ret;
143 }
144 if (aspect_ratio->num < 0 || aspect_ratio->den <= 0) {
145 av_log(ctx, AV_LOG_ERROR,
146 "Invalid string '%s' for aspect ratio\n", s->ratio_expr);
147 return AVERROR(EINVAL);
148 }
149 return 0;
150}
151
152#if CONFIG_SETDAR_FILTER
153
154static int setdar_config_props(AVFilterLink *inlink)
155{
156 AspectContext *s = inlink->dst->priv;
157 AVRational dar;
158 AVRational old_dar;
159 AVRational old_sar = inlink->sample_aspect_ratio;
160 int ret;
161
162#if FF_API_OLD_FILTER_OPTS
163 if (!(s->ratio_expr && s->aspect_den > 0)) {
164#endif
165 if ((ret = get_aspect_ratio(inlink, &s->dar)))
166 return ret;
167#if FF_API_OLD_FILTER_OPTS
168 }
169#endif
170
171 if (s->dar.num && s->dar.den) {
172 av_reduce(&s->sar.num, &s->sar.den,
173 s->dar.num * inlink->h,
174 s->dar.den * inlink->w, INT_MAX);
175 inlink->sample_aspect_ratio = s->sar;
176 dar = s->dar;
177 } else {
178 inlink->sample_aspect_ratio = (AVRational){ 1, 1 };
179 dar = (AVRational){ inlink->w, inlink->h };
180 }
181
182 compute_dar(&old_dar, old_sar, inlink->w, inlink->h);
183 av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d dar:%d/%d sar:%d/%d -> dar:%d/%d sar:%d/%d\n",
184 inlink->w, inlink->h, old_dar.num, old_dar.den, old_sar.num, old_sar.den,
185 dar.num, dar.den, inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den);
186
187 return 0;
188}
189
190static const AVOption setdar_options[] = {
191 { "dar", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
192 { "ratio", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
193 { "r", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
194#if FF_API_OLD_FILTER_OPTS
195 { "dar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS },
196#endif
197 { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS },
198 { NULL }
199};
200
201AVFILTER_DEFINE_CLASS(setdar);
202
203static const AVFilterPad avfilter_vf_setdar_inputs[] = {
204 {
205 .name = "default",
206 .type = AVMEDIA_TYPE_VIDEO,
207 .config_props = setdar_config_props,
208 .filter_frame = filter_frame,
209 },
210 { NULL }
211};
212
213static const AVFilterPad avfilter_vf_setdar_outputs[] = {
214 {
215 .name = "default",
216 .type = AVMEDIA_TYPE_VIDEO,
217 },
218 { NULL }
219};
220
221AVFilter ff_vf_setdar = {
222 .name = "setdar",
223 .description = NULL_IF_CONFIG_SMALL("Set the frame display aspect ratio."),
224 .init = init,
225 .priv_size = sizeof(AspectContext),
226 .priv_class = &setdar_class,
227 .inputs = avfilter_vf_setdar_inputs,
228 .outputs = avfilter_vf_setdar_outputs,
229};
230
231#endif /* CONFIG_SETDAR_FILTER */
232
233#if CONFIG_SETSAR_FILTER
234
235static int setsar_config_props(AVFilterLink *inlink)
236{
237 AspectContext *s = inlink->dst->priv;
238 AVRational old_sar = inlink->sample_aspect_ratio;
239 AVRational old_dar, dar;
240 int ret;
241
242#if FF_API_OLD_FILTER_OPTS
243 if (!(s->ratio_expr && s->aspect_den > 0)) {
244#endif
245 if ((ret = get_aspect_ratio(inlink, &s->sar)))
246 return ret;
247#if FF_API_OLD_FILTER_OPTS
248 }
249#endif
250
251 inlink->sample_aspect_ratio = s->sar;
252
253 compute_dar(&old_dar, old_sar, inlink->w, inlink->h);
254 compute_dar(&dar, s->sar, inlink->w, inlink->h);
255 av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d dar:%d/%d -> sar:%d/%d dar:%d/%d\n",
256 inlink->w, inlink->h, old_sar.num, old_sar.den, old_dar.num, old_dar.den,
257 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, dar.num, dar.den);
258
259 return 0;
260}
261
262static const AVOption setsar_options[] = {
263 { "sar", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
264 { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
265 { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS },
266#if FF_API_OLD_FILTER_OPTS
267 { "sar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS },
268#endif
269 { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS },
270 { NULL }
271};
272
273AVFILTER_DEFINE_CLASS(setsar);
274
275static const AVFilterPad avfilter_vf_setsar_inputs[] = {
276 {
277 .name = "default",
278 .type = AVMEDIA_TYPE_VIDEO,
279 .config_props = setsar_config_props,
280 .filter_frame = filter_frame,
281 },
282 { NULL }
283};
284
285static const AVFilterPad avfilter_vf_setsar_outputs[] = {
286 {
287 .name = "default",
288 .type = AVMEDIA_TYPE_VIDEO,
289 },
290 { NULL }
291};
292
293AVFilter ff_vf_setsar = {
294 .name = "setsar",
295 .description = NULL_IF_CONFIG_SMALL("Set the pixel sample aspect ratio."),
296 .init = init,
297 .priv_size = sizeof(AspectContext),
298 .priv_class = &setsar_class,
299 .inputs = avfilter_vf_setsar_inputs,
300 .outputs = avfilter_vf_setsar_outputs,
301};
302
303#endif /* CONFIG_SETSAR_FILTER */