FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_scale.c
Date: 2026-10-29 23:19:09
Exec Total Coverage
Lines: 442 609 72.6%
Functions: 18 21 85.7%
Branches: 280 517 54.2%

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 "filters.h"
32 #include "formats.h"
33 #include "framesync.h"
34 #include "libavutil/pixfmt.h"
35 #include "scale_eval.h"
36 #include "video.h"
37 #include "libavutil/eval.h"
38 #include "libavutil/imgutils_internal.h"
39 #include "libavutil/internal.h"
40 #include "libavutil/mem.h"
41 #include "libavutil/opt.h"
42 #include "libavutil/parseutils.h"
43 #include "libavutil/pixdesc.h"
44 #include "libswscale/swscale.h"
45
46 static const char *const var_names[] = {
47 "in_w", "iw",
48 "in_h", "ih",
49 "out_w", "ow",
50 "out_h", "oh",
51 "a",
52 "sar",
53 "dar",
54 "hsub",
55 "vsub",
56 "ohsub",
57 "ovsub",
58 "n",
59 "t",
60 "ref_w", "rw",
61 "ref_h", "rh",
62 "ref_a",
63 "ref_sar",
64 "ref_dar", "rdar",
65 "ref_hsub",
66 "ref_vsub",
67 "ref_n",
68 "ref_t",
69 "ref_pos",
70 /* Legacy variables for scale2ref */
71 "main_w",
72 "main_h",
73 "main_a",
74 "main_sar",
75 "main_dar", "mdar",
76 "main_hsub",
77 "main_vsub",
78 "main_n",
79 "main_t",
80 "main_pos",
81 NULL
82 };
83
84 enum var_name {
85 VAR_IN_W, VAR_IW,
86 VAR_IN_H, VAR_IH,
87 VAR_OUT_W, VAR_OW,
88 VAR_OUT_H, VAR_OH,
89 VAR_A,
90 VAR_SAR,
91 VAR_DAR,
92 VAR_HSUB,
93 VAR_VSUB,
94 VAR_OHSUB,
95 VAR_OVSUB,
96 VAR_N,
97 VAR_T,
98 VAR_REF_W, VAR_RW,
99 VAR_REF_H, VAR_RH,
100 VAR_REF_A,
101 VAR_REF_SAR,
102 VAR_REF_DAR, VAR_RDAR,
103 VAR_REF_HSUB,
104 VAR_REF_VSUB,
105 VAR_REF_N,
106 VAR_REF_T,
107 VAR_REF_POS,
108 VAR_S2R_MAIN_W,
109 VAR_S2R_MAIN_H,
110 VAR_S2R_MAIN_A,
111 VAR_S2R_MAIN_SAR,
112 VAR_S2R_MAIN_DAR, VAR_S2R_MDAR,
113 VAR_S2R_MAIN_HSUB,
114 VAR_S2R_MAIN_VSUB,
115 VAR_S2R_MAIN_N,
116 VAR_S2R_MAIN_T,
117 VAR_S2R_MAIN_POS,
118 VARS_NB
119 };
120
121 enum EvalMode {
122 EVAL_MODE_INIT,
123 EVAL_MODE_FRAME,
124 EVAL_MODE_NB
125 };
126
127 typedef struct ScaleContext {
128 const AVClass *class;
129 SwsContext *sws;
130 FFFrameSync fs;
131
132 /**
133 * New dimensions. Special values are:
134 * 0 = original width/height
135 * -1 = keep original aspect
136 * -N = try to keep aspect but make sure it is divisible by N
137 */
138 int w, h;
139 char *size_str;
140 double param[2]; // sws params
141
142 int hsub, vsub; ///< chroma subsampling
143 int slice_y; ///< top of current output slice
144 int interlaced;
145 int uses_ref;
146
147 char *w_expr; ///< width expression string
148 char *h_expr; ///< height expression string
149 AVExpr *w_pexpr;
150 AVExpr *h_pexpr;
151 double var_values[VARS_NB];
152
153 char *flags_str;
154
155 int in_color_matrix;
156 int out_color_matrix;
157 int in_primaries;
158 int out_primaries;
159 int in_transfer;
160 int out_transfer;
161 int in_range;
162 int out_range;
163
164 int in_chroma_loc;
165 int out_chroma_loc;
166 int out_h_chr_pos;
167 int out_v_chr_pos;
168 int in_h_chr_pos;
169 int in_v_chr_pos;
170
171 int force_original_aspect_ratio;
172 int force_divisible_by;
173 int reset_sar;
174
175 int eval_mode; ///< expression evaluation mode
176
177 } ScaleContext;
178
179 const FFFilter ff_vf_scale2ref;
180 #define IS_SCALE2REF(ctx) ((ctx)->filter == &ff_vf_scale2ref.p)
181
182 static int config_props(AVFilterLink *outlink);
183
184 23048 static int check_exprs(AVFilterContext *ctx)
185 {
186 23048 ScaleContext *scale = ctx->priv;
187 23048 unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
188
189
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 23048 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
23048 if (!scale->w_pexpr && !scale->h_pexpr)
190 ✗ return AVERROR(EINVAL);
191
192
1/2
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
23048 if (scale->w_pexpr)
193 23048 av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
194
2/2
✓ Branch 0 taken 11543 times.
✓ Branch 1 taken 11505 times.
23048 if (scale->h_pexpr)
195 11543 av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
196
197
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23048 times.
23048 if (vars_w[VAR_OUT_W] || vars_w[VAR_OW]) {
198 ✗ av_log(ctx, AV_LOG_ERROR, "Width expression cannot be self-referencing: '%s'.\n", scale->w_expr);
199 ✗ return AVERROR(EINVAL);
200 }
201
202
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23048 times.
23048 if (vars_h[VAR_OUT_H] || vars_h[VAR_OH]) {
203 ✗ av_log(ctx, AV_LOG_ERROR, "Height expression cannot be self-referencing: '%s'.\n", scale->h_expr);
204 ✗ return AVERROR(EINVAL);
205 }
206
207
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23048 times.
23048 if ((vars_w[VAR_OUT_H] || vars_w[VAR_OH]) &&
208 ✗ (vars_h[VAR_OUT_W] || vars_h[VAR_OW])) {
209 ✗ av_log(ctx, AV_LOG_WARNING, "Circular references detected for width '%s' and height '%s' - possibly invalid.\n", scale->w_expr, scale->h_expr);
210 }
211
212
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23048 times.
✗ Branch 3 not taken.
23048 if (vars_w[VAR_REF_W] || vars_h[VAR_REF_W] ||
213
3/4
✓ Branch 0 taken 23040 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23048 vars_w[VAR_RW] || vars_h[VAR_RW] ||
214
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_H] || vars_h[VAR_REF_H] ||
215
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_RH] || vars_h[VAR_RH] ||
216
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_A] || vars_h[VAR_REF_A] ||
217
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_SAR] || vars_h[VAR_REF_SAR] ||
218
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_DAR] || vars_h[VAR_REF_DAR] ||
219
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_RDAR] || vars_h[VAR_RDAR] ||
220
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_HSUB] || vars_h[VAR_REF_HSUB] ||
221
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_VSUB] || vars_h[VAR_REF_VSUB] ||
222
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_N] || vars_h[VAR_REF_N] ||
223
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_REF_T] || vars_h[VAR_REF_T] ||
224
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23040 times.
23040 vars_w[VAR_REF_POS] || vars_h[VAR_REF_POS]) {
225 8 scale->uses_ref = 1;
226 }
227
228
2/2
✓ Branch 0 taken 23040 times.
✓ Branch 1 taken 8 times.
23048 if (!IS_SCALE2REF(ctx) &&
229
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
230
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
231
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
232
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
233
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
234
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
235
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] ||
236
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] ||
237
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
238
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23040 times.
✗ Branch 3 not taken.
23040 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
239
2/4
✓ Branch 0 taken 23040 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23040 times.
23040 vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
240 ✗ av_log(ctx, AV_LOG_ERROR, "Expressions with scale2ref variables are not valid in scale filter.\n");
241 ✗ return AVERROR(EINVAL);
242 }
243
244
1/2
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
23048 if (scale->eval_mode == EVAL_MODE_INIT &&
245
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23048 times.
✗ Branch 3 not taken.
23048 (vars_w[VAR_N] || vars_h[VAR_N] ||
246
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23048 times.
✗ Branch 3 not taken.
23048 vars_w[VAR_T] || vars_h[VAR_T] ||
247
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23048 times.
✗ Branch 3 not taken.
23048 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
248
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23048 times.
✗ Branch 3 not taken.
23048 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
249
2/4
✓ Branch 0 taken 23048 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23048 times.
23048 vars_w[VAR_S2R_MAIN_POS] || vars_h[VAR_S2R_MAIN_POS]) ) {
250 ✗ av_log(ctx, AV_LOG_ERROR, "Expressions with frame variables 'n', 't', 'pos' are not valid in init eval_mode.\n");
251 ✗ return AVERROR(EINVAL);
252 }
253
254 23048 return 0;
255 }
256
257 23048 static int scale_parse_expr(AVFilterContext *ctx, char *str_expr, AVExpr **pexpr_ptr, const char *var, const char *args)
258 {
259 23048 ScaleContext *scale = ctx->priv;
260 23048 int ret, is_inited = 0;
261 23048 char *old_str_expr = NULL;
262 23048 AVExpr *old_pexpr = NULL;
263
264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23048 times.
23048 if (str_expr) {
265 ✗ old_str_expr = av_strdup(str_expr);
266 ✗ if (!old_str_expr)
267 ✗ return AVERROR(ENOMEM);
268 ✗ av_opt_set(scale, var, args, 0);
269 }
270
271
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 23010 times.
23048 if (*pexpr_ptr) {
272 38 old_pexpr = *pexpr_ptr;
273 38 *pexpr_ptr = NULL;
274 38 is_inited = 1;
275 }
276
277 23048 ret = av_expr_parse(pexpr_ptr, args, var_names,
278 NULL, NULL, NULL, NULL, 0, ctx);
279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23048 times.
23048 if (ret < 0) {
280 ✗ av_log(ctx, AV_LOG_ERROR, "Cannot parse expression for %s: '%s'\n", var, args);
281 ✗ goto revert;
282 }
283
284 23048 ret = check_exprs(ctx);
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23048 times.
23048 if (ret < 0)
286 ✗ goto revert;
287
288
3/4
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 23010 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 38 times.
23048 if (is_inited && (ret = config_props(ctx->outputs[0])) < 0)
289 ✗ goto revert;
290
291 23048 av_expr_free(old_pexpr);
292 23048 old_pexpr = NULL;
293 23048 av_freep(&old_str_expr);
294
295 23048 return 0;
296
297 ✗ revert:
298 ✗ av_expr_free(*pexpr_ptr);
299 ✗ *pexpr_ptr = NULL;
300 ✗ if (old_str_expr) {
301 ✗ av_opt_set(scale, var, old_str_expr, 0);
302 ✗ av_free(old_str_expr);
303 }
304 ✗ if (old_pexpr)
305 ✗ *pexpr_ptr = old_pexpr;
306
307 ✗ return ret;
308 }
309
310 11505 static av_cold int preinit(AVFilterContext *ctx)
311 {
312 11505 ScaleContext *scale = ctx->priv;
313
314 11505 scale->sws = sws_alloc_context();
315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
11505 if (!scale->sws)
316 ✗ return AVERROR(ENOMEM);
317
318 // set threads=0, so we can later check whether the user modified it
319 11505 scale->sws->threads = 0;
320
321 11505 ff_framesync_preinit(&scale->fs);
322
323 11505 return 0;
324 }
325
326 static int do_scale(FFFrameSync *fs);
327
328 11505 static av_cold int init(AVFilterContext *ctx)
329 {
330 11505 ScaleContext *scale = ctx->priv;
331 int ret;
332
333
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11501 times.
11505 if (IS_SCALE2REF(ctx))
334 4 av_log(ctx, AV_LOG_WARNING, "scale2ref is deprecated, use scale=rw:rh instead\n");
335
336
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
11505 if (scale->size_str && (scale->w_expr || scale->h_expr)) {
337 ✗ av_log(ctx, AV_LOG_ERROR,
338 "Size and width/height expressions cannot be set at the same time.\n");
339 ✗ return AVERROR(EINVAL);
340 }
341
342
3/4
✓ Branch 0 taken 1927 times.
✓ Branch 1 taken 9578 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1927 times.
11505 if (scale->w_expr && !scale->h_expr)
343 ✗ FFSWAP(char *, scale->w_expr, scale->size_str);
344
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
11505 if (scale->size_str) {
346 char buf[32];
347 ✗ if ((ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str)) < 0) {
348 ✗ av_log(ctx, AV_LOG_ERROR,
349 "Invalid size '%s'\n", scale->size_str);
350 ✗ return ret;
351 }
352 ✗ snprintf(buf, sizeof(buf)-1, "%d", scale->w);
353 ✗ av_opt_set(scale, "w", buf, 0);
354 ✗ snprintf(buf, sizeof(buf)-1, "%d", scale->h);
355 ✗ av_opt_set(scale, "h", buf, 0);
356 }
357
2/2
✓ Branch 0 taken 9578 times.
✓ Branch 1 taken 1927 times.
11505 if (!scale->w_expr)
358 9578 av_opt_set(scale, "w", "iw", 0);
359
2/2
✓ Branch 0 taken 9578 times.
✓ Branch 1 taken 1927 times.
11505 if (!scale->h_expr)
360 9578 av_opt_set(scale, "h", "ih", 0);
361
362 11505 ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
11505 if (ret < 0)
364 ✗ return ret;
365
366 11505 ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
11505 if (ret < 0)
368 ✗ return ret;
369
370
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
11505 if (scale->in_primaries != -1 && !sws_test_primaries(scale->in_primaries, 0)) {
371 ✗ av_log(ctx, AV_LOG_ERROR, "Unsupported input primaries '%s'\n",
372 ✗ av_color_primaries_name(scale->in_primaries));
373 ✗ return AVERROR(EINVAL);
374 }
375
376
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
11505 if (scale->out_primaries != -1 && !sws_test_primaries(scale->out_primaries, 1)) {
377 ✗ av_log(ctx, AV_LOG_ERROR, "Unsupported output primaries '%s'\n",
378 ✗ av_color_primaries_name(scale->out_primaries));
379 ✗ return AVERROR(EINVAL);
380 }
381
382
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
11505 if (scale->in_transfer != -1 && !sws_test_transfer(scale->in_transfer, 0)) {
383 ✗ av_log(ctx, AV_LOG_ERROR, "Unsupported input transfer '%s'\n",
384 ✗ av_color_transfer_name(scale->in_transfer));
385 ✗ return AVERROR(EINVAL);
386 }
387
388
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11505 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
11505 if (scale->out_transfer != -1 && !sws_test_transfer(scale->out_transfer, 1)) {
389 ✗ av_log(ctx, AV_LOG_ERROR, "Unsupported output transfer '%s'\n",
390 ✗ av_color_transfer_name(scale->out_transfer));
391 ✗ return AVERROR(EINVAL);
392 }
393
394
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 11499 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
11505 if (scale->in_color_matrix != -1 && !sws_test_colorspace(scale->in_color_matrix, 0)) {
395 ✗ av_log(ctx, AV_LOG_ERROR, "Unsupported input color matrix '%s'\n",
396 ✗ av_color_space_name(scale->in_color_matrix));
397 ✗ return AVERROR(EINVAL);
398 }
399
400
2/4
✓ Branch 0 taken 11505 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11505 times.
11505 if (scale->out_color_matrix != -1 && !sws_test_colorspace(scale->out_color_matrix, 1)) {
401 ✗ av_log(ctx, AV_LOG_ERROR, "Unsupported output color matrix '%s'\n",
402 ✗ av_color_space_name(scale->out_color_matrix));
403 ✗ return AVERROR(EINVAL);
404 }
405
406 11505 av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
407 11505 scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
408
409
3/4
✓ Branch 0 taken 11505 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2324 times.
✓ Branch 3 taken 9181 times.
11505 if (scale->flags_str && *scale->flags_str) {
410 2324 ret = av_opt_set(scale->sws, "sws_flags", scale->flags_str, 0);
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2324 times.
2324 if (ret < 0)
412 ✗ return ret;
413 }
414
415
2/2
✓ Branch 0 taken 23010 times.
✓ Branch 1 taken 11505 times.
34515 for (int i = 0; i < FF_ARRAY_ELEMS(scale->param); i++)
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23010 times.
23010 if (scale->param[i] != DBL_MAX)
417 ✗ scale->sws->scaler_params[i] = scale->param[i];
418
419 11505 scale->sws->src_h_chr_pos = scale->in_h_chr_pos;
420 11505 scale->sws->src_v_chr_pos = scale->in_v_chr_pos;
421 11505 scale->sws->dst_h_chr_pos = scale->out_h_chr_pos;
422 11505 scale->sws->dst_v_chr_pos = scale->out_v_chr_pos;
423
424 // use generic thread-count if the user did not set it explicitly
425
1/2
✓ Branch 0 taken 11505 times.
✗ Branch 1 not taken.
11505 if (!scale->sws->threads)
426 11505 scale->sws->threads = ff_filter_get_nb_threads(ctx);
427
428
4/4
✓ Branch 0 taken 11501 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 11497 times.
11505 if (!IS_SCALE2REF(ctx) && scale->uses_ref) {
429 4 AVFilterPad pad = {
430 .name = "ref",
431 .type = AVMEDIA_TYPE_VIDEO,
432 };
433 4 ret = ff_append_inpad(ctx, &pad);
434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
435 ✗ return ret;
436 }
437
438 11505 return 0;
439 }
440
441 11505 static av_cold void uninit(AVFilterContext *ctx)
442 {
443 11505 ScaleContext *scale = ctx->priv;
444 11505 av_expr_free(scale->w_pexpr);
445 11505 av_expr_free(scale->h_pexpr);
446 11505 scale->w_pexpr = scale->h_pexpr = NULL;
447 11505 ff_framesync_uninit(&scale->fs);
448 11505 sws_free_context(&scale->sws);
449 11505 }
450
451 6874 static int query_formats(const AVFilterContext *ctx,
452 AVFilterFormatsConfig **cfg_in,
453 AVFilterFormatsConfig **cfg_out)
454 {
455 6874 const ScaleContext *scale = ctx->priv;
456 AVFilterFormats *formats;
457 const AVPixFmtDescriptor *desc;
458 enum AVPixelFormat pix_fmt;
459 int ret;
460
461 6874 desc = NULL;
462 6874 formats = NULL;
463
2/2
✓ Branch 1 taken 1855980 times.
✓ Branch 2 taken 6874 times.
1862854 while ((desc = av_pix_fmt_desc_next(desc))) {
464 1855980 pix_fmt = av_pix_fmt_desc_get_id(desc);
465
2/2
✓ Branch 1 taken 1594768 times.
✓ Branch 2 taken 261212 times.
1855980 if (sws_test_format(pix_fmt, 0)) {
466
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1594768 times.
1594768 if ((ret = ff_add_format(&formats, pix_fmt)) < 0)
467 ✗ return ret;
468 }
469 }
470
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0)
471 ✗ return ret;
472
473 6874 desc = NULL;
474 6874 formats = NULL;
475
2/2
✓ Branch 1 taken 1855980 times.
✓ Branch 2 taken 6874 times.
1862854 while ((desc = av_pix_fmt_desc_next(desc))) {
476 1855980 pix_fmt = av_pix_fmt_desc_get_id(desc);
477
4/4
✓ Branch 1 taken 453684 times.
✓ Branch 2 taken 1402296 times.
✓ Branch 3 taken 6874 times.
✓ Branch 4 taken 446810 times.
1855980 if (sws_test_format(pix_fmt, 1) || pix_fmt == AV_PIX_FMT_PAL8) {
478
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1409170 times.
1409170 if ((ret = ff_add_format(&formats, pix_fmt)) < 0)
479 ✗ return ret;
480 }
481 }
482
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(formats, &cfg_out[0]->formats)) < 0)
483 ✗ return ret;
484
485 /* accept all supported inputs, even if user overrides their properties */
486 6874 formats = ff_all_color_spaces();
487
2/2
✓ Branch 0 taken 116858 times.
✓ Branch 1 taken 6874 times.
123732 for (int i = 0; i < formats->nb_formats; i++) {
488
2/2
✓ Branch 1 taken 61866 times.
✓ Branch 2 taken 54992 times.
116858 if (!sws_test_colorspace(formats->formats[i], 0)) {
489
2/2
✓ Branch 0 taken 254338 times.
✓ Branch 1 taken 61866 times.
316204 for (int j = i--; j + 1 < formats->nb_formats; j++)
490 254338 formats->formats[j] = formats->formats[j + 1];
491 61866 formats->nb_formats--;
492 }
493 }
494
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(formats, &cfg_in[0]->color_spaces)) < 0)
495 ✗ return ret;
496
497
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(ff_all_color_ranges(),
498 6874 &cfg_in[0]->color_ranges)) < 0)
499 ✗ return ret;
500
501 /* propagate output properties if overridden */
502
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6871 times.
6874 if (scale->out_color_matrix != AVCOL_SPC_UNSPECIFIED) {
503 3 formats = ff_make_formats_list_singleton(scale->out_color_matrix);
504 } else {
505 6871 formats = ff_all_color_spaces();
506
2/2
✓ Branch 0 taken 116807 times.
✓ Branch 1 taken 6871 times.
123678 for (int i = 0; i < formats->nb_formats; i++) {
507
2/2
✓ Branch 1 taken 61839 times.
✓ Branch 2 taken 54968 times.
116807 if (!sws_test_colorspace(formats->formats[i], 1)) {
508
2/2
✓ Branch 0 taken 254227 times.
✓ Branch 1 taken 61839 times.
316066 for (int j = i--; j + 1 < formats->nb_formats; j++)
509 254227 formats->formats[j] = formats->formats[j + 1];
510 61839 formats->nb_formats--;
511 }
512 }
513 }
514
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(formats, &cfg_out[0]->color_spaces)) < 0)
515 ✗ return ret;
516
517 13748 formats = scale->out_range != AVCOL_RANGE_UNSPECIFIED
518 3 ? ff_make_formats_list_singleton(scale->out_range)
519
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6871 times.
6874 : ff_all_color_ranges();
520
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(formats, &cfg_out[0]->color_ranges)) < 0)
521 ✗ return ret;
522
523
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(ff_all_chroma_locations(),
524 6874 &cfg_in[0]->chroma_locations)) < 0)
525 ✗ return ret;
526
527 13748 formats = scale->out_chroma_loc != AVCHROMA_LOC_UNSPECIFIED
528 11 ? ff_make_formats_list_singleton(scale->out_chroma_loc)
529
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6863 times.
6874 : ff_all_chroma_locations();
530
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6874 times.
6874 if ((ret = ff_formats_ref(formats, &cfg_out[0]->chroma_locations)) < 0)
531 ✗ return ret;
532
533
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6872 times.
6874 if (scale->sws->alpha_blend) {
534
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_formats_ref(ff_make_formats_list_singleton(AVALPHA_MODE_STRAIGHT),
535 2 &cfg_in[0]->alpha_modes)) < 0)
536 ✗ return ret;
537 }
538
539 6874 return 0;
540 }
541
542 6885 static int scale_eval_dimensions(AVFilterContext *ctx)
543 {
544 6885 ScaleContext *scale = ctx->priv;
545 6885 const char scale2ref = IS_SCALE2REF(ctx);
546
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6883 times.
6885 const AVFilterLink *inlink = scale2ref ? ctx->inputs[1] : ctx->inputs[0];
547 6885 const AVFilterLink *outlink = ctx->outputs[0];
548 6885 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
549 6885 const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
550 char *expr;
551 int eval_w, eval_h;
552 int ret;
553 double res;
554 const AVPixFmtDescriptor *main_desc;
555 const AVFilterLink *main_link;
556
557
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6883 times.
6885 if (scale2ref) {
558 2 main_link = ctx->inputs[0];
559 2 main_desc = av_pix_fmt_desc_get(main_link->format);
560 }
561
562 6885 scale->var_values[VAR_IN_W] = scale->var_values[VAR_IW] = inlink->w;
563 6885 scale->var_values[VAR_IN_H] = scale->var_values[VAR_IH] = inlink->h;
564 6885 scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = NAN;
565 6885 scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = NAN;
566 6885 scale->var_values[VAR_A] = (double) inlink->w / inlink->h;
567 13770 scale->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
568
2/2
✓ Branch 0 taken 2664 times.
✓ Branch 1 taken 4221 times.
6885 (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
569 6885 scale->var_values[VAR_DAR] = scale->var_values[VAR_A] * scale->var_values[VAR_SAR];
570 6885 scale->var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
571 6885 scale->var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
572 6885 scale->var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w;
573 6885 scale->var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h;
574
575
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6883 times.
6885 if (scale2ref) {
576 2 scale->var_values[VAR_S2R_MAIN_W] = main_link->w;
577 2 scale->var_values[VAR_S2R_MAIN_H] = main_link->h;
578 2 scale->var_values[VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h;
579 4 scale->var_values[VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ?
580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 (double) main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1;
581 2 scale->var_values[VAR_S2R_MAIN_DAR] = scale->var_values[VAR_S2R_MDAR] =
582 2 scale->var_values[VAR_S2R_MAIN_A] * scale->var_values[VAR_S2R_MAIN_SAR];
583 2 scale->var_values[VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w;
584 2 scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h;
585 }
586
587
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6883 times.
6885 if (scale->uses_ref) {
588 2 const AVFilterLink *reflink = ctx->inputs[1];
589 2 const AVPixFmtDescriptor *ref_desc = av_pix_fmt_desc_get(reflink->format);
590 2 scale->var_values[VAR_REF_W] = scale->var_values[VAR_RW] = reflink->w;
591 2 scale->var_values[VAR_REF_H] = scale->var_values[VAR_RH] = reflink->h;
592 2 scale->var_values[VAR_REF_A] = (double) reflink->w / reflink->h;
593 4 scale->var_values[VAR_REF_SAR] = reflink->sample_aspect_ratio.num ?
594
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (double) reflink->sample_aspect_ratio.num / reflink->sample_aspect_ratio.den : 1;
595 2 scale->var_values[VAR_REF_DAR] = scale->var_values[VAR_RDAR] =
596 2 scale->var_values[VAR_REF_A] * scale->var_values[VAR_REF_SAR];
597 2 scale->var_values[VAR_REF_HSUB] = 1 << ref_desc->log2_chroma_w;
598 2 scale->var_values[VAR_REF_VSUB] = 1 << ref_desc->log2_chroma_h;
599 }
600
601 6885 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6885 times.
6885 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
603
604 6885 res = av_expr_eval(scale->h_pexpr, scale->var_values, NULL);
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6885 times.
6885 if (isnan(res)) {
606 ✗ expr = scale->h_expr;
607 ✗ ret = AVERROR(EINVAL);
608 ✗ goto fail;
609 }
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6885 times.
6885 eval_h = scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = (int) res == 0 ? inlink->h : (int) res;
611
612 6885 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6885 times.
6885 if (isnan(res)) {
614 ✗ expr = scale->w_expr;
615 ✗ ret = AVERROR(EINVAL);
616 ✗ goto fail;
617 }
618
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6885 times.
6885 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
619
620 6885 scale->w = eval_w;
621 6885 scale->h = eval_h;
622
623 6885 return 0;
624
625 ✗ fail:
626 ✗ av_log(ctx, AV_LOG_ERROR,
627 "Error when evaluating the expression '%s'.\n", expr);
628 ✗ return ret;
629 }
630
631 6885 static int config_props(AVFilterLink *outlink)
632 {
633 6885 AVFilterContext *ctx = outlink->src;
634 6885 AVFilterLink *inlink0 = outlink->src->inputs[0];
635 13770 AVFilterLink *inlink = IS_SCALE2REF(ctx) ?
636
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6883 times.
6885 outlink->src->inputs[1] :
637 6883 outlink->src->inputs[0];
638 6885 ScaleContext *scale = ctx->priv;
639 6885 uint8_t *flags_val = NULL;
640 6885 double w_adj = 1.0;
641 int ret;
642
643
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6885 times.
6885 if ((ret = scale_eval_dimensions(ctx)) < 0)
644 ✗ goto fail;
645
646 6885 outlink->w = scale->w;
647 6885 outlink->h = scale->h;
648
649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6885 times.
6885 if (scale->reset_sar)
650 ✗ w_adj = IS_SCALE2REF(ctx) ? scale->var_values[VAR_S2R_MAIN_SAR] :
651 scale->var_values[VAR_SAR];
652
653 6885 ret = ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
654 scale->force_original_aspect_ratio,
655 scale->force_divisible_by, w_adj);
656
657
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6884 times.
6885 if (ret < 0)
658 1 goto fail;
659
660 6884 if (outlink->w > INT_MAX ||
661 outlink->h > INT_MAX ||
662
1/2
✓ Branch 0 taken 6884 times.
✗ Branch 1 not taken.
6884 (outlink->h * (uint64_t)inlink->w) > INT_MAX ||
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6884 times.
6884 (outlink->w * (uint64_t)inlink->h) > INT_MAX)
664 ✗ av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
665
666 /* TODO: make algorithm configurable */
667
668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6884 times.
6884 if (scale->reset_sar)
669 ✗ outlink->sample_aspect_ratio = (AVRational){1, 1};
670
2/2
✓ Branch 0 taken 2663 times.
✓ Branch 1 taken 4221 times.
6884 else if (inlink0->sample_aspect_ratio.num){
671 2663 AVRational q = av_div_q((AVRational){inlink0->w, inlink0->h}, (AVRational){outlink->w, outlink->h});
672 2663 outlink->sample_aspect_ratio = av_mul_q(q, inlink0->sample_aspect_ratio);
673 } else
674 4221 outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
675
676 6884 av_opt_get(scale->sws, "sws_flags", 0, &flags_val);
677 20652 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",
678 6884 inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
679 av_color_space_name(inlink->colorspace), av_color_range_name(inlink->color_range),
680 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
681 6884 outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
682 av_color_space_name(outlink->colorspace), av_color_range_name(outlink->color_range),
683 outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
684 flags_val);
685 6884 av_freep(&flags_val);
686
687
4/4
✓ Branch 0 taken 6416 times.
✓ Branch 1 taken 468 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 6403 times.
6884 if (inlink->w != outlink->w || inlink->h != outlink->h) {
688 481 av_frame_side_data_remove_by_props(&outlink->side_data, &outlink->nb_side_data,
689 AV_SIDE_DATA_PROP_SIZE_DEPENDENT);
690 }
691
692
2/4
✓ Branch 0 taken 6884 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6884 times.
6884 if (scale->in_primaries != scale->out_primaries || scale->in_transfer != scale->out_transfer) {
693 ✗ av_frame_side_data_remove_by_props(&outlink->side_data, &outlink->nb_side_data,
694 AV_SIDE_DATA_PROP_COLOR_DEPENDENT);
695 }
696
697
2/2
✓ Branch 0 taken 6882 times.
✓ Branch 1 taken 2 times.
6884 if (!IS_SCALE2REF(ctx)) {
698 6882 ff_framesync_uninit(&scale->fs);
699 6882 ret = ff_framesync_init(&scale->fs, ctx, ctx->nb_inputs);
700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6882 times.
6882 if (ret < 0)
701 ✗ return ret;
702 6882 scale->fs.on_event = do_scale;
703 6882 scale->fs.in[0].time_base = ctx->inputs[0]->time_base;
704 6882 scale->fs.in[0].sync = 1;
705 6882 scale->fs.in[0].before = EXT_STOP;
706 6882 scale->fs.in[0].after = EXT_STOP;
707
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6880 times.
6882 if (scale->uses_ref) {
708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(ctx->nb_inputs == 2);
709 2 scale->fs.in[1].time_base = ctx->inputs[1]->time_base;
710 2 scale->fs.in[1].sync = 0;
711 2 scale->fs.in[1].before = EXT_NULL;
712 2 scale->fs.in[1].after = EXT_INFINITY;
713 }
714
715 6882 ret = ff_framesync_configure(&scale->fs);
716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6882 times.
6882 if (ret < 0)
717 ✗ return ret;
718 }
719
720 6884 return 0;
721
722 1 fail:
723 1 return ret;
724 }
725
726 2 static int config_props_ref(AVFilterLink *outlink)
727 {
728 2 AVFilterLink *inlink = outlink->src->inputs[1];
729 2 FilterLink *il = ff_filter_link(inlink);
730 2 FilterLink *ol = ff_filter_link(outlink);
731
732 2 outlink->w = inlink->w;
733 2 outlink->h = inlink->h;
734 2 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
735 2 outlink->time_base = inlink->time_base;
736 2 ol->frame_rate = il->frame_rate;
737 2 outlink->colorspace = inlink->colorspace;
738 2 outlink->color_range = inlink->color_range;
739
740 2 return 0;
741 }
742
743 210 static int request_frame(AVFilterLink *outlink)
744 {
745 210 return ff_request_frame(outlink->src->inputs[0]);
746 }
747
748 214 static int request_frame_ref(AVFilterLink *outlink)
749 {
750 214 return ff_request_frame(outlink->src->inputs[1]);
751 }
752
753 /* Takes over ownership of *frame_in, passes ownership of *frame_out to caller */
754 117764 static int scale_frame(AVFilterLink *link, AVFrame **frame_in,
755 AVFrame **frame_out)
756 {
757 117764 FilterLink *inl = ff_filter_link(link);
758 117764 AVFilterContext *ctx = link->dst;
759 117764 ScaleContext *scale = ctx->priv;
760 117764 AVFilterLink *outlink = ctx->outputs[0];
761 117764 AVFrame *out, *in = *frame_in;
762 117764 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
763 char buf[32];
764 int ret, flags_orig, frame_changed;
765
766 117764 *frame_in = NULL;
767
768 353291 frame_changed = in->width != link->w ||
769
1/2
✓ Branch 0 taken 117763 times.
✗ Branch 1 not taken.
117763 in->height != link->h ||
770
1/2
✓ Branch 0 taken 117763 times.
✗ Branch 1 not taken.
117763 in->format != link->format ||
771
1/2
✓ Branch 0 taken 117763 times.
✗ Branch 1 not taken.
117763 in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
772
1/2
✓ Branch 0 taken 117763 times.
✗ Branch 1 not taken.
117763 in->sample_aspect_ratio.num != link->sample_aspect_ratio.num ||
773
4/4
✓ Branch 0 taken 117763 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 117747 times.
✓ Branch 3 taken 16 times.
353274 in->colorspace != link->colorspace ||
774
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 117745 times.
117747 in->color_range != link->color_range;
775
776
3/4
✓ Branch 0 taken 117764 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 117745 times.
117764 if (scale->eval_mode == EVAL_MODE_FRAME || frame_changed) {
777 19 unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
778
779 19 av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
780 19 av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
781
782
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
19 if (scale->eval_mode == EVAL_MODE_FRAME &&
783 ✗ !frame_changed &&
784 ✗ !IS_SCALE2REF(ctx) &&
785 ✗ !(vars_w[VAR_N] || vars_w[VAR_T]) &&
786 ✗ !(vars_h[VAR_N] || vars_h[VAR_T]) &&
787 ✗ scale->w && scale->h)
788 ✗ goto scale;
789
790
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if (scale->eval_mode == EVAL_MODE_INIT) {
791 19 snprintf(buf, sizeof(buf) - 1, "%d", scale->w);
792 19 av_opt_set(scale, "w", buf, 0);
793 19 snprintf(buf, sizeof(buf) - 1, "%d", scale->h);
794 19 av_opt_set(scale, "h", buf, 0);
795
796 19 ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (ret < 0)
798 ✗ goto err;
799
800 19 ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (ret < 0)
802 ✗ goto err;
803 }
804
805
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
19 if (IS_SCALE2REF(ctx)) {
806 ✗ scale->var_values[VAR_S2R_MAIN_N] = inl->frame_count_out;
807 ✗ scale->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base);
808 } else {
809 19 scale->var_values[VAR_N] = inl->frame_count_out;
810
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
811 }
812
813 19 link->format = in->format;
814 19 link->w = in->width;
815 19 link->h = in->height;
816 19 link->colorspace = in->colorspace;
817 19 link->color_range = in->color_range;
818 19 link->sample_aspect_ratio = in->sample_aspect_ratio;
819
820
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
19 if ((ret = config_props(outlink)) < 0)
821 ✗ goto err;
822 }
823
824 117745 scale:
825 117764 scale->hsub = desc->log2_chroma_w;
826 117764 scale->vsub = desc->log2_chroma_h;
827
828 117764 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (!out) {
830 ✗ ret = AVERROR(ENOMEM);
831 ✗ goto err;
832 }
833
834
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 117759 times.
117764 if (scale->in_color_matrix != -1)
835 5 in->colorspace = scale->in_color_matrix;
836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (scale->in_primaries != -1)
837 ✗ in->color_primaries = scale->in_primaries;
838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (scale->in_transfer != -1)
839 ✗ in->color_trc = scale->in_transfer;
840
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 117759 times.
117764 if (scale->in_range != AVCOL_RANGE_UNSPECIFIED)
841 5 in->color_range = scale->in_range;
842
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 117757 times.
117764 if (scale->in_chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
843 7 in->chroma_location = scale->in_chroma_loc;
844
845 117764 flags_orig = in->flags;
846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (scale->interlaced > 0)
847 ✗ in->flags |= AV_FRAME_FLAG_INTERLACED;
848
1/2
✓ Branch 0 taken 117764 times.
✗ Branch 1 not taken.
117764 else if (!scale->interlaced)
849 117764 in->flags &= ~AV_FRAME_FLAG_INTERLACED;
850
851 117764 av_frame_copy_props(out, in);
852 117764 out->width = outlink->w;
853 117764 out->height = outlink->h;
854 117764 out->color_range = outlink->color_range;
855 117764 out->colorspace = outlink->colorspace;
856 117764 out->alpha_mode = outlink->alpha_mode;
857
2/2
✓ Branch 0 taken 28962 times.
✓ Branch 1 taken 88802 times.
117764 if (outlink->chroma_location != AVCHROMA_LOC_UNSPECIFIED)
858 28962 out->chroma_location = outlink->chroma_location;
859
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 117729 times.
117764 if (scale->out_chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
860 35 out->chroma_location = scale->out_chroma_loc;
861
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (scale->out_primaries != -1)
862 ✗ out->color_primaries = scale->out_primaries;
863
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (scale->out_transfer != -1)
864 ✗ out->color_trc = scale->out_transfer;
865
866
4/4
✓ Branch 0 taken 111565 times.
✓ Branch 1 taken 6199 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 111546 times.
117764 if (out->width != in->width || out->height != in->height) {
867 6218 av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data,
868 AV_SIDE_DATA_PROP_SIZE_DEPENDENT);
869 }
870
871
2/4
✓ Branch 0 taken 117764 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 117764 times.
117764 if (in->color_primaries != out->color_primaries || in->color_trc != out->color_trc) {
872 ✗ av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data,
873 AV_SIDE_DATA_PROP_COLOR_DEPENDENT);
874 }
875
876
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117764 times.
117764 if (scale->reset_sar) {
877 ✗ out->sample_aspect_ratio = outlink->sample_aspect_ratio;
878 } else {
879 117764 av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
880 117764 (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
881 117764 (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
882 INT_MAX);
883 }
884
885
2/2
✓ Branch 1 taken 5030 times.
✓ Branch 2 taken 112734 times.
117764 if (sws_is_noop(out, in)) {
886 5030 in->chroma_location = out->chroma_location;
887 5030 av_frame_free(&out);
888 5030 in->flags = flags_orig;
889 5030 *frame_out = in;
890 5030 return 0;
891 }
892
893
2/2
✓ Branch 0 taken 589 times.
✓ Branch 1 taken 112145 times.
112734 if (out->format == AV_PIX_FMT_PAL8) {
894 589 out->format = AV_PIX_FMT_BGR8;
895 589 avpriv_set_systematic_pal2((uint32_t*) out->data[1], out->format);
896 }
897
898 112734 ret = sws_scale_frame(scale->sws, out, in);
899 112734 av_frame_free(&in);
900 112734 out->flags = flags_orig;
901 112734 out->format = outlink->format; /* undo PAL8 handling */
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112734 times.
112734 if (ret < 0)
903 ✗ av_frame_free(&out);
904 112734 *frame_out = out;
905 112734 return ret;
906
907 ✗ err:
908 ✗ av_frame_free(&in);
909 ✗ return ret;
910 }
911
912 117679 static int do_scale(FFFrameSync *fs)
913 {
914 117679 AVFilterContext *ctx = fs->parent;
915 117679 ScaleContext *scale = ctx->priv;
916 117679 AVFilterLink *outlink = ctx->outputs[0];
917 117679 AVFrame *out, *in = NULL, *ref = NULL;
918 117679 int ret = 0, frame_changed;
919
920 117679 ret = ff_framesync_get_frame(fs, 0, &in, 1);
921
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117679 times.
117679 if (ret < 0)
922 ✗ goto err;
923
924
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 117672 times.
117679 if (scale->uses_ref) {
925 7 ret = ff_framesync_get_frame(fs, 1, &ref, 0);
926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
927 ✗ goto err;
928 }
929
930
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 117672 times.
117679 if (ref) {
931 7 AVFilterLink *reflink = ctx->inputs[1];
932 7 FilterLink *rl = ff_filter_link(reflink);
933
934 21 frame_changed = ref->width != reflink->w ||
935
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ref->height != reflink->h ||
936
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ref->format != reflink->format ||
937
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ref->sample_aspect_ratio.den != reflink->sample_aspect_ratio.den ||
938
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ref->sample_aspect_ratio.num != reflink->sample_aspect_ratio.num ||
939
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
21 ref->colorspace != reflink->colorspace ||
940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 ref->color_range != reflink->color_range;
941
942
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (frame_changed) {
943 ✗ reflink->format = ref->format;
944 ✗ reflink->w = ref->width;
945 ✗ reflink->h = ref->height;
946 ✗ reflink->sample_aspect_ratio.num = ref->sample_aspect_ratio.num;
947 ✗ reflink->sample_aspect_ratio.den = ref->sample_aspect_ratio.den;
948 ✗ reflink->colorspace = ref->colorspace;
949 ✗ reflink->color_range = ref->color_range;
950
951 ✗ ret = config_props(outlink);
952 ✗ if (ret < 0)
953 ✗ goto err;
954 }
955
956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (scale->eval_mode == EVAL_MODE_FRAME) {
957 ✗ scale->var_values[VAR_REF_N] = rl->frame_count_out;
958 ✗ scale->var_values[VAR_REF_T] = TS2T(ref->pts, reflink->time_base);
959 }
960 }
961
962 117679 ret = scale_frame(ctx->inputs[0], &in, &out);
963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117679 times.
117679 if (ret < 0)
964 ✗ goto err;
965
966
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117679 times.
117679 av_assert0(out);
967 117679 out->pts = av_rescale_q_rnd(fs->pts, fs->time_base, outlink->time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);
968 117679 return ff_filter_frame(outlink, out);
969
970 ✗ err:
971 ✗ av_frame_free(&in);
972 ✗ return ret;
973 }
974
975 85 static int filter_frame(AVFilterLink *link, AVFrame *in)
976 {
977 85 AVFilterContext *ctx = link->dst;
978 85 AVFilterLink *outlink = ctx->outputs[0];
979 AVFrame *out;
980 int ret;
981
982 85 ret = scale_frame(link, &in, &out);
983
1/2
✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
85 if (out)
984 85 return ff_filter_frame(outlink, out);
985
986 ✗ return ret;
987 }
988
989 84 static int filter_frame_ref(AVFilterLink *link, AVFrame *in)
990 {
991 84 FilterLink *l = ff_filter_link(link);
992 84 ScaleContext *scale = link->dst->priv;
993 84 AVFilterLink *outlink = link->dst->outputs[1];
994 int frame_changed;
995
996 252 frame_changed = in->width != link->w ||
997
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 in->height != link->h ||
998
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 in->format != link->format ||
999
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
1000
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 in->sample_aspect_ratio.num != link->sample_aspect_ratio.num ||
1001
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
252 in->colorspace != link->colorspace ||
1002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 in->color_range != link->color_range;
1003
1004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (frame_changed) {
1005 ✗ link->format = in->format;
1006 ✗ link->w = in->width;
1007 ✗ link->h = in->height;
1008 ✗ link->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
1009 ✗ link->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
1010 ✗ link->colorspace = in->colorspace;
1011 ✗ link->color_range = in->color_range;
1012
1013 ✗ config_props_ref(outlink);
1014 }
1015
1016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
84 if (scale->eval_mode == EVAL_MODE_FRAME) {
1017 ✗ scale->var_values[VAR_N] = l->frame_count_out;
1018 ✗ scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
1019 }
1020
1021 84 return ff_filter_frame(outlink, in);
1022 }
1023
1024 ✗ static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1025 char *res, int res_len, int flags)
1026 {
1027 ✗ ScaleContext *scale = ctx->priv;
1028 char *str_expr;
1029 AVExpr **pexpr_ptr;
1030 int ret, w, h;
1031
1032 ✗ w = !strcmp(cmd, "width") || !strcmp(cmd, "w");
1033 ✗ h = !strcmp(cmd, "height") || !strcmp(cmd, "h");
1034
1035 ✗ if (w || h) {
1036 ✗ str_expr = w ? scale->w_expr : scale->h_expr;
1037 ✗ pexpr_ptr = w ? &scale->w_pexpr : &scale->h_pexpr;
1038
1039 ✗ ret = scale_parse_expr(ctx, str_expr, pexpr_ptr, cmd, args);
1040 } else
1041 ✗ ret = AVERROR(ENOSYS);
1042
1043 ✗ if (ret < 0)
1044 ✗ av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
1045
1046 ✗ return ret;
1047 }
1048
1049 235397 static int activate(AVFilterContext *ctx)
1050 {
1051 235397 ScaleContext *scale = ctx->priv;
1052 235397 return ff_framesync_activate(&scale->fs);
1053 }
1054
1055 ✗ static const AVClass *child_class_iterate(void **iter)
1056 {
1057 ✗ switch ((uintptr_t) *iter) {
1058 ✗ case 0:
1059 ✗ *iter = (void*)(uintptr_t) 1;
1060 ✗ return sws_get_class();
1061 ✗ case 1:
1062 ✗ *iter = (void*)(uintptr_t) 2;
1063 ✗ return &ff_framesync_class;
1064 }
1065
1066 ✗ return NULL;
1067 }
1068
1069 26110 static void *child_next(void *obj, void *prev)
1070 {
1071 26110 ScaleContext *s = obj;
1072
2/2
✓ Branch 0 taken 13650 times.
✓ Branch 1 taken 12460 times.
26110 if (!prev)
1073 13650 return s->sws;
1074
2/2
✓ Branch 0 taken 6230 times.
✓ Branch 1 taken 6230 times.
12460 if (prev == s->sws)
1075 6230 return &s->fs;
1076 6230 return NULL;
1077 }
1078
1079 #define OFFSET(x) offsetof(ScaleContext, x)
1080 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
1081 #define TFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
1082
1083 static const AVOption scale_options[] = {
1084 { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1085 { "width", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1086 { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1087 { "height","Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1088 { "flags", "Flags to pass to libswscale", OFFSET(flags_str), AV_OPT_TYPE_STRING, { .str = "" }, .flags = FLAGS },
1089 { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_BOOL, {.i64 = 0 }, -1, 1, FLAGS },
1090 { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, .flags = FLAGS },
1091 { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, .flags = FLAGS },
1092 { "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" },
1093 { "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"},
1094 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "color" },
1095 { "bt601", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, 0, 0, FLAGS, .unit = "color" },
1096 { "bt470", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, 0, 0, FLAGS, .unit = "color" },
1097 { "smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, 0, 0, FLAGS, .unit = "color" },
1098 { "bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, 0, 0, FLAGS, .unit = "color" },
1099 { "bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709}, 0, 0, FLAGS, .unit = "color" },
1100 { "fcc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_FCC}, 0, 0, FLAGS, .unit = "color" },
1101 { "smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M}, 0, 0, FLAGS, .unit = "color" },
1102 { "bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, 0, 0, FLAGS, .unit = "color" },
1103 { "bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, 0, 0, FLAGS, .unit = "color" },
1104 { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, .unit = "range" },
1105 { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, .unit = "range" },
1106 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, .unit = "range" },
1107 { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, .unit = "range" },
1108 { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1109 { "limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1110 { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1111 { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1112 { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1113 { "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1114 { "in_chroma_loc", "set input chroma sample location", OFFSET(in_chroma_loc), AV_OPT_TYPE_INT, { .i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, .flags = FLAGS, .unit = "chroma_loc" },
1115 { "out_chroma_loc", "set output chroma sample location", OFFSET(out_chroma_loc), AV_OPT_TYPE_INT, { .i64 = AVCHROMA_LOC_UNSPECIFIED }, 0, AVCHROMA_LOC_NB-1, .flags = FLAGS, .unit = "chroma_loc" },
1116 {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"},
1117 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"},
1118 {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
1119 {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, FLAGS, .unit = "chroma_loc"},
1120 {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
1121 {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, FLAGS, .unit = "chroma_loc"},
1122 {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
1123 {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, FLAGS, .unit = "chroma_loc"},
1124 { "in_primaries", "set input primaries", OFFSET(in_primaries), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AVCOL_PRI_NB-1, .flags = FLAGS, .unit = "primaries" },
1125 { "out_primaries", "set output primaries", OFFSET(out_primaries), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AVCOL_PRI_NB-1, .flags = FLAGS, .unit = "primaries"},
1126 {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "primaries"},
1127 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, 0, 0, FLAGS, .unit = "primaries"},
1128 {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, 0, 0, FLAGS, .unit = "primaries"},
1129 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, 0, 0, FLAGS, .unit = "primaries"},
1130 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, 0, 0, FLAGS, .unit = "primaries"},
1131 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, 0, 0, FLAGS, .unit = "primaries"},
1132 {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, 0, 0, FLAGS, .unit = "primaries"},
1133 {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, 0, 0, FLAGS, .unit = "primaries"},
1134 {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, 0, 0, FLAGS, .unit = "primaries"},
1135 {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, 0, 0, FLAGS, .unit = "primaries"},
1136 {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, 0, 0, FLAGS, .unit = "primaries"},
1137 {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, 0, 0, FLAGS, .unit = "primaries"},
1138 {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, 0, 0, FLAGS, .unit = "primaries"},
1139 { "in_transfer", "set output color transfer", OFFSET(in_transfer), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AVCOL_TRC_NB-1, .flags = FLAGS, .unit = "transfer"},
1140 {"out_transfer", "set output color transfer", OFFSET(out_transfer), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AVCOL_TRC_NB-1, .flags = FLAGS, .unit = "transfer"},
1141 {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, .unit = "transfer"},
1142 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, 0, 0, FLAGS, .unit = "transfer"},
1143 {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, 0, 0, FLAGS, .unit = "transfer"},
1144 {"gamma22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, 0, 0, FLAGS, .unit = "transfer"},
1145 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, 0, 0, FLAGS, .unit = "transfer"},
1146 {"gamma28", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, 0, 0, FLAGS, .unit = "transfer"},
1147 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, 0, 0, FLAGS, .unit = "transfer"},
1148 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, 0, 0, FLAGS, .unit = "transfer"},
1149 {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, 0, 0, FLAGS, .unit = "transfer"},
1150 {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, 0, 0, FLAGS, .unit = "transfer"},
1151 {"srgb", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, 0, 0, FLAGS, .unit = "transfer"},
1152 {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, 0, 0, FLAGS, .unit = "transfer"},
1153 {"xvycc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, 0, 0, FLAGS, .unit = "transfer"},
1154 {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, 0, 0, FLAGS, .unit = "transfer"},
1155 {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, 0, 0, FLAGS, .unit = "transfer"},
1156 {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, 0, 0, FLAGS, .unit = "transfer"},
1157 {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, 0, 0, FLAGS, .unit = "transfer"},
1158 {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE428}, 0, 0, FLAGS, .unit = "transfer"},
1159 {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, 0, 0, FLAGS, .unit = "transfer"},
1160 { "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 },
1161 { "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 },
1162 { "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 },
1163 { "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 },
1164 { "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, SCALE_FORCE_OAR_NB-1, FLAGS, .unit = "force_oar" },
1165 { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, FLAGS, .unit = "force_oar" },
1166 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, FLAGS, .unit = "force_oar" },
1167 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, FLAGS, .unit = "force_oar" },
1168 { "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 },
1169 { "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS },
1170 { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
1171 { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
1172 { "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" },
1173 { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
1174 { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
1175 { NULL }
1176 };
1177
1178 static const AVClass scale_class = {
1179 .class_name = "scale",
1180 .item_name = av_default_item_name,
1181 .option = scale_options,
1182 .version = LIBAVUTIL_VERSION_INT,
1183 .category = AV_CLASS_CATEGORY_FILTER,
1184 .child_class_iterate = child_class_iterate,
1185 .child_next = child_next,
1186 };
1187
1188 static const AVFilterPad avfilter_vf_scale_inputs[] = {
1189 {
1190 .name = "default",
1191 .type = AVMEDIA_TYPE_VIDEO,
1192 },
1193 };
1194
1195 static const AVFilterPad avfilter_vf_scale_outputs[] = {
1196 {
1197 .name = "default",
1198 .type = AVMEDIA_TYPE_VIDEO,
1199 .config_props = config_props,
1200 },
1201 };
1202
1203 const FFFilter ff_vf_scale = {
1204 .p.name = "scale",
1205 .p.description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),
1206 .p.priv_class = &scale_class,
1207 .p.flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
1208 .preinit = preinit,
1209 .init = init,
1210 .uninit = uninit,
1211 .priv_size = sizeof(ScaleContext),
1212 FILTER_INPUTS(avfilter_vf_scale_inputs),
1213 FILTER_OUTPUTS(avfilter_vf_scale_outputs),
1214 FILTER_QUERY_FUNC2(query_formats),
1215 .activate = activate,
1216 .process_command = process_command,
1217 .flags_internal = FF_FILTER_FLAG_DYNAMIC_FRAME_PARAMS,
1218 };
1219
1220 ✗ static const AVClass *scale2ref_child_class_iterate(void **iter)
1221 {
1222 ✗ const AVClass *c = *iter ? NULL : sws_get_class();
1223 ✗ *iter = (void*)(uintptr_t)c;
1224 ✗ return c;
1225 }
1226
1227 16 static void *scale2ref_child_next(void *obj, void *prev)
1228 {
1229 16 ScaleContext *s = obj;
1230
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (!prev)
1231 8 return s->sws;
1232 8 return NULL;
1233 }
1234
1235 static const AVClass scale2ref_class = {
1236 .class_name = "scale(2ref)",
1237 .item_name = av_default_item_name,
1238 .option = scale_options,
1239 .version = LIBAVUTIL_VERSION_INT,
1240 .category = AV_CLASS_CATEGORY_FILTER,
1241 .child_class_iterate = scale2ref_child_class_iterate,
1242 .child_next = scale2ref_child_next,
1243 };
1244
1245 static const AVFilterPad avfilter_vf_scale2ref_inputs[] = {
1246 {
1247 .name = "default",
1248 .type = AVMEDIA_TYPE_VIDEO,
1249 .filter_frame = filter_frame,
1250 },
1251 {
1252 .name = "ref",
1253 .type = AVMEDIA_TYPE_VIDEO,
1254 .filter_frame = filter_frame_ref,
1255 },
1256 };
1257
1258 static const AVFilterPad avfilter_vf_scale2ref_outputs[] = {
1259 {
1260 .name = "default",
1261 .type = AVMEDIA_TYPE_VIDEO,
1262 .config_props = config_props,
1263 .request_frame= request_frame,
1264 },
1265 {
1266 .name = "ref",
1267 .type = AVMEDIA_TYPE_VIDEO,
1268 .config_props = config_props_ref,
1269 .request_frame= request_frame_ref,
1270 },
1271 };
1272
1273 const FFFilter ff_vf_scale2ref = {
1274 .p.name = "scale2ref",
1275 .p.description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."),
1276 .p.priv_class = &scale2ref_class,
1277 .preinit = preinit,
1278 .init = init,
1279 .uninit = uninit,
1280 .priv_size = sizeof(ScaleContext),
1281 FILTER_INPUTS(avfilter_vf_scale2ref_inputs),
1282 FILTER_OUTPUTS(avfilter_vf_scale2ref_outputs),
1283 FILTER_QUERY_FUNC2(query_formats),
1284 .process_command = process_command,
1285 .flags_internal = FF_FILTER_FLAG_DYNAMIC_FRAME_PARAMS,
1286 };
1287