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 ff_cmp_q64(a, b) == 1 ? b : a;
150}
151
153{
154 return ff_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 ? ff_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 for (int i = 0; i < 4; i++)
228 x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
229 }
230 return;
231 case SWS_OP_DITHER:
233 for (int i = 0; i < 4; i++) {
234 if (op->dither.y_offset[i] >= 0 && x[i].den)
235 x[i] = ff_add_q64(x[i], ff_make_q64(1, 2));
236 }
237 return;
238 case SWS_OP_MIN:
239 for (int i = 0; i < 4; i++)
240 x[i] = av_min_q64(x[i], op->clamp.limit[i]);
241 return;
242 case SWS_OP_MAX:
243 for (int i = 0; i < 4; i++)
244 x[i] = av_max_q64(x[i], op->clamp.limit[i]);
245 return;
246 case SWS_OP_LINEAR: {
247 const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
248 for (int i = 0; i < 4; i++) {
249 AVRational64 sum = op->lin.m[i][4];
250 for (int j = 0; j < 4; j++)
251 sum = ff_add_q64(sum, ff_mul_q64(orig[j], op->lin.m[i][j]));
252 x[i] = sum;
253 }
254 return;
255 }
256 case SWS_OP_SCALE:
257 for (int i = 0; i < 4; i++)
258 x[i] = x[i].den ? ff_mul_q64(x[i], op->scale.factor) : x[i];
259 return;
260 case SWS_OP_FILTER_H:
261 case SWS_OP_FILTER_V:
262 /* Filters have normalized energy by definition, so they don't
263 * conceptually modify individual components */
264 return;
265 case SWS_OP_LUT_3D:
266 /* 3D LUTs are treated as a black box, so set those values to NaN */
267 for (int i = 0; i < 3; i++)
268 x[i] = (AVRational64) {0};
269 return;
270 }
271
272 av_unreachable("Invalid operation type!");
273}
274
275enum {
278
280};
281
282/* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
284{
286 const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
287 return ((a & b) & flags_and) | ((a | b) & flags_or);
288}
289
290static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
292{
293 const AVRational64 posw = { weights->sum_positive, SWS_FILTER_SCALE };
294 const AVRational64 negw = { weights->sum_negative, SWS_FILTER_SCALE };
295 for (int i = 0; i < 4; i++) {
296 comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
297 comps->dep_in[i] = prev->dep_in[i];
298 /* Only point sampling preserves exactness */
299 if (weights->filter_size != 1)
300 comps->flags[i] &= ~SWS_COMP_EXACT;
301 /* Update min/max assuming extremes */
302 comps->min[i] = ff_add_q64(ff_mul_q64(prev->min[i], posw),
303 ff_mul_q64(prev->max[i], negw));
304 comps->max[i] = ff_add_q64(ff_mul_q64(prev->min[i], negw),
305 ff_mul_q64(prev->max[i], posw));
306 }
307}
308
309/* Infer + propagate known information about components */
311{
312 SwsComps prev = { .flags = {
314 }};
315
316 /* Forwards pass, propagates knowledge about the incoming pixel values */
317 for (int n = 0; n < ops->num_ops; n++) {
318 SwsOp *op = &ops->ops[n];
319
320 switch (op->op) {
321 case SWS_OP_LINEAR:
322 case SWS_OP_DITHER:
324 case SWS_OP_UNPACK:
325 case SWS_OP_FILTER_H:
326 case SWS_OP_FILTER_V:
327 case SWS_OP_LUT_3D:
328 break; /* special cases, handled below */
329 default:
330 memcpy(op->comps.min, prev.min, sizeof(prev.min));
331 memcpy(op->comps.max, prev.max, sizeof(prev.max));
332 ff_sws_apply_op_q(op, op->comps.min);
333 ff_sws_apply_op_q(op, op->comps.max);
334 break;
335 }
336
337 for (int i = 0; i < 4; i++) {
338 op->comps.flags[i] = SWS_COMP_IDENTITY;
339 op->comps.dep_in[i] = SWS_COMP_NONE;
340 }
341
342 #define FORWARD(I, J, EXPR) do { \
343 SwsCompFlags flags = prev.flags[J]; \
344 op->comps.flags[I] = merge_comp_flags(op->comps.flags[I], (EXPR)); \
345 op->comps.dep_in[I] |= prev.dep_in[J]; \
346 } while (0)
347
348 #define RESET(I) do { \
349 op->comps.flags[I] = SWS_COMP_GARBAGE; \
350 op->comps.min[I] = op->comps.max[I] = (AVRational64) {0}; \
351 op->comps.dep_in[I] = SWS_COMP_NONE; \
352 } while (0)
353
354 switch (op->op) {
355 case SWS_OP_READ:
356 /* Active components are taken from the user-provided values,
357 * other components are explicitly stripped */
358 for (int i = 0; i < op->rw.elems; i++) {
359 int idx = 0;
360 switch (op->rw.mode) {
361 case SWS_RW_PALETTE: idx = i; break;
362 case SWS_RW_PACKED: idx = i; break;
363 case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
364 }
365
367 op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
368 op->comps.min[i] = ops->comps_src.min[idx];
369 op->comps.max[i] = ops->comps_src.max[idx];
370 op->comps.dep_in[i] = SWS_COMP(i);
371
372 /**
373 * Don't mark packed or fractional reads as a copy, because the
374 * read operation implicitly unpacks the data into separate
375 * components. The only case in which op lists involving such
376 * reads can be refcopies is in the case of a true noop, which
377 * is already covered by the no-op check.
378 */
379 if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
380 op->comps.flags[i] |= SWS_COMP_COPY;
381 }
382
383 if (op->rw.filter.op) {
384 const SwsComps prev = op->comps;
385 apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
386 }
387 break;
389 for (int i = 0; i < 4; i++) {
391 op->comps.min[i] = prev.min[i];
392 op->comps.max[i] = prev.max[i];
393 }
394 break;
395 case SWS_OP_WRITE:
396 for (int i = 0; i < op->rw.elems; i++)
398 for (int i = 0; i < 4; i++)
399 FORWARD(i, i, flags);
400 break;
401 case SWS_OP_LSHIFT:
402 case SWS_OP_RSHIFT:
403 for (int i = 0; i < 4; i++)
405 break;
406 case SWS_OP_MIN:
407 case SWS_OP_MAX: {
408 AVRational64 *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
409 for (int i = 0; i < 4; i++) {
410 FORWARD(i, i, flags);
411 if (op->clamp.limit[i].den)
412 op->comps.flags[i] &= SWS_COMP_DIRTY;
413 if (!bound[i].den) /* reset undefined bounds to known range */
414 bound[i] = op->clamp.limit[i];
415 }
416 break;
417 }
418 case SWS_OP_DITHER:
419 for (int i = 0; i < 4; i++) {
420 FORWARD(i, i, flags);
421 op->comps.min[i] = prev.min[i];
422 op->comps.max[i] = prev.max[i];
423 if (op->dither.y_offset[i] < 0)
424 continue;
425 /* Strip zero flag because of the nonzero dithering offset */
426 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
427 op->comps.min[i] = ff_add_q64(op->comps.min[i], op->dither.min);
428 op->comps.max[i] = ff_add_q64(op->comps.max[i], op->dither.max);
429 }
430 break;
431 case SWS_OP_UNPACK:
432 for (int i = 0; i < 4; i++) {
433 const int pattern = op->pack.pattern[i];
434 if (pattern) {
435 av_assert1(pattern < 32);
437 op->comps.min[i] = Q(0);
438 op->comps.max[i] = Q((1ULL << pattern) - 1);
439 } else
440 RESET(i);
441 }
442 break;
443 case SWS_OP_PACK:
444 for (int i = 0; i < 4; i++) {
445 if (op->pack.pattern[i])
447 if (i > 0) /* clear remaining comps for sanity */
448 RESET(i);
449 }
450 break;
451 case SWS_OP_CLEAR:
452 for (int i = 0; i < 4; i++) {
453 if (SWS_COMP_TEST(op->clear.mask, i)) {
454 op->comps.flags[i] = SWS_COMP_CONST;
455 if (op->clear.value[i].num == 0)
456 op->comps.flags[i] |= SWS_COMP_ZERO;
457 if (op->clear.value[i].den == 1)
458 op->comps.flags[i] |= SWS_COMP_EXACT;
459 } else {
460 FORWARD(i, i, flags);
461 }
462 }
463 break;
464 case SWS_OP_SWIZZLE:
465 for (int i = 0; i < 4; i++)
466 FORWARD(i, op->swizzle.in[i], flags);
467 break;
468 case SWS_OP_CONVERT:
469 for (int i = 0; i < 4; i++) {
470 FORWARD(i, i, flags);
471 if (!(prev.flags[i] & SWS_COMP_EXACT))
472 op->comps.flags[i] &= SWS_COMP_DIRTY;
473 if (ff_sws_pixel_type_is_int(op->convert.to))
474 op->comps.flags[i] |= SWS_COMP_EXACT;
475 }
476 break;
477 case SWS_OP_LINEAR:
478 for (int i = 0; i < 4; i++) {
479 AVRational64 min = Q(0), max = Q(0);
480 bool first = true;
481 for (int j = 0; j < 4; j++) {
482 const AVRational64 k = op->lin.m[i][j];
483 AVRational64 mink = ff_mul_q64(prev.min[j], k);
484 AVRational64 maxk = ff_mul_q64(prev.max[j], k);
485 if (k.num) {
486 FORWARD(i, j, flags);
487 if (k.den != 1) /* fractional coefficient */
488 op->comps.flags[i] &= ~SWS_COMP_EXACT;
489 if (k.num < 0)
490 FFSWAP(AVRational64, mink, maxk);
491 min = ff_add_q64(min, mink);
492 max = ff_add_q64(max, maxk);
493 if (!first || ff_cmp_q64(k, Q(1)))
494 op->comps.flags[i] &= SWS_COMP_DIRTY;
495 first = false;
496 }
497 }
498 if (op->lin.m[i][4].num) { /* nonzero offset */
499 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
500 if (op->lin.m[i][4].den != 1) /* fractional offset */
501 op->comps.flags[i] &= ~SWS_COMP_EXACT;
502 min = ff_add_q64(min, op->lin.m[i][4]);
503 max = ff_add_q64(max, op->lin.m[i][4]);
504 }
505 op->comps.min[i] = min;
506 op->comps.max[i] = max;
507 }
508 break;
509 case SWS_OP_SCALE:
510 for (int i = 0; i < 4; i++) {
512 if (op->scale.factor.den != 1) /* fractional scale */
513 op->comps.flags[i] &= ~SWS_COMP_EXACT;
514 if (op->scale.factor.num < 0)
515 FFSWAP(AVRational64, op->comps.min[i], op->comps.max[i]);
516 }
517 break;
518 case SWS_OP_FILTER_H:
519 case SWS_OP_FILTER_V: {
520 apply_filter_weights(&op->comps, &prev, op->filter.kernel);
521 break;
522 }
523 case SWS_OP_LUT_3D:
524 for (int i = 0; i < 3; i++) {
525 /* 3x3 dependency matrix; strip all information except
526 * SWS_COMP_GARBAGE (for correctness validation) */
527 for (int j = 0; j < 3; j++)
529 /* LUT output domain is always scaled to full 16-bit range */
530 op->comps.min[i] = Q(0);
531 op->comps.max[i] = Q(UINT16_MAX);
532 }
533 /* Pass through alpha channel untouched */
534 FORWARD(3, 3, flags);
535 op->comps.min[3] = prev.min[3];
536 op->comps.max[3] = prev.max[3];
537 break;
538 case SWS_OP_INVALID:
539 case SWS_OP_TYPE_NB:
540 av_unreachable("Invalid operation type!");
541 }
542
543 prev = op->comps;
544 }
545
546 /* Backwards pass, solves for output component dependencies */
547 SwsCompMask need_out[4] = {0};
548
549 for (int n = ops->num_ops - 1; n >= 0; n--) {
550 SwsOp *op = &ops->ops[n];
551 SwsCompMask need_in[4] = {0};
552
553 for (int i = 0; i < 4; i++) {
554 op->comps.dep_out[i] = need_out[i];
555 if (!need_out[i])
556 RESET(i);
557 }
558
559 switch (op->op) {
560 case SWS_OP_READ:
561 case SWS_OP_WRITE:
562 for (int i = 0; i < op->rw.elems; i++)
563 need_in[i] = (op->op == SWS_OP_WRITE) ? SWS_COMP(i) : 0;
564 for (int i = op->rw.elems; i < 4; i++)
565 need_in[i] = need_out[i];
566 break;
568 case SWS_OP_LSHIFT:
569 case SWS_OP_RSHIFT:
570 case SWS_OP_CONVERT:
571 case SWS_OP_DITHER:
572 case SWS_OP_MIN:
573 case SWS_OP_MAX:
574 case SWS_OP_SCALE:
575 case SWS_OP_FILTER_H:
576 case SWS_OP_FILTER_V:
577 for (int i = 0; i < 4; i++)
578 need_in[i] = need_out[i];
579 break;
580 case SWS_OP_UNPACK:
581 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
582 need_in[0] |= need_out[i];
583 break;
584 case SWS_OP_PACK:
585 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
586 need_in[i] = need_out[0];
587 break;
588 case SWS_OP_CLEAR:
589 for (int i = 0; i < 4; i++) {
590 if (!SWS_COMP_TEST(op->clear.mask, i))
591 need_in[i] = need_out[i];
592 }
593 break;
594 case SWS_OP_SWIZZLE:
595 for (int i = 0; i < 4; i++)
596 need_in[op->swizzle.in[i]] |= need_out[i];
597 break;
598 case SWS_OP_LINEAR:
599 for (int i = 0; i < 4; i++) {
600 for (int j = 0; j < 4; j++) {
601 if (op->lin.m[i][j].num)
602 need_in[j] |= need_out[i];
603 }
604 }
605 break;
606 case SWS_OP_LUT_3D:
607 for (int i = 0; i < 3; i++)
608 need_in[i] = need_out[0] | need_out[1] | need_out[2];
609 need_in[3] = need_out[3];
610 break;
611 }
612
613 memcpy(need_out, need_in, sizeof(need_in));
614 }
615
616 #undef FORWARD
617 #undef RESET
618}
619
620static void op_uninit(SwsOp *op)
621{
622 switch (op->op) {
623 case SWS_OP_READ:
624 av_refstruct_unref(&op->rw.filter.kernel);
625 break;
626 case SWS_OP_DITHER:
627 av_refstruct_unref(&op->dither.matrix);
628 break;
629 case SWS_OP_FILTER_H:
630 case SWS_OP_FILTER_V:
631 av_refstruct_unref(&op->filter.kernel);
632 break;
633 case SWS_OP_LUT_3D:
634 av_refstruct_unref(&op->lut3d.lut);
635 break;
636 }
637
638 *op = (SwsOp) {0};
639}
640
642{
643 SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
644 if (!ops)
645 return NULL;
646
647 for (int i = 0; i < 4; i++)
648 ops->plane_src[i] = ops->plane_dst[i] = i;
649 ff_fmt_clear(&ops->src);
650 ff_fmt_clear(&ops->dst);
651 return ops;
652}
653
655{
656 SwsOpList *ops = *p_ops;
657 if (!ops)
658 return;
659
660 for (int i = 0; i < ops->num_ops; i++)
661 op_uninit(&ops->ops[i]);
662
663 av_freep(&ops->ops);
664 av_free(ops);
665 *p_ops = NULL;
666}
667
669{
670 SwsOpList *copy = av_malloc(sizeof(*copy));
671 if (!copy)
672 return NULL;
673
674 int num = ops->num_ops;
675 if (num)
676 num = 1 << av_ceil_log2(num);
677
678 *copy = *ops;
679 copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
680 if (!copy->ops) {
681 av_free(copy);
682 return NULL;
683 }
684
685 for (int i = 0; i < copy->num_ops; i++) {
686 const SwsOp *op = &copy->ops[i];
687 switch (op->op) {
688 case SWS_OP_READ:
689 if (op->rw.filter.kernel)
690 av_refstruct_ref(op->rw.filter.kernel);
691 break;
692 case SWS_OP_DITHER:
693 av_refstruct_ref(op->dither.matrix);
694 break;
695 case SWS_OP_FILTER_H:
696 case SWS_OP_FILTER_V:
697 av_refstruct_ref(op->filter.kernel);
698 break;
699 case SWS_OP_LUT_3D:
700 av_refstruct_ref_c(op->lut3d.lut);
701 break;
702 }
703 }
704
705 return copy;
706}
707
709{
710 if (!ops->num_ops)
711 return NULL;
712
713 const SwsOp *read = &ops->ops[0];
714 return read->op == SWS_OP_READ ? read : NULL;
715}
716
718{
719 if (!ops->num_ops)
720 return NULL;
721
722 const SwsOp *write = &ops->ops[ops->num_ops - 1];
723 return write->op == SWS_OP_WRITE ? write : NULL;
724}
725
726void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
727{
728 const int end = ops->num_ops - count;
729 av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
730 for (int i = 0; i < count; i++)
731 op_uninit(&ops->ops[index + i]);
732 for (int i = index; i < end; i++)
733 ops->ops[i] = ops->ops[i + count];
734 ops->num_ops = end;
735}
736
738{
739 void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
740 if (!ret) {
741 op_uninit(op);
742 return AVERROR(ENOMEM);
743 }
744
745 for (int i = ops->num_ops - 1; i > index; i--)
746 ops->ops[i] = ops->ops[i - 1];
747 ops->ops[index] = *op;
748 return 0;
749}
750
752{
753 return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
754}
755
757{
758 if (!ops->num_ops)
759 return true;
760
761 const SwsOp *read = ff_sws_op_list_input(ops);
762 const SwsOp *write = ff_sws_op_list_output(ops);
763 if (!read || !write || ops->num_ops > 2 ||
764 read->type != write->type ||
765 read->rw.mode != write->rw.mode ||
766 read->rw.elems != write->rw.elems ||
767 read->rw.frac != write->rw.frac ||
768 read->rw.filter.op || write->rw.filter.op)
769 return false;
770
771 /**
772 * Note that this check is unlikely to ever be hit in practice, since it
773 * would imply the existence of planar formats with different plane orders
774 * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
775 * However, the check is cheap and lets me sleep at night.
776 */
777 const int num_planes = ff_sws_rw_op_planes(read);
778 for (int i = 0; i < num_planes; i++) {
779 if (ops->plane_src[i] != ops->plane_dst[i])
780 return false;
781 }
782
783 return true;
784}
785
787{
788 int max_size = 0;
789 for (int i = 0; i < ops->num_ops; i++) {
790 const int size = ff_sws_pixel_type_size(ops->ops[i].type);
791 max_size = FFMAX(max_size, size);
792 }
793
794 return max_size;
795}
796
798{
799 uint32_t mask = 0;
800 for (int i = 0; i < 4; i++) {
801 for (int j = 0; j < 5; j++) {
802 if (ff_cmp_q64(c->m[i][j], Q(i == j)))
803 mask |= SWS_MASK(i, j);
804 }
805 }
806 return mask;
807}
808
810{
812 return 'X';
813 else if (flags & SWS_COMP_ZERO)
814 return '0';
815 else if (flags & SWS_COMP_SWAPPED)
816 return 'z';
817 else if (flags & SWS_COMP_CONST)
818 return '$';
819 else if (flags & SWS_COMP_COPY)
820 return '=';
821 else if (flags & SWS_COMP_EXACT)
822 return '+';
823 else
824 return '.';
825}
826
827static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
828{
829 av_bprintf(bp, "{");
830 for (int i = 0; i < 4; i++) {
831 if (i)
832 av_bprintf(bp, " ");
833 av_bprintf(bp, "%s", deps[i] ? ff_sws_comp_mask_str(deps[i]) : "_");
834 }
835 av_bprintf(bp, "}");
836}
837
838static void print_q(AVBPrint *bp, const AVRational64 q)
839{
840 if (!q.den) {
841 av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
842 } else if (q.den == 1) {
843 av_bprintf(bp, "%"PRId64, q.num);
844 } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) {
845 av_bprintf(bp, "%f", ff_q2d_64(q));
846 } else {
847 av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den);
848 }
849}
850
851static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
852{
853 av_bprintf(bp, "{");
854 for (int i = 0; i < 4; i++) {
855 if (i)
856 av_bprintf(bp, " ");
857 if (!SWS_COMP_TEST(mask, i)) {
858 av_bprintf(bp, "_");
859 } else {
860 print_q(bp, q4[i]);
861 }
862 }
863 av_bprintf(bp, "}");
864}
865
866static const char *const rw_mode_names[] = {
867 [SWS_RW_PLANAR] = "planar",
868 [SWS_RW_PACKED] = "packed",
869 [SWS_RW_PALETTE] = "palette"
870};
871
872void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
873{
874 const char *name = ff_sws_op_type_name(op->op);
876
877 switch (op->op) {
878 case SWS_OP_INVALID:
880 av_bprintf(bp, "%s", name);
881 break;
882 case SWS_OP_READ:
883 case SWS_OP_WRITE:
884 av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
885 op->rw.elems, rw_mode_names[op->rw.mode],
886 op->rw.frac);
887 if (!op->rw.filter.op)
888 break;
889 const SwsFilterWeights *kernel = op->rw.filter.kernel;
890 av_bprintf(bp, " + %d tap %s filter (%c)",
891 kernel->filter_size, kernel->name,
892 op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
893 break;
894 case SWS_OP_LSHIFT:
895 av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
896 break;
897 case SWS_OP_RSHIFT:
898 av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
899 break;
900 case SWS_OP_PACK:
901 case SWS_OP_UNPACK:
902 av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
903 op->pack.pattern[0], op->pack.pattern[1],
904 op->pack.pattern[2], op->pack.pattern[3]);
905 break;
906 case SWS_OP_CLEAR:
907 av_bprintf(bp, "%-20s: ", name);
908 print_q4(bp, op->clear.value, mask & op->clear.mask);
909 break;
910 case SWS_OP_SWIZZLE:
911 av_bprintf(bp, "%-20s: %d%d%d%d", name,
912 op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
913 break;
914 case SWS_OP_CONVERT:
915 av_bprintf(bp, "%-20s: %s -> %s", name,
917 ff_sws_pixel_type_name(op->convert.to));
918 break;
919 case SWS_OP_DITHER:
920 av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
921 1 << op->dither.size_log2, 1 << op->dither.size_log2,
922 op->dither.y_offset[0], op->dither.y_offset[1],
923 op->dither.y_offset[2], op->dither.y_offset[3]);
924 break;
925 case SWS_OP_MIN:
926 av_bprintf(bp, "%-20s: x <= ", name);
927 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
928 break;
929 case SWS_OP_MAX:
930 av_bprintf(bp, "%-20s: ", name);
931 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
932 av_bprintf(bp, " <= x");
933 break;
934 case SWS_OP_LINEAR:
935 av_bprintf(bp, "%-20s: [", name);
936 for (int i = 0; i < 4; i++) {
937 av_bprintf(bp, "%s[", i ? " " : "");
938 for (int j = 0; j < 5; j++) {
939 av_bprintf(bp, j ? " " : "");
940 print_q(bp, op->lin.m[i][j]);
941 }
942 av_bprintf(bp, "]");
943 }
944 av_bprintf(bp, "]");
945 break;
946 case SWS_OP_SCALE:
947 av_bprintf(bp, "%-20s: * %"PRId64, name, op->scale.factor.num);
948 if (op->scale.factor.den != 1)
949 av_bprintf(bp, "/%"PRId64, op->scale.factor.den);
950 break;
951 case SWS_OP_FILTER_H:
952 case SWS_OP_FILTER_V: {
953 const SwsFilterWeights *kernel = op->filter.kernel;
954 av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
955 kernel->src_size, kernel->dst_size,
956 kernel->name, kernel->filter_size);
957 break;
958 }
959 case SWS_OP_LUT_3D:
960 av_bprintf(bp, "%-20s: %s", name, op->lut3d.dynamic ? "dynamic" : "static");
961 break;
962 case SWS_OP_TYPE_NB:
963 break;
964 }
965}
966
967static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
968{
969 bool inorder = true;
970 for (int i = 0; i < nb_planes; i++)
971 inorder &= order[i] == i;
972 if (inorder)
973 return;
974
975 av_bprintf(bp, ", via {");
976 for (int i = 0; i < nb_planes; i++)
977 av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
978 av_bprintf(bp, "}");
979}
980
981void ff_sws_op_list_print(void *log, int lev, int lev_extra,
982 const SwsOpList *ops)
983{
984 AVBPrint bp;
985 if (!ops->num_ops) {
986 av_log(log, lev, " (empty)\n");
987 return;
988 }
989
991
992 for (int i = 0; i < ops->num_ops; i++) {
993 const SwsOp *op = &ops->ops[i];
995 av_bprint_clear(&bp);
996 av_bprintf(&bp, " [%3s %c%c%c%c] ",
998 describe_comp_flags(op->comps.flags[0]),
999 describe_comp_flags(op->comps.flags[1]),
1000 describe_comp_flags(op->comps.flags[2]),
1001 describe_comp_flags(op->comps.flags[3]));
1002
1003 ff_sws_op_desc(&bp, op);
1004
1005 if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
1006 const int planes = ff_sws_rw_op_planes(op);
1008 op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
1009 }
1010
1012 av_log(log, lev, "%s\n", bp.str);
1013
1014 /* Only print value ranges if any are relevant */
1015 SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
1016 ff_sws_comp_mask_q4(op->comps.max);
1017 if (range_mask & mask) {
1018 av_bprint_clear(&bp);
1019 av_bprintf(&bp, " min: ");
1020 print_q4(&bp, op->comps.min, mask);
1021 av_bprintf(&bp, ", max: ");
1022 print_q4(&bp, op->comps.max, mask);
1024 av_log(log, lev_extra, "%s\n", bp.str);
1025 }
1026
1027 bool has_deps = false;
1028 for (int i = 0; i < 4; i++)
1029 has_deps |= op->comps.dep_in[i] || op->comps.dep_out[i];
1030 if (has_deps) {
1031 av_bprint_clear(&bp);
1032 av_bprintf(&bp, " inputs: ");
1033 print_deps(&bp, op->comps.dep_in);
1034 av_bprintf(&bp, ", outputs: ");
1035 print_deps(&bp, op->comps.dep_out);
1037 av_log(log, lev_extra, "%s\n", bp.str);
1038 }
1039
1040 }
1041
1042 av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
1043}
const SwsOpBackend backend_aarch64
Definition ops.c:241
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:121
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:68
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:452
static void ff_fmt_clear(SwsFormat *fmt)
Definition format.h:90
AVRational64 ff_mul_q64(AVRational64 b, AVRational64 c)
Multiply two 64-bit rationals.
Definition rational64.c:208
static AVRational64 ff_make_q64(int64_t num, int64_t den)
Create an AVRational64.
Definition rational64.h:64
static double ff_q2d_64(AVRational64 a)
Convert an AVRational64 to a double.
Definition rational64.h:90
AVRational64 ff_add_q64(AVRational64 b, AVRational64 c)
Add two 64-bit rationals.
Definition rational64.c:222
int ff_cmp_q64(AVRational64 a, AVRational64 b)
Compare two 64-bit rationals.
Definition rational64.c:185
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:226
#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:447
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition mem.c:408
int index
Definition gxfenc.c:90
int a
static const int weights[]
Definition hevc_pel.c:32
#define Q(q)
#define b
Definition input.c:43
uint32_t type
Definition jpegmpfenc.c:80
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.
static char ** deps
Definition mscl.c:62
int ff_sws_op_list_max_size(const SwsOpList *ops)
Returns the size of the largest pixel type used in ops.
Definition ops.c:786
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition ops.c:310
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition ops.c:872
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition ops.c:797
static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
Definition ops.c:851
static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
Definition ops.c:967
static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
Definition ops.c:827
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition ops.c:737
const SwsOpBackend backend_x86
Definition ops.c:748
static void op_uninit(SwsOp *op)
Definition ops.c:620
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:708
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition ops.c:654
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:751
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:641
#define FORWARD(I, J, EXPR)
const char * ff_sws_op_type_name(SwsOpType op)
Definition ops.c:71
@ SWS_COMP_IDENTITY
Definition ops.c:276
@ SWS_COMP_DIRTY
Definition ops.c:279
static AVRational64 av_max_q64(AVRational64 a, AVRational64 b)
Definition ops.c:152
static char describe_comp_flags(SwsCompFlags flags)
Definition ops.c:809
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:283
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:717
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:756
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:981
static const char *const rw_mode_names[]
Definition ops.c:866
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:726
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
Definition ops.c:668
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition ops.c:290
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:57
@ 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:269
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:121
const void * av_refstruct_ref_c(const void *obj)
Analog of av_refstruct_ref(), but for constant objects.
Definition refstruct.c:150
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition refstruct.c:141
#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:297
SwsFormat dst
Definition ops.h:302
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition ops.h:316
uint8_t plane_src[4]
Definition ops.h:305
uint8_t plane_dst[4]
Definition ops.h:305
SwsOp * ops
Definition ops.h:298
int num_ops
Definition ops.h:299
SwsFormat src
Definition ops.h:302
Definition ops.h:241
SwsPixelType type
Definition ops.h:243
SwsOpType op
Definition ops.h:242
SwsReadWriteOp rw
Definition ops.h:246
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 num
Definition error.c:23
int size
@ SWS_COMP_NONE
Definition uops.h:120
SwsPixelType
Definition uops.h:40
@ SWS_PIXEL_F32
Definition uops.h:45
@ SWS_PIXEL_U32
Definition uops.h:44
@ SWS_PIXEL_U16
Definition uops.h:43
@ SWS_PIXEL_TYPE_NB
Definition uops.h:46
@ SWS_PIXEL_NONE
Definition uops.h:41
@ SWS_PIXEL_U8
Definition uops.h:42
#define SWS_COMP(X)
Definition uops.h:122
#define ff_sws_comp_mask_str(mask)
Definition uops.h:135
#define SWS_COMP_TEST(mask, X)
Definition uops.h:123
#define SWS_MASK(I, J)
Definition uops.h:259
static av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition uops.h:64
uint8_t SwsCompMask
Bit-mask of components.
Definition uops.h:118
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition uops.h:51
static void copy(const float *p1, float *p2, const int length)
static double c[64]