FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_scale.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 424 676 62.7%
Functions: 13 24 54.2%
Branches: 285 597 47.7%

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 "scale_eval.h"
35 #include "video.h"
36 #include "libavutil/eval.h"
37 #include "libavutil/imgutils_internal.h"
38 #include "libavutil/internal.h"
39 #include "libavutil/mem.h"
40 #include "libavutil/opt.h"
41 #include "libavutil/parseutils.h"
42 #include "libavutil/pixdesc.h"
43 #include "libswscale/swscale.h"
44
45 static const char *const var_names[] = {
46 "in_w", "iw",
47 "in_h", "ih",
48 "out_w", "ow",
49 "out_h", "oh",
50 "a",
51 "sar",
52 "dar",
53 "hsub",
54 "vsub",
55 "ohsub",
56 "ovsub",
57 "n",
58 "t",
59 #if FF_API_FRAME_PKT
60 "pos",
61 #endif
62 "ref_w", "rw",
63 "ref_h", "rh",
64 "ref_a",
65 "ref_sar",
66 "ref_dar", "rdar",
67 "ref_hsub",
68 "ref_vsub",
69 "ref_n",
70 "ref_t",
71 "ref_pos",
72 /* Legacy variables for scale2ref */
73 "main_w",
74 "main_h",
75 "main_a",
76 "main_sar",
77 "main_dar", "mdar",
78 "main_hsub",
79 "main_vsub",
80 "main_n",
81 "main_t",
82 "main_pos",
83 NULL
84 };
85
86 enum var_name {
87 VAR_IN_W, VAR_IW,
88 VAR_IN_H, VAR_IH,
89 VAR_OUT_W, VAR_OW,
90 VAR_OUT_H, VAR_OH,
91 VAR_A,
92 VAR_SAR,
93 VAR_DAR,
94 VAR_HSUB,
95 VAR_VSUB,
96 VAR_OHSUB,
97 VAR_OVSUB,
98 VAR_N,
99 VAR_T,
100 #if FF_API_FRAME_PKT
101 VAR_POS,
102 #endif
103 VAR_REF_W, VAR_RW,
104 VAR_REF_H, VAR_RH,
105 VAR_REF_A,
106 VAR_REF_SAR,
107 VAR_REF_DAR, VAR_RDAR,
108 VAR_REF_HSUB,
109 VAR_REF_VSUB,
110 VAR_REF_N,
111 VAR_REF_T,
112 VAR_REF_POS,
113 VAR_S2R_MAIN_W,
114 VAR_S2R_MAIN_H,
115 VAR_S2R_MAIN_A,
116 VAR_S2R_MAIN_SAR,
117 VAR_S2R_MAIN_DAR, VAR_S2R_MDAR,
118 VAR_S2R_MAIN_HSUB,
119 VAR_S2R_MAIN_VSUB,
120 VAR_S2R_MAIN_N,
121 VAR_S2R_MAIN_T,
122 VAR_S2R_MAIN_POS,
123 VARS_NB
124 };
125
126 enum EvalMode {
127 EVAL_MODE_INIT,
128 EVAL_MODE_FRAME,
129 EVAL_MODE_NB
130 };
131
132 typedef struct ScaleContext {
133 const AVClass *class;
134 struct SwsContext *sws; ///< software scaler context
135 struct SwsContext *isws[2]; ///< software scaler context for interlaced material
136 // context used for forwarding options to sws
137 struct SwsContext *sws_opts;
138 FFFrameSync fs;
139
140 /**
141 * New dimensions. Special values are:
142 * 0 = original width/height
143 * -1 = keep original aspect
144 * -N = try to keep aspect but make sure it is divisible by N
145 */
146 int w, h;
147 char *size_str;
148 double param[2]; // sws params
149
150 int hsub, vsub; ///< chroma subsampling
151 int slice_y; ///< top of current output slice
152 int input_is_pal; ///< set to 1 if the input format is paletted
153 int output_is_pal; ///< set to 1 if the output format is paletted
154 int interlaced;
155 int uses_ref;
156
157 char *w_expr; ///< width expression string
158 char *h_expr; ///< height expression string
159 AVExpr *w_pexpr;
160 AVExpr *h_pexpr;
161 double var_values[VARS_NB];
162
163 char *flags_str;
164
165 int in_color_matrix;
166 int out_color_matrix;
167
168 int in_range;
169 int out_range;
170
171 int in_chroma_loc;
172 int out_chroma_loc;
173 int out_h_chr_pos;
174 int out_v_chr_pos;
175 int in_h_chr_pos;
176 int in_v_chr_pos;
177
178 int force_original_aspect_ratio;
179 int force_divisible_by;
180
181 int eval_mode; ///< expression evaluation mode
182
183 } ScaleContext;
184
185 const AVFilter ff_vf_scale2ref;
186
187 static int config_props(AVFilterLink *outlink);
188
189 19842 static int check_exprs(AVFilterContext *ctx)
190 {
191 19842 ScaleContext *scale = ctx->priv;
192 19842 unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
193
194
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19842 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
19842 if (!scale->w_pexpr && !scale->h_pexpr)
195 return AVERROR(EINVAL);
196
197
1/2
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
19842 if (scale->w_pexpr)
198 19842 av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
199
2/2
✓ Branch 0 taken 9938 times.
✓ Branch 1 taken 9904 times.
19842 if (scale->h_pexpr)
200 9938 av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
201
202
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19842 times.
19842 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 19842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19842 times.
19842 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 19842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19842 times.
19842 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 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 if (vars_w[VAR_REF_W] || vars_h[VAR_REF_W] ||
218
3/4
✓ Branch 0 taken 19838 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_RW] || vars_h[VAR_RW] ||
219
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_H] || vars_h[VAR_REF_H] ||
220
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_RH] || vars_h[VAR_RH] ||
221
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_A] || vars_h[VAR_REF_A] ||
222
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_SAR] || vars_h[VAR_REF_SAR] ||
223
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_DAR] || vars_h[VAR_REF_DAR] ||
224
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_RDAR] || vars_h[VAR_RDAR] ||
225
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_HSUB] || vars_h[VAR_REF_HSUB] ||
226
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_VSUB] || vars_h[VAR_REF_VSUB] ||
227
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_N] || vars_h[VAR_REF_N] ||
228
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19838 times.
✗ Branch 3 not taken.
19838 vars_w[VAR_REF_T] || vars_h[VAR_REF_T] ||
229
2/4
✓ Branch 0 taken 19838 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19838 times.
19838 vars_w[VAR_REF_POS] || vars_h[VAR_REF_POS]) {
230 4 scale->uses_ref = 1;
231 }
232
233
1/2
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
19842 if (ctx->filter != &ff_vf_scale2ref &&
234
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
235
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
236
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
237
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
238
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
239
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
240
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] ||
241
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] ||
242
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
243
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
244
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19842 times.
19842 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 19842 times.
✗ Branch 1 not taken.
19842 if (ctx->filter != &ff_vf_scale2ref &&
250
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 (vars_w[VAR_S2R_MAIN_W] || vars_h[VAR_S2R_MAIN_W] ||
251
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_H] || vars_h[VAR_S2R_MAIN_H] ||
252
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_A] || vars_h[VAR_S2R_MAIN_A] ||
253
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_SAR] || vars_h[VAR_S2R_MAIN_SAR] ||
254
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_DAR] || vars_h[VAR_S2R_MAIN_DAR] ||
255
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MDAR] || vars_h[VAR_S2R_MDAR] ||
256
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_HSUB] || vars_h[VAR_S2R_MAIN_HSUB] ||
257
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_VSUB] || vars_h[VAR_S2R_MAIN_VSUB] ||
258
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
259
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
260
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19842 times.
19842 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 19842 times.
✗ Branch 1 not taken.
19842 if (scale->eval_mode == EVAL_MODE_INIT &&
266
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 (vars_w[VAR_N] || vars_h[VAR_N] ||
267
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_T] || vars_h[VAR_T] ||
268 #if FF_API_FRAME_PKT
269
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_POS] || vars_h[VAR_POS] ||
270 #endif
271
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_N] || vars_h[VAR_S2R_MAIN_N] ||
272
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19842 times.
✗ Branch 3 not taken.
19842 vars_w[VAR_S2R_MAIN_T] || vars_h[VAR_S2R_MAIN_T] ||
273
2/4
✓ Branch 0 taken 19842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19842 times.
19842 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 19842 return 0;
279 }
280
281 19842 static int scale_parse_expr(AVFilterContext *ctx, char *str_expr, AVExpr **pexpr_ptr, const char *var, const char *args)
282 {
283 19842 ScaleContext *scale = ctx->priv;
284 19842 int ret, is_inited = 0;
285 19842 char *old_str_expr = NULL;
286 19842 AVExpr *old_pexpr = NULL;
287
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19842 times.
19842 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 19808 times.
19842 if (*pexpr_ptr) {
296 34 old_pexpr = *pexpr_ptr;
297 34 *pexpr_ptr = NULL;
298 34 is_inited = 1;
299 }
300
301 19842 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 19842 times.
19842 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 19842 ret = check_exprs(ctx);
309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19842 times.
19842 if (ret < 0)
310 goto revert;
311
312
3/4
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 19808 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
19842 if (is_inited && (ret = config_props(ctx->outputs[0])) < 0)
313 goto revert;
314
315 19842 av_expr_free(old_pexpr);
316 19842 old_pexpr = NULL;
317 19842 av_freep(&old_str_expr);
318
319 19842 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 9904 static av_cold int preinit(AVFilterContext *ctx)
335 {
336 9904 ScaleContext *scale = ctx->priv;
337 int ret;
338
339 9904 scale->sws_opts = sws_alloc_context();
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (!scale->sws_opts)
341 return AVERROR(ENOMEM);
342
343 // set threads=0, so we can later check whether the user modified it
344 9904 ret = av_opt_set_int(scale->sws_opts, "threads", 0, 0);
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (ret < 0)
346 return ret;
347
348 9904 ff_framesync_preinit(&scale->fs);
349
350 9904 return 0;
351 }
352
353 static const int sws_colorspaces[] = {
354 AVCOL_SPC_UNSPECIFIED,
355 AVCOL_SPC_RGB,
356 AVCOL_SPC_BT709,
357 AVCOL_SPC_BT470BG,
358 AVCOL_SPC_SMPTE170M,
359 AVCOL_SPC_FCC,
360 AVCOL_SPC_SMPTE240M,
361 AVCOL_SPC_BT2020_NCL,
362 -1
363 };
364
365 static int do_scale(FFFrameSync *fs);
366
367 9904 static av_cold int init(AVFilterContext *ctx)
368 {
369 9904 ScaleContext *scale = ctx->priv;
370 int64_t threads;
371 int ret;
372
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (ctx->filter == &ff_vf_scale2ref)
374 av_log(ctx, AV_LOG_WARNING, "scale2ref is deprecated, use scale=rw:rh instead\n");
375
376
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9904 if (scale->size_str && (scale->w_expr || scale->h_expr)) {
377 av_log(ctx, AV_LOG_ERROR,
378 "Size and width/height expressions cannot be set at the same time.\n");
379 return AVERROR(EINVAL);
380 }
381
382
3/4
✓ Branch 0 taken 1509 times.
✓ Branch 1 taken 8395 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1509 times.
9904 if (scale->w_expr && !scale->h_expr)
383 FFSWAP(char *, scale->w_expr, scale->size_str);
384
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (scale->size_str) {
386 char buf[32];
387 if ((ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str)) < 0) {
388 av_log(ctx, AV_LOG_ERROR,
389 "Invalid size '%s'\n", scale->size_str);
390 return ret;
391 }
392 snprintf(buf, sizeof(buf)-1, "%d", scale->w);
393 av_opt_set(scale, "w", buf, 0);
394 snprintf(buf, sizeof(buf)-1, "%d", scale->h);
395 av_opt_set(scale, "h", buf, 0);
396 }
397
2/2
✓ Branch 0 taken 8395 times.
✓ Branch 1 taken 1509 times.
9904 if (!scale->w_expr)
398 8395 av_opt_set(scale, "w", "iw", 0);
399
2/2
✓ Branch 0 taken 8395 times.
✓ Branch 1 taken 1509 times.
9904 if (!scale->h_expr)
400 8395 av_opt_set(scale, "h", "ih", 0);
401
402 9904 ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (ret < 0)
404 return ret;
405
406 9904 ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (ret < 0)
408 return ret;
409
410
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9900 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
9908 if (scale->in_color_matrix != -1 &&
411 4 !ff_fmt_is_in(scale->in_color_matrix, sws_colorspaces)) {
412 av_log(ctx, AV_LOG_ERROR, "Unsupported input color matrix '%s'\n",
413 av_color_space_name(scale->in_color_matrix));
414 return AVERROR(EINVAL);
415 }
416
417
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9904 times.
9904 if (!ff_fmt_is_in(scale->out_color_matrix, sws_colorspaces)) {
418 av_log(ctx, AV_LOG_ERROR, "Unsupported output color matrix '%s'\n",
419 av_color_space_name(scale->out_color_matrix));
420 return AVERROR(EINVAL);
421 }
422
423 9904 av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
424 9904 scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
425
426
3/4
✓ Branch 0 taken 9904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1596 times.
✓ Branch 3 taken 8308 times.
9904 if (scale->flags_str && *scale->flags_str) {
427 1596 ret = av_opt_set(scale->sws_opts, "sws_flags", scale->flags_str, 0);
428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1596 times.
1596 if (ret < 0)
429 return ret;
430 }
431
432
2/2
✓ Branch 0 taken 19808 times.
✓ Branch 1 taken 9904 times.
29712 for (int i = 0; i < FF_ARRAY_ELEMS(scale->param); i++)
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19808 times.
19808 if (scale->param[i] != DBL_MAX) {
434 ret = av_opt_set_double(scale->sws_opts, i ? "param1" : "param0",
435 scale->param[i], 0);
436 if (ret < 0)
437 return ret;
438 }
439
440 // use generic thread-count if the user did not set it explicitly
441 9904 ret = av_opt_get_int(scale->sws_opts, "threads", 0, &threads);
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9904 times.
9904 if (ret < 0)
443 return ret;
444
1/2
✓ Branch 0 taken 9904 times.
✗ Branch 1 not taken.
9904 if (!threads)
445 9904 av_opt_set_int(scale->sws_opts, "threads", ff_filter_get_nb_threads(ctx), 0);
446
447
3/4
✓ Branch 0 taken 9904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 9902 times.
9904 if (ctx->filter != &ff_vf_scale2ref && scale->uses_ref) {
448 2 AVFilterPad pad = {
449 .name = "ref",
450 .type = AVMEDIA_TYPE_VIDEO,
451 };
452 2 ret = ff_append_inpad(ctx, &pad);
453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
454 return ret;
455 }
456
457 9904 return 0;
458 }
459
460 9904 static av_cold void uninit(AVFilterContext *ctx)
461 {
462 9904 ScaleContext *scale = ctx->priv;
463 9904 av_expr_free(scale->w_pexpr);
464 9904 av_expr_free(scale->h_pexpr);
465 9904 scale->w_pexpr = scale->h_pexpr = NULL;
466 9904 ff_framesync_uninit(&scale->fs);
467 9904 sws_freeContext(scale->sws_opts);
468 9904 sws_freeContext(scale->sws);
469 9904 sws_freeContext(scale->isws[0]);
470 9904 sws_freeContext(scale->isws[1]);
471 9904 scale->sws = NULL;
472 9904 }
473
474 5825 static int query_formats(const AVFilterContext *ctx,
475 AVFilterFormatsConfig **cfg_in,
476 AVFilterFormatsConfig **cfg_out)
477 {
478 5825 const ScaleContext *scale = ctx->priv;
479 AVFilterFormats *formats;
480 const AVPixFmtDescriptor *desc;
481 enum AVPixelFormat pix_fmt;
482 int ret;
483
484 5825 desc = NULL;
485 5825 formats = NULL;
486
2/2
✓ Branch 1 taken 1415475 times.
✓ Branch 2 taken 5825 times.
1421300 while ((desc = av_pix_fmt_desc_next(desc))) {
487 1415475 pix_fmt = av_pix_fmt_desc_get_id(desc);
488
3/4
✓ Branch 1 taken 186400 times.
✓ Branch 2 taken 1229075 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 186400 times.
1601875 if ((sws_isSupportedInput(pix_fmt) ||
489 186400 sws_isSupportedEndiannessConversion(pix_fmt))
490
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1229075 times.
1229075 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
491 return ret;
492 }
493 }
494
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5825 times.
5825 if ((ret = ff_formats_ref(formats, &cfg_in[0]->formats)) < 0)
495 return ret;
496
497 5825 desc = NULL;
498 5825 formats = NULL;
499
2/2
✓ Branch 1 taken 1415475 times.
✓ Branch 2 taken 5825 times.
1421300 while ((desc = av_pix_fmt_desc_next(desc))) {
500 1415475 pix_fmt = av_pix_fmt_desc_get_id(desc);
501
5/6
✓ Branch 1 taken 285425 times.
✓ Branch 2 taken 1130050 times.
✓ Branch 3 taken 279600 times.
✓ Branch 4 taken 5825 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 279600 times.
1695075 if ((sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8 ||
502 279600 sws_isSupportedEndiannessConversion(pix_fmt))
503
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1135875 times.
1135875 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
504 return ret;
505 }
506 }
507
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5825 times.
5825 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5825 times.
5825 if ((ret = ff_formats_ref(ff_make_format_list(sws_colorspaces),
512 5825 &cfg_in[0]->color_spaces)) < 0)
513 return ret;
514
515
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5825 times.
5825 if ((ret = ff_formats_ref(ff_all_color_ranges(),
516 5825 &cfg_in[0]->color_ranges)) < 0)
517 return ret;
518
519 /* propagate output properties if overridden */
520 11650 formats = scale->out_color_matrix != AVCOL_SPC_UNSPECIFIED
521 2 ? ff_make_formats_list_singleton(scale->out_color_matrix)
522
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5823 times.
5825 : ff_make_format_list(sws_colorspaces);
523
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5825 times.
5825 if ((ret = ff_formats_ref(formats, &cfg_out[0]->color_spaces)) < 0)
524 return ret;
525
526 11650 formats = scale->out_range != AVCOL_RANGE_UNSPECIFIED
527 2 ? ff_make_formats_list_singleton(scale->out_range)
528
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5823 times.
5825 : ff_all_color_ranges();
529
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5825 times.
5825 if ((ret = ff_formats_ref(formats, &cfg_out[0]->color_ranges)) < 0)
530 return ret;
531
532 5825 return 0;
533 }
534
535 5831 static int scale_eval_dimensions(AVFilterContext *ctx)
536 {
537 5831 ScaleContext *scale = ctx->priv;
538 5831 const char scale2ref = ctx->filter == &ff_vf_scale2ref;
539
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 const AVFilterLink *inlink = scale2ref ? ctx->inputs[1] : ctx->inputs[0];
540 5831 const AVFilterLink *outlink = ctx->outputs[0];
541 5831 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
542 5831 const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
543 char *expr;
544 int eval_w, eval_h;
545 int ret;
546 double res;
547 const AVPixFmtDescriptor *main_desc;
548 const AVFilterLink *main_link;
549
550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (scale2ref) {
551 main_link = ctx->inputs[0];
552 main_desc = av_pix_fmt_desc_get(main_link->format);
553 }
554
555 5831 scale->var_values[VAR_IN_W] = scale->var_values[VAR_IW] = inlink->w;
556 5831 scale->var_values[VAR_IN_H] = scale->var_values[VAR_IH] = inlink->h;
557 5831 scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = NAN;
558 5831 scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = NAN;
559 5831 scale->var_values[VAR_A] = (double) inlink->w / inlink->h;
560 11662 scale->var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
561
2/2
✓ Branch 0 taken 1848 times.
✓ Branch 1 taken 3983 times.
5831 (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
562 5831 scale->var_values[VAR_DAR] = scale->var_values[VAR_A] * scale->var_values[VAR_SAR];
563 5831 scale->var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
564 5831 scale->var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
565 5831 scale->var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w;
566 5831 scale->var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h;
567
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (scale2ref) {
569 scale->var_values[VAR_S2R_MAIN_W] = main_link->w;
570 scale->var_values[VAR_S2R_MAIN_H] = main_link->h;
571 scale->var_values[VAR_S2R_MAIN_A] = (double) main_link->w / main_link->h;
572 scale->var_values[VAR_S2R_MAIN_SAR] = main_link->sample_aspect_ratio.num ?
573 (double) main_link->sample_aspect_ratio.num / main_link->sample_aspect_ratio.den : 1;
574 scale->var_values[VAR_S2R_MAIN_DAR] = scale->var_values[VAR_S2R_MDAR] =
575 scale->var_values[VAR_S2R_MAIN_A] * scale->var_values[VAR_S2R_MAIN_SAR];
576 scale->var_values[VAR_S2R_MAIN_HSUB] = 1 << main_desc->log2_chroma_w;
577 scale->var_values[VAR_S2R_MAIN_VSUB] = 1 << main_desc->log2_chroma_h;
578 }
579
580
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5830 times.
5831 if (scale->uses_ref) {
581 1 const AVFilterLink *reflink = ctx->inputs[1];
582 1 const AVPixFmtDescriptor *ref_desc = av_pix_fmt_desc_get(reflink->format);
583 1 scale->var_values[VAR_REF_W] = scale->var_values[VAR_RW] = reflink->w;
584 1 scale->var_values[VAR_REF_H] = scale->var_values[VAR_RH] = reflink->h;
585 1 scale->var_values[VAR_REF_A] = (double) reflink->w / reflink->h;
586 2 scale->var_values[VAR_REF_SAR] = reflink->sample_aspect_ratio.num ?
587
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (double) reflink->sample_aspect_ratio.num / reflink->sample_aspect_ratio.den : 1;
588 1 scale->var_values[VAR_REF_DAR] = scale->var_values[VAR_RDAR] =
589 1 scale->var_values[VAR_REF_A] * scale->var_values[VAR_REF_SAR];
590 1 scale->var_values[VAR_REF_HSUB] = 1 << ref_desc->log2_chroma_w;
591 1 scale->var_values[VAR_REF_VSUB] = 1 << ref_desc->log2_chroma_h;
592 }
593
594 5831 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
595
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
596
597 5831 res = av_expr_eval(scale->h_pexpr, scale->var_values, NULL);
598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (isnan(res)) {
599 expr = scale->h_expr;
600 ret = AVERROR(EINVAL);
601 goto fail;
602 }
603
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 eval_h = scale->var_values[VAR_OUT_H] = scale->var_values[VAR_OH] = (int) res == 0 ? inlink->h : (int) res;
604
605 5831 res = av_expr_eval(scale->w_pexpr, scale->var_values, NULL);
606
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (isnan(res)) {
607 expr = scale->w_expr;
608 ret = AVERROR(EINVAL);
609 goto fail;
610 }
611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 eval_w = scale->var_values[VAR_OUT_W] = scale->var_values[VAR_OW] = (int) res == 0 ? inlink->w : (int) res;
612
613 5831 scale->w = eval_w;
614 5831 scale->h = eval_h;
615
616 5831 return 0;
617
618 fail:
619 av_log(ctx, AV_LOG_ERROR,
620 "Error when evaluating the expression '%s'.\n", expr);
621 return ret;
622 }
623
624 11100 static void calc_chroma_pos(int *h_pos_out, int *v_pos_out, int chroma_loc,
625 int h_pos_override, int v_pos_override,
626 int h_sub, int v_sub, int index)
627 {
628 int h_pos, v_pos;
629
630 /* Explicitly default to center siting for compatibility with swscale */
631
2/2
✓ Branch 0 taken 11099 times.
✓ Branch 1 taken 1 times.
11100 if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED)
632 11099 chroma_loc = AVCHROMA_LOC_CENTER;
633
634 /* av_chroma_location_enum_to_pos() always gives us values in the range from
635 * 0 to 256, but we need to adjust this to the true value range of the
636 * subsampling grid, which may be larger for h/v_sub > 1 */
637 11100 av_chroma_location_enum_to_pos(&h_pos, &v_pos, chroma_loc);
638 11100 h_pos *= (1 << h_sub) - 1;
639 11100 v_pos *= (1 << v_sub) - 1;
640
641
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11100 times.
11100 if (h_pos_override != -513)
642 h_pos = h_pos_override;
643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11100 times.
11100 if (v_pos_override != -513)
644 v_pos = v_pos_override;
645
646 /* Fix vertical chroma position for interlaced frames */
647
3/4
✓ Branch 0 taken 4625 times.
✓ Branch 1 taken 6475 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4625 times.
11100 if (v_sub && index > 0) {
648 /* When vertically subsampling, chroma samples are effectively only
649 * placed next to even rows. To access them from the odd field, we need
650 * to account for this shift by offsetting the distance of one luma row.
651 *
652 * For 4x vertical subsampling (v_sub == 2), they are only placed
653 * next to every *other* even row, so we need to shift by three luma
654 * rows to get to the chroma sample. */
655 if (index == 2)
656 v_pos += (256 << v_sub) - 256;
657
658 /* Luma row distance is doubled for fields, so halve offsets */
659 v_pos >>= 1;
660 }
661
662 /* Explicitly strip chroma offsets when not subsampling, because it
663 * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
664
2/2
✓ Branch 0 taken 5671 times.
✓ Branch 1 taken 5429 times.
11100 *h_pos_out = h_sub ? h_pos : -513;
665
2/2
✓ Branch 0 taken 4625 times.
✓ Branch 1 taken 6475 times.
11100 *v_pos_out = v_sub ? v_pos : -513;
666 11100 }
667
668 5831 static int config_props(AVFilterLink *outlink)
669 {
670 5831 AVFilterContext *ctx = outlink->src;
671 5831 AVFilterLink *inlink0 = outlink->src->inputs[0];
672 11662 AVFilterLink *inlink = ctx->filter == &ff_vf_scale2ref ?
673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 outlink->src->inputs[1] :
674 5831 outlink->src->inputs[0];
675 5831 enum AVPixelFormat outfmt = outlink->format;
676 5831 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
677 5831 const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(outfmt);
678 5831 ScaleContext *scale = ctx->priv;
679 5831 uint8_t *flags_val = NULL;
680 int in_range, in_colorspace;
681 int ret;
682
683
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5831 times.
5831 if ((ret = scale_eval_dimensions(ctx)) < 0)
684 goto fail;
685
686 5831 outlink->w = scale->w;
687 5831 outlink->h = scale->h;
688
689 5831 ret = ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
690 scale->force_original_aspect_ratio,
691 scale->force_divisible_by);
692
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (ret < 0)
694 goto fail;
695
696 if (outlink->w > INT_MAX ||
697 outlink->h > INT_MAX ||
698 (outlink->h * inlink->w) > INT_MAX ||
699 (outlink->w * inlink->h) > INT_MAX)
700 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
701
702 /* TODO: make algorithm configurable */
703
704 5831 scale->input_is_pal = desc->flags & AV_PIX_FMT_FLAG_PAL;
705
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 5814 times.
5831 if (outfmt == AV_PIX_FMT_PAL8) outfmt = AV_PIX_FMT_BGR8;
706 5831 scale->output_is_pal = av_pix_fmt_desc_get(outfmt)->flags & AV_PIX_FMT_FLAG_PAL;
707
708 5831 in_range = scale->in_range;
709
2/2
✓ Branch 0 taken 5829 times.
✓ Branch 1 taken 2 times.
5831 if (in_range == AVCOL_RANGE_UNSPECIFIED)
710 5829 in_range = inlink0->color_range;
711
712 5831 in_colorspace = scale->in_color_matrix;
713
2/2
✓ Branch 0 taken 5829 times.
✓ Branch 1 taken 2 times.
5831 if (in_colorspace == -1 /* auto */)
714 5829 in_colorspace = inlink0->colorspace;
715
716
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 5792 times.
5831 if (scale->sws)
717 39 sws_freeContext(scale->sws);
718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (scale->isws[0])
719 sws_freeContext(scale->isws[0]);
720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (scale->isws[1])
721 sws_freeContext(scale->isws[1]);
722 5831 scale->isws[0] = scale->isws[1] = scale->sws = NULL;
723
2/2
✓ Branch 0 taken 5387 times.
✓ Branch 1 taken 444 times.
5831 if (inlink0->w == outlink->w &&
724
2/2
✓ Branch 0 taken 5377 times.
✓ Branch 1 taken 10 times.
5387 inlink0->h == outlink->h &&
725
2/2
✓ Branch 0 taken 2674 times.
✓ Branch 1 taken 2703 times.
5377 in_range == outlink->color_range &&
726
2/2
✓ Branch 0 taken 2419 times.
✓ Branch 1 taken 255 times.
2674 in_colorspace == outlink->colorspace &&
727
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 2138 times.
2419 inlink0->format == outlink->format &&
728
1/2
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
281 scale->in_chroma_loc == scale->out_chroma_loc)
729 ;
730 else {
731 5550 struct SwsContext **swscs[3] = {&scale->sws, &scale->isws[0], &scale->isws[1]};
732 int i;
733
734
1/2
✓ Branch 0 taken 5550 times.
✗ Branch 1 not taken.
5550 for (i = 0; i < 3; i++) {
735 int in_full, out_full, brightness, contrast, saturation;
736 int h_chr_pos, v_chr_pos;
737 const int *inv_table, *table;
738 5550 struct SwsContext *const s = sws_alloc_context();
739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5550 times.
5550 if (!s)
740 return AVERROR(ENOMEM);
741 5550 *swscs[i] = s;
742
743 5550 ret = av_opt_copy(s, scale->sws_opts);
744
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5550 times.
5550 if (ret < 0)
745 return ret;
746
747 5550 av_opt_set_int(s, "srcw", inlink0 ->w, 0);
748 5550 av_opt_set_int(s, "srch", inlink0 ->h >> !!i, 0);
749 5550 av_opt_set_int(s, "src_format", inlink0->format, 0);
750 5550 av_opt_set_int(s, "dstw", outlink->w, 0);
751 5550 av_opt_set_int(s, "dsth", outlink->h >> !!i, 0);
752 5550 av_opt_set_int(s, "dst_format", outfmt, 0);
753
2/2
✓ Branch 0 taken 4531 times.
✓ Branch 1 taken 1019 times.
5550 if (in_range != AVCOL_RANGE_UNSPECIFIED)
754 4531 av_opt_set_int(s, "src_range",
755 in_range == AVCOL_RANGE_JPEG, 0);
756
2/2
✓ Branch 0 taken 4875 times.
✓ Branch 1 taken 675 times.
5550 if (outlink->color_range != AVCOL_RANGE_UNSPECIFIED)
757 4875 av_opt_set_int(s, "dst_range",
758 4875 outlink->color_range == AVCOL_RANGE_JPEG, 0);
759
760 5550 calc_chroma_pos(&h_chr_pos, &v_chr_pos, scale->in_chroma_loc,
761 scale->in_h_chr_pos, scale->in_v_chr_pos,
762 5550 desc->log2_chroma_w, desc->log2_chroma_h, i);
763 5550 av_opt_set_int(s, "src_h_chr_pos", h_chr_pos, 0);
764 5550 av_opt_set_int(s, "src_v_chr_pos", v_chr_pos, 0);
765
766 5550 calc_chroma_pos(&h_chr_pos, &v_chr_pos, scale->out_chroma_loc,
767 scale->out_h_chr_pos, scale->out_v_chr_pos,
768 5550 outdesc->log2_chroma_w, outdesc->log2_chroma_h, i);
769 5550 av_opt_set_int(s, "dst_h_chr_pos", h_chr_pos, 0);
770 5550 av_opt_set_int(s, "dst_v_chr_pos", v_chr_pos, 0);
771
772
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5550 times.
5550 if ((ret = sws_init_context(s, NULL, NULL)) < 0)
773 return ret;
774
775 5550 sws_getColorspaceDetails(s, (int **)&inv_table, &in_full,
776 (int **)&table, &out_full,
777 &brightness, &contrast, &saturation);
778
779
2/2
✓ Branch 0 taken 5548 times.
✓ Branch 1 taken 2 times.
5550 if (scale->in_color_matrix == -1 /* auto */)
780 5548 inv_table = sws_getCoefficients(inlink0->colorspace);
781
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (scale->in_color_matrix != AVCOL_SPC_UNSPECIFIED)
782 2 inv_table = sws_getCoefficients(scale->in_color_matrix);
783
2/2
✓ Branch 0 taken 2014 times.
✓ Branch 1 taken 3536 times.
5550 if (outlink->colorspace != AVCOL_SPC_UNSPECIFIED)
784 2014 table = sws_getCoefficients(outlink->colorspace);
785
1/2
✓ Branch 0 taken 3536 times.
✗ Branch 1 not taken.
3536 else if (scale->in_color_matrix != AVCOL_SPC_UNSPECIFIED)
786 3536 table = inv_table;
787
788 5550 sws_setColorspaceDetails(s, inv_table, in_full,
789 table, out_full,
790 brightness, contrast, saturation);
791
792
1/2
✓ Branch 0 taken 5550 times.
✗ Branch 1 not taken.
5550 if (!scale->interlaced)
793 5550 break;
794 }
795 }
796
797
2/2
✓ Branch 0 taken 1848 times.
✓ Branch 1 taken 3983 times.
5831 if (inlink0->sample_aspect_ratio.num){
798 1848 outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink0->w, outlink->w * inlink0->h}, inlink0->sample_aspect_ratio);
799 } else
800 3983 outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
801
802
2/2
✓ Branch 0 taken 5550 times.
✓ Branch 1 taken 281 times.
5831 if (scale->sws)
803 5550 av_opt_get(scale->sws, "sws_flags", 0, &flags_val);
804
805 17493 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",
806 5831 inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
807 av_color_space_name(inlink->colorspace), av_color_range_name(inlink->color_range),
808 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
809 5831 outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
810 av_color_space_name(outlink->colorspace), av_color_range_name(outlink->color_range),
811 outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
812 flags_val);
813 5831 av_freep(&flags_val);
814
815
1/2
✓ Branch 0 taken 5831 times.
✗ Branch 1 not taken.
5831 if (ctx->filter != &ff_vf_scale2ref) {
816 5831 ff_framesync_uninit(&scale->fs);
817 5831 ret = ff_framesync_init(&scale->fs, ctx, ctx->nb_inputs);
818
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (ret < 0)
819 return ret;
820 5831 scale->fs.on_event = do_scale;
821 5831 scale->fs.in[0].time_base = ctx->inputs[0]->time_base;
822 5831 scale->fs.in[0].sync = 1;
823 5831 scale->fs.in[0].before = EXT_STOP;
824 5831 scale->fs.in[0].after = EXT_STOP;
825
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5830 times.
5831 if (scale->uses_ref) {
826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(ctx->nb_inputs == 2);
827 1 scale->fs.in[1].time_base = ctx->inputs[1]->time_base;
828 1 scale->fs.in[1].sync = 0;
829 1 scale->fs.in[1].before = EXT_NULL;
830 1 scale->fs.in[1].after = EXT_INFINITY;
831 }
832
833 5831 ret = ff_framesync_configure(&scale->fs);
834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5831 times.
5831 if (ret < 0)
835 return ret;
836 }
837
838 5831 return 0;
839
840 fail:
841 return ret;
842 }
843
844 static int config_props_ref(AVFilterLink *outlink)
845 {
846 AVFilterLink *inlink = outlink->src->inputs[1];
847 FilterLink *il = ff_filter_link(inlink);
848 FilterLink *ol = ff_filter_link(outlink);
849
850 outlink->w = inlink->w;
851 outlink->h = inlink->h;
852 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
853 outlink->time_base = inlink->time_base;
854 ol->frame_rate = il->frame_rate;
855 outlink->colorspace = inlink->colorspace;
856 outlink->color_range = inlink->color_range;
857
858 return 0;
859 }
860
861 static int request_frame(AVFilterLink *outlink)
862 {
863 return ff_request_frame(outlink->src->inputs[0]);
864 }
865
866 static int request_frame_ref(AVFilterLink *outlink)
867 {
868 return ff_request_frame(outlink->src->inputs[1]);
869 }
870
871 static void frame_offset(AVFrame *frame, int dir, int is_pal)
872 {
873 for (int i = 0; i < 4 && frame->data[i]; i++) {
874 if (i == 1 && is_pal)
875 break;
876 frame->data[i] += frame->linesize[i] * dir;
877 }
878 }
879
880 static int scale_field(ScaleContext *scale, AVFrame *dst, AVFrame *src,
881 int field)
882 {
883 int orig_h_src = src->height;
884 int orig_h_dst = dst->height;
885 int ret;
886
887 // offset the data pointers for the bottom field
888 if (field) {
889 frame_offset(src, 1, scale->input_is_pal);
890 frame_offset(dst, 1, scale->output_is_pal);
891 }
892
893 // take every second line
894 for (int i = 0; i < 4; i++) {
895 src->linesize[i] *= 2;
896 dst->linesize[i] *= 2;
897 }
898 src->height /= 2;
899 dst->height /= 2;
900
901 ret = sws_scale_frame(scale->isws[field], dst, src);
902 if (ret < 0)
903 return ret;
904
905 // undo the changes we made above
906 for (int i = 0; i < 4; i++) {
907 src->linesize[i] /= 2;
908 dst->linesize[i] /= 2;
909 }
910 src->height = orig_h_src;
911 dst->height = orig_h_dst;
912
913 if (field) {
914 frame_offset(src, -1, scale->input_is_pal);
915 frame_offset(dst, -1, scale->output_is_pal);
916 }
917
918 return 0;
919 }
920
921 /* Takes over ownership of *frame_in, passes ownership of *frame_out to caller */
922 88964 static int scale_frame(AVFilterLink *link, AVFrame **frame_in,
923 AVFrame **frame_out)
924 {
925 88964 FilterLink *inl = ff_filter_link(link);
926 88964 AVFilterContext *ctx = link->dst;
927 88964 ScaleContext *scale = ctx->priv;
928 88964 AVFilterLink *outlink = ctx->outputs[0];
929 88964 AVFrame *out, *in = *frame_in;
930 88964 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
931 char buf[32];
932 int ret;
933 int frame_changed;
934
935 88964 *frame_in = NULL;
936
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88964 times.
88964 if (in->colorspace == AVCOL_SPC_YCGCO)
937 av_log(link->dst, AV_LOG_WARNING, "Detected unsupported YCgCo colorspace.\n");
938
939 266891 frame_changed = in->width != link->w ||
940
1/2
✓ Branch 0 taken 88963 times.
✗ Branch 1 not taken.
88963 in->height != link->h ||
941
1/2
✓ Branch 0 taken 88963 times.
✗ Branch 1 not taken.
88963 in->format != link->format ||
942
1/2
✓ Branch 0 taken 88963 times.
✗ Branch 1 not taken.
88963 in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
943
1/2
✓ Branch 0 taken 88963 times.
✗ Branch 1 not taken.
88963 in->sample_aspect_ratio.num != link->sample_aspect_ratio.num ||
944
4/4
✓ Branch 0 taken 88963 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 88948 times.
✓ Branch 3 taken 15 times.
266875 in->colorspace != link->colorspace ||
945
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 88947 times.
88948 in->color_range != link->color_range;
946
947
3/4
✓ Branch 0 taken 88964 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 88947 times.
88964 if (scale->eval_mode == EVAL_MODE_FRAME || frame_changed) {
948 17 unsigned vars_w[VARS_NB] = { 0 }, vars_h[VARS_NB] = { 0 };
949
950 17 av_expr_count_vars(scale->w_pexpr, vars_w, VARS_NB);
951 17 av_expr_count_vars(scale->h_pexpr, vars_h, VARS_NB);
952
953
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 &&
954 !frame_changed &&
955 ctx->filter != &ff_vf_scale2ref &&
956 !(vars_w[VAR_N] || vars_w[VAR_T]
957 #if FF_API_FRAME_PKT
958 || vars_w[VAR_POS]
959 #endif
960 ) &&
961 !(vars_h[VAR_N] || vars_h[VAR_T]
962 #if FF_API_FRAME_PKT
963 || vars_h[VAR_POS]
964 #endif
965 ) &&
966 scale->w && scale->h)
967 goto scale;
968
969
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 if (scale->eval_mode == EVAL_MODE_INIT) {
970 17 snprintf(buf, sizeof(buf) - 1, "%d", scale->w);
971 17 av_opt_set(scale, "w", buf, 0);
972 17 snprintf(buf, sizeof(buf) - 1, "%d", scale->h);
973 17 av_opt_set(scale, "h", buf, 0);
974
975 17 ret = scale_parse_expr(ctx, NULL, &scale->w_pexpr, "width", scale->w_expr);
976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ret < 0)
977 goto err;
978
979 17 ret = scale_parse_expr(ctx, NULL, &scale->h_pexpr, "height", scale->h_expr);
980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ret < 0)
981 goto err;
982 }
983
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (ctx->filter == &ff_vf_scale2ref) {
985 scale->var_values[VAR_S2R_MAIN_N] = inl->frame_count_out;
986 scale->var_values[VAR_S2R_MAIN_T] = TS2T(in->pts, link->time_base);
987 #if FF_API_FRAME_PKT
988 FF_DISABLE_DEPRECATION_WARNINGS
989 scale->var_values[VAR_S2R_MAIN_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
990 FF_ENABLE_DEPRECATION_WARNINGS
991 #endif
992 } else {
993 17 scale->var_values[VAR_N] = inl->frame_count_out;
994
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
995 #if FF_API_FRAME_PKT
996 FF_DISABLE_DEPRECATION_WARNINGS
997
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;
998 FF_ENABLE_DEPRECATION_WARNINGS
999 #endif
1000 }
1001
1002 17 link->dst->inputs[0]->format = in->format;
1003 17 link->dst->inputs[0]->w = in->width;
1004 17 link->dst->inputs[0]->h = in->height;
1005 17 link->dst->inputs[0]->colorspace = in->colorspace;
1006 17 link->dst->inputs[0]->color_range = in->color_range;
1007
1008 17 link->dst->inputs[0]->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
1009 17 link->dst->inputs[0]->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
1010
1011
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
17 if ((ret = config_props(outlink)) < 0)
1012 goto err;
1013 }
1014
1015 88947 scale:
1016
2/2
✓ Branch 0 taken 4367 times.
✓ Branch 1 taken 84597 times.
88964 if (!scale->sws) {
1017 4367 *frame_out = in;
1018 4367 return 0;
1019 }
1020
1021 84597 scale->hsub = desc->log2_chroma_w;
1022 84597 scale->vsub = desc->log2_chroma_h;
1023
1024 84597 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84597 times.
84597 if (!out) {
1026 ret = AVERROR(ENOMEM);
1027 goto err;
1028 }
1029
1030 84597 av_frame_copy_props(out, in);
1031 84597 out->width = outlink->w;
1032 84597 out->height = outlink->h;
1033 84597 out->color_range = outlink->color_range;
1034 84597 out->colorspace = outlink->colorspace;
1035
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 84572 times.
84597 if (scale->out_chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
1036 25 out->chroma_location = scale->out_chroma_loc;
1037
1038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84597 times.
84597 if (scale->output_is_pal)
1039 avpriv_set_systematic_pal2((uint32_t*)out->data[1], outlink->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink->format);
1040
1041 84597 av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
1042 84597 (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
1043 84597 (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
1044 INT_MAX);
1045
1046
2/4
✓ Branch 0 taken 84597 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84597 times.
84597 if (scale->interlaced>0 || (scale->interlaced<0 &&
1047 (in->flags & AV_FRAME_FLAG_INTERLACED))) {
1048 ret = scale_field(scale, out, in, 0);
1049 if (ret >= 0)
1050 ret = scale_field(scale, out, in, 1);
1051 } else {
1052 84597 ret = sws_scale_frame(scale->sws, out, in);
1053 }
1054
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84597 times.
84597 if (ret < 0)
1056 av_frame_free(&out);
1057 84597 *frame_out = out;
1058
1059 84597 err:
1060 84597 av_frame_free(&in);
1061 84597 return ret;
1062 }
1063
1064 88964 static int do_scale(FFFrameSync *fs)
1065 {
1066 88964 AVFilterContext *ctx = fs->parent;
1067 88964 ScaleContext *scale = ctx->priv;
1068 88964 AVFilterLink *outlink = ctx->outputs[0];
1069 88964 AVFrame *out, *in = NULL, *ref = NULL;
1070 88964 int ret = 0, frame_changed;
1071
1072 88964 ret = ff_framesync_get_frame(fs, 0, &in, 1);
1073
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88964 times.
88964 if (ret < 0)
1074 goto err;
1075
1076
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 88959 times.
88964 if (scale->uses_ref) {
1077 5 ret = ff_framesync_get_frame(fs, 1, &ref, 0);
1078
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
1079 goto err;
1080 }
1081
1082
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 88959 times.
88964 if (ref) {
1083 5 AVFilterLink *reflink = ctx->inputs[1];
1084 5 FilterLink *rl = ff_filter_link(reflink);
1085
1086 15 frame_changed = ref->width != reflink->w ||
1087
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ref->height != reflink->h ||
1088
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ref->format != reflink->format ||
1089
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ref->sample_aspect_ratio.den != reflink->sample_aspect_ratio.den ||
1090
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ref->sample_aspect_ratio.num != reflink->sample_aspect_ratio.num ||
1091
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 ||
1092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 ref->color_range != reflink->color_range;
1093
1094
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (frame_changed) {
1095 reflink->format = ref->format;
1096 reflink->w = ref->width;
1097 reflink->h = ref->height;
1098 reflink->sample_aspect_ratio.num = ref->sample_aspect_ratio.num;
1099 reflink->sample_aspect_ratio.den = ref->sample_aspect_ratio.den;
1100 reflink->colorspace = ref->colorspace;
1101 reflink->color_range = ref->color_range;
1102
1103 ret = config_props(outlink);
1104 if (ret < 0)
1105 goto err;
1106 }
1107
1108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (scale->eval_mode == EVAL_MODE_FRAME) {
1109 scale->var_values[VAR_REF_N] = rl->frame_count_out;
1110 scale->var_values[VAR_REF_T] = TS2T(ref->pts, reflink->time_base);
1111 #if FF_API_FRAME_PKT
1112 FF_DISABLE_DEPRECATION_WARNINGS
1113 scale->var_values[VAR_REF_POS] = ref->pkt_pos == -1 ? NAN : ref->pkt_pos;
1114 FF_ENABLE_DEPRECATION_WARNINGS
1115 #endif
1116 }
1117 }
1118
1119 88964 ret = scale_frame(ctx->inputs[0], &in, &out);
1120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88964 times.
88964 if (ret < 0)
1121 goto err;
1122
1123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88964 times.
88964 av_assert0(out);
1124 88964 out->pts = av_rescale_q(fs->pts, fs->time_base, outlink->time_base);
1125 88964 return ff_filter_frame(outlink, out);
1126
1127 err:
1128 av_frame_free(&in);
1129 return ret;
1130 }
1131
1132 static int filter_frame(AVFilterLink *link, AVFrame *in)
1133 {
1134 AVFilterContext *ctx = link->dst;
1135 AVFilterLink *outlink = ctx->outputs[0];
1136 AVFrame *out;
1137 int ret;
1138
1139 ret = scale_frame(link, &in, &out);
1140 if (out)
1141 return ff_filter_frame(outlink, out);
1142
1143 return ret;
1144 }
1145
1146 static int filter_frame_ref(AVFilterLink *link, AVFrame *in)
1147 {
1148 FilterLink *l = ff_filter_link(link);
1149 ScaleContext *scale = link->dst->priv;
1150 AVFilterLink *outlink = link->dst->outputs[1];
1151 int frame_changed;
1152
1153 frame_changed = in->width != link->w ||
1154 in->height != link->h ||
1155 in->format != link->format ||
1156 in->sample_aspect_ratio.den != link->sample_aspect_ratio.den ||
1157 in->sample_aspect_ratio.num != link->sample_aspect_ratio.num ||
1158 in->colorspace != link->colorspace ||
1159 in->color_range != link->color_range;
1160
1161 if (frame_changed) {
1162 link->format = in->format;
1163 link->w = in->width;
1164 link->h = in->height;
1165 link->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
1166 link->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
1167 link->colorspace = in->colorspace;
1168 link->color_range = in->color_range;
1169
1170 config_props_ref(outlink);
1171 }
1172
1173 if (scale->eval_mode == EVAL_MODE_FRAME) {
1174 scale->var_values[VAR_N] = l->frame_count_out;
1175 scale->var_values[VAR_T] = TS2T(in->pts, link->time_base);
1176 #if FF_API_FRAME_PKT
1177 FF_DISABLE_DEPRECATION_WARNINGS
1178 scale->var_values[VAR_POS] = in->pkt_pos == -1 ? NAN : in->pkt_pos;
1179 FF_ENABLE_DEPRECATION_WARNINGS
1180 #endif
1181 }
1182
1183 return ff_filter_frame(outlink, in);
1184 }
1185
1186 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
1187 char *res, int res_len, int flags)
1188 {
1189 ScaleContext *scale = ctx->priv;
1190 char *str_expr;
1191 AVExpr **pexpr_ptr;
1192 int ret, w, h;
1193
1194 w = !strcmp(cmd, "width") || !strcmp(cmd, "w");
1195 h = !strcmp(cmd, "height") || !strcmp(cmd, "h");
1196
1197 if (w || h) {
1198 str_expr = w ? scale->w_expr : scale->h_expr;
1199 pexpr_ptr = w ? &scale->w_pexpr : &scale->h_pexpr;
1200
1201 ret = scale_parse_expr(ctx, str_expr, pexpr_ptr, cmd, args);
1202 } else
1203 ret = AVERROR(ENOSYS);
1204
1205 if (ret < 0)
1206 av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n");
1207
1208 return ret;
1209 }
1210
1211 176913 static int activate(AVFilterContext *ctx)
1212 {
1213 176913 ScaleContext *scale = ctx->priv;
1214 176913 return ff_framesync_activate(&scale->fs);
1215 }
1216
1217 static const AVClass *child_class_iterate(void **iter)
1218 {
1219 switch ((uintptr_t) *iter) {
1220 case 0:
1221 *iter = (void*)(uintptr_t) 1;
1222 return sws_get_class();
1223 case 1:
1224 *iter = (void*)(uintptr_t) 2;
1225 return &ff_framesync_class;
1226 }
1227
1228 return NULL;
1229 }
1230
1231 19986 static void *child_next(void *obj, void *prev)
1232 {
1233 19986 ScaleContext *s = obj;
1234
2/2
✓ Branch 0 taken 10720 times.
✓ Branch 1 taken 9266 times.
19986 if (!prev)
1235 10720 return s->sws_opts;
1236
2/2
✓ Branch 0 taken 4633 times.
✓ Branch 1 taken 4633 times.
9266 if (prev == s->sws_opts)
1237 4633 return &s->fs;
1238 4633 return NULL;
1239 }
1240
1241 #define OFFSET(x) offsetof(ScaleContext, x)
1242 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
1243 #define TFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
1244
1245 static const AVOption scale_options[] = {
1246 { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1247 { "width", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1248 { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1249 { "height","Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, .flags = TFLAGS },
1250 { "flags", "Flags to pass to libswscale", OFFSET(flags_str), AV_OPT_TYPE_STRING, { .str = "" }, .flags = FLAGS },
1251 { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_BOOL, {.i64 = 0 }, -1, 1, FLAGS },
1252 { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, .flags = FLAGS },
1253 { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, .flags = FLAGS },
1254 { "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" },
1255 { "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"},
1256 { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, FLAGS, .unit = "color" },
1257 { "bt601", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG }, 0, 0, FLAGS, .unit = "color" },
1258 { "bt470", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG }, 0, 0, FLAGS, .unit = "color" },
1259 { "smpte170m", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT470BG }, 0, 0, FLAGS, .unit = "color" },
1260 { "bt709", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT709 }, 0, 0, FLAGS, .unit = "color" },
1261 { "fcc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_FCC }, 0, 0, FLAGS, .unit = "color" },
1262 { "smpte240m", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_SMPTE240M }, 0, 0, FLAGS, .unit = "color" },
1263 { "bt2020", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_SPC_BT2020_NCL }, 0, 0, FLAGS, .unit = "color" },
1264 { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, .unit = "range" },
1265 { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, .unit = "range" },
1266 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, .unit = "range" },
1267 { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, .unit = "range" },
1268 { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1269 { "limited",NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1270 { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1271 { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1272 { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, .unit = "range" },
1273 { "pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, .unit = "range" },
1274 { "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" },
1275 { "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" },
1276 {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"},
1277 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, FLAGS, .unit = "chroma_loc"},
1278 {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
1279 {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, FLAGS, .unit = "chroma_loc"},
1280 {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
1281 {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, FLAGS, .unit = "chroma_loc"},
1282 {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, FLAGS, .unit = "chroma_loc"},
1283 {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, FLAGS, .unit = "chroma_loc"},
1284 { "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 },
1285 { "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 },
1286 { "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 },
1287 { "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 },
1288 { "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" },
1289 { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, .unit = "force_oar" },
1290 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, .unit = "force_oar" },
1291 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, .unit = "force_oar" },
1292 { "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 },
1293 { "param0", "Scaler param 0", OFFSET(param[0]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
1294 { "param1", "Scaler param 1", OFFSET(param[1]), AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX }, -DBL_MAX, DBL_MAX, FLAGS },
1295 { "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" },
1296 { "init", "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT}, .flags = FLAGS, .unit = "eval" },
1297 { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
1298 { NULL }
1299 };
1300
1301 static const AVClass scale_class = {
1302 .class_name = "scale",
1303 .item_name = av_default_item_name,
1304 .option = scale_options,
1305 .version = LIBAVUTIL_VERSION_INT,
1306 .category = AV_CLASS_CATEGORY_FILTER,
1307 .child_class_iterate = child_class_iterate,
1308 .child_next = child_next,
1309 };
1310
1311 static const AVFilterPad avfilter_vf_scale_inputs[] = {
1312 {
1313 .name = "default",
1314 .type = AVMEDIA_TYPE_VIDEO,
1315 },
1316 };
1317
1318 static const AVFilterPad avfilter_vf_scale_outputs[] = {
1319 {
1320 .name = "default",
1321 .type = AVMEDIA_TYPE_VIDEO,
1322 .config_props = config_props,
1323 },
1324 };
1325
1326 const AVFilter ff_vf_scale = {
1327 .name = "scale",
1328 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),
1329 .preinit = preinit,
1330 .init = init,
1331 .uninit = uninit,
1332 .priv_size = sizeof(ScaleContext),
1333 .priv_class = &scale_class,
1334 FILTER_INPUTS(avfilter_vf_scale_inputs),
1335 FILTER_OUTPUTS(avfilter_vf_scale_outputs),
1336 FILTER_QUERY_FUNC2(query_formats),
1337 .activate = activate,
1338 .process_command = process_command,
1339 .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
1340 };
1341
1342 static const AVClass *scale2ref_child_class_iterate(void **iter)
1343 {
1344 const AVClass *c = *iter ? NULL : sws_get_class();
1345 *iter = (void*)(uintptr_t)c;
1346 return c;
1347 }
1348
1349 static void *scale2ref_child_next(void *obj, void *prev)
1350 {
1351 ScaleContext *s = obj;
1352 if (!prev)
1353 return s->sws_opts;
1354 return NULL;
1355 }
1356
1357 static const AVClass scale2ref_class = {
1358 .class_name = "scale(2ref)",
1359 .item_name = av_default_item_name,
1360 .option = scale_options,
1361 .version = LIBAVUTIL_VERSION_INT,
1362 .category = AV_CLASS_CATEGORY_FILTER,
1363 .child_class_iterate = scale2ref_child_class_iterate,
1364 .child_next = scale2ref_child_next,
1365 };
1366
1367 static const AVFilterPad avfilter_vf_scale2ref_inputs[] = {
1368 {
1369 .name = "default",
1370 .type = AVMEDIA_TYPE_VIDEO,
1371 .filter_frame = filter_frame,
1372 },
1373 {
1374 .name = "ref",
1375 .type = AVMEDIA_TYPE_VIDEO,
1376 .filter_frame = filter_frame_ref,
1377 },
1378 };
1379
1380 static const AVFilterPad avfilter_vf_scale2ref_outputs[] = {
1381 {
1382 .name = "default",
1383 .type = AVMEDIA_TYPE_VIDEO,
1384 .config_props = config_props,
1385 .request_frame= request_frame,
1386 },
1387 {
1388 .name = "ref",
1389 .type = AVMEDIA_TYPE_VIDEO,
1390 .config_props = config_props_ref,
1391 .request_frame= request_frame_ref,
1392 },
1393 };
1394
1395 const AVFilter ff_vf_scale2ref = {
1396 .name = "scale2ref",
1397 .description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format to the given reference."),
1398 .preinit = preinit,
1399 .init = init,
1400 .uninit = uninit,
1401 .priv_size = sizeof(ScaleContext),
1402 .priv_class = &scale2ref_class,
1403 FILTER_INPUTS(avfilter_vf_scale2ref_inputs),
1404 FILTER_OUTPUTS(avfilter_vf_scale2ref_outputs),
1405 FILTER_QUERY_FUNC2(query_formats),
1406 .process_command = process_command,
1407 };
1408