FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_scale.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 376 600 62.7%
Functions: 12 21 57.1%
Branches: 263 545 48.3%

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