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 
42 const SwsOpBackend * const ff_sws_op_backends[] = {
44 #if ARCH_AARCH64 && HAVE_NEON
46 #elif ARCH_X86_64 && HAVE_X86ASM
47  &backend_x86,
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  }
183  case SWS_OP_SWAP_BYTES:
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 
280 enum {
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 
295 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
296  const SwsFilterWeights *weights)
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:
328  case SWS_OP_SWAP_BYTES:
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 
371  av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
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(idx);
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;
393  case SWS_OP_SWAP_BYTES:
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++)
402  av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
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);
441  FORWARD(i, 0, flags & SWS_COMP_DIRTY);
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])
451  FORWARD(0, i, flags & SWS_COMP_DIRTY);
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;
572  case SWS_OP_SWAP_BYTES:
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 
625 static 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 
731 void 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 {
816  if (flags & SWS_COMP_GARBAGE)
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 
832 static 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 
843 static 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 
856 static 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 
871 static const char *const rw_mode_names[] = {
872  [SWS_RW_PLANAR] = "planar",
873  [SWS_RW_PACKED] = "packed",
874  [SWS_RW_PALETTE] = "palette"
875 };
876 
877 void 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:
884  case SWS_OP_SWAP_BYTES:
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,
921  ff_sws_pixel_type_name(op->type),
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 
973 static 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 
987 void 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] ",
1003  ff_sws_pixel_type_name(op->type),
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);
1013  desc_plane_order(&bp, planes,
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 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:40
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:659
ff_sws_rw_op_planes
int ff_sws_rw_op_planes(const SwsOp *op)
Return the number of planes involved in a read/write operation.
Definition: ops.c:133
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:43
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:646
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:89
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:48
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:46
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:673
SWS_RW_PLANAR
@ 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
apply_filter_weights
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition: ops.c:295
rw_mode_names
static const char *const rw_mode_names[]
Definition: ops.c:871
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
SwsOpList::comps_src
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition: ops.h:312
merge_comp_flags
static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
Definition: ops.c:288
SWS_PIXEL_NONE
@ SWS_PIXEL_NONE
Definition: uops.h:40
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:713
SWS_COMP_ZERO
@ SWS_COMP_ZERO
Definition: ops.h:80
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:52
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:791
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:705
print_deps
static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
Definition: ops.c:832
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:756
planes
static const struct @607 planes[]
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
ff_sws_comp_mask_q4
SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
Definition: ops.c:100
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:242
ops.h
ff_sws_pixel_type_is_int
static av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: uops.h:63
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:60
SwsFilterWeights
Represents a computed filter kernel.
Definition: filters.h:85
describe_comp_flags
static char describe_comp_flags(SwsCompFlags flags)
Definition: ops.c:814
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:341
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:973
max
#define max(a, b)
Definition: cuda_runtime.h:33
SWS_OP_TYPE_NB
@ SWS_OP_TYPE_NB
Definition: ops.h:69
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_min_q64
static AVRational64 av_min_q64(AVRational64 a, AVRational64 b)
Definition: ops.c:147
format.h
RESET
#define RESET(I)
FORWARD
#define FORWARD(I, J, EXPR)
ff_sws_comp_mask_needed
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition: ops.c:123
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:302
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:301
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:987
print_q4
static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
Definition: ops.c:856
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: uops.h:98
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:42
av_ceil_log2
#define av_ceil_log2
Definition: common.h:97
SwsOpList::num_ops
int num_ops
Definition: ops.h:295
SwsCompFlags
SwsCompFlags
Definition: ops.h:77
print_q
static void print_q(AVBPrint *bp, const AVRational64 q)
Definition: ops.c:843
SwsSwizzleOp
Definition: ops.h:148
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
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
refstruct.h
SwsOp::op
SwsOpType op
Definition: ops.h:238
SWS_RW_PACKED
@ SWS_RW_PACKED
Definition: ops.h:108
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:56
first
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But first
Definition: rate_distortion.txt:12
avassert.h
backend_aarch64
const SwsOpBackend backend_aarch64
Definition: ops.c:268
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:265
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:504
ff_sws_pixel_expand
static AVRational64 ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
Definition: ops_internal.h:31
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
backend_c
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
Definition: uops_backend.c:199
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
av_cmp_q64
int av_cmp_q64(AVRational64 a, AVRational64 b)
Compare two 64-bit rationals.
Definition: rational64.c:108
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:54
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: uops.h:88
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:59
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:722
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:63
av_mul_q64
AVRational64 av_mul_q64(AVRational64 b, AVRational64 c)
Multiply two 64-bit rationals.
Definition: rational64.c:124
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpBackend
Definition: ops_dispatch.h:134
if
if(ret)
Definition: filter_design.txt:179
ff_sws_pixel_type_size
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition: uops.h:50
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:47
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:761
SWS_COMP_NONE
@ SWS_COMP_NONE
Definition: uops.h:95
NULL
#define NULL
Definition: coverity.c:32
SWS_PIXEL_TYPE_NB
@ SWS_PIXEL_TYPE_NB
Definition: uops.h:45
SwsFilterWeights::dst_size
int dst_size
Definition: filters.h:111
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:124
SWS_COMP_GARBAGE
@ SWS_COMP_GARBAGE
Definition: ops.h:78
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:64
SwsOpType
SwsOpType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:36
ff_sws_op_list_remove_at
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
Definition: ops.c:731
attributes.h
ff_sws_apply_op_q
void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4])
Apply an operation to an AVRational64.
Definition: ops.c:157
SwsFilterWeights::src_size
int src_size
Copy of the parameters used to generate this filter, for reference.
Definition: filters.h:110
SwsPixelType
SwsPixelType
Definition: uops.h:39
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_comp_mask_swizzle
void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz)
Definition: ops.c:110
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
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:239
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:742
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition: ops.c:802
size
int size
Definition: twinvq_data.h:10344
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:49
SwsOpList::src
SwsFormat src
Definition: ops.h:298
SWS_OP_INVALID
@ SWS_OP_INVALID
Definition: ops.h:37
av_malloc
#define av_malloc(s)
Definition: ops_static.c:52
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:315
SWS_OP_LUT_3D
@ SWS_OP_LUT_3D
Definition: ops.h:67
AVRational64
64-bit Rational number (pair of numerator and denominator).
Definition: rational64.h:52
SWS_COMP_DIRTY
@ SWS_COMP_DIRTY
Definition: ops.c:284
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:41
SWS_COMP
#define SWS_COMP(X)
Definition: uops.h:97
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: uops.h:43
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:625
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:119
SWS_COMP_CONST
@ SWS_COMP_CONST
Definition: ops.h:83
SwsLinearOp
Definition: ops.h:192
ff_sws_op_desc
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition: ops.c:877
SwsReadWriteOp::op
SwsOpType op
Definition: ops.h:134
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
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:68
bprint.h
SWS_COMP_IDENTITY
@ SWS_COMP_IDENTITY
Definition: ops.c:281
SwsOpList::ops
SwsOp * ops
Definition: ops.h:294
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_PIXEL_U8
@ SWS_PIXEL_U8
Definition: uops.h:41
ops_internal.h
lev
static LevelCodes lev[4+3+3]
Definition: clearvideo.c:80
SwsOp
Definition: ops.h:237
AVRational64::den
int64_t den
Denominator.
Definition: rational64.h:54
bound
static double bound(const double threshold, const double val)
Definition: af_dynaudnorm.c:413
SwsComps::flags
SwsCompFlags flags[4]
Definition: ops.h:87
ret
ret
Definition: filter_design.txt:187
bswap.h
backend_murder
const SwsOpBackend backend_murder
Definition: ops_memcpy.c:144
SwsComps::min
AVRational64 min[4]
Definition: ops.h:91
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:298
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:55
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
av_q2d_64
static double av_q2d_64(AVRational64 a)
Convert an AVRational64 to a double.
Definition: rational64.h:90
SWS_RW_PALETTE
@ SWS_RW_PALETTE
Definition: ops.h:109
av_make_q64
static AVRational64 av_make_q64(int64_t num, int64_t den)
Create an AVRational64.
Definition: rational64.h:64
SwsComps
Definition: ops.h:86
av_refstruct_ref_c
const void * av_refstruct_ref_c(const void *obj)
Analog of av_refstruct_ref(), but for constant objects.
Definition: refstruct.c:149
SWS_COMP_SWAPPED
@ SWS_COMP_SWAPPED
Definition: ops.h:81
ff_sws_pixel_type_name
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition: ops.c:56
av_max_q64
static AVRational64 av_max_q64(AVRational64 a, AVRational64 b)
Definition: ops.c:152
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:42
SWS_COMP_COPY
@ SWS_COMP_COPY
Definition: ops.h:82
SwsComps::dep_in
SwsCompMask dep_in[4]
Definition: ops.h:94
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
SWS_COMP_EXACT
@ SWS_COMP_EXACT
Definition: ops.h:79
SwsReadWriteOp::elems
uint8_t elems
Definition: ops.h:123
mem.h
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: uops.h:44
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
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
AVRational64::num
int64_t num
Numerator.
Definition: rational64.h:53
SwsComps::max
AVRational64 max[4]
Definition: ops.h:91
SwsSwizzleOp::in
uint8_t in[4]
Definition: ops.h:155
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:53
SwsReadWriteOp::filter
struct SwsReadWriteOp::@583 filter
Filter kernel to apply to each plane while sampling.
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
avstring.h
SwsReadWriteOp::mode
SwsReadWriteMode mode
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition: ops.h:122
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:301
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:293
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:71
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: uops.h:42
SWS_MASK
#define SWS_MASK(I, J)
Definition: uops.h:231
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_fmt_clear
static void ff_fmt_clear(SwsFormat *fmt)
Definition: format.h:90
ff_sws_comp_mask_str
#define ff_sws_comp_mask_str(mask)
Definition: uops.h:110
av_add_q64
AVRational64 av_add_q64(AVRational64 b, AVRational64 c)
Add two 64-bit rationals.
Definition: rational64.c:135
min
float min
Definition: vorbis_enc_data.h:429