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