FFmpeg
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 
21 #include "libavutil/attributes.h"
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 
34 extern const SwsOpBackend backend_c;
35 extern const SwsOpBackend backend_murder;
36 extern const SwsOpBackend backend_aarch64;
37 extern const SwsOpBackend backend_x86;
38 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
39 extern const SwsOpBackend backend_spirv;
40 #endif
41 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
42 extern const SwsOpBackend backend_glsl;
43 #endif
44 
45 const SwsOpBackend * const ff_sws_op_backends[] = {
47 #if ARCH_AARCH64 && HAVE_NEON
49 #elif ARCH_X86_64 && HAVE_X86ASM
50  &backend_x86,
51 #endif
52  &backend_c,
53 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
54  &backend_spirv,
55 #endif
56 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
57  &backend_glsl,
58 #endif
59  NULL
60 };
61 
63 {
64  switch (type) {
65  case SWS_PIXEL_U8: return "u8";
66  case SWS_PIXEL_U16: return "u16";
67  case SWS_PIXEL_U32: return "u32";
68  case SWS_PIXEL_F32: return "f32";
69  case SWS_PIXEL_NONE: return "none";
70  case SWS_PIXEL_TYPE_NB: break;
71  }
72 
73  av_unreachable("Invalid pixel type!");
74  return "ERR";
75 }
76 
78 {
79  switch (type) {
80  case SWS_PIXEL_U8: return sizeof(uint8_t);
81  case SWS_PIXEL_U16: return sizeof(uint16_t);
82  case SWS_PIXEL_U32: return sizeof(uint32_t);
83  case SWS_PIXEL_F32: return sizeof(float);
84  case SWS_PIXEL_NONE: break;
85  case SWS_PIXEL_TYPE_NB: break;
86  }
87 
88  av_unreachable("Invalid pixel type!");
89  return 0;
90 }
91 
93 {
94  switch (type) {
95  case SWS_PIXEL_U8:
96  case SWS_PIXEL_U16:
97  case SWS_PIXEL_U32:
98  return true;
99  case SWS_PIXEL_F32:
100  return false;
101  case SWS_PIXEL_NONE:
102  case SWS_PIXEL_TYPE_NB: break;
103  }
104 
105  av_unreachable("Invalid pixel type!");
106  return false;
107 }
108 
110 {
111  switch (op) {
112  case SWS_OP_READ: return "SWS_OP_READ";
113  case SWS_OP_WRITE: return "SWS_OP_WRITE";
114  case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
115  case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
116  case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
117  case SWS_OP_PACK: return "SWS_OP_PACK";
118  case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
119  case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
120  case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
121  case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
122  case SWS_OP_MIN: return "SWS_OP_MIN";
123  case SWS_OP_MAX: return "SWS_OP_MAX";
124  case SWS_OP_SCALE: return "SWS_OP_SCALE";
125  case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
126  case SWS_OP_DITHER: return "SWS_OP_DITHER";
127  case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
128  case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
129  case SWS_OP_INVALID: return "SWS_OP_INVALID";
130  case SWS_OP_TYPE_NB: break;
131  }
132 
133  av_unreachable("Invalid operation type!");
134  return "ERR";
135 }
136 
138 {
139  SwsCompMask mask = 0;
140  for (int i = 0; i < 4; i++) {
141  if (q[i].den)
142  mask |= SWS_COMP(i);
143  }
144  return mask;
145 }
146 
148 {
149  SwsCompMask res = 0;
150  for (int i = 0; i < 4; i++) {
151  const int src = swiz.in[i];
152  if (SWS_COMP_TEST(mask, src))
153  res |= SWS_COMP(i);
154  }
155 
156  return res;
157 }
158 
160 {
161  SwsCompMask mask = 0;
162  for (int i = 0; i < 4; i++) {
163  if (SWS_OP_NEEDED(op, i))
164  mask |= SWS_COMP(i);
165  }
166  return mask;
167 }
168 
169 /* biased towards `a` */
171 {
172  return av_cmp_q(a, b) == 1 ? b : a;
173 }
174 
176 {
177  return av_cmp_q(a, b) == -1 ? b : a;
178 }
179 
181 {
182  uint64_t mask[4];
183  int shift[4];
184 
185  switch (op->op) {
186  case SWS_OP_READ:
187  case SWS_OP_WRITE:
188  return;
189  case SWS_OP_UNPACK: {
192  unsigned val = x[0].num;
193  for (int i = 0; i < 4; i++)
194  x[i] = Q((val >> shift[i]) & mask[i]);
195  return;
196  }
197  case SWS_OP_PACK: {
200  unsigned val = 0;
201  for (int i = 0; i < 4; i++)
202  val |= (x[i].num & mask[i]) << shift[i];
203  x[0] = Q(val);
204  return;
205  }
206  case SWS_OP_SWAP_BYTES:
208  switch (ff_sws_pixel_type_size(op->type)) {
209  case 2:
210  for (int i = 0; i < 4; i++)
211  x[i].num = av_bswap16(x[i].num);
212  break;
213  case 4:
214  for (int i = 0; i < 4; i++)
215  x[i].num = av_bswap32(x[i].num);
216  break;
217  }
218  return;
219  case SWS_OP_CLEAR:
220  for (int i = 0; i < 4; i++) {
221  if (SWS_COMP_TEST(op->clear.mask, i))
222  x[i] = op->clear.value[i];
223  }
224  return;
225  case SWS_OP_LSHIFT: {
227  AVRational mult = Q(1 << op->shift.amount);
228  for (int i = 0; i < 4; i++)
229  x[i] = x[i].den ? av_mul_q(x[i], mult) : x[i];
230  return;
231  }
232  case SWS_OP_RSHIFT: {
234  for (int i = 0; i < 4; i++)
235  x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->shift.amount) : x[i];
236  return;
237  }
238  case SWS_OP_SWIZZLE: {
239  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
240  for (int i = 0; i < 4; i++)
241  x[i] = orig[op->swizzle.in[i]];
242  return;
243  }
244  case SWS_OP_CONVERT:
245  if (ff_sws_pixel_type_is_int(op->convert.to)) {
246  const AVRational scale = ff_sws_pixel_expand(op->type, op->convert.to);
247  for (int i = 0; i < 4; i++) {
248  x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
249  if (op->convert.expand)
250  x[i] = av_mul_q(x[i], scale);
251  }
252  }
253  return;
254  case SWS_OP_DITHER:
256  for (int i = 0; i < 4; i++) {
257  if (op->dither.y_offset[i] >= 0 && x[i].den)
258  x[i] = av_add_q(x[i], av_make_q(1, 2));
259  }
260  return;
261  case SWS_OP_MIN:
262  for (int i = 0; i < 4; i++)
263  x[i] = av_min_q(x[i], op->clamp.limit[i]);
264  return;
265  case SWS_OP_MAX:
266  for (int i = 0; i < 4; i++)
267  x[i] = av_max_q(x[i], op->clamp.limit[i]);
268  return;
269  case SWS_OP_LINEAR: {
271  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
272  for (int i = 0; i < 4; i++) {
273  AVRational sum = op->lin.m[i][4];
274  for (int j = 0; j < 4; j++)
275  sum = av_add_q(sum, av_mul_q(orig[j], op->lin.m[i][j]));
276  x[i] = sum;
277  }
278  return;
279  }
280  case SWS_OP_SCALE:
281  for (int i = 0; i < 4; i++)
282  x[i] = x[i].den ? av_mul_q(x[i], op->scale.factor) : x[i];
283  return;
284  case SWS_OP_FILTER_H:
285  case SWS_OP_FILTER_V:
286  /* Filters have normalized energy by definition, so they don't
287  * conceptually modify individual components */
288  return;
289  }
290 
291  av_unreachable("Invalid operation type!");
292 }
293 
294 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
295 enum {
297 };
298 
300 {
301  const SwsCompFlags flags_or = SWS_COMP_GARBAGE;
302  const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
303  return ((a & b) & flags_and) | ((a | b) & flags_or);
304 }
305 
306 /* Linearly propagate flags per component */
307 static void propagate_flags(SwsOp *op, const SwsComps *prev)
308 {
309  for (int i = 0; i < 4; i++)
310  op->comps.flags[i] = prev->flags[i];
311 }
312 
313 /* Clear undefined values in dst with src */
315 {
316  for (int i = 0; i < 4; i++) {
317  if (dst[i].den == 0)
318  dst[i] = src[i];
319  }
320 }
321 
322 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
323  const SwsFilterWeights *weights)
324 {
325  const AVRational posw = { weights->sum_positive, SWS_FILTER_SCALE };
326  const AVRational negw = { weights->sum_negative, SWS_FILTER_SCALE };
327  for (int i = 0; i < 4; i++) {
328  comps->flags[i] = prev->flags[i];
329  /* Only point sampling preserves exactness */
330  if (weights->filter_size != 1)
331  comps->flags[i] &= ~SWS_COMP_EXACT;
332  /* Update min/max assuming extremes */
333  comps->min[i] = av_add_q(av_mul_q(prev->min[i], posw),
334  av_mul_q(prev->max[i], negw));
335  comps->max[i] = av_add_q(av_mul_q(prev->min[i], negw),
336  av_mul_q(prev->max[i], posw));
337  }
338 }
339 
340 /* Infer + propagate known information about components */
342 {
343  SwsComps prev = { .flags = {
345  }};
346 
347  /* Forwards pass, propagates knowledge about the incoming pixel values */
348  for (int n = 0; n < ops->num_ops; n++) {
349  SwsOp *op = &ops->ops[n];
350 
351  switch (op->op) {
352  case SWS_OP_READ:
353  case SWS_OP_LINEAR:
354  case SWS_OP_DITHER:
355  case SWS_OP_SWAP_BYTES:
356  case SWS_OP_UNPACK:
357  case SWS_OP_FILTER_H:
358  case SWS_OP_FILTER_V:
359  break; /* special cases, handled below */
360  default:
361  memcpy(op->comps.min, prev.min, sizeof(prev.min));
362  memcpy(op->comps.max, prev.max, sizeof(prev.max));
363  ff_sws_apply_op_q(op, op->comps.min);
364  ff_sws_apply_op_q(op, op->comps.max);
365  break;
366  }
367 
368  switch (op->op) {
369  case SWS_OP_READ:
370  /* Active components are taken from the user-provided values,
371  * other components are explicitly stripped */
372  for (int i = 0; i < op->rw.elems; i++) {
373  const int idx = op->rw.packed ? i : ops->plane_src[i];
374  av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
375  op->comps.flags[i] = ops->comps_src.flags[idx];
376  op->comps.min[i] = ops->comps_src.min[idx];
377  op->comps.max[i] = ops->comps_src.max[idx];
378  }
379  for (int i = op->rw.elems; i < 4; i++) {
380  op->comps.flags[i] = prev.flags[i];
381  op->comps.min[i] = prev.min[i];
382  op->comps.max[i] = prev.max[i];
383  }
384 
385  if (op->rw.filter) {
386  const SwsComps prev = op->comps;
387  apply_filter_weights(&op->comps, &prev, op->rw.kernel);
388  }
389  break;
390  case SWS_OP_SWAP_BYTES:
391  for (int i = 0; i < 4; i++) {
392  op->comps.flags[i] = prev.flags[i] ^ SWS_COMP_SWAPPED;
393  op->comps.min[i] = prev.min[i];
394  op->comps.max[i] = prev.max[i];
395  }
396  break;
397  case SWS_OP_WRITE:
398  for (int i = 0; i < op->rw.elems; i++)
399  av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
401  case SWS_OP_LSHIFT:
402  case SWS_OP_RSHIFT:
403  propagate_flags(op, &prev);
404  break;
405  case SWS_OP_MIN:
406  propagate_flags(op, &prev);
407  clear_undefined_values(op->comps.max, op->clamp.limit);
408  break;
409  case SWS_OP_MAX:
410  propagate_flags(op, &prev);
411  clear_undefined_values(op->comps.min, op->clamp.limit);
412  break;
413  case SWS_OP_DITHER:
414  for (int i = 0; i < 4; i++) {
415  op->comps.min[i] = prev.min[i];
416  op->comps.max[i] = prev.max[i];
417  if (op->dither.y_offset[i] < 0)
418  continue;
419  /* Strip zero flag because of the nonzero dithering offset */
420  op->comps.flags[i] = prev.flags[i] & ~SWS_COMP_ZERO;
421  op->comps.min[i] = av_add_q(op->comps.min[i], op->dither.min);
422  op->comps.max[i] = av_add_q(op->comps.max[i], op->dither.max);
423  }
424  break;
425  case SWS_OP_UNPACK:
426  for (int i = 0; i < 4; i++) {
427  const int pattern = op->pack.pattern[i];
428  if (pattern) {
429  av_assert1(pattern < 32);
430  op->comps.flags[i] = prev.flags[0];
431  op->comps.min[i] = Q(0);
432  op->comps.max[i] = Q((1ULL << pattern) - 1);
433  } else
434  op->comps.flags[i] = SWS_COMP_GARBAGE;
435  }
436  break;
437  case SWS_OP_PACK: {
439  for (int i = 0; i < 4; i++) {
440  if (op->pack.pattern[i])
441  flags = merge_comp_flags(flags, prev.flags[i]);
442  if (i > 0) /* clear remaining comps for sanity */
443  op->comps.flags[i] = SWS_COMP_GARBAGE;
444  }
445  op->comps.flags[0] = flags;
446  break;
447  }
448  case SWS_OP_CLEAR:
449  for (int i = 0; i < 4; i++) {
450  if (SWS_COMP_TEST(op->clear.mask, i)) {
451  op->comps.flags[i] = 0;
452  if (op->clear.value[i].num == 0)
453  op->comps.flags[i] |= SWS_COMP_ZERO;
454  if (op->clear.value[i].den == 1)
455  op->comps.flags[i] |= SWS_COMP_EXACT;
456  } else {
457  op->comps.flags[i] = prev.flags[i];
458  }
459  }
460  break;
461  case SWS_OP_SWIZZLE:
462  for (int i = 0; i < 4; i++)
463  op->comps.flags[i] = prev.flags[op->swizzle.in[i]];
464  break;
465  case SWS_OP_CONVERT:
466  for (int i = 0; i < 4; i++) {
467  op->comps.flags[i] = prev.flags[i];
468  if (ff_sws_pixel_type_is_int(op->convert.to))
469  op->comps.flags[i] |= SWS_COMP_EXACT;
470  }
471  break;
472  case SWS_OP_LINEAR:
473  for (int i = 0; i < 4; i++) {
475  AVRational min = Q(0), max = Q(0);
476  for (int j = 0; j < 4; j++) {
477  const AVRational k = op->lin.m[i][j];
478  AVRational mink = av_mul_q(prev.min[j], k);
479  AVRational maxk = av_mul_q(prev.max[j], k);
480  if (k.num) {
481  flags = merge_comp_flags(flags, prev.flags[j]);
482  if (k.den != 1) /* fractional coefficient */
483  flags &= ~SWS_COMP_EXACT;
484  if (k.num < 0)
485  FFSWAP(AVRational, mink, maxk);
486  min = av_add_q(min, mink);
487  max = av_add_q(max, maxk);
488  }
489  }
490  if (op->lin.m[i][4].num) { /* nonzero offset */
491  flags &= ~SWS_COMP_ZERO;
492  if (op->lin.m[i][4].den != 1) /* fractional offset */
493  flags &= ~SWS_COMP_EXACT;
494  min = av_add_q(min, op->lin.m[i][4]);
495  max = av_add_q(max, op->lin.m[i][4]);
496  }
497  op->comps.flags[i] = flags;
498  op->comps.min[i] = min;
499  op->comps.max[i] = max;
500  }
501  break;
502  case SWS_OP_SCALE:
503  for (int i = 0; i < 4; i++) {
504  op->comps.flags[i] = prev.flags[i];
505  if (op->scale.factor.den != 1) /* fractional scale */
506  op->comps.flags[i] &= ~SWS_COMP_EXACT;
507  if (op->scale.factor.num < 0)
508  FFSWAP(AVRational, op->comps.min[i], op->comps.max[i]);
509  }
510  break;
511  case SWS_OP_FILTER_H:
512  case SWS_OP_FILTER_V: {
513  apply_filter_weights(&op->comps, &prev, op->filter.kernel);
514  break;
515  }
516 
517  case SWS_OP_INVALID:
518  case SWS_OP_TYPE_NB:
519  av_unreachable("Invalid operation type!");
520  }
521 
522  prev = op->comps;
523  }
524 
525  /* Backwards pass, solves for component dependencies */
526  bool need_out[4] = { false, false, false, false };
527  for (int n = ops->num_ops - 1; n >= 0; n--) {
528  SwsOp *op = &ops->ops[n];
529  bool need_in[4] = { false, false, false, false };
530 
531  for (int i = 0; i < 4; i++) {
532  if (!need_out[i])
533  op->comps.flags[i] = SWS_COMP_GARBAGE;
534  }
535 
536  switch (op->op) {
537  case SWS_OP_READ:
538  case SWS_OP_WRITE:
539  for (int i = 0; i < op->rw.elems; i++)
540  need_in[i] = op->op == SWS_OP_WRITE;
541  for (int i = op->rw.elems; i < 4; i++)
542  need_in[i] = need_out[i];
543  break;
544  case SWS_OP_SWAP_BYTES:
545  case SWS_OP_LSHIFT:
546  case SWS_OP_RSHIFT:
547  case SWS_OP_CONVERT:
548  case SWS_OP_DITHER:
549  case SWS_OP_MIN:
550  case SWS_OP_MAX:
551  case SWS_OP_SCALE:
552  case SWS_OP_FILTER_H:
553  case SWS_OP_FILTER_V:
554  for (int i = 0; i < 4; i++)
555  need_in[i] = need_out[i];
556  break;
557  case SWS_OP_UNPACK:
558  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
559  need_in[0] |= need_out[i];
560  break;
561  case SWS_OP_PACK:
562  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
563  need_in[i] = need_out[0];
564  break;
565  case SWS_OP_CLEAR:
566  for (int i = 0; i < 4; i++) {
567  if (!SWS_COMP_TEST(op->clear.mask, i))
568  need_in[i] = need_out[i];
569  }
570  break;
571  case SWS_OP_SWIZZLE:
572  for (int i = 0; i < 4; i++)
573  need_in[op->swizzle.in[i]] |= need_out[i];
574  break;
575  case SWS_OP_LINEAR:
576  for (int i = 0; i < 4; i++) {
577  for (int j = 0; j < 4; j++) {
578  if (op->lin.m[i][j].num)
579  need_in[j] |= need_out[i];
580  }
581  }
582  break;
583  }
584 
585  memcpy(need_out, need_in, sizeof(need_in));
586  }
587 }
588 
589 static void op_uninit(SwsOp *op)
590 {
591  switch (op->op) {
592  case SWS_OP_READ:
593  av_refstruct_unref(&op->rw.kernel);
594  break;
595  case SWS_OP_DITHER:
596  av_refstruct_unref(&op->dither.matrix);
597  break;
598  case SWS_OP_FILTER_H:
599  case SWS_OP_FILTER_V:
600  av_refstruct_unref(&op->filter.kernel);
601  break;
602  }
603 
604  *op = (SwsOp) {0};
605 }
606 
608 {
609  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
610  if (!ops)
611  return NULL;
612 
613  for (int i = 0; i < 4; i++)
614  ops->plane_src[i] = ops->plane_dst[i] = i;
615  ff_fmt_clear(&ops->src);
616  ff_fmt_clear(&ops->dst);
617  return ops;
618 }
619 
621 {
622  SwsOpList *ops = *p_ops;
623  if (!ops)
624  return;
625 
626  for (int i = 0; i < ops->num_ops; i++)
627  op_uninit(&ops->ops[i]);
628 
629  av_freep(&ops->ops);
630  av_free(ops);
631  *p_ops = NULL;
632 }
633 
635 {
636  SwsOpList *copy = av_malloc(sizeof(*copy));
637  if (!copy)
638  return NULL;
639 
640  int num = ops->num_ops;
641  if (num)
642  num = 1 << av_ceil_log2(num);
643 
644  *copy = *ops;
645  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
646  if (!copy->ops) {
647  av_free(copy);
648  return NULL;
649  }
650 
651  for (int i = 0; i < copy->num_ops; i++) {
652  const SwsOp *op = &copy->ops[i];
653  switch (op->op) {
654  case SWS_OP_READ:
655  if (op->rw.kernel)
656  av_refstruct_ref(op->rw.kernel);
657  break;
658  case SWS_OP_DITHER:
659  av_refstruct_ref(op->dither.matrix);
660  break;
661  case SWS_OP_FILTER_H:
662  case SWS_OP_FILTER_V:
663  av_refstruct_ref(op->filter.kernel);
664  break;
665  }
666  }
667 
668  return copy;
669 }
670 
672 {
673  if (!ops->num_ops)
674  return NULL;
675 
676  const SwsOp *read = &ops->ops[0];
677  return read->op == SWS_OP_READ ? read : NULL;
678 }
679 
681 {
682  if (!ops->num_ops)
683  return NULL;
684 
685  const SwsOp *write = &ops->ops[ops->num_ops - 1];
686  return write->op == SWS_OP_WRITE ? write : NULL;
687 }
688 
689 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
690 {
691  const int end = ops->num_ops - count;
692  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
693  for (int i = 0; i < count; i++)
694  op_uninit(&ops->ops[index + i]);
695  for (int i = index; i < end; i++)
696  ops->ops[i] = ops->ops[i + count];
697  ops->num_ops = end;
698 }
699 
701 {
702  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
703  if (!ret) {
704  op_uninit(op);
705  return AVERROR(ENOMEM);
706  }
707 
708  for (int i = ops->num_ops - 1; i > index; i--)
709  ops->ops[i] = ops->ops[i - 1];
710  ops->ops[index] = *op;
711  return 0;
712 }
713 
715 {
716  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
717 }
718 
720 {
721  if (!ops->num_ops)
722  return true;
723 
724  const SwsOp *read = ff_sws_op_list_input(ops);
725  const SwsOp *write = ff_sws_op_list_output(ops);
726  if (!read || !write || ops->num_ops > 2 ||
727  read->type != write->type ||
728  read->rw.packed != write->rw.packed ||
729  read->rw.elems != write->rw.elems ||
730  read->rw.frac != write->rw.frac)
731  return false;
732 
733  /**
734  * Note that this check is unlikely to ever be hit in practice, since it
735  * would imply the existence of planar formats with different plane orders
736  * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
737  * However, the check is cheap and lets me sleep at night.
738  */
739  const int num_planes = read->rw.packed ? 1 : read->rw.elems;
740  for (int i = 0; i < num_planes; i++) {
741  if (ops->plane_src[i] != ops->plane_dst[i])
742  return false;
743  }
744 
745  return true;
746 }
747 
749 {
750  int max_size = 0;
751  for (int i = 0; i < ops->num_ops; i++) {
752  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
753  max_size = FFMAX(max_size, size);
754  }
755 
756  return max_size;
757 }
758 
760 {
761  uint32_t mask = 0;
762  for (int i = 0; i < 4; i++) {
763  for (int j = 0; j < 5; j++) {
764  if (av_cmp_q(c.m[i][j], Q(i == j)))
765  mask |= SWS_MASK(i, j);
766  }
767  }
768  return mask;
769 }
770 
771 static const char *describe_lin_mask(uint32_t mask)
772 {
773  /* Try to be fairly descriptive without assuming too much */
774  static const struct {
775  char name[24];
776  uint32_t mask;
777  } patterns[] = {
778  { "noop", 0 },
779  { "luma", SWS_MASK_LUMA },
780  { "alpha", SWS_MASK_ALPHA },
781  { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA },
782  { "dot3", 0x7 },
783  { "dot4", 0xF },
784  { "row0", SWS_MASK_ROW(0) },
785  { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA },
786  { "col0", SWS_MASK_COL(0) },
787  { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 },
788  { "off3", SWS_MASK_OFF3 },
789  { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA },
790  { "diag3", SWS_MASK_DIAG3 },
791  { "diag4", SWS_MASK_DIAG4 },
792  { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA },
793  { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 },
794  { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
795  { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 },
796  { "matrix3", SWS_MASK_MAT3 },
797  { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 },
798  { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
799  { "matrix4", SWS_MASK_MAT4 },
800  { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 },
801  };
802 
803  for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
804  if (!(mask & ~patterns[i].mask))
805  return patterns[i].name;
806  }
807 
808  av_unreachable("Invalid linear mask!");
809  return "ERR";
810 }
811 
813 {
814  if (flags & SWS_COMP_GARBAGE)
815  return 'X';
816  else if (flags & SWS_COMP_ZERO)
817  return '0';
818  else if (flags & SWS_COMP_SWAPPED)
819  return 'z';
820  else if (flags & SWS_COMP_EXACT)
821  return '+';
822  else
823  return '.';
824 }
825 
826 static void print_q(AVBPrint *bp, const AVRational q)
827 {
828  if (!q.den) {
829  av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
830  } else if (q.den == 1) {
831  av_bprintf(bp, "%d", q.num);
832  } else if (abs(q.num) > 1000 || abs(q.den) > 1000) {
833  av_bprintf(bp, "%f", av_q2d(q));
834  } else {
835  av_bprintf(bp, "%d/%d", q.num, q.den);
836  }
837 }
838 
839 static void print_q4(AVBPrint *bp, const AVRational q4[4], SwsCompMask mask)
840 {
841  av_bprintf(bp, "{");
842  for (int i = 0; i < 4; i++) {
843  if (i)
844  av_bprintf(bp, " ");
845  if (!SWS_COMP_TEST(mask, i)) {
846  av_bprintf(bp, "_");
847  } else {
848  print_q(bp, q4[i]);
849  }
850  }
851  av_bprintf(bp, "}");
852 }
853 
854 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
855 {
856  const char *name = ff_sws_op_type_name(op->op);
858 
859  switch (op->op) {
860  case SWS_OP_INVALID:
861  case SWS_OP_SWAP_BYTES:
862  av_bprintf(bp, "%s", name);
863  break;
864  case SWS_OP_READ:
865  case SWS_OP_WRITE:
866  av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
867  op->rw.elems, op->rw.packed ? "packed" : "planar",
868  op->rw.frac);
869  if (!op->rw.filter)
870  break;
871  const SwsFilterWeights *kernel = op->rw.kernel;
872  av_bprintf(bp, " + %d tap %s filter (%c)",
873  kernel->filter_size, kernel->name,
874  op->rw.filter == SWS_OP_FILTER_H ? 'H' : 'V');
875  break;
876  case SWS_OP_LSHIFT:
877  av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
878  break;
879  case SWS_OP_RSHIFT:
880  av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
881  break;
882  case SWS_OP_PACK:
883  case SWS_OP_UNPACK:
884  av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
885  op->pack.pattern[0], op->pack.pattern[1],
886  op->pack.pattern[2], op->pack.pattern[3]);
887  break;
888  case SWS_OP_CLEAR:
889  av_bprintf(bp, "%-20s: ", name);
890  print_q4(bp, op->clear.value, mask & op->clear.mask);
891  break;
892  case SWS_OP_SWIZZLE:
893  av_bprintf(bp, "%-20s: %d%d%d%d", name,
894  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
895  break;
896  case SWS_OP_CONVERT:
897  av_bprintf(bp, "%-20s: %s -> %s%s", name,
898  ff_sws_pixel_type_name(op->type),
899  ff_sws_pixel_type_name(op->convert.to),
900  op->convert.expand ? " (expand)" : "");
901  break;
902  case SWS_OP_DITHER:
903  av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
904  1 << op->dither.size_log2, 1 << op->dither.size_log2,
905  op->dither.y_offset[0], op->dither.y_offset[1],
906  op->dither.y_offset[2], op->dither.y_offset[3]);
907  break;
908  case SWS_OP_MIN:
909  av_bprintf(bp, "%-20s: x <= ", name);
910  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
911  break;
912  case SWS_OP_MAX:
913  av_bprintf(bp, "%-20s: ", name);
914  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
915  av_bprintf(bp, " <= x");
916  break;
917  case SWS_OP_LINEAR:
918  av_bprintf(bp, "%-20s: %s [", name, describe_lin_mask(op->lin.mask));
919  for (int i = 0; i < 4; i++) {
920  av_bprintf(bp, "%s[", i ? " " : "");
921  for (int j = 0; j < 5; j++) {
922  av_bprintf(bp, j ? " " : "");
923  print_q(bp, op->lin.m[i][j]);
924  }
925  av_bprintf(bp, "]");
926  }
927  av_bprintf(bp, "]");
928  break;
929  case SWS_OP_SCALE:
930  av_bprintf(bp, "%-20s: * %d", name, op->scale.factor.num);
931  if (op->scale.factor.den != 1)
932  av_bprintf(bp, "/%d", op->scale.factor.den);
933  break;
934  case SWS_OP_FILTER_H:
935  case SWS_OP_FILTER_V: {
936  const SwsFilterWeights *kernel = op->filter.kernel;
937  av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
938  kernel->src_size, kernel->dst_size,
939  kernel->name, kernel->filter_size);
940  break;
941  }
942  case SWS_OP_TYPE_NB:
943  break;
944  }
945 }
946 
947 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
948 {
949  bool inorder = true;
950  for (int i = 0; i < nb_planes; i++)
951  inorder &= order[i] == i;
952  if (inorder)
953  return;
954 
955  av_bprintf(bp, ", via {");
956  for (int i = 0; i < nb_planes; i++)
957  av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
958  av_bprintf(bp, "}");
959 }
960 
961 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
962  const SwsOpList *ops)
963 {
964  AVBPrint bp;
965  if (!ops->num_ops) {
966  av_log(log, lev, " (empty)\n");
967  return;
968  }
969 
971 
972  for (int i = 0; i < ops->num_ops; i++) {
973  const SwsOp *op = &ops->ops[i];
975  av_bprint_clear(&bp);
976  av_bprintf(&bp, " [%3s %c%c%c%c] ",
977  ff_sws_pixel_type_name(op->type),
978  describe_comp_flags(op->comps.flags[0]),
979  describe_comp_flags(op->comps.flags[1]),
980  describe_comp_flags(op->comps.flags[2]),
981  describe_comp_flags(op->comps.flags[3]));
982 
983  ff_sws_op_desc(&bp, op);
984 
985  if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
986  const int planes = op->rw.packed ? 1 : op->rw.elems;
988  op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
989  }
990 
992  av_log(log, lev, "%s\n", bp.str);
993 
994  /* Only print value ranges if any are relevant */
995  SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
996  ff_sws_comp_mask_q4(op->comps.max);
997  if (range_mask & mask) {
998  av_bprint_clear(&bp);
999  av_bprintf(&bp, " min: ");
1000  print_q4(&bp, op->comps.min, mask);
1001  av_bprintf(&bp, ", max: ");
1002  print_q4(&bp, op->comps.max, mask);
1004  av_log(log, lev_extra, "%s\n", bp.str);
1005  }
1006 
1007  }
1008 
1009  av_log(log, lev, " (X = unused, z = byteswapped, + = exact, 0 = zero)\n");
1010 }
1011 
1012 static int enum_ops_fmt(SwsContext *ctx, void *opaque,
1013  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1014  int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1015 {
1016  int ret;
1019  if (!ops)
1020  return AVERROR(ENOMEM);
1021 
1022  ff_fmt_from_pixfmt(src_fmt, &ops->src);
1023  ff_fmt_from_pixfmt(dst_fmt, &ops->dst);
1024  ops->src.width = ops->dst.width = 16;
1025  ops->src.height = ops->dst.height = 16;
1026 
1027  bool incomplete = ff_infer_colors(&ops->src.color, &ops->dst.color);
1028  if (ff_sws_decode_pixfmt(ops, src_fmt) < 0 ||
1029  ff_sws_decode_colors(ctx, type, ops, &ops->src, &incomplete) < 0 ||
1030  ff_sws_encode_colors(ctx, type, ops, &ops->src, &ops->dst, &incomplete) < 0 ||
1031  ff_sws_encode_pixfmt(ops, dst_fmt) < 0)
1032  {
1033  ret = 0; /* silently skip unsupported formats */
1034  goto fail;
1035  }
1036 
1038  if (ret < 0)
1039  goto fail;
1040 
1041  ret = cb(ctx, opaque, ops);
1042  if (ret < 0)
1043  goto fail;
1044 
1045 fail:
1046  ff_sws_op_list_free(&ops);
1047  return ret;
1048 }
1049 
1051  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1052  int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1053 {
1054  const AVPixFmtDescriptor *src_start = av_pix_fmt_desc_next(NULL);
1055  const AVPixFmtDescriptor *dst_start = src_start;
1056  if (src_fmt != AV_PIX_FMT_NONE)
1057  src_start = av_pix_fmt_desc_get(src_fmt);
1058  if (dst_fmt != AV_PIX_FMT_NONE)
1059  dst_start = av_pix_fmt_desc_get(dst_fmt);
1060 
1061  const AVPixFmtDescriptor *src, *dst;
1062  for (src = src_start; src; src = av_pix_fmt_desc_next(src)) {
1063  const enum AVPixelFormat src_f = av_pix_fmt_desc_get_id(src);
1064  for (dst = dst_start; dst; dst = av_pix_fmt_desc_next(dst)) {
1065  const enum AVPixelFormat dst_f = av_pix_fmt_desc_get_id(dst);
1066  int ret = enum_ops_fmt(ctx, opaque, src_f, dst_f, cb);
1067  if (ret < 0)
1068  return ret;
1069  if (dst_fmt != AV_PIX_FMT_NONE)
1070  break;
1071  }
1072  if (src_fmt != AV_PIX_FMT_NONE)
1073  break;
1074  }
1075 
1076  return 0;
1077 }
1078 
1079 struct EnumOpaque {
1080  void *opaque;
1081  int (*cb)(SwsContext *ctx, void *opaque, SwsOp *op);
1082 };
1083 
1084 static int enum_ops(SwsContext *ctx, void *opaque, SwsOpList *ops)
1085 {
1086  struct EnumOpaque *priv = opaque;
1087  for (int i = 0; i < ops->num_ops; i++) {
1088  int ret = priv->cb(ctx, priv->opaque, &ops->ops[i]);
1089  if (ret < 0)
1090  return ret;
1091  }
1092  return 0;
1093 }
1094 
1096  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1097  int (*cb)(SwsContext *ctx, void *opaque, SwsOp *op))
1098 {
1099  struct EnumOpaque priv = { opaque, cb };
1100  return ff_sws_enum_op_lists(ctx, &priv, src_fmt, dst_fmt, enum_ops);
1101 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:50
flags
const SwsFlags flags[]
Definition: swscale.c:72
ff_sws_enum_ops
int ff_sws_enum_ops(SwsContext *ctx, void *opaque, enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int(*cb)(SwsContext *ctx, void *opaque, SwsOp *op))
Helper function to enumerate over all possible operations, under the current set of options in ctx,...
Definition: ops.c:1095
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: ops.h:36
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:620
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:53
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:607
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
SwsFilterWeights::filter_size
int filter_size
The number of source texels to convolve over for each row.
Definition: filters.h:68
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:58
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:56
ff_sws_op_list_duplicate
SwsOpList * ff_sws_op_list_duplicate(const SwsOpList *ops)
Returns a duplicate of ops, or NULL on OOM.
Definition: ops.c:634
apply_filter_weights
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition: ops.c:322
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
cb
static double cb(void *priv, double x, double y)
Definition: vf_geq.c:247
av_min_q
static AVRational av_min_q(AVRational a, AVRational b)
Definition: ops.c:170
SwsOpList::comps_src
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition: ops.h:307
merge_comp_flags
static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
Definition: ops.c:299
ff_sws_op_list_input
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:671
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
SWS_COMP_ZERO
@ SWS_COMP_ZERO
Definition: ops.h:105
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:62
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp c)
Definition: ops.c:759
ff_sws_op_list_max_size
int ff_sws_op_list_max_size(const SwsOpList *ops)
Returns the size of the largest pixel type used in ops.
Definition: ops.c:748
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:1057
SWS_MASK_MAT4
@ SWS_MASK_MAT4
Definition: ops.h:228
rational.h
ff_sws_op_list_append
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:714
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:243
ff_sws_decode_colors
int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, const SwsFormat *fmt, bool *incomplete)
Append a set of operations for transforming decoded pixel values to/from normalized RGB in the specif...
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:70
SwsFilterWeights
Represents a computed filter kernel.
Definition: filters.h:64
describe_comp_flags
static char describe_comp_flags(SwsCompFlags flags)
Definition: ops.c:812
av_dynarray2_add
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:343
b
#define b
Definition: input.c:43
desc_plane_order
static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
Definition: ops.c:947
av_pix_fmt_desc_next
const AVPixFmtDescriptor * av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev)
Iterate over all pixel format descriptors known to libavutil.
Definition: pixdesc.c:3463
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: ops.h:84
enum_ops_fmt
static int enum_ops_fmt(SwsContext *ctx, void *opaque, enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int(*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
Definition: ops.c:1012
max
#define max(a, b)
Definition: cuda_runtime.h:33
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: ops.h:37
SWS_OP_TYPE_NB
@ SWS_OP_TYPE_NB
Definition: ops.h:76
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
format.h
enum_ops
static int enum_ops(SwsContext *ctx, void *opaque, SwsOpList *ops)
Definition: ops.c:1084
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:77
clear_undefined_values
static void clear_undefined_values(AVRational dst[4], const AVRational src[4])
Definition: ops.c:314
ff_sws_comp_mask_needed
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition: ops.c:159
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:212
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:304
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:33
SwsComps::max
AVRational max[4]
Definition: ops.h:114
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:296
ff_sws_op_list_print
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:961
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:45
av_ceil_log2
#define av_ceil_log2
Definition: common.h:97
fail
#define fail()
Definition: checkasm.h:224
SwsOpList::num_ops
int num_ops
Definition: ops.h:290
SwsCompFlags
SwsCompFlags
Definition: ops.h:102
SWS_MASK_COL
#define SWS_MASK_COL(J)
Definition: ops.h:213
SWS_MASK_LUMA
@ SWS_MASK_LUMA
Definition: ops.h:217
SWS_PIXEL_U8
@ SWS_PIXEL_U8
Definition: ops.h:35
SwsSwizzleOp
Definition: ops.h:149
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: ops.h:89
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:92
val
static double val(void *priv, double ch)
Definition: aeval.c:77
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
SWS_MASK_ALPHA
@ SWS_MASK_ALPHA
Definition: ops.h:218
AVRational::num
int num
Numerator.
Definition: rational.h:59
refstruct.h
SwsOp::op
SwsOpType op
Definition: ops.h:239
Q
#define Q(q)
mult
static int16_t mult(Float11 *f1, Float11 *f2)
Definition: g726.c:60
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:66
avassert.h
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
backend_aarch64
const SwsOpBackend backend_aarch64
Definition: ops.c:255
SwsFormat::height
int height
Definition: format.h:78
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:265
float
float
Definition: af_crystalizer.c:122
print_q
static void print_q(AVBPrint *bp, const AVRational q)
Definition: ops.c:826
print_q4
static void print_q4(AVBPrint *bp, const AVRational q4[4], SwsCompMask mask)
Definition: ops.c:839
SwsComps::min
AVRational min[4]
Definition: ops.h:114
op
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
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
backend_c
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
Definition: ops_backend.c:112
SWS_MASK_OFF3
@ SWS_MASK_OFF3
Definition: ops.h:221
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:64
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
ff_sws_pixel_expand
static AVRational ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
Definition: ops_internal.h:31
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:69
ff_sws_op_list_output
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:680
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:73
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
av_fallthrough
#define av_fallthrough
Definition: attributes.h:67
SwsOpBackend
Definition: ops_internal.h:55
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:57
ff_sws_op_list_is_noop
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:719
NULL
#define NULL
Definition: coverity.c:32
SwsFilterWeights::dst_size
int dst_size
Definition: filters.h:90
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_unreachable
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition: avassert.h:116
SwsReadWriteOp::frac
uint8_t frac
Definition: ops.h:127
SWS_MASK_DIAG4
@ SWS_MASK_DIAG4
Definition: ops.h:226
ff_infer_colors
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition: format.c:540
SWS_COMP_GARBAGE
@ SWS_COMP_GARBAGE
Definition: ops.h:103
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:74
SwsOpType
SwsOpType
Definition: ops.h:46
abs
#define abs(x)
Definition: cuda_runtime.h:35
ff_sws_op_list_remove_at
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
Definition: ops.c:689
SWS_COMP
#define SWS_COMP(X)
Definition: ops.h:88
SwsFilterWeights::src_size
int src_size
Copy of the parameters used to generate this filter, for reference.
Definition: filters.h:89
SWS_MASK
#define SWS_MASK(I, J)
Definition: ops.h:210
SWS_PIXEL_NONE
@ SWS_PIXEL_NONE
Definition: ops.h:34
index
int index
Definition: gxfenc.c:90
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
ff_sws_apply_op_q
void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
Apply an operation to an AVRational.
Definition: ops.c:180
SWS_FILTER_SCALE
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
Definition: filters.h:40
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
shift
static int shift(int a, int b)
Definition: bonk.c:261
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
av_bswap32
#define av_bswap32
Definition: bswap.h:47
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:424
SwsOp::type
SwsPixelType type
Definition: ops.h:240
SWS_MASK_OFF4
@ SWS_MASK_OFF4
Definition: ops.h:227
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:700
size
int size
Definition: twinvq_data.h:10344
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:59
SwsOpList::src
SwsFormat src
Definition: ops.h:293
SWS_OP_INVALID
@ SWS_OP_INVALID
Definition: ops.h:47
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:341
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:51
av_refstruct_ref
void * av_refstruct_ref(void *obj)
Create a new reference to an object managed via this API, i.e.
Definition: refstruct.c:140
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
op_uninit
static void op_uninit(SwsOp *op)
Definition: ops.c:589
planes
static const struct @585 planes[]
attributes.h
av_pix_fmt_desc_get_id
enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc)
Definition: pixdesc.c:3475
SwsFilterWeights::name
char name[16]
Extra metadata about the filter, used to inform the optimizer / range tracker about the filter's beha...
Definition: filters.h:96
SwsLinearOp
Definition: ops.h:193
ff_sws_op_desc
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition: ops.c:854
ff_sws_comp_mask_swizzle
SwsCompMask ff_sws_comp_mask_swizzle(const SwsCompMask mask, const SwsSwizzleOp swiz)
Definition: ops.c:147
av_refstruct_unref
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
ff_sws_comp_mask_q4
SwsCompMask ff_sws_comp_mask_q4(const AVRational q[4])
Definition: ops.c:137
EnumOpaque::opaque
void * opaque
Definition: ops.c:1080
ff_sws_op_list_optimize
int ff_sws_op_list_optimize(SwsOpList *ops)
Fuse compatible and eliminate redundant operations, as well as replacing some operations with more ef...
Definition: ops_optimizer.c:340
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:68
ff_fmt_from_pixfmt
void ff_fmt_from_pixfmt(enum AVPixelFormat pixfmt, SwsFormat *fmt)
Subset of ff_fmt_from_frame() that sets default metadata for the format.
Definition: format.c:483
bprint.h
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
SWS_COMP_IDENTITY
@ SWS_COMP_IDENTITY
Definition: ops.c:296
av_max_q
static AVRational av_max_q(AVRational a, AVRational b)
Definition: ops.c:175
SwsOpList::ops
SwsOp * ops
Definition: ops.h:289
weights
static const int weights[]
Definition: hevc_pel.c:32
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
SWS_MASK_MAT3
@ SWS_MASK_MAT3
Definition: ops.h:222
ff_sws_encode_colors
int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, const SwsFormat *src, const SwsFormat *dst, bool *incomplete)
ops_internal.h
SwsFormat::width
int width
Definition: format.h:78
ff_sws_enum_op_lists
int ff_sws_enum_op_lists(SwsContext *ctx, void *opaque, enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt, int(*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
Helper function to enumerate over all possible (optimized) operation lists, under the current set of ...
Definition: ops.c:1050
lev
static LevelCodes lev[4+3+3]
Definition: clearvideo.c:80
SwsOp
Definition: ops.h:238
ff_sws_decode_pixfmt
int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
Append a set of operations for decoding/encoding raw pixels.
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
SwsComps::flags
SwsCompFlags flags[4]
Definition: ops.h:110
ret
ret
Definition: filter_design.txt:187
bswap.h
backend_murder
const SwsOpBackend backend_murder
Definition: ops_memcpy.c:143
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:293
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:65
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
SWS_PIXEL_TYPE_NB
@ SWS_PIXEL_TYPE_NB
Definition: ops.h:39
SwsComps
Definition: ops.h:109
EnumOpaque::cb
int(* cb)(SwsContext *ctx, void *opaque, SwsOp *op)
Definition: ops.c:1081
AVRational::den
int den
Denominator.
Definition: rational.h:60
SWS_COMP_SWAPPED
@ SWS_COMP_SWAPPED
Definition: ops.h:106
SwsReadWriteOp::packed
bool packed
Definition: ops.h:128
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
ff_sws_pixel_type_name
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition: ops.c:62
av_bprint_clear
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
SWS_OP_SWAP_BYTES
@ SWS_OP_SWAP_BYTES
Definition: ops.h:52
SwsFormat::color
SwsColor color
Definition: format.h:86
av_mul_q
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
SWS_COMP_EXACT
@ SWS_COMP_EXACT
Definition: ops.h:104
describe_lin_mask
static const char * describe_lin_mask(uint32_t mask)
Definition: ops.c:771
SwsReadWriteOp::elems
uint8_t elems
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition: ops.h:126
mem.h
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
scale
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition: intra.c:278
av_add_q
AVRational av_add_q(AVRational b, AVRational c)
Add two rationals.
Definition: rational.c:93
ff_sws_pack_op_decode
static void ff_sws_pack_op_decode(const SwsOp *op, uint64_t mask[4], int shift[4])
Definition: ops_internal.h:43
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
EnumOpaque
Definition: ops.c:1079
SwsSwizzleOp::in
uint8_t in[4]
Definition: ops.h:156
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:63
SWS_MASK_DIAG3
@ SWS_MASK_DIAG3
Definition: ops.h:220
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
propagate_flags
static void propagate_flags(SwsOp *op, const SwsComps *prev)
Definition: ops.c:307
avstring.h
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:296
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:288
av_bswap16
#define av_bswap16
Definition: bswap.h:28
ff_sws_op_type_name
const char * ff_sws_op_type_name(SwsOpType op)
Definition: ops.c:109
SwsContext
Main external API structure.
Definition: swscale.h:206
src
#define src
Definition: vp8dsp.c:248
read
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.
Definition: bitstream_template.h:239
ff_sws_encode_pixfmt
int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
ff_fmt_clear
static void ff_fmt_clear(SwsFormat *fmt)
Definition: format.h:89
min
float min
Definition: vorbis_enc_data.h:429