vf_scale.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 Bobby Bingham
3  *
4  * This file is part of Libav.
5  *
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.
10  *
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.
15  *
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
19  */
20 
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "avfilter.h"
30 #include "formats.h"
31 #include "internal.h"
32 #include "video.h"
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"
40 
41 static const char *const var_names[] = {
42  "PI",
43  "PHI",
44  "E",
45  "in_w", "iw",
46  "in_h", "ih",
47  "out_w", "ow",
48  "out_h", "oh",
49  "a", "dar",
50  "sar",
51  "hsub",
52  "vsub",
53  NULL
54 };
55 
56 enum var_name {
69 };
70 
71 typedef struct {
72  struct SwsContext *sws;
73 
79  int w, h;
80  unsigned int flags;
81 
82  int hsub, vsub;
83  int slice_y;
85 
86  char w_expr[256];
87  char h_expr[256];
88 } ScaleContext;
89 
90 static av_cold int init(AVFilterContext *ctx, const char *args)
91 {
92  ScaleContext *scale = ctx->priv;
93  const char *p;
94 
95  av_strlcpy(scale->w_expr, "iw", sizeof(scale->w_expr));
96  av_strlcpy(scale->h_expr, "ih", sizeof(scale->h_expr));
97 
98  scale->flags = SWS_BILINEAR;
99  if (args) {
100  sscanf(args, "%255[^:]:%255[^:]", scale->w_expr, scale->h_expr);
101  p = strstr(args,"flags=");
102  if (p) {
103  const AVClass *class = sws_get_class();
104  const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0,
106  int ret = av_opt_eval_flags(&class, o, p + 6, &scale->flags);
107 
108  if (ret < 0)
109  return ret;
110  }
111  }
112 
113  return 0;
114 }
115 
116 static av_cold void uninit(AVFilterContext *ctx)
117 {
118  ScaleContext *scale = ctx->priv;
119  sws_freeContext(scale->sws);
120  scale->sws = NULL;
121 }
122 
124 {
126  enum AVPixelFormat pix_fmt;
127  int ret;
128 
129  if (ctx->inputs[0]) {
130  formats = NULL;
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);
135  return ret;
136  }
137  ff_formats_ref(formats, &ctx->inputs[0]->out_formats);
138  }
139  if (ctx->outputs[0]) {
140  formats = NULL;
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);
145  return ret;
146  }
147  ff_formats_ref(formats, &ctx->outputs[0]->in_formats);
148  }
149 
150  return 0;
151 }
152 
153 static int config_props(AVFilterLink *outlink)
154 {
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);
159  int64_t w, h;
160  double var_values[VARS_NB], res;
161  char *expr;
162  int ret;
163 
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;
176 
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)
185  goto fail;
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)
191  goto fail;
192  scale->w = res;
193 
194  w = scale->w;
195  h = scale->h;
196 
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);
201  }
202  if (w == -1 && h == -1)
203  scale->w = scale->h = 0;
204 
205  if (!(w = scale->w))
206  w = inlink->w;
207  if (!(h = scale->h))
208  h = inlink->h;
209  if (w == -1)
210  w = av_rescale(h, inlink->w, inlink->h);
211  if (h == -1)
212  h = av_rescale(w, inlink->h, inlink->w);
213 
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");
218 
219  outlink->w = w;
220  outlink->h = h;
221 
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),
226  scale->flags);
227 
228  scale->input_is_pal = desc->flags & PIX_FMT_PAL ||
229  desc->flags & PIX_FMT_PSEUDOPAL;
230 
231  if (scale->sws)
232  sws_freeContext(scale->sws);
233  if (inlink->w == outlink->w && inlink->h == outlink->h &&
234  inlink->format == outlink->format)
235  scale->sws = NULL;
236  else {
237  scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
238  outlink->w, outlink->h, outlink->format,
239  scale->flags, NULL, NULL, NULL);
240  if (!scale->sws)
241  return AVERROR(EINVAL);
242  }
243 
244 
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);
249  else
250  outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
251 
252  return 0;
253 
254 fail:
256  "Error when evaluating the expression '%s'\n", expr);
257  return ret;
258 }
259 
261 {
262  ScaleContext *scale = link->dst->priv;
263  AVFilterLink *outlink = link->dst->outputs[0];
264  AVFilterBufferRef *out;
265  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
266 
267  if (!scale->sws)
268  return ff_filter_frame(outlink, in);
269 
270  scale->hsub = desc->log2_chroma_w;
271  scale->vsub = desc->log2_chroma_h;
272 
273  out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
274  if (!out) {
276  return AVERROR(ENOMEM);
277  }
278 
280  out->video->w = outlink->w;
281  out->video->h = outlink->h;
282 
284  (int64_t)in->video->pixel_aspect.num * outlink->h * link->w,
285  (int64_t)in->video->pixel_aspect.den * outlink->w * link->h,
286  INT_MAX);
287 
288  sws_scale(scale->sws, in->data, in->linesize, 0, in->video->h,
289  out->data, out->linesize);
290 
292  return ff_filter_frame(outlink, out);
293 }
294 
296  {
297  .name = "default",
298  .type = AVMEDIA_TYPE_VIDEO,
299  .filter_frame = filter_frame,
300  .min_perms = AV_PERM_READ,
301  },
302  { NULL }
303 };
304 
306  {
307  .name = "default",
308  .type = AVMEDIA_TYPE_VIDEO,
309  .config_props = config_props,
310  },
311  { NULL }
312 };
313 
315  .name = "scale",
316  .description = NULL_IF_CONFIG_SMALL("Scale the input video to width:height size and/or convert the image format."),
317 
318  .init = init,
319  .uninit = uninit,
320 
321  .query_formats = query_formats,
322 
323  .priv_size = sizeof(ScaleContext),
324 
325  .inputs = avfilter_vf_scale_inputs,
326  .outputs = avfilter_vf_scale_outputs,
327 };