FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_scale.c
Date: 2024-03-28 14:59:00
Exec Total Coverage
Lines: 355 515 68.9%
Functions: 15 19 78.9%
Branches: 212 428 49.5%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2007 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 * scale video filter
24 */
25
26 #include <float.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "avfilter.h"
31 #include "formats.h"
32 #include "internal.h"
33 #include "scale_eval.h"
34 #include "video.h"
35 #include "libavutil/avstring.h"
36 #include "libavutil/eval.h"
37 #include "libavutil/internal.h"
38 #include "libavutil/mathematics.h"
39 #include "libavutil/opt.h"
40 #include "libavutil/parseutils.h"
41 #include "libavutil/pixdesc.h"
42 #include "libavutil/imgutils.h"
43 #include "libswscale/swscale.h"
44
45 static const char *const var_names[] = {
46 "in_w", "iw",
47 "in_h", "ih",
48 "out_w", "ow",
49 "out_h", "oh",
50 "a",
51 "sar",
52 "dar",
53 "hsub",
54 "vsub",
55 "ohsub",
56 "ovsub",
57 "n",
58 "t",
59 #if FF_API_FRAME_PKT
60 "pos",
61 #endif
62 "main_w",
63 "main_h",
64 "main_a",
65 "main_sar",
66 "main_dar", "mdar",
67 "main_hsub",
68 "main_vsub",
69 "main_n",
70 "main_t",
71 "main_pos",
72 NULL
73 };
74
75 enum var_name {
76 VAR_IN_W, VAR_IW,
77 VAR_IN_H, VAR_IH,
78 VAR_OUT_W, VAR_OW,
79 VAR_OUT_H, VAR_OH,
80 VAR_A,
81 VAR_SAR,
82 VAR_DAR,
83 VAR_HSUB,
84 VAR_VSUB,
85 VAR_OHSUB,
86 VAR_OVSUB,
87 VAR_N,
88 VAR_T,
89 #if FF_API_FRAME_PKT
90 VAR_POS,
91 #endif
92 VAR_S2R_MAIN_W,
93 VAR_S2R_MAIN_H,
94 VAR_S2R_MAIN_A,
95 VAR_S2R_MAIN_SAR,
96 VAR_S2R_MAIN_DAR, VAR_S2R_MDAR,
97 VAR_S2R_MAIN_HSUB,
98 VAR_S2R_MAIN_VSUB,
99 VAR_S2R_MAIN_N,
100 VAR_S2R_MAIN_T,
101 VAR_S2R_MAIN_POS,
102 VARS_NB
103 };
104
105 enum EvalMode {
106 EVAL_MODE_INIT,
107 EVAL_MODE_FRAME,
108 EVAL_MODE_NB
109 };
110
111 typedef struct ScaleContext {
112 const AVClass *class;
113 struct SwsContext *sws; ///< software scaler context
114 struct SwsContext *isws[2]; ///< software scaler context for interlaced material
115 // context used for forwarding options to sws
116 struct SwsContext *sws_opts;
117
118 /**
119 * New dimensions. Special values are:
120 * 0 = original width/height
121 * -1 = keep original aspect
122 * -N = try to keep aspect but make sure it is divisible by N
123 */
124 int w, h;
125 char *size_str;
126 double param[2]; // sws params
127
128 int hsub, vsub; ///< chroma subsampling
129 int slice_y; ///< top of current output slice
130 int input_is_pal; ///< set to 1 if the input format is paletted
131 int output_is_pal; ///< set to 1 if the output format is paletted
132 int interlaced;
133
134 char *w_expr; ///< width expression string
135 char *h_expr; ///< height expression string
136 AVExpr *w_pexpr;
137 AVExpr *h_pexpr;
138 double var_values[VARS_NB];
139
140 char *flags_str;
141
142 int in_color_matrix;
143 int out_color_matrix;
144
145 int in_range;
146 int out_range;
147
148 int out_h_chr_pos;
149 int out_v_chr_pos;
150 int in_h_chr_pos;
151 int in_v_chr_pos;
152
153 int force_original_aspect_ratio;
154 int force_divisible_by;
155
156 int eval_mode; ///< expression evaluation mode
157
158 } ScaleContext;
159
160 const AVFilter ff_vf_scale2ref;
161
162 static int config_props(AVFilterLink *outlink);
163
164 13668 static int check_exprs(AVFilterContext *ctx)
165 {
166 13668 ScaleContext *scale = ctx->priv;
167 13668 unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
168
169
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 13668 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13668 if (!scale->w_pexpr && !scale->h_pexpr)
170 return AVERROR(EINVAL);
171
172
1/2
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
13668 if (scale->w_pexpr)
173 13668 av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
174
2/2
✓ Branch 0 taken 6888 times.
✓ Branch 1 taken 6780 times.
13668 if (scale->h_pexpr)
175 6888 av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
176
177
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13668 times.
13668 if (vars_w[VAR_OUT_W] || vars_w[VAR_OW]) {
178 av_log(ctx, AV_LOG_ERROR, "Width expression cannot be self-referencing: '%s'.\n", scale->w_expr);
179 return AVERROR(EINVAL);
180 }
181
182
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13668 times.
13668 if (vars_h[VAR_OUT_H] || vars_h[VAR_OH]) {
183 av_log(ctx, AV_LOG_ERROR, "Height expression cannot be self-referencing: '%s'.\n", scale->h_expr);
184 return AVERROR(EINVAL);
185 }
186
187
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13668 times.
13668 if ((vars_w[VAR_OUT_H] || vars_w[VAR_OH]) &&
188 (vars_h[VAR_OUT_W] || vars_h[VAR_OW])) {
189 av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);
190 }
191
192
2/2
✓ Branch 0 taken 13664 times.
✓ Branch 1 taken 4 times.
13668 if (ctx->filter != &ff_vf_scale2ref &&
193
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
194
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
195
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
196
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
197
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
198
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
199
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] ||
200
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] ||
201
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
202
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13664 times.
✗ Branch 3 not taken.
13664 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
203
2/4
✓ Branch 0 taken 13664 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13664 times.
13664 vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
204 av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref variables are not valid in scale filter.\n");
205 return AVERROR(EINVAL);
206 }
207
208
1/2
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
13668 if (scale->eval_mode == EVAL_MODE_INIT &&
209
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13668 times.
✗ Branch 3 not taken.
13668 (vars_w[VAR_N] || vars_h[VAR_N] ||
210
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13668 times.
✗ Branch 3 not taken.
13668 vars_w[VAR_T] || vars_h[VAR_T] ||
211 #if FF_API_FRAME_PKT
212
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13668 times.
✗ Branch 3 not taken.
13668 vars_w[VAR_POS] || vars_h[VAR_POS] ||
213 #endif
214
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13668 times.
✗ Branch 3 not taken.
13668 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
215
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13668 times.
✗ Branch 3 not taken.
13668 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
216
2/4
✓ Branch 0 taken 13668 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13668 times.
13668 vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
217 av_log(ctx, AV_LOG_ERROR, "Expressions with frame variables 'n', 't', 'pos' are not valid in init eval_mode.\n");
218 return AVERROR(EINVAL);
219 }
220
221 13668 return 0;
222 }
223
224 13668 static int scale_parse_expr(AVFilterContext *ctx, char *str_expr, AVExpr **pexpr_ptr, const char *var, const char *args)
225 {
226 13668 ScaleContext *scale = ctx->priv;
227 13668 int ret, is_inited = 0;
228 13668 char *old_str_expr = NULL;
229 13668 AVExpr *old_pexpr = NULL;
230
231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13668 times.
13668 if (str_expr) {
232 old_str_expr = av_strdup(str_expr);
233 if (!old_str_expr)
234 return AVERROR(ENOMEM);
235 av_opt_set(scale, var, args, 0);
236 }
237
238
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 13560 times.
13668 if (*pexpr_ptr) {
239 108 old_pexpr = *pexpr_ptr;
240 108 *pexpr_ptr = NULL;
241 108 is_inited = 1;
242 }
243
244 13668 ret = av_expr_parse(pexpr_ptr, args, var_names,
245 NULL, NULL, NULL, NULL, 0, ctx);
246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13668 times.
13668 if (ret < 0) {
247 av_log(ctx, AV_LOG_ERROR, "Cannot parse expression for %s: '%s'\n", var, args);
248 goto revert;
249 }
250
251 13668 ret = check_exprs(ctx);
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13668 times.
13668 if (ret < 0)
253 goto revert;
254
255
3/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 13560 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
13668 if (is_inited && (ret = config_props(ctx->outputs[0])) < 0)
256 goto revert;
257
258 13668 av_expr_free(old_pexpr);
259 13668 old_pexpr = NULL;
260 13668 av_freep(&old_str_expr);
261
262 13668 return 0;
263
264 revert:
265 av_expr_free(*pexpr_ptr);
266 *pexpr_ptr = NULL;
267 if (old_str_expr) {
268 av_opt_set(scale, var, old_str_expr, 0);
269 av_free(old_str_expr);
270 }
271 if (old_pexpr)
272 *pexpr_ptr = old_pexpr;
273
274 return ret;
275 }
276
277 6780 static av_cold int preinit(AVFilterContext *ctx)
278 {
279 6780 ScaleContext *scale = ctx->priv;
280 int ret;
281
282 6780 scale->sws_opts = sws_alloc_context();
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
6780 if (!scale->sws_opts)
284 return AVERROR(ENOMEM);
285
286 // set threads=0, so we can later check whether the user modified it
287 6780 ret = av_opt_set_int(scale->sws_opts, "threads", 0, 0);
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
6780 if (ret < 0)
289 return ret;
290
291 6780 return 0;
292 }
293
294 static const int sws_colorspaces[] = {
295 AVCOL_SPC_UNSPECIFIED,
296 AVCOL_SPC_RGB,
297 AVCOL_SPC_BT709,
298 AVCOL_SPC_BT470BG,
299 AVCOL_SPC_SMPTE170M,
300 AVCOL_SPC_FCC,
301 AVCOL_SPC_SMPTE240M,
302 AVCOL_SPC_BT2020_NCL,
303 -1
304 };
305
306 6780 static av_cold int init(AVFilterContext *ctx)
307 {
308 6780 ScaleContext *scale = ctx->priv;
309 int64_t threads;
310 int ret;
311
312
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6780 if (scale->size_str && (scale->w_expr || scale->h_expr)) {
313 av_log(ctx, AV_LOG_ERROR,
314 "Size and width/height expressions cannot be set at the same time.\n");
315 return AVERROR(EINVAL);
316 }
317
318
3/4
✓ Branch 0 taken 704 times.
✓ Branch 1 taken 6076 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 704 times.
6780 if (scale->w_expr && !scale->h_expr)
319 FFSWAP(char *, scale->w_expr, scale->size_str);
320
321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
6780 if (scale->size_str) {
322 char buf[32];
323 if ((ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str)) < 0) {
324 av_log(ctx, AV_LOG_ERROR,
325 "Invalid size '%s'\n", scale->size_str);
326 return ret;
327 }
328 snprintf(buf, sizeof(buf)-1, "%d", scale->w);
329 av_opt_set(scale, "w", buf, 0);
330 snprintf(buf, sizeof(buf)-1, "%d", scale->h);
331 av_opt_set(scale, "h", buf, 0);
332 }
333
2/2
✓ Branch 0 taken 6076 times.
✓ Branch 1 taken 704 times.
6780 if (!scale->w_expr)
334 6076 av_opt_set(scale, "w", "iw", 0);
335
2/2
✓ Branch 0 taken 6076 times.
✓ Branch 1 taken 704 times.
6780 if (!scale->h_expr)
336 6076 av_opt_set(scale, "h", "ih", 0);
337
338 6780 ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
6780 if (ret < 0)
340 return ret;
341
342 6780 ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
6780 if (ret < 0)
344 return ret;
345
346
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6776 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6784 if (scale->in_color_matrix != -1 &&
347 4 !ff_fmt_is_in(scale->in_color_matrix, sws_colorspaces)) {
348 av_log(ctx, AV_LOG_ERROR, "Unsupported input color matrix '%s'\n",
349 av_color_space_name(scale->in_color_matrix));
350 return AVERROR(EINVAL);
351 }
352
353
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6780 times.
6780 if (!ff_fmt_is_in(scale->out_color_matrix, sws_colorspaces)) {
354 av_log(ctx, AV_LOG_ERROR, "Unsupported output color matrix '%s'\n",
355 av_color_space_name(scale->out_color_matrix));
356 return AVERROR(EINVAL);
357 }
358
359 6780 av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
360 6780 scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
361
362
3/4
✓ Branch 0 taken 6780 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 6722 times.
6780 if (scale->flags_str && *scale->flags_str) {
363 58 ret = av_opt_set(scale->sws_opts, "sws_flags", scale->flags_str, 0);
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (ret < 0)
365 return ret;
366 }
367
368
2/2
✓ Branch 0 taken 13560 times.
✓ Branch 1 taken 6780 times.
20340 for (int i = 0; i < FF_ARRAY_ELEMS(scale->param); i++)
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13560 times.
13560 if (scale->param[i] != DBL_MAX) {
370 ret = av_opt_set_double(scale->sws_opts, i ? "param1" : "param0",
371 scale->param[i], 0);
372 if (ret < 0)
373 return ret;
374 }
375
376 // use generic thread-count if the user did not set it explicitly
377 6780 ret = av_opt_get_int(scale->sws_opts, "threads", 0, &threads);
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6780 times.
6780 if (ret < 0)
379 return ret;
380
1/2
✓ Branch 0 taken 6780 times.
✗ Branch 1 not taken.
6780 if (!threads)
381 6780 av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0);
382
383 6780 return 0;
384 }
385
386 6780 static av_cold void uninit(AVFilterContext *ctx)
387 {
388 6780 ScaleContext *scale = ctx->priv;
389 6780 av_expr_free(scale->w_pexpr);
390 6780 av_expr_free(scale->h_pexpr);
391 6780 scale->w_pexpr = scale->h_pexpr = NULL;
392 6780 sws_freeContext(scale->sws_opts);
393 6780 sws_freeContext(scale->sws);
394 6780 sws_freeContext(scale->isws[0]);
395 6780 sws_freeContext(scale->isws[1]);
396 6780 scale->sws = NULL;
397 6780 }
398
399 3858 static int query_formats(AVFilterContext *ctx)
400 {
401 3858 ScaleContext *scale = ctx->priv;
402 AVFilterFormats *formats;
403 const AVPixFmtDescriptor *desc;
404 enum AVPixelFormat pix_fmt;
405 int ret;
406
407 3858 desc = NULL;
408 3858 formats = NULL;
409
2/2
✓ Branch 1 taken 879624 times.
✓ Branch 2 taken 3858 times.
883482 while ((desc = av_pix_fmt_desc_next(desc))) {
410 879624 pix_fmt = av_pix_fmt_desc_get_id(desc);
411
3/4
✓ Branch 1 taken 115740 times.
✓ Branch 2 taken 763884 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 115740 times.
995364 if ((sws_isSupportedInput(pix_fmt) ||
412 115740 sws_isSupportedEndiannessConversion(pix_fmt))
413
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 763884 times.
763884 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
414 return ret;
415 }
416 }
417
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3858 times.
3858 if ((ret = ff_formats_ref(formats, &ctx->inputs[0]->outcfg.formats)) < 0)
418 return ret;
419
420 3858 desc = NULL;
421 3858 formats = NULL;
422
2/2
✓ Branch 1 taken 879624 times.
✓ Branch 2 taken 3858 times.
883482 while ((desc = av_pix_fmt_desc_next(desc))) {
423 879624 pix_fmt = av_pix_fmt_desc_get_id(desc);
424
5/6
✓ Branch 1 taken 165894 times.
✓ Branch 2 taken 713730 times.
✓ Branch 3 taken 162036 times.
✓ Branch 4 taken 3858 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 162036 times.
1041660 if ((sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8 ||
425 162036 sws_isSupportedEndiannessConversion(pix_fmt))
426
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 717588 times.
717588 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
427 return ret;
428 }
429 }
430
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3858 times.
3858 if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->incfg.formats)) < 0)
431 return ret;
432
433 /* accept all supported inputs, even if user overrides their properties */
434
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3858 times.
3858 if ((ret = ff_formats_ref(ff_make_format_list(sws_colorspaces),
435 3858 &ctx->inputs[0]->outcfg.color_spaces)) < 0)
436 return ret;
437
438
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3858 times.
3858 if ((ret = ff_formats_ref(ff_all_color_ranges(),
439 3858 &ctx->inputs[0]->outcfg.color_ranges)) < 0)
440 return ret;
441
442 /* propagate output properties if overridden */
443 7716 formats = scale->out_color_matrix != AVCOL_SPC_UNSPECIFIED
444 2 ? ff_make_formats_list_singleton(scale->out_color_matrix)
445
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3856 times.
3858 : ff_make_format_list(sws_colorspaces);
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3858 times.
3858 if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->incfg.color_spaces)) < 0)
447 return ret;
448
449 7716 formats = scale->out_range != AVCOL_RANGE_UNSPECIFIED
450 2 ? ff_make_formats_list_singleton(scale->out_range)
451
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3856 times.
3858 : ff_all_color_ranges();
452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3858 times.
3858 if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->incfg.color_ranges)) < 0)
453 return ret;
454
455 3858 return 0;
456 }
457
458 3975 static int scale_eval_dimensions(AVFilterContext *ctx)
459 {
460 3975 ScaleContext *scale = ctx->priv;
461 3975 const char scale2ref = ctx->filter == &ff_vf_scale2ref;
462
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3974 times.
3975 const AVFilterLink *inlink = scale2ref ? ctx->inputs[1] : ctx->inputs[0];
463 3975 const AVFilterLink *outlink = ctx->outputs[0];
464 3975 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
465 3975 const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
466 char *expr;
467 int eval_w, eval_h;
468 int ret;
469 double res;
470 const AVPixFmtDescriptor *main_desc;
471 const AVFilterLink *main_link;
472
473
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3974 times.
3975 if (scale2ref) {
474 1 main_link = ctx->inputs[0];
475 1 main_desc = av_pix_fmt_desc_get(main_link->format);
476 }
477
478 3975 scale->var_values[VAR_IN_W] = scale->var_values[VAR_IW] = inlink->w;
479 3975 scale->var_values[VAR_IN_H] = scale->var_values[VAR_IH] = inlink->h;
480 3975 scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = NAN;
481 3975 scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = NAN;
482 3975 scale->var_values[VAR_A] = (double) inlink->w / inlink->h;
483 7950 scale->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
484
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 3718 times.
3975 (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
485 3975 scale->var_values[VAR_DAR] = scale->var_values[VAR_A] * scale->var_values[VAR_SAR];
486 3975 scale->var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
487 3975 scale->var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
488 3975 scale->var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w;
489 3975 scale->var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h;
490
491
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3974 times.
3975 if (scale2ref) {
492 1 scale->var_values[VAR_S2R_MAIN_W] = main_link->w;
493 1 scale->var_values[VAR_S2R_MAIN_H] = main_link->h;
494 1 scale->var_values[VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h;
495 2 scale->var_values[VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ?
496
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (double) main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1;
497 1 scale->var_values[VAR_S2R_MAIN_DAR] = scale->var_values[VAR_S2R_MDAR] =
498 1 scale->var_values[VAR_S2R_MAIN_A] * scale->var_values[VAR_S2R_MAIN_SAR];
499 1 scale->var_values[VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w;
500 1 scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h;
501 }
502
503 3975 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
505
506 3975 res = av_expr_eval(scale->h_pexpr, scale->var_values, NULL);
507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 if (isnan(res)) {
508 expr = scale->h_expr;
509 ret = AVERROR(EINVAL);
510 goto fail;
511 }
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 eval_h = scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = (int) res == 0 ? inlink->h : (int) res;
513
514 3975 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 if (isnan(res)) {
516 expr = scale->w_expr;
517 ret = AVERROR(EINVAL);
518 goto fail;
519 }
520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
521
522 3975 scale->w = eval_w;
523 3975 scale->h = eval_h;
524
525 3975 return 0;
526
527 fail:
528 av_log(ctx, AV_LOG_ERROR,
529 "Error when evaluating the expression '%s'.\n", expr);
530 return ret;
531 }
532
533 3975 static int config_props(AVFilterLink *outlink)
534 {
535 3975 AVFilterContext *ctx = outlink->src;
536 3975 AVFilterLink *inlink0 = outlink->src->inputs[0];
537 7950 AVFilterLink *inlink = ctx->filter == &ff_vf_scale2ref ?
538
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3974 times.
3975 outlink->src->inputs[1] :
539 3974 outlink->src->inputs[0];
540 3975 enum AVPixelFormat outfmt = outlink->format;
541 3975 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
542 3975 const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(outfmt);
543 3975 ScaleContext *scale = ctx->priv;
544 3975 uint8_t *flags_val = NULL;
545 int in_range, in_colorspace;
546 int ret;
547
548
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3975 times.
3975 if ((ret = scale_eval_dimensions(ctx)) < 0)
549 goto fail;
550
551 3975 outlink->w = scale->w;
552 3975 outlink->h = scale->h;
553
554 3975 ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
555 scale->force_original_aspect_ratio,
556 scale->force_divisible_by);
557
558 if (outlink->w > INT_MAX ||
559 outlink->h > INT_MAX ||
560 (outlink->h * inlink->w) > INT_MAX ||
561 (outlink->w * inlink->h) > INT_MAX)
562 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
563
564 /* TODO: make algorithm configurable */
565
566 3975 scale->input_is_pal = desc->flags & AV_PIX_FMT_FLAG_PAL;
567
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3958 times.
3975 if (outfmt == AV_PIX_FMT_PAL8) outfmt = AV_PIX_FMT_BGR8;
568 3975 scale->output_is_pal = av_pix_fmt_desc_get(outfmt)->flags & AV_PIX_FMT_FLAG_PAL;
569
570 3975 in_range = scale->in_range;
571
2/2
✓ Branch 0 taken 3973 times.
✓ Branch 1 taken 2 times.
3975 if (in_range == AVCOL_RANGE_UNSPECIFIED)
572 3973 in_range = inlink0->color_range;
573
574 3975 in_colorspace = scale->in_color_matrix;
575
2/2
✓ Branch 0 taken 3973 times.
✓ Branch 1 taken 2 times.
3975 if (in_colorspace == -1 /* auto */)
576 3973 in_colorspace = inlink0->colorspace;
577
578
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 3825 times.
3975 if (scale->sws)
579 150 sws_freeContext(scale->sws);
580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 if (scale->isws[0])
581 sws_freeContext(scale->isws[0]);
582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3975 times.
3975 if (scale->isws[1])
583 sws_freeContext(scale->isws[1]);
584 3975 scale->isws[0] = scale->isws[1] = scale->sws = NULL;
585
2/2
✓ Branch 0 taken 3545 times.
✓ Branch 1 taken 430 times.
3975 if (inlink0->w == outlink->w &&
586
2/2
✓ Branch 0 taken 3535 times.
✓ Branch 1 taken 10 times.
3545 inlink0->h == outlink->h &&
587
2/2
✓ Branch 0 taken 1959 times.
✓ Branch 1 taken 1576 times.
3535 in_range == outlink->color_range &&
588
2/2
✓ Branch 0 taken 1817 times.
✓ Branch 1 taken 142 times.
1959 in_colorspace == outlink->colorspace &&
589
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 1633 times.
1817 inlink0->format == outlink->format)
590 ;
591 else {
592 3791 struct SwsContext **swscs[3] = {&scale->sws, &scale->isws[0], &scale->isws[1]};
593 int i;
594
595
1/2
✓ Branch 0 taken 3791 times.
✗ Branch 1 not taken.
3791 for (i = 0; i < 3; i++) {
596 3791 int in_v_chr_pos = scale->in_v_chr_pos, out_v_chr_pos = scale->out_v_chr_pos;
597 int in_full, out_full, brightness, contrast, saturation;
598 const int *inv_table, *table;
599 3791 struct SwsContext *const s = sws_alloc_context();
600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3791 times.
3791 if (!s)
601 return AVERROR(ENOMEM);
602 3791 *swscs[i] = s;
603
604 3791 ret = av_opt_copy(s, scale->sws_opts);
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3791 times.
3791 if (ret < 0)
606 return ret;
607
608 3791 av_opt_set_int(s, "srcw", inlink0 ->w, 0);
609 3791 av_opt_set_int(s, "srch", inlink0 ->h >> !!i, 0);
610 3791 av_opt_set_int(s, "src_format", inlink0->format, 0);
611 3791 av_opt_set_int(s, "dstw", outlink->w, 0);
612 3791 av_opt_set_int(s, "dsth", outlink->h >> !!i, 0);
613 3791 av_opt_set_int(s, "dst_format", outfmt, 0);
614
2/2
✓ Branch 0 taken 3268 times.
✓ Branch 1 taken 523 times.
3791 if (in_range != AVCOL_RANGE_UNSPECIFIED)
615 3268 av_opt_set_int(s, "src_range",
616 in_range == AVCOL_RANGE_JPEG, 0);
617
2/2
✓ Branch 0 taken 3060 times.
✓ Branch 1 taken 731 times.
3791 if (outlink->color_range != AVCOL_RANGE_UNSPECIFIED)
618 3060 av_opt_set_int(s, "dst_range",
619 3060 outlink->color_range == AVCOL_RANGE_JPEG, 0);
620
621 /* Override chroma location default settings to have the correct
622 * chroma positions. MPEG chroma positions are used by convention.
623 * Note that this works for both MPEG-1/JPEG and MPEG-2/4 chroma
624 * locations, since they share a vertical alignment */
625
3/4
✓ Branch 0 taken 3021 times.
✓ Branch 1 taken 770 times.
✓ Branch 2 taken 3021 times.
✗ Branch 3 not taken.
3791 if (desc->log2_chroma_h == 1 && scale->in_v_chr_pos == -513) {
626
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3021 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3021 in_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192;
627 }
628
629
4/4
✓ Branch 0 taken 1014 times.
✓ Branch 1 taken 2777 times.
✓ Branch 2 taken 1013 times.
✓ Branch 3 taken 1 times.
3791 if (outdesc->log2_chroma_h == 1 && scale->out_v_chr_pos == -513) {
630
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1013 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1013 out_v_chr_pos = (i == 0) ? 128 : (i == 1) ? 64 : 192;
631 }
632
633 3791 av_opt_set_int(s, "src_h_chr_pos", scale->in_h_chr_pos, 0);
634 3791 av_opt_set_int(s, "src_v_chr_pos", in_v_chr_pos, 0);
635 3791 av_opt_set_int(s, "dst_h_chr_pos", scale->out_h_chr_pos, 0);
636 3791 av_opt_set_int(s, "dst_v_chr_pos", out_v_chr_pos, 0);
637
638
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3791 times.
3791 if ((ret = sws_init_context(s, NULL, NULL)) < 0)
639 return ret;
640
641 3791 sws_getColorspaceDetails(s, (int **)&inv_table, &in_full,
642 (int **)&table, &out_full,
643 &brightness, &contrast, &saturation);
644
645
2/2
✓ Branch 0 taken 3789 times.
✓ Branch 1 taken 2 times.
3791 if (scale->in_color_matrix == -1 /* auto */)
646 3789 inv_table = sws_getCoefficients(inlink0->colorspace);
647
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (scale->in_color_matrix != AVCOL_SPC_UNSPECIFIED)
648 2 inv_table = sws_getCoefficients(scale->in_color_matrix);
649
2/2
✓ Branch 0 taken 1346 times.
✓ Branch 1 taken 2445 times.
3791 if (outlink->colorspace != AVCOL_SPC_UNSPECIFIED)
650 1346 table = sws_getCoefficients(outlink->colorspace);
651
1/2
✓ Branch 0 taken 2445 times.
✗ Branch 1 not taken.
2445 else if (scale->in_color_matrix != AVCOL_SPC_UNSPECIFIED)
652 2445 table = inv_table;
653
654 3791 sws_setColorspaceDetails(s, inv_table, in_full,
655 table, out_full,
656 brightness, contrast, saturation);
657
658
1/2
✓ Branch 0 taken 3791 times.
✗ Branch 1 not taken.
3791 if (!scale->interlaced)
659 3791 break;
660 }
661 }
662
663
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 3718 times.
3975 if (inlink0->sample_aspect_ratio.num){
664 257 outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink0->w, outlink->w * inlink0->h}, inlink0->sample_aspect_ratio);
665 } else
666 3718 outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
667
668
2/2
✓ Branch 0 taken 3791 times.
✓ Branch 1 taken 184 times.
3975 if (scale->sws)
669 3791 av_opt_get(scale->sws, "sws_flags", 0, &flags_val);
670
671 11925 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s csp:%s range:%s sar:%d/%d -> w:%d h:%d fmt:%s csp:%s range:%s sar:%d/%d flags:%s\n",
672 3975 inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
673 av_color_space_name(inlink->colorspace), av_color_range_name(inlink->color_range),
674 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
675 3975 outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
676 av_color_space_name(outlink->colorspace), av_color_range_name(outlink->color_range),
677 outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
678 flags_val);
679 3975 av_freep(&flags_val);
680
681 3975 return 0;
682
683 fail:
684 return ret;
685 }
686
687 1 static int config_props_ref(AVFilterLink *outlink)
688 {
689 1 AVFilterLink *inlink = outlink->src->inputs[1];
690
691 1 outlink->w = inlink->w;
692 1 outlink->h = inlink->h;
693 1 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
694 1 outlink->time_base = inlink->time_base;
695 1 outlink->frame_rate = inlink->frame_rate;
696 1 outlink->colorspace = inlink->colorspace;
697 1 outlink->color_range = inlink->color_range;
698
699 1 return 0;
700 }
701
702 5 static int request_frame(AVFilterLink *outlink)
703 {
704 5 return ff_request_frame(outlink->src->inputs[0]);
705 }
706
707 6 static int request_frame_ref(AVFilterLink *outlink)
708 {
709 6 return ff_request_frame(outlink->src->inputs[1]);
710 }
711
712 static void frame_offset(AVFrame *frame, int dir, int is_pal)
713 {
714 for (int i = 0; i < 4 && frame->data[i]; i++) {
715 if (i == 1 && is_pal)
716 break;
717 frame->data[i] += frame->linesize[i] * dir;
718 }
719 }
720
721 static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src,
722 int field)
723 {
724 int orig_h_src = src->height;
725 int orig_h_dst = dst->height;
726 int ret;
727
728 // offset the data pointers for the bottom field
729 if (field) {
730 frame_offset(src, 1, scale->input_is_pal);
731 frame_offset(dst, 1, scale->output_is_pal);
732 }
733
734 // take every second line
735 for (int i = 0; i < 4; i++) {
736 src->linesize[i] *= 2;
737 dst->linesize[i] *= 2;
738 }
739 src->height /= 2;
740 dst->height /= 2;
741
742 ret = sws_scale_frame(scale->isws[field], dst, src);
743 if (ret < 0)
744 return ret;
745
746 // undo the changes we made above
747 for (int i = 0; i < 4; i++) {
748 src->linesize[i] /= 2;
749 dst->linesize[i] /= 2;
750 }
751 src->height = orig_h_src;
752 dst->height = orig_h_dst;
753
754 if (field) {
755 frame_offset(src, -1, scale->input_is_pal);
756 frame_offset(dst, -1, scale->output_is_pal);
757 }
758
759 return 0;
760 }
761
762 46354 static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out)
763 {
764 46354 AVFilterContext *ctx = link->dst;
765 46354 ScaleContext *scale = ctx->priv;
766 46354 AVFilterLink *outlink = ctx->outputs[0];
767 AVFrame *out;
768 46354 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
769 char buf[32];
770 int ret;
771 int frame_changed;
772
773 46354 *frame_out = NULL;
774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46354 times.
46354 if (in->colorspace == AVCOL_SPC_YCGCO)
775 av_log(link->dst, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n");
776
777 139061 frame_changed = in->width != link->w ||
778
1/2
✓ Branch 0 taken 46353 times.
✗ Branch 1 not taken.
46353 in->height != link->h ||
779
1/2
✓ Branch 0 taken 46353 times.
✗ Branch 1 not taken.
46353 in->format != link->format ||
780
1/2
✓ Branch 0 taken 46353 times.
✗ Branch 1 not taken.
46353 in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
781
1/2
✓ Branch 0 taken 46353 times.
✗ Branch 1 not taken.
46353 in->sample_aspect_ratio.num != link->sample_aspect_ratio.num ||
782
4/4
✓ Branch 0 taken 46353 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 46301 times.
✓ Branch 3 taken 52 times.
139008 in->colorspace != link->colorspace ||
783
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 46300 times.
46301 in->color_range != link->color_range;
784
785
3/4
✓ Branch 0 taken 46354 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 46300 times.
46354 if (scale->eval_mode == EVAL_MODE_FRAME || frame_changed) {
786 54 unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
787
788 54 av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
789 54 av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
790
791
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
54 if (scale->eval_mode == EVAL_MODE_FRAME &&
792 !frame_changed &&
793 ctx->filter != &ff_vf_scale2ref &&
794 !(vars_w[VAR_N] || vars_w[VAR_T]
795 #if FF_API_FRAME_PKT
796 || vars_w[VAR_POS]
797 #endif
798 ) &&
799 !(vars_h[VAR_N] || vars_h[VAR_T]
800 #if FF_API_FRAME_PKT
801 || vars_h[VAR_POS]
802 #endif
803 ) &&
804 scale->w && scale->h)
805 goto scale;
806
807
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (scale->eval_mode == EVAL_MODE_INIT) {
808 54 snprintf(buf, sizeof(buf) - 1, "%d", scale->w);
809 54 av_opt_set(scale, "w", buf, 0);
810 54 snprintf(buf, sizeof(buf) - 1, "%d", scale->h);
811 54 av_opt_set(scale, "h", buf, 0);
812
813 54 ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
815 return ret;
816
817 54 ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
818
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ret < 0)
819 return ret;
820 }
821
822
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (ctx->filter == &ff_vf_scale2ref) {
823 scale->var_values[VAR_S2R_MAIN_N] = link->frame_count_out;
824 scale->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base);
825 #if FF_API_FRAME_PKT
826 FF_DISABLE_DEPRECATION_WARNINGS
827 scale->var_values[VAR_S2R_MAIN_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
828 FF_ENABLE_DEPRECATION_WARNINGS
829 #endif
830 } else {
831 54 scale->var_values[VAR_N] = link->frame_count_out;
832
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
833 #if FF_API_FRAME_PKT
834 FF_DISABLE_DEPRECATION_WARNINGS
835
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 9 times.
54 scale->var_values[VAR_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
836 FF_ENABLE_DEPRECATION_WARNINGS
837 #endif
838 }
839
840 54 link->dst->inputs[0]->format = in->format;
841 54 link->dst->inputs[0]->w = in->width;
842 54 link->dst->inputs[0]->h = in->height;
843 54 link->dst->inputs[0]->colorspace = in->colorspace;
844 54 link->dst->inputs[0]->color_range = in->color_range;
845
846 54 link->dst->inputs[0]->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
847 54 link->dst->inputs[0]->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
848
849
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
54 if ((ret = config_props(outlink)) < 0)
850 return ret;
851 }
852
853 46300 scale:
854
2/2
✓ Branch 0 taken 3764 times.
✓ Branch 1 taken 42590 times.
46354 if (!scale->sws) {
855 3764 *frame_out = in;
856 3764 return 0;
857 }
858
859 42590 scale->hsub = desc->log2_chroma_w;
860 42590 scale->vsub = desc->log2_chroma_h;
861
862 42590 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42590 times.
42590 if (!out) {
864 av_frame_free(&in);
865 return AVERROR(ENOMEM);
866 }
867 42590 *frame_out = out;
868
869 42590 av_frame_copy_props(out, in);
870 42590 out->width = outlink->w;
871 42590 out->height = outlink->h;
872 42590 out->color_range = outlink->color_range;
873 42590 out->colorspace = outlink->colorspace;
874
875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42590 times.
42590 if (scale->output_is_pal)
876 avpriv_set_systematic_pal2((uint32_t*)out->data[1], outlink->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink->format);
877
878 42590 av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
879 42590 (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
880 42590 (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
881 INT_MAX);
882
883
2/4
✓ Branch 0 taken 42590 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42590 times.
42590 if (scale->interlaced>0 || (scale->interlaced<0 &&
884 (in->flags & AV_FRAME_FLAG_INTERLACED))) {
885 ret = scale_field(scale, out, in, 0);
886 if (ret >= 0)
887 ret = scale_field(scale, out, in, 1);
888 } else {
889 42590 ret = sws_scale_frame(scale->sws, out, in);
890 }
891
892 42590 av_frame_free(&in);
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42590 times.
42590 if (ret < 0)
894 av_frame_free(frame_out);
895 42590 return ret;
896 }
897
898 46354 static int filter_frame(AVFilterLink *link, AVFrame *in)
899 {
900 46354 AVFilterContext *ctx = link->dst;
901 46354 AVFilterLink *outlink = ctx->outputs[0];
902 AVFrame *out;
903 int ret;
904
905 46354 ret = scale_frame(link, in, &out);
906
1/2
✓ Branch 0 taken 46354 times.
✗ Branch 1 not taken.
46354 if (out)
907 46354 return ff_filter_frame(outlink, out);
908
909 return ret;
910 }
911
912 6 static int filter_frame_ref(AVFilterLink *link, AVFrame *in)
913 {
914 6 ScaleContext *scale = link->dst->priv;
915 6 AVFilterLink *outlink = link->dst->outputs[1];
916 int frame_changed;
917
918 18 frame_changed = in->width != link->w ||
919
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 in->height != link->h ||
920
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 in->format != link->format ||
921
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
922
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 in->sample_aspect_ratio.num != link->sample_aspect_ratio.num ||
923
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
18 in->colorspace != link->colorspace ||
924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 in->color_range != link->color_range;
925
926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (frame_changed) {
927 link->format = in->format;
928 link->w = in->width;
929 link->h = in->height;
930 link->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
931 link->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
932 link->colorspace = in->colorspace;
933 link->color_range = in->color_range;
934
935 config_props_ref(outlink);
936 }
937
938
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (scale->eval_mode == EVAL_MODE_FRAME) {
939 scale->var_values[VAR_N] = link->frame_count_out;
940 scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
941 #if FF_API_FRAME_PKT
942 FF_DISABLE_DEPRECATION_WARNINGS
943 scale->var_values[VAR_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
944 FF_ENABLE_DEPRECATION_WARNINGS
945 #endif
946 }
947
948 6 return ff_filter_frame(outlink, in);
949 }
950
951 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
952 char *res, int res_len, int flags)
953 {
954 ScaleContext *scale = ctx->priv;
955 char *str_expr;
956 AVExpr **pexpr_ptr;
957 int ret, w, h;
958
959 w = !strcmp(cmd, "width") || !strcmp(cmd, "w");
960 h = !strcmp(cmd, "height") || !strcmp(cmd, "h");
961
962 if (w || h) {
963 str_expr = w ? scale->w_expr : scale->h_expr;
964 pexpr_ptr = w ? &scale->w_pexpr : &scale->h_pexpr;
965
966 ret = scale_parse_expr(ctx, str_expr, pexpr_ptr, cmd, args);
967 } else
968 ret = AVERROR(ENOSYS);
969
970 if (ret < 0)
971 av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
972
973 return ret;
974 }
975
976 static const AVClass *child_class_iterate(void **iter)
977 {
978 const AVClass *c = *iter ? NULL : sws_get_class();
979 *iter = (void*)(uintptr_t)c;
980 return c;
981 }
982
983 6408 static void *child_next(void *obj, void *prev)
984 {
985 6408 ScaleContext *s = obj;
986
2/2
✓ Branch 0 taken 4921 times.
✓ Branch 1 taken 1487 times.
6408 if (!prev)
987 4921 return s->sws_opts;
988 1487 return NULL;
989 }
990
991 #define OFFSET(x) offsetof(ScaleContext, x)
992 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
993 #define TFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
994
995 static const AVOption scale_options[] = {
996 { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
997 { "width", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
998 { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
999 { "height","Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1000 { "flags", "Flags to pass to libswscale", OFFSET(flags_str), AV_OPT_TYPE_STRING, { .str = "" }, .flags = FLAGS },
1001 { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_BOOL, {.i64 = 0 }, -1, 1, FLAGS },
1002 { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS },
1003 { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS },
1004 { "in_color_matrix", "set input YCbCr type", OFFSET(in_color_matrix), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AVCOL_SPC_NB-1, .flags = FLAGS, .unit = "color" },
1005 { "out_color_matrix", "set output YCbCr type", OFFSET(out_color_matrix), AV_OPT_TYPE_INT, { .i64 = AVCOL_SPC_UNSPECIFIED }, 0, AVCOL_SPC_NB-1, .flags = FLAGS, .unit = "color"},
1006 { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, FLAGS, .unit = "color" },
1007 { "bt601", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG }, 0, 0, FLAGS, .unit = "color" },
1008 { "bt470", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG }, 0, 0, FLAGS, .unit = "color" },
1009 { "smpte170m", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG }, 0, 0, FLAGS, .unit = "color" },
1010 { "bt709", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT709 }, 0, 0, FLAGS, .unit = "color" },
1011 { "fcc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_FCC }, 0, 0, FLAGS, .unit = "color" },
1012 { "smpte240m", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_SMPTE240M }, 0, 0, FLAGS, .unit = "color" },
1013 { "bt2020", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT2020_NCL }, 0, 0, FLAGS, .unit = "color" },
1014 { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, .unit = "range" },
1015 { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, .unit = "range" },
1016 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, .unit = "range" },
1017 { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, .unit = "range" },
1018 { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1019 { "limited",NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1020 { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1021 { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1022 { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1023 { "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1024 { "in_v_chr_pos", "input vertical chroma position in luma grid/256" , OFFSET(in_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
1025 { "in_h_chr_pos", "input horizontal chroma position in luma grid/256", OFFSET(in_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
1026 { "out_v_chr_pos", "output vertical chroma position in luma grid/256" , OFFSET(out_v_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
1027 { "out_h_chr_pos", "output horizontal chroma position in luma grid/256", OFFSET(out_h_chr_pos), AV_OPT_TYPE_INT, { .i64 = -513}, -513, 512, FLAGS },
1028 { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, .unit = "force_oar" },
1029 { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
1030 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
1031 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
1032 { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS },
1033 { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
1034 { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
1035 { "eval", "specify when to evaluate expressions", OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, .unit = "eval" },
1036 { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
1037 { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
1038 { NULL }
1039 };
1040
1041 static const AVClass scale_class = {
1042 .class_name = "scale(2ref)",
1043 .item_name = av_default_item_name,
1044 .option = scale_options,
1045 .version = LIBAVUTIL_VERSION_INT,
1046 .category = AV_CLASS_CATEGORY_FILTER,
1047 .child_class_iterate = child_class_iterate,
1048 .child_next = child_next,
1049 };
1050
1051 static const AVFilterPad avfilter_vf_scale_inputs[] = {
1052 {
1053 .name = "default",
1054 .type = AVMEDIA_TYPE_VIDEO,
1055 .filter_frame = filter_frame,
1056 },
1057 };
1058
1059 static const AVFilterPad avfilter_vf_scale_outputs[] = {
1060 {
1061 .name = "default",
1062 .type = AVMEDIA_TYPE_VIDEO,
1063 .config_props = config_props,
1064 },
1065 };
1066
1067 const AVFilter ff_vf_scale = {
1068 .name = "scale",
1069 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),
1070 .preinit = preinit,
1071 .init = init,
1072 .uninit = uninit,
1073 .priv_size = sizeof(ScaleContext),
1074 .priv_class = &scale_class,
1075 FILTER_INPUTS(avfilter_vf_scale_inputs),
1076 FILTER_OUTPUTS(avfilter_vf_scale_outputs),
1077 FILTER_QUERY_FUNC(query_formats),
1078 .process_command = process_command,
1079 };
1080
1081 static const AVFilterPad avfilter_vf_scale2ref_inputs[] = {
1082 {
1083 .name = "default",
1084 .type = AVMEDIA_TYPE_VIDEO,
1085 .filter_frame = filter_frame,
1086 },
1087 {
1088 .name = "ref",
1089 .type = AVMEDIA_TYPE_VIDEO,
1090 .filter_frame = filter_frame_ref,
1091 },
1092 };
1093
1094 static const AVFilterPad avfilter_vf_scale2ref_outputs[] = {
1095 {
1096 .name = "default",
1097 .type = AVMEDIA_TYPE_VIDEO,
1098 .config_props = config_props,
1099 .request_frame= request_frame,
1100 },
1101 {
1102 .name = "ref",
1103 .type = AVMEDIA_TYPE_VIDEO,
1104 .config_props = config_props_ref,
1105 .request_frame= request_frame_ref,
1106 },
1107 };
1108
1109 const AVFilter ff_vf_scale2ref = {
1110 .name = "scale2ref",
1111 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."),
1112 .preinit = preinit,
1113 .init = init,
1114 .uninit = uninit,
1115 .priv_size = sizeof(ScaleContext),
1116 .priv_class = &scale_class,
1117 FILTER_INPUTS(avfilter_vf_scale2ref_inputs),
1118 FILTER_OUTPUTS(avfilter_vf_scale2ref_outputs),
1119 FILTER_QUERY_FUNC(query_formats),
1120 .process_command = process_command,
1121 };
1122