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