2 * Copyright (c) 2010 Bobby Bingham
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
23 * aspect ratio modification video filters
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"
39 static const char *const var_names
[] = {
59 typedef struct AspectContext
{
64 #if FF_API_OLD_FILTER_OPTS
70 static av_cold
int init(AVFilterContext
*ctx
)
72 AspectContext
*s
= ctx
->priv
;
75 #if FF_API_OLD_FILTER_OPTS
76 if (s
->ratio_expr
&& s
->aspect_den
> 0) {
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
);
83 av_log(ctx
, AV_LOG_ERROR
, "Unable to parse ratio numerator \"%s\"\n", s
->ratio_expr
);
84 return AVERROR(EINVAL
);
86 s
->sar
= s
->dar
= av_d2q(num
/ s
->aspect_den
, s
->max
);
93 static int filter_frame(AVFilterLink
*link
, AVFrame
*frame
)
95 AspectContext
*s
= link
->dst
->priv
;
97 frame
->sample_aspect_ratio
= s
->sar
;
98 return ff_filter_frame(link
->dst
->outputs
[0], frame
);
101 #define OFFSET(x) offsetof(AspectContext, x)
102 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
104 static inline void compute_dar(AVRational
*dar
, AVRational sar
, int w
, int h
)
106 if (sar
.num
&& sar
.den
) {
107 av_reduce(&dar
->num
, &dar
->den
, sar
.num
* w
, sar
.den
* h
, INT_MAX
);
109 av_reduce(&dar
->num
, &dar
->den
, w
, h
, INT_MAX
);
113 static int get_aspect_ratio(AVFilterLink
*inlink
, AVRational
*aspect_ratio
)
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
;
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
;
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
);
135 ret
= av_parse_ratio(aspect_ratio
, s
->ratio_expr
, s
->max
, 0, ctx
);
137 *aspect_ratio
= av_d2q(res
, s
->max
);
140 av_log(ctx
, AV_LOG_ERROR
,
141 "Error when evaluating the expression '%s'\n", s
->ratio_expr
);
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
);
152 #if CONFIG_SETDAR_FILTER
154 static int setdar_config_props(AVFilterLink
*inlink
)
156 AspectContext
*s
= inlink
->dst
->priv
;
159 AVRational old_sar
= inlink
->sample_aspect_ratio
;
162 #if FF_API_OLD_FILTER_OPTS
163 if (!(s
->ratio_expr
&& s
->aspect_den
> 0)) {
165 if ((ret
= get_aspect_ratio(inlink
, &s
->dar
)))
167 #if FF_API_OLD_FILTER_OPTS
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
;
178 inlink
->sample_aspect_ratio
= (AVRational
){ 1, 1 };
179 dar
= (AVRational
){ inlink
->w
, inlink
->h
};
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
);
190 static 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
},
197 { "max", "set max value for nominator or denominator in the ratio", OFFSET(max
), AV_OPT_TYPE_INT
, {.i64
=100}, 1, INT_MAX
, FLAGS
},
201 AVFILTER_DEFINE_CLASS(setdar
);
203 static const AVFilterPad avfilter_vf_setdar_inputs
[] = {
206 .type
= AVMEDIA_TYPE_VIDEO
,
207 .config_props
= setdar_config_props
,
208 .filter_frame
= filter_frame
,
213 static const AVFilterPad avfilter_vf_setdar_outputs
[] = {
216 .type
= AVMEDIA_TYPE_VIDEO
,
221 AVFilter ff_vf_setdar
= {
223 .description
= NULL_IF_CONFIG_SMALL("Set the frame display aspect ratio."),
225 .priv_size
= sizeof(AspectContext
),
226 .priv_class
= &setdar_class
,
227 .inputs
= avfilter_vf_setdar_inputs
,
228 .outputs
= avfilter_vf_setdar_outputs
,
231 #endif /* CONFIG_SETDAR_FILTER */
233 #if CONFIG_SETSAR_FILTER
235 static int setsar_config_props(AVFilterLink
*inlink
)
237 AspectContext
*s
= inlink
->dst
->priv
;
238 AVRational old_sar
= inlink
->sample_aspect_ratio
;
239 AVRational old_dar
, dar
;
242 #if FF_API_OLD_FILTER_OPTS
243 if (!(s
->ratio_expr
&& s
->aspect_den
> 0)) {
245 if ((ret
= get_aspect_ratio(inlink
, &s
->sar
)))
247 #if FF_API_OLD_FILTER_OPTS
251 inlink
->sample_aspect_ratio
= s
->sar
;
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
);
262 static 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
},
269 { "max", "set max value for nominator or denominator in the ratio", OFFSET(max
), AV_OPT_TYPE_INT
, {.i64
=100}, 1, INT_MAX
, FLAGS
},
273 AVFILTER_DEFINE_CLASS(setsar
);
275 static const AVFilterPad avfilter_vf_setsar_inputs
[] = {
278 .type
= AVMEDIA_TYPE_VIDEO
,
279 .config_props
= setsar_config_props
,
280 .filter_frame
= filter_frame
,
285 static const AVFilterPad avfilter_vf_setsar_outputs
[] = {
288 .type
= AVMEDIA_TYPE_VIDEO
,
293 AVFilter ff_vf_setsar
= {
295 .description
= NULL_IF_CONFIG_SMALL("Set the pixel sample aspect ratio."),
297 .priv_size
= sizeof(AspectContext
),
298 .priv_class
= &setsar_class
,
299 .inputs
= avfilter_vf_setsar_inputs
,
300 .outputs
= avfilter_vf_setsar_outputs
,
303 #endif /* CONFIG_SETSAR_FILTER */