2 * Copyright (c) 2007 Bobby Bingham
4 * This file is part of Libav.
6 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 #include "libavutil/avstring.h"
34 #include "libavutil/eval.h"
35 #include "libavutil/internal.h"
36 #include "libavutil/mathematics.h"
37 #include "libavutil/opt.h"
38 #include "libavutil/pixdesc.h"
39 #include "libswscale/swscale.h"
41 static const char *const var_names
[] = {
72 struct SwsContext
*sws
; ///< software scaler context
75 * New dimensions. Special values are:
76 * 0 = original width/height
77 * -1 = keep original aspect
80 unsigned int flags
; ///sws flags
82 int hsub
, vsub
; ///< chroma subsampling
83 int slice_y
; ///< top of current output slice
84 int input_is_pal
; ///< set to 1 if the input format is paletted
86 char w_expr
[256]; ///< width expression string
87 char h_expr
[256]; ///< height expression string
90 static av_cold
int init(AVFilterContext
*ctx
, const char *args
)
92 ScaleContext
*scale
= ctx
->priv
;
95 av_strlcpy(scale
->w_expr
, "iw", sizeof(scale
->w_expr
));
96 av_strlcpy(scale
->h_expr
, "ih", sizeof(scale
->h_expr
));
98 scale
->flags
= SWS_BILINEAR
;
100 sscanf(args
, "%255[^:]:%255[^:]", scale
->w_expr
, scale
->h_expr
);
101 p
= strstr(args
,"flags=");
103 const AVClass
*class = sws_get_class();
104 const AVOption
*o
= av_opt_find(&class, "sws_flags", NULL
, 0,
105 AV_OPT_SEARCH_FAKE_OBJ
);
106 int ret
= av_opt_eval_flags(&class, o
, p
+ 6, &scale
->flags
);
116 static av_cold
void uninit(AVFilterContext
*ctx
)
118 ScaleContext
*scale
= ctx
->priv
;
119 sws_freeContext(scale
->sws
);
123 static int query_formats(AVFilterContext
*ctx
)
125 AVFilterFormats
*formats
;
126 enum AVPixelFormat pix_fmt
;
129 if (ctx
->inputs
[0]) {
131 for (pix_fmt
= 0; pix_fmt
< AV_PIX_FMT_NB
; pix_fmt
++)
132 if ( sws_isSupportedInput(pix_fmt
)
133 && (ret
= ff_add_format(&formats
, pix_fmt
)) < 0) {
134 ff_formats_unref(&formats
);
137 ff_formats_ref(formats
, &ctx
->inputs
[0]->out_formats
);
139 if (ctx
->outputs
[0]) {
141 for (pix_fmt
= 0; pix_fmt
< AV_PIX_FMT_NB
; pix_fmt
++)
142 if ( sws_isSupportedOutput(pix_fmt
)
143 && (ret
= ff_add_format(&formats
, pix_fmt
)) < 0) {
144 ff_formats_unref(&formats
);
147 ff_formats_ref(formats
, &ctx
->outputs
[0]->in_formats
);
153 static int config_props(AVFilterLink
*outlink
)
155 AVFilterContext
*ctx
= outlink
->src
;
156 AVFilterLink
*inlink
= outlink
->src
->inputs
[0];
157 ScaleContext
*scale
= ctx
->priv
;
158 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
160 double var_values
[VARS_NB
], res
;
164 var_values
[VAR_PI
] = M_PI
;
165 var_values
[VAR_PHI
] = M_PHI
;
166 var_values
[VAR_E
] = M_E
;
167 var_values
[VAR_IN_W
] = var_values
[VAR_IW
] = inlink
->w
;
168 var_values
[VAR_IN_H
] = var_values
[VAR_IH
] = inlink
->h
;
169 var_values
[VAR_OUT_W
] = var_values
[VAR_OW
] = NAN
;
170 var_values
[VAR_OUT_H
] = var_values
[VAR_OH
] = NAN
;
171 var_values
[VAR_DAR
] = var_values
[VAR_A
] = (double) inlink
->w
/ inlink
->h
;
172 var_values
[VAR_SAR
] = inlink
->sample_aspect_ratio
.num
?
173 (double) inlink
->sample_aspect_ratio
.num
/ inlink
->sample_aspect_ratio
.den
: 1;
174 var_values
[VAR_HSUB
] = 1 << desc
->log2_chroma_w
;
175 var_values
[VAR_VSUB
] = 1 << desc
->log2_chroma_h
;
177 /* evaluate width and height */
178 av_expr_parse_and_eval(&res
, (expr
= scale
->w_expr
),
179 var_names
, var_values
,
180 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
);
181 scale
->w
= var_values
[VAR_OUT_W
] = var_values
[VAR_OW
] = res
;
182 if ((ret
= av_expr_parse_and_eval(&res
, (expr
= scale
->h_expr
),
183 var_names
, var_values
,
184 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
)) < 0)
186 scale
->h
= var_values
[VAR_OUT_H
] = var_values
[VAR_OH
] = res
;
187 /* evaluate again the width, as it may depend on the output height */
188 if ((ret
= av_expr_parse_and_eval(&res
, (expr
= scale
->w_expr
),
189 var_names
, var_values
,
190 NULL
, NULL
, NULL
, NULL
, NULL
, 0, ctx
)) < 0)
197 /* sanity check params */
198 if (w
< -1 || h
< -1) {
199 av_log(ctx
, AV_LOG_ERROR
, "Size values less than -1 are not acceptable.\n");
200 return AVERROR(EINVAL
);
202 if (w
== -1 && h
== -1)
203 scale
->w
= scale
->h
= 0;
210 w
= av_rescale(h
, inlink
->w
, inlink
->h
);
212 h
= av_rescale(w
, inlink
->h
, inlink
->w
);
214 if (w
> INT_MAX
|| h
> INT_MAX
||
215 (h
* inlink
->w
) > INT_MAX
||
216 (w
* inlink
->h
) > INT_MAX
)
217 av_log(ctx
, AV_LOG_ERROR
, "Rescaled value for width or height is too big.\n");
222 /* TODO: make algorithm configurable */
223 av_log(ctx
, AV_LOG_VERBOSE
, "w:%d h:%d fmt:%s -> w:%d h:%d fmt:%s flags:0x%0x\n",
224 inlink
->w
, inlink
->h
, av_get_pix_fmt_name(inlink
->format
),
225 outlink
->w
, outlink
->h
, av_get_pix_fmt_name(outlink
->format
),
228 scale
->input_is_pal
= desc
->flags
& PIX_FMT_PAL
||
229 desc
->flags
& PIX_FMT_PSEUDOPAL
;
232 sws_freeContext(scale
->sws
);
233 if (inlink
->w
== outlink
->w
&& inlink
->h
== outlink
->h
&&
234 inlink
->format
== outlink
->format
)
237 scale
->sws
= sws_getContext(inlink
->w
, inlink
->h
, inlink
->format
,
238 outlink
->w
, outlink
->h
, outlink
->format
,
239 scale
->flags
, NULL
, NULL
, NULL
);
241 return AVERROR(EINVAL
);
245 if (inlink
->sample_aspect_ratio
.num
)
246 outlink
->sample_aspect_ratio
= av_mul_q((AVRational
){outlink
->h
*inlink
->w
,
247 outlink
->w
*inlink
->h
},
248 inlink
->sample_aspect_ratio
);
250 outlink
->sample_aspect_ratio
= inlink
->sample_aspect_ratio
;
255 av_log(NULL
, AV_LOG_ERROR
,
256 "Error when evaluating the expression '%s'\n", expr
);
260 static int filter_frame(AVFilterLink
*link
, AVFrame
*in
)
262 ScaleContext
*scale
= link
->dst
->priv
;
263 AVFilterLink
*outlink
= link
->dst
->outputs
[0];
265 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(link
->format
);
268 return ff_filter_frame(outlink
, in
);
270 scale
->hsub
= desc
->log2_chroma_w
;
271 scale
->vsub
= desc
->log2_chroma_h
;
273 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
276 return AVERROR(ENOMEM
);
279 av_frame_copy_props(out
, in
);
280 out
->width
= outlink
->w
;
281 out
->height
= outlink
->h
;
283 av_reduce(&out
->sample_aspect_ratio
.num
, &out
->sample_aspect_ratio
.den
,
284 (int64_t)in
->sample_aspect_ratio
.num
* outlink
->h
* link
->w
,
285 (int64_t)in
->sample_aspect_ratio
.den
* outlink
->w
* link
->h
,
288 sws_scale(scale
->sws
, in
->data
, in
->linesize
, 0, in
->height
,
289 out
->data
, out
->linesize
);
292 return ff_filter_frame(outlink
, out
);
295 static const AVFilterPad avfilter_vf_scale_inputs
[] = {
298 .type
= AVMEDIA_TYPE_VIDEO
,
299 .filter_frame
= filter_frame
,
304 static const AVFilterPad avfilter_vf_scale_outputs
[] = {
307 .type
= AVMEDIA_TYPE_VIDEO
,
308 .config_props
= config_props
,
313 AVFilter avfilter_vf_scale
= {
315 .description
= NULL_IF_CONFIG_SMALL("Scale the input video to width:height size and/or convert the image format."),
320 .query_formats
= query_formats
,
322 .priv_size
= sizeof(ScaleContext
),
324 .inputs
= avfilter_vf_scale_inputs
,
325 .outputs
= avfilter_vf_scale_outputs
,