FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_scale.c
Date: 2022-11-26 13:19:19
Exec Total Coverage
Lines: 350 492 71.1%
Branches: 223 446 50.0%

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