FFmpeg
Loading...
Searching...
No Matches
ops.c
Go to the documentation of this file.
1/**
2 * Copyright (C) 2025 Niklas Haas
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
22#include "libavutil/avassert.h"
23#include "libavutil/avstring.h"
24#include "libavutil/bprint.h"
25#include "libavutil/bswap.h"
26#include "libavutil/mem.h"
27#include "libavutil/rational.h"
28#include "libavutil/refstruct.h"
29
30#include "format.h"
31#include "ops.h"
32#include "ops_internal.h"
33
34extern const SwsOpBackend backend_c;
35extern const SwsOpBackend backend_murder;
36extern const SwsOpBackend backend_aarch64;
37extern const SwsOpBackend backend_x86;
38#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
39extern const SwsOpBackend backend_spirv;
40#endif
41
44#if ARCH_AARCH64 && HAVE_NEON
46#elif ARCH_X86_64 && HAVE_X86ASM
48#endif
49 &backend_c,
50#if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
51 &backend_spirv,
52#endif
53 NULL
54};
55
57{
58 switch (type) {
59 case SWS_PIXEL_U8: return "u8";
60 case SWS_PIXEL_U16: return "u16";
61 case SWS_PIXEL_U32: return "u32";
62 case SWS_PIXEL_F32: return "f32";
63 case SWS_PIXEL_NONE: return "none";
64 case SWS_PIXEL_TYPE_NB: break;
65 }
66
67 av_unreachable("Invalid pixel type!");
68 return "ERR";
69}
70
72{
73 switch (op) {
74 case SWS_OP_READ: return "SWS_OP_READ";
75 case SWS_OP_WRITE: return "SWS_OP_WRITE";
76 case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
77 case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
78 case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
79 case SWS_OP_PACK: return "SWS_OP_PACK";
80 case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
81 case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
82 case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
83 case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
84 case SWS_OP_MIN: return "SWS_OP_MIN";
85 case SWS_OP_MAX: return "SWS_OP_MAX";
86 case SWS_OP_SCALE: return "SWS_OP_SCALE";
87 case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
88 case SWS_OP_DITHER: return "SWS_OP_DITHER";
89 case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
90 case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
91 case SWS_OP_LUT_3D: return "SWS_OP_LUT_3D";
92 case SWS_OP_INVALID: return "SWS_OP_INVALID";
93 case SWS_OP_TYPE_NB: break;
94 }
95
96 av_unreachable("Invalid operation type!");
97 return "ERR";
98}
99
101{
102 SwsCompMask mask = 0;
103 for (int i = 0; i < 4; i++) {
104 if (q[i].den)
105 mask |= SWS_COMP(i);
106 }
107 return mask;
108}
109
111{
112 const SwsCompMask orig = *mask;
113 SwsCompMask res = 0;
114 for (int i = 0; i < 4; i++) {
115 const int src = swiz->in[i];
116 if (SWS_COMP_TEST(orig, src))
117 res |= SWS_COMP(i);
118 }
119
120 *mask = res;
121}
122
124{
125 SwsCompMask mask = 0;
126 for (int i = 0; i < 4; i++) {
127 if (SWS_OP_NEEDED(op, i))
128 mask |= SWS_COMP(i);
129 }
130 return mask;
131}
132
134{
135 av_assert2(op->op == SWS_OP_READ || op->op == SWS_OP_WRITE);
136 switch (op->rw.mode) {
137 case SWS_RW_PLANAR: return op->rw.elems;
138 case SWS_RW_PACKED: return 1;
139 case SWS_RW_PALETTE: return 2;
140 }
141
142 av_unreachable("Invalid read/write mode!");
143 return 0;
144}
145
146/* biased towards `a` */
148{
149 return av_cmp_q64(a, b) == 1 ? b : a;
150}
151
153{
154 return av_cmp_q64(a, b) == -1 ? b : a;
155}
156
158{
159 uint64_t mask[4];
160 int shift[4];
161
162 switch (op->op) {
163 case SWS_OP_READ:
164 case SWS_OP_WRITE:
165 return;
166 case SWS_OP_UNPACK: {
169 unsigned val = x[0].num;
170 for (int i = 0; i < 4; i++)
171 x[i] = Q((val >> shift[i]) & mask[i]);
172 return;
173 }
174 case SWS_OP_PACK: {
177 unsigned val = 0;
178 for (int i = 0; i < 4; i++)
179 val |= (x[i].num & mask[i]) << shift[i];
180 x[0] = Q(val);
181 return;
182 }
184 switch (op->type) {
185 case SWS_PIXEL_U16:
186 for (int i = 0; i < 4; i++) {
187 av_assert2(x[i].num >= 0 && x[i].num <= UINT16_MAX);
188 x[i].num = av_bswap16(x[i].num);
189 }
190 return;
191 case SWS_PIXEL_U32:
192 for (int i = 0; i < 4; i++) {
193 av_assert2(x[i].num >= 0 && x[i].num <= UINT32_MAX);
194 x[i].num = av_bswap32(x[i].num);
195 }
196 return;
197 }
198 av_unreachable("Invalid pixel type for SWS_OP_SWAP_BYTES!");
199 return;
200 case SWS_OP_CLEAR:
201 for (int i = 0; i < 4; i++) {
202 if (SWS_COMP_TEST(op->clear.mask, i))
203 x[i] = op->clear.value[i];
204 }
205 return;
206 case SWS_OP_LSHIFT: {
208 AVRational64 mult = Q(1 << op->shift.amount);
209 for (int i = 0; i < 4; i++)
210 x[i] = x[i].den ? av_mul_q64(x[i], mult) : x[i];
211 return;
212 }
213 case SWS_OP_RSHIFT: {
215 for (int i = 0; i < 4; i++)
216 x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->shift.amount) : x[i];
217 return;
218 }
219 case SWS_OP_SWIZZLE: {
220 const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
221 for (int i = 0; i < 4; i++)
222 x[i] = orig[op->swizzle.in[i]];
223 return;
224 }
225 case SWS_OP_CONVERT:
226 if (ff_sws_pixel_type_is_int(op->convert.to)) {
227 const AVRational64 scale = ff_sws_pixel_expand(op->type, op->convert.to);
228 for (int i = 0; i < 4; i++) {
229 x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
230 if (op->convert.expand)
231 x[i] = av_mul_q64(x[i], scale);
232 }
233 }
234 return;
235 case SWS_OP_DITHER:
237 for (int i = 0; i < 4; i++) {
238 if (op->dither.y_offset[i] >= 0 && x[i].den)
239 x[i] = av_add_q64(x[i], av_make_q64(1, 2));
240 }
241 return;
242 case SWS_OP_MIN:
243 for (int i = 0; i < 4; i++)
244 x[i] = av_min_q64(x[i], op->clamp.limit[i]);
245 return;
246 case SWS_OP_MAX:
247 for (int i = 0; i < 4; i++)
248 x[i] = av_max_q64(x[i], op->clamp.limit[i]);
249 return;
250 case SWS_OP_LINEAR: {
252 const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
253 for (int i = 0; i < 4; i++) {
254 AVRational64 sum = op->lin.m[i][4];
255 for (int j = 0; j < 4; j++)
256 sum = av_add_q64(sum, av_mul_q64(orig[j], op->lin.m[i][j]));
257 x[i] = sum;
258 }
259 return;
260 }
261 case SWS_OP_SCALE:
262 for (int i = 0; i < 4; i++)
263 x[i] = x[i].den ? av_mul_q64(x[i], op->scale.factor) : x[i];
264 return;
265 case SWS_OP_FILTER_H:
266 case SWS_OP_FILTER_V:
267 /* Filters have normalized energy by definition, so they don't
268 * conceptually modify individual components */
269 return;
270 case SWS_OP_LUT_3D:
271 /* 3D LUTs are treated as a black box, so set those values to NaN */
272 for (int i = 0; i < 3; i++)
273 x[i] = (AVRational64) {0};
274 return;
275 }
276
277 av_unreachable("Invalid operation type!");
278}
279
280enum {
283
285};
286
287/* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
289{
291 const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
292 return ((a & b) & flags_and) | ((a | b) & flags_or);
293}
294
295static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
297{
298 const AVRational64 posw = { weights->sum_positive, SWS_FILTER_SCALE };
299 const AVRational64 negw = { weights->sum_negative, SWS_FILTER_SCALE };
300 for (int i = 0; i < 4; i++) {
301 comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
302 comps->dep_in[i] = prev->dep_in[i];
303 /* Only point sampling preserves exactness */
304 if (weights->filter_size != 1)
305 comps->flags[i] &= ~SWS_COMP_EXACT;
306 /* Update min/max assuming extremes */
307 comps->min[i] = av_add_q64(av_mul_q64(prev->min[i], posw),
308 av_mul_q64(prev->max[i], negw));
309 comps->max[i] = av_add_q64(av_mul_q64(prev->min[i], negw),
310 av_mul_q64(prev->max[i], posw));
311 }
312}
313
314/* Infer + propagate known information about components */
316{
317 SwsComps prev = { .flags = {
319 }};
320
321 /* Forwards pass, propagates knowledge about the incoming pixel values */
322 for (int n = 0; n < ops->num_ops; n++) {
323 SwsOp *op = &ops->ops[n];
324
325 switch (op->op) {
326 case SWS_OP_LINEAR:
327 case SWS_OP_DITHER:
329 case SWS_OP_UNPACK:
330 case SWS_OP_FILTER_H:
331 case SWS_OP_FILTER_V:
332 case SWS_OP_LUT_3D:
333 break; /* special cases, handled below */
334 default:
335 memcpy(op->comps.min, prev.min, sizeof(prev.min));
336 memcpy(op->comps.max, prev.max, sizeof(prev.max));
337 ff_sws_apply_op_q(op, op->comps.min);
338 ff_sws_apply_op_q(op, op->comps.max);
339 break;
340 }
341
342 for (int i = 0; i < 4; i++) {
343 op->comps.flags[i] = SWS_COMP_IDENTITY;
344 op->comps.dep_in[i] = SWS_COMP_NONE;
345 }
346
347 #define FORWARD(I, J, EXPR) do { \
348 SwsCompFlags flags = prev.flags[J]; \
349 op->comps.flags[I] = merge_comp_flags(op->comps.flags[I], (EXPR)); \
350 op->comps.dep_in[I] |= prev.dep_in[J]; \
351 } while (0)
352
353 #define RESET(I) do { \
354 op->comps.flags[I] = SWS_COMP_GARBAGE; \
355 op->comps.min[I] = op->comps.max[I] = (AVRational64) {0}; \
356 op->comps.dep_in[I] = SWS_COMP_NONE; \
357 } while (0)
358
359 switch (op->op) {
360 case SWS_OP_READ:
361 /* Active components are taken from the user-provided values,
362 * other components are explicitly stripped */
363 for (int i = 0; i < op->rw.elems; i++) {
364 int idx = 0;
365 switch (op->rw.mode) {
366 case SWS_RW_PALETTE: idx = i; break;
367 case SWS_RW_PACKED: idx = i; break;
368 case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
369 }
370
372 op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
373 op->comps.min[i] = ops->comps_src.min[idx];
374 op->comps.max[i] = ops->comps_src.max[idx];
375 op->comps.dep_in[i] = SWS_COMP(i);
376
377 /**
378 * Don't mark packed or fractional reads as a copy, because the
379 * read operation implicitly unpacks the data into separate
380 * components. The only case in which op lists involving such
381 * reads can be refcopies is in the case of a true noop, which
382 * is already covered by the no-op check.
383 */
384 if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
385 op->comps.flags[i] |= SWS_COMP_COPY;
386 }
387
388 if (op->rw.filter.op) {
389 const SwsComps prev = op->comps;
390 apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
391 }
392 break;
394 for (int i = 0; i < 4; i++) {
396 op->comps.min[i] = prev.min[i];
397 op->comps.max[i] = prev.max[i];
398 }
399 break;
400 case SWS_OP_WRITE:
401 for (int i = 0; i < op->rw.elems; i++)
403 for (int i = 0; i < 4; i++)
404 FORWARD(i, i, flags);
405 break;
406 case SWS_OP_LSHIFT:
407 case SWS_OP_RSHIFT:
408 for (int i = 0; i < 4; i++)
410 break;
411 case SWS_OP_MIN:
412 case SWS_OP_MAX: {
413 AVRational64 *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
414 for (int i = 0; i < 4; i++) {
415 FORWARD(i, i, flags);
416 if (op->clamp.limit[i].den)
417 op->comps.flags[i] &= SWS_COMP_DIRTY;
418 if (!bound[i].den) /* reset undefined bounds to known range */
419 bound[i] = op->clamp.limit[i];
420 }
421 break;
422 }
423 case SWS_OP_DITHER:
424 for (int i = 0; i < 4; i++) {
425 FORWARD(i, i, flags);
426 op->comps.min[i] = prev.min[i];
427 op->comps.max[i] = prev.max[i];
428 if (op->dither.y_offset[i] < 0)
429 continue;
430 /* Strip zero flag because of the nonzero dithering offset */
431 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
432 op->comps.min[i] = av_add_q64(op->comps.min[i], op->dither.min);
433 op->comps.max[i] = av_add_q64(op->comps.max[i], op->dither.max);
434 }
435 break;
436 case SWS_OP_UNPACK:
437 for (int i = 0; i < 4; i++) {
438 const int pattern = op->pack.pattern[i];
439 if (pattern) {
440 av_assert1(pattern < 32);
442 op->comps.min[i] = Q(0);
443 op->comps.max[i] = Q((1ULL << pattern) - 1);
444 } else
445 RESET(i);
446 }
447 break;
448 case SWS_OP_PACK:
449 for (int i = 0; i < 4; i++) {
450 if (op->pack.pattern[i])
452 if (i > 0) /* clear remaining comps for sanity */
453 RESET(i);
454 }
455 break;
456 case SWS_OP_CLEAR:
457 for (int i = 0; i < 4; i++) {
458 if (SWS_COMP_TEST(op->clear.mask, i)) {
459 op->comps.flags[i] = SWS_COMP_CONST;
460 if (op->clear.value[i].num == 0)
461 op->comps.flags[i] |= SWS_COMP_ZERO;
462 if (op->clear.value[i].den == 1)
463 op->comps.flags[i] |= SWS_COMP_EXACT;
464 } else {
465 FORWARD(i, i, flags);
466 }
467 }
468 break;
469 case SWS_OP_SWIZZLE:
470 for (int i = 0; i < 4; i++)
471 FORWARD(i, op->swizzle.in[i], flags);
472 break;
473 case SWS_OP_CONVERT:
474 for (int i = 0; i < 4; i++) {
475 FORWARD(i, i, flags);
476 if (!(prev.flags[i] & SWS_COMP_EXACT) || op->convert.expand)
477 op->comps.flags[i] &= SWS_COMP_DIRTY;
478 if (ff_sws_pixel_type_is_int(op->convert.to))
479 op->comps.flags[i] |= SWS_COMP_EXACT;
480 }
481 break;
482 case SWS_OP_LINEAR:
483 for (int i = 0; i < 4; i++) {
484 AVRational64 min = Q(0), max = Q(0);
485 bool first = true;
486 for (int j = 0; j < 4; j++) {
487 const AVRational64 k = op->lin.m[i][j];
488 AVRational64 mink = av_mul_q64(prev.min[j], k);
489 AVRational64 maxk = av_mul_q64(prev.max[j], k);
490 if (k.num) {
491 FORWARD(i, j, flags);
492 if (k.den != 1) /* fractional coefficient */
493 op->comps.flags[i] &= ~SWS_COMP_EXACT;
494 if (k.num < 0)
495 FFSWAP(AVRational64, mink, maxk);
496 min = av_add_q64(min, mink);
497 max = av_add_q64(max, maxk);
498 if (!first || av_cmp_q64(k, Q(1)))
499 op->comps.flags[i] &= SWS_COMP_DIRTY;
500 first = false;
501 }
502 }
503 if (op->lin.m[i][4].num) { /* nonzero offset */
504 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
505 if (op->lin.m[i][4].den != 1) /* fractional offset */
506 op->comps.flags[i] &= ~SWS_COMP_EXACT;
507 min = av_add_q64(min, op->lin.m[i][4]);
508 max = av_add_q64(max, op->lin.m[i][4]);
509 }
510 op->comps.min[i] = min;
511 op->comps.max[i] = max;
512 }
513 break;
514 case SWS_OP_SCALE:
515 for (int i = 0; i < 4; i++) {
517 if (op->scale.factor.den != 1) /* fractional scale */
518 op->comps.flags[i] &= ~SWS_COMP_EXACT;
519 if (op->scale.factor.num < 0)
520 FFSWAP(AVRational64, op->comps.min[i], op->comps.max[i]);
521 }
522 break;
523 case SWS_OP_FILTER_H:
524 case SWS_OP_FILTER_V: {
525 apply_filter_weights(&op->comps, &prev, op->filter.kernel);
526 break;
527 }
528 case SWS_OP_LUT_3D:
529 for (int i = 0; i < 3; i++) {
530 /* 3x3 dependency matrix; strip all information except
531 * SWS_COMP_GARBAGE (for correctness validation) */
532 for (int j = 0; j < 3; j++)
534 /* LUT output domain is always scaled to full 16-bit range */
535 op->comps.min[i] = Q(0);
536 op->comps.max[i] = Q(UINT16_MAX);
537 }
538 /* Pass through alpha channel untouched */
539 FORWARD(3, 3, flags);
540 op->comps.min[3] = prev.min[3];
541 op->comps.max[3] = prev.max[3];
542 break;
543 case SWS_OP_INVALID:
544 case SWS_OP_TYPE_NB:
545 av_unreachable("Invalid operation type!");
546 }
547
548 prev = op->comps;
549 }
550
551 /* Backwards pass, solves for output component dependencies */
552 SwsCompMask need_out[4] = {0};
553
554 for (int n = ops->num_ops - 1; n >= 0; n--) {
555 SwsOp *op = &ops->ops[n];
556 SwsCompMask need_in[4] = {0};
557
558 for (int i = 0; i < 4; i++) {
559 op->comps.dep_out[i] = need_out[i];
560 if (!need_out[i])
561 RESET(i);
562 }
563
564 switch (op->op) {
565 case SWS_OP_READ:
566 case SWS_OP_WRITE:
567 for (int i = 0; i < op->rw.elems; i++)
568 need_in[i] = (op->op == SWS_OP_WRITE) ? SWS_COMP(i) : 0;
569 for (int i = op->rw.elems; i < 4; i++)
570 need_in[i] = need_out[i];
571 break;
573 case SWS_OP_LSHIFT:
574 case SWS_OP_RSHIFT:
575 case SWS_OP_CONVERT:
576 case SWS_OP_DITHER:
577 case SWS_OP_MIN:
578 case SWS_OP_MAX:
579 case SWS_OP_SCALE:
580 case SWS_OP_FILTER_H:
581 case SWS_OP_FILTER_V:
582 for (int i = 0; i < 4; i++)
583 need_in[i] = need_out[i];
584 break;
585 case SWS_OP_UNPACK:
586 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
587 need_in[0] |= need_out[i];
588 break;
589 case SWS_OP_PACK:
590 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
591 need_in[i] = need_out[0];
592 break;
593 case SWS_OP_CLEAR:
594 for (int i = 0; i < 4; i++) {
595 if (!SWS_COMP_TEST(op->clear.mask, i))
596 need_in[i] = need_out[i];
597 }
598 break;
599 case SWS_OP_SWIZZLE:
600 for (int i = 0; i < 4; i++)
601 need_in[op->swizzle.in[i]] |= need_out[i];
602 break;
603 case SWS_OP_LINEAR:
604 for (int i = 0; i < 4; i++) {
605 for (int j = 0; j < 4; j++) {
606 if (op->lin.m[i][j].num)
607 need_in[j] |= need_out[i];
608 }
609 }
610 break;
611 case SWS_OP_LUT_3D:
612 for (int i = 0; i < 3; i++)
613 need_in[i] = need_out[0] | need_out[1] | need_out[2];
614 need_in[3] = need_out[3];
615 break;
616 }
617
618 memcpy(need_out, need_in, sizeof(need_in));
619 }
620
621 #undef FORWARD
622 #undef RESET
623}
624
625static void op_uninit(SwsOp *op)
626{
627 switch (op->op) {
628 case SWS_OP_READ:
629 av_refstruct_unref(&op->rw.filter.kernel);
630 break;
631 case SWS_OP_DITHER:
632 av_refstruct_unref(&op->dither.matrix);
633 break;
634 case SWS_OP_FILTER_H:
635 case SWS_OP_FILTER_V:
636 av_refstruct_unref(&op->filter.kernel);
637 break;
638 case SWS_OP_LUT_3D:
639 av_refstruct_unref(&op->lut3d.lut);
640 break;
641 }
642
643 *op = (SwsOp) {0};
644}
645
647{
648 SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
649 if (!ops)
650 return NULL;
651
652 for (int i = 0; i < 4; i++)
653 ops->plane_src[i] = ops->plane_dst[i] = i;
654 ff_fmt_clear(&ops->src);
655 ff_fmt_clear(&ops->dst);
656 return ops;
657}
658
660{
661 SwsOpList *ops = *p_ops;
662 if (!ops)
663 return;
664
665 for (int i = 0; i < ops->num_ops; i++)
666 op_uninit(&ops->ops[i]);
667
668 av_freep(&ops->ops);
669 av_free(ops);
670 *p_ops = NULL;
671}
672
674{
675 SwsOpList *copy = av_malloc(sizeof(*copy));
676 if (!copy)
677 return NULL;
678
679 int num = ops->num_ops;
680 if (num)
681 num = 1 << av_ceil_log2(num);
682
683 *copy = *ops;
684 copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
685 if (!copy->ops) {
686 av_free(copy);
687 return NULL;
688 }
689
690 for (int i = 0; i < copy->num_ops; i++) {
691 const SwsOp *op = &copy->ops[i];
692 switch (op->op) {
693 case SWS_OP_READ:
694 if (op->rw.filter.kernel)
695 av_refstruct_ref(op->rw.filter.kernel);
696 break;
697 case SWS_OP_DITHER:
698 av_refstruct_ref(op->dither.matrix);
699 break;
700 case SWS_OP_FILTER_H:
701 case SWS_OP_FILTER_V:
702 av_refstruct_ref(op->filter.kernel);
703 break;
704 case SWS_OP_LUT_3D:
705 av_refstruct_ref_c(op->lut3d.lut);
706 break;
707 }
708 }
709
710 return copy;
711}
712
714{
715 if (!ops->num_ops)
716 return NULL;
717
718 const SwsOp *read = &ops->ops[0];
719 return read->op == SWS_OP_READ ? read : NULL;
720}
721
723{
724 if (!ops->num_ops)
725 return NULL;
726
727 const SwsOp *write = &ops->ops[ops->num_ops - 1];
728 return write->op == SWS_OP_WRITE ? write : NULL;
729}
730
731void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
732{
733 const int end = ops->num_ops - count;
734 av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
735 for (int i = 0; i < count; i++)
736 op_uninit(&ops->ops[index + i]);
737 for (int i = index; i < end; i++)
738 ops->ops[i] = ops->ops[i + count];
739 ops->num_ops = end;
740}
741
743{
744 void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
745 if (!ret) {
746 op_uninit(op);
747 return AVERROR(ENOMEM);
748 }
749
750 for (int i = ops->num_ops - 1; i > index; i--)
751 ops->ops[i] = ops->ops[i - 1];
752 ops->ops[index] = *op;
753 return 0;
754}
755
757{
758 return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
759}
760
762{
763 if (!ops->num_ops)
764 return true;
765
766 const SwsOp *read = ff_sws_op_list_input(ops);
767 const SwsOp *write = ff_sws_op_list_output(ops);
768 if (!read || !write || ops->num_ops > 2 ||
769 read->type != write->type ||
770 read->rw.mode != write->rw.mode ||
771 read->rw.elems != write->rw.elems ||
772 read->rw.frac != write->rw.frac ||
773 read->rw.filter.op || write->rw.filter.op)
774 return false;
775
776 /**
777 * Note that this check is unlikely to ever be hit in practice, since it
778 * would imply the existence of planar formats with different plane orders
779 * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
780 * However, the check is cheap and lets me sleep at night.
781 */
782 const int num_planes = ff_sws_rw_op_planes(read);
783 for (int i = 0; i < num_planes; i++) {
784 if (ops->plane_src[i] != ops->plane_dst[i])
785 return false;
786 }
787
788 return true;
789}
790
792{
793 int max_size = 0;
794 for (int i = 0; i < ops->num_ops; i++) {
795 const int size = ff_sws_pixel_type_size(ops->ops[i].type);
796 max_size = FFMAX(max_size, size);
797 }
798
799 return max_size;
800}
801
803{
804 uint32_t mask = 0;
805 for (int i = 0; i < 4; i++) {
806 for (int j = 0; j < 5; j++) {
807 if (av_cmp_q64(c->m[i][j], Q(i == j)))
808 mask |= SWS_MASK(i, j);
809 }
810 }
811 return mask;
812}
813
815{
817 return 'X';
818 else if (flags & SWS_COMP_ZERO)
819 return '0';
820 else if (flags & SWS_COMP_SWAPPED)
821 return 'z';
822 else if (flags & SWS_COMP_CONST)
823 return '$';
824 else if (flags & SWS_COMP_COPY)
825 return '=';
826 else if (flags & SWS_COMP_EXACT)
827 return '+';
828 else
829 return '.';
830}
831
832static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
833{
834 av_bprintf(bp, "{");
835 for (int i = 0; i < 4; i++) {
836 if (i)
837 av_bprintf(bp, " ");
838 av_bprintf(bp, "%s", deps[i] ? ff_sws_comp_mask_str(deps[i]) : "_");
839 }
840 av_bprintf(bp, "}");
841}
842
843static void print_q(AVBPrint *bp, const AVRational64 q)
844{
845 if (!q.den) {
846 av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
847 } else if (q.den == 1) {
848 av_bprintf(bp, "%"PRId64, q.num);
849 } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) {
850 av_bprintf(bp, "%f", av_q2d_64(q));
851 } else {
852 av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den);
853 }
854}
855
856static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
857{
858 av_bprintf(bp, "{");
859 for (int i = 0; i < 4; i++) {
860 if (i)
861 av_bprintf(bp, " ");
862 if (!SWS_COMP_TEST(mask, i)) {
863 av_bprintf(bp, "_");
864 } else {
865 print_q(bp, q4[i]);
866 }
867 }
868 av_bprintf(bp, "}");
869}
870
871static const char *const rw_mode_names[] = {
872 [SWS_RW_PLANAR] = "planar",
873 [SWS_RW_PACKED] = "packed",
874 [SWS_RW_PALETTE] = "palette"
875};
876
877void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
878{
879 const char *name = ff_sws_op_type_name(op->op);
881
882 switch (op->op) {
883 case SWS_OP_INVALID:
885 av_bprintf(bp, "%s", name);
886 break;
887 case SWS_OP_READ:
888 case SWS_OP_WRITE:
889 av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
890 op->rw.elems, rw_mode_names[op->rw.mode],
891 op->rw.frac);
892 if (!op->rw.filter.op)
893 break;
894 const SwsFilterWeights *kernel = op->rw.filter.kernel;
895 av_bprintf(bp, " + %d tap %s filter (%c)",
896 kernel->filter_size, kernel->name,
897 op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
898 break;
899 case SWS_OP_LSHIFT:
900 av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
901 break;
902 case SWS_OP_RSHIFT:
903 av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
904 break;
905 case SWS_OP_PACK:
906 case SWS_OP_UNPACK:
907 av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
908 op->pack.pattern[0], op->pack.pattern[1],
909 op->pack.pattern[2], op->pack.pattern[3]);
910 break;
911 case SWS_OP_CLEAR:
912 av_bprintf(bp, "%-20s: ", name);
913 print_q4(bp, op->clear.value, mask & op->clear.mask);
914 break;
915 case SWS_OP_SWIZZLE:
916 av_bprintf(bp, "%-20s: %d%d%d%d", name,
917 op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
918 break;
919 case SWS_OP_CONVERT:
920 av_bprintf(bp, "%-20s: %s -> %s%s", name,
922 ff_sws_pixel_type_name(op->convert.to),
923 op->convert.expand ? " (expand)" : "");
924 break;
925 case SWS_OP_DITHER:
926 av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
927 1 << op->dither.size_log2, 1 << op->dither.size_log2,
928 op->dither.y_offset[0], op->dither.y_offset[1],
929 op->dither.y_offset[2], op->dither.y_offset[3]);
930 break;
931 case SWS_OP_MIN:
932 av_bprintf(bp, "%-20s: x <= ", name);
933 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
934 break;
935 case SWS_OP_MAX:
936 av_bprintf(bp, "%-20s: ", name);
937 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
938 av_bprintf(bp, " <= x");
939 break;
940 case SWS_OP_LINEAR:
941 av_bprintf(bp, "%-20s: [", name);
942 for (int i = 0; i < 4; i++) {
943 av_bprintf(bp, "%s[", i ? " " : "");
944 for (int j = 0; j < 5; j++) {
945 av_bprintf(bp, j ? " " : "");
946 print_q(bp, op->lin.m[i][j]);
947 }
948 av_bprintf(bp, "]");
949 }
950 av_bprintf(bp, "]");
951 break;
952 case SWS_OP_SCALE:
953 av_bprintf(bp, "%-20s: * %"PRId64, name, op->scale.factor.num);
954 if (op->scale.factor.den != 1)
955 av_bprintf(bp, "/%"PRId64, op->scale.factor.den);
956 break;
957 case SWS_OP_FILTER_H:
958 case SWS_OP_FILTER_V: {
959 const SwsFilterWeights *kernel = op->filter.kernel;
960 av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
961 kernel->src_size, kernel->dst_size,
962 kernel->name, kernel->filter_size);
963 break;
964 }
965 case SWS_OP_LUT_3D:
966 av_bprintf(bp, "%-20s: %s", name, op->lut3d.dynamic ? "dynamic" : "static");
967 break;
968 case SWS_OP_TYPE_NB:
969 break;
970 }
971}
972
973static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
974{
975 bool inorder = true;
976 for (int i = 0; i < nb_planes; i++)
977 inorder &= order[i] == i;
978 if (inorder)
979 return;
980
981 av_bprintf(bp, ", via {");
982 for (int i = 0; i < nb_planes; i++)
983 av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
984 av_bprintf(bp, "}");
985}
986
987void ff_sws_op_list_print(void *log, int lev, int lev_extra,
988 const SwsOpList *ops)
989{
990 AVBPrint bp;
991 if (!ops->num_ops) {
992 av_log(log, lev, " (empty)\n");
993 return;
994 }
995
997
998 for (int i = 0; i < ops->num_ops; i++) {
999 const SwsOp *op = &ops->ops[i];
1001 av_bprint_clear(&bp);
1002 av_bprintf(&bp, " [%3s %c%c%c%c] ",
1004 describe_comp_flags(op->comps.flags[0]),
1005 describe_comp_flags(op->comps.flags[1]),
1006 describe_comp_flags(op->comps.flags[2]),
1007 describe_comp_flags(op->comps.flags[3]));
1008
1009 ff_sws_op_desc(&bp, op);
1010
1011 if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
1012 const int planes = ff_sws_rw_op_planes(op);
1014 op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
1015 }
1016
1018 av_log(log, lev, "%s\n", bp.str);
1019
1020 /* Only print value ranges if any are relevant */
1021 SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
1022 ff_sws_comp_mask_q4(op->comps.max);
1023 if (range_mask & mask) {
1024 av_bprint_clear(&bp);
1025 av_bprintf(&bp, " min: ");
1026 print_q4(&bp, op->comps.min, mask);
1027 av_bprintf(&bp, ", max: ");
1028 print_q4(&bp, op->comps.max, mask);
1030 av_log(log, lev_extra, "%s\n", bp.str);
1031 }
1032
1033 bool has_deps = false;
1034 for (int i = 0; i < 4; i++)
1035 has_deps |= op->comps.dep_in[i] || op->comps.dep_out[i];
1036 if (has_deps) {
1037 av_bprint_clear(&bp);
1038 av_bprintf(&bp, " inputs: ");
1039 print_deps(&bp, op->comps.dep_in);
1040 av_bprintf(&bp, ", outputs: ");
1041 print_deps(&bp, op->comps.dep_out);
1043 av_log(log, lev_extra, "%s\n", bp.str);
1044 }
1045
1046 }
1047
1048 av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
1049}
const SwsOpBackend backend_aarch64
Definition ops.c:268
static double val(void *priv, double ch)
Definition aeval.c:77
static double bound(const double threshold, const double val)
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition avassert.h:68
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition avassert.h:58
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
AVBPrint public header.
#define AV_BPRINT_SIZE_AUTOMATIC
byte swapping routines
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
static LevelCodes lev[4+3+3]
Definition clearvideo.c:80
#define av_ceil_log2
Definition common.h:97
#define NULL
Definition coverity.c:32
#define min(a, b)
#define max(a, b)
#define print_q(k, v, s)
Definition ffprobe.c:450
static void ff_fmt_clear(SwsFormat *fmt)
Definition format.h:90
AVRational64 av_mul_q64(AVRational64 b, AVRational64 c)
Multiply two 64-bit rationals.
Definition rational64.c:124
int av_cmp_q64(AVRational64 a, AVRational64 b)
Compare two 64-bit rationals.
Definition rational64.c:108
AVRational64 av_add_q64(AVRational64 b, AVRational64 c)
Add two 64-bit rationals.
Definition rational64.c:135
static double av_q2d_64(AVRational64 a)
Convert an AVRational64 to a double.
Definition rational64.h:90
static AVRational64 av_make_q64(int64_t num, int64_t den)
Create an AVRational64.
Definition rational64.h:64
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition bprint.c:227
#define AVERROR(e)
Definition error.h:45
void * av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, const uint8_t *elem_data)
Add an element of size elem_size to a dynamic array.
Definition mem.c:341
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition mem.c:302
int index
Definition gxfenc.c:90
int a
static const int weights[]
Definition hevc_pel.c:32
#define Q(q)
cl_device_type type
#define b
Definition input.c:43
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition intra.c:278
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition anm.c:76
static int shift(int a, int b)
Definition bonk.c:261
static int16_t mult(Float11 *f1, Float11 *f2)
Definition g726.c:60
Macro definitions for various function/variable attributes.
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
Definition filters.h:40
static const struct @257111027162314367033347246032313251342043035002 planes[]
static const uint16_t mask[17]
Definition lzw.c:38
#define FFSWAP(type, a, b)
Definition macros.h:52
#define FFMAX(a, b)
Definition macros.h:47
Memory handling functions.
int ff_sws_op_list_max_size(const SwsOpList *ops)
Returns the size of the largest pixel type used in ops.
Definition ops.c:791
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition ops.c:315
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition ops.c:877
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition ops.c:802
static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
Definition ops.c:856
static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
Definition ops.c:973
static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
Definition ops.c:832
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition ops.c:742
const SwsOpBackend backend_x86
Definition ops.c:705
static void op_uninit(SwsOp *op)
Definition ops.c:625
const SwsOp * ff_sws_op_list_input(const SwsOpList *ops)
Returns the input operation for a given op list, or NULL if there is none (e.g.
Definition ops.c:713
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition ops.c:659
const SwsOpBackend *const ff_sws_op_backends[]
Definition ops.c:42
static AVRational64 av_min_q64(AVRational64 a, AVRational64 b)
Definition ops.c:147
const SwsOpBackend backend_murder
Definition ops_memcpy.c:147
int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op)
These will take over ownership of op and set it to {0}, even on failure.
Definition ops.c:756
void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz)
Definition ops.c:110
SwsOpList * ff_sws_op_list_alloc(void)
Definition ops.c:646
#define FORWARD(I, J, EXPR)
const char * ff_sws_op_type_name(SwsOpType op)
Definition ops.c:71
@ SWS_COMP_IDENTITY
Definition ops.c:281
@ SWS_COMP_DIRTY
Definition ops.c:284
static AVRational64 av_max_q64(AVRational64 a, AVRational64 b)
Definition ops.c:152
static char describe_comp_flags(SwsCompFlags flags)
Definition ops.c:814
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition ops.c:123
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition ops.c:56
static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
Definition ops.c:288
SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
Definition ops.c:100
#define RESET(I)
int ff_sws_rw_op_planes(const SwsOp *op)
Return the number of planes involved in a read/write operation.
Definition ops.c:133
const SwsOp * ff_sws_op_list_output(const SwsOpList *ops)
Returns the output operation for a given op list, or NULL if there is none.
Definition ops.c:722
bool ff_sws_op_list_is_noop(const SwsOpList *ops)
Returns whether an op list represents a true no-op operation, i.e.
Definition ops.c:761
void ff_sws_op_list_print(void *log, int lev, int lev_extra, const SwsOpList *ops)
Print out the contents of an operation list.
Definition ops.c:987
static const char *const rw_mode_names[]
Definition ops.c:871
void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4])
Apply an operation to an AVRational64.
Definition ops.c:157
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
Definition ops.c:731
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
Definition ops.c:673
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition ops.c:295
SwsOpType
Copyright (C) 2025 Niklas Haas.
Definition ops.h:36
@ SWS_OP_TYPE_NB
Definition ops.h:69
@ SWS_OP_INVALID
Definition ops.h:37
@ SWS_OP_RSHIFT
Definition ops.h:49
@ SWS_OP_SWIZZLE
Definition ops.h:43
@ SWS_OP_LSHIFT
Definition ops.h:48
@ SWS_OP_FILTER_V
Definition ops.h:64
@ SWS_OP_SCALE
Definition ops.h:56
@ SWS_OP_FILTER_H
Definition ops.h:63
@ SWS_OP_WRITE
Definition ops.h:41
@ SWS_OP_READ
Definition ops.h:40
@ SWS_OP_CLEAR
Definition ops.h:52
@ SWS_OP_SWAP_BYTES
Definition ops.h:42
@ SWS_OP_MIN
Definition ops.h:54
@ SWS_OP_UNPACK
Definition ops.h:46
@ SWS_OP_LINEAR
Definition ops.h:59
@ SWS_OP_PACK
Definition ops.h:47
@ SWS_OP_DITHER
Definition ops.h:60
@ SWS_OP_MAX
Definition ops.h:55
@ SWS_OP_LUT_3D
Definition ops.h:67
@ SWS_OP_CONVERT
Definition ops.h:53
@ SWS_RW_PALETTE
Definition ops.h:109
@ SWS_RW_PLANAR
Note: 1-component reads are either SWS_RW_PLANAR or SWS_RW_PACKED, depending on the underlying interp...
Definition ops.h:107
@ SWS_RW_PACKED
Definition ops.h:108
SwsCompFlags
Definition ops.h:77
@ SWS_COMP_CONST
Definition ops.h:83
@ SWS_COMP_ZERO
Definition ops.h:80
@ SWS_COMP_EXACT
Definition ops.h:79
@ SWS_COMP_SWAPPED
Definition ops.h:81
@ SWS_COMP_COPY
Definition ops.h:82
@ SWS_COMP_GARBAGE
Definition ops.h:78
#define SWS_OP_NEEDED(op, idx)
Definition ops.h:265
static AVRational64 ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
static void ff_sws_pack_op_decode(const SwsOp *op, uint64_t mask[4], int shift[4])
#define av_malloc(s)
Definition ops_static.c:52
const char * name
Definition qsvenc.c:142
Utilities for rational number calculation.
void av_refstruct_unref(void *objp)
Decrement the reference count of the underlying object and automatically free the object if there are...
Definition refstruct.c:120
const void * av_refstruct_ref_c(const void *obj)
Analog of av_refstruct_ref(), but for constant objects.
Definition refstruct.c:149
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition refstruct.c:140
#define av_bswap32
Definition bswap.h:47
#define av_bswap16
Definition bswap.h:28
64-bit Rational number (pair of numerator and denominator).
Definition rational64.h:52
int64_t num
Numerator.
Definition rational64.h:53
int64_t den
Denominator.
Definition rational64.h:54
Definition ops.h:86
SwsCompMask dep_in[4]
Definition ops.h:94
SwsCompFlags flags[4]
Definition ops.h:87
AVRational64 min[4]
Definition ops.h:91
AVRational64 max[4]
Definition ops.h:91
Represents a computed filter kernel.
Definition filters.h:85
int src_size
Copy of the parameters used to generate this filter, for reference.
Definition filters.h:110
char name[16]
Extra metadata about the filter, used to inform the optimizer / range tracker about the filter's beha...
Definition filters.h:119
int filter_size
The number of source texels to convolve over for each row.
Definition filters.h:89
Helper struct for representing a list of operations.
Definition ops.h:293
SwsFormat dst
Definition ops.h:298
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition ops.h:312
uint8_t plane_src[4]
Definition ops.h:301
uint8_t plane_dst[4]
Definition ops.h:301
SwsOp * ops
Definition ops.h:294
int num_ops
Definition ops.h:295
SwsFormat src
Definition ops.h:298
Definition ops.h:237
SwsPixelType type
Definition ops.h:239
SwsOpType op
Definition ops.h:238
SwsReadWriteOp rw
Definition ops.h:242
SwsReadWriteMode mode
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition ops.h:122
SwsOpType op
Definition ops.h:134
uint8_t frac
Definition ops.h:124
uint8_t elems
Definition ops.h:123
struct SwsReadWriteOp::@312356277033155231251141106170064356360153154105 filter
Filter kernel to apply to each plane while sampling.
uint8_t in[4]
Definition ops.h:155
#define av_free(p)
#define av_mallocz(s)
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
int size
@ SWS_COMP_NONE
Definition uops.h:95
SwsPixelType
Definition uops.h:39
@ SWS_PIXEL_F32
Definition uops.h:44
@ SWS_PIXEL_U32
Definition uops.h:43
@ SWS_PIXEL_U16
Definition uops.h:42
@ SWS_PIXEL_TYPE_NB
Definition uops.h:45
@ SWS_PIXEL_NONE
Definition uops.h:40
@ SWS_PIXEL_U8
Definition uops.h:41
#define SWS_COMP(X)
Definition uops.h:97
#define ff_sws_comp_mask_str(mask)
Definition uops.h:110
#define SWS_COMP_TEST(mask, X)
Definition uops.h:98
#define SWS_MASK(I, J)
Definition uops.h:231
static av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition uops.h:63
uint8_t SwsCompMask
Bit-mask of components.
Definition uops.h:93
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition uops.h:50
static void copy(const float *p1, float *p2, const int length)
static double c[64]