FFmpeg coverage


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