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/avassert.h"
22 #include "libavutil/avstring.h"
23 #include "libavutil/bprint.h"
24 #include "libavutil/bswap.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/rational.h"
27 #include "libavutil/refstruct.h"
28 
29 #include "format.h"
30 #include "ops.h"
31 #include "ops_internal.h"
32 
33 extern const SwsOpBackend backend_c;
34 extern const SwsOpBackend backend_murder;
35 extern const SwsOpBackend backend_aarch64;
36 extern const SwsOpBackend backend_x86;
37 extern const SwsOpBackend backend_vulkan;
38 
39 const SwsOpBackend * const ff_sws_op_backends[] = {
41 #if ARCH_AARCH64 && HAVE_NEON
43 #elif ARCH_X86_64 && HAVE_X86ASM
44  &backend_x86,
45 #endif
46  &backend_c,
47 #if CONFIG_VULKAN
49 #endif
50  NULL
51 };
52 
54 {
55  switch (type) {
56  case SWS_PIXEL_U8: return "u8";
57  case SWS_PIXEL_U16: return "u16";
58  case SWS_PIXEL_U32: return "u32";
59  case SWS_PIXEL_F32: return "f32";
60  case SWS_PIXEL_NONE: return "none";
61  case SWS_PIXEL_TYPE_NB: break;
62  }
63 
64  av_unreachable("Invalid pixel type!");
65  return "ERR";
66 }
67 
69 {
70  switch (type) {
71  case SWS_PIXEL_U8: return sizeof(uint8_t);
72  case SWS_PIXEL_U16: return sizeof(uint16_t);
73  case SWS_PIXEL_U32: return sizeof(uint32_t);
74  case SWS_PIXEL_F32: return sizeof(float);
75  case SWS_PIXEL_NONE: break;
76  case SWS_PIXEL_TYPE_NB: break;
77  }
78 
79  av_unreachable("Invalid pixel type!");
80  return 0;
81 }
82 
84 {
85  switch (type) {
86  case SWS_PIXEL_U8:
87  case SWS_PIXEL_U16:
88  case SWS_PIXEL_U32:
89  return true;
90  case SWS_PIXEL_F32:
91  return false;
92  case SWS_PIXEL_NONE:
93  case SWS_PIXEL_TYPE_NB: break;
94  }
95 
96  av_unreachable("Invalid pixel type!");
97  return false;
98 }
99 
101 {
102  switch (op) {
103  case SWS_OP_READ: return "SWS_OP_READ";
104  case SWS_OP_WRITE: return "SWS_OP_WRITE";
105  case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
106  case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
107  case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
108  case SWS_OP_PACK: return "SWS_OP_PACK";
109  case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
110  case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
111  case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
112  case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
113  case SWS_OP_MIN: return "SWS_OP_MIN";
114  case SWS_OP_MAX: return "SWS_OP_MAX";
115  case SWS_OP_SCALE: return "SWS_OP_SCALE";
116  case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
117  case SWS_OP_DITHER: return "SWS_OP_DITHER";
118  case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
119  case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
120  case SWS_OP_INVALID: return "SWS_OP_INVALID";
121  case SWS_OP_TYPE_NB: break;
122  }
123 
124  av_unreachable("Invalid operation type!");
125  return "ERR";
126 }
127 
128 /* biased towards `a` */
130 {
131  return av_cmp_q(a, b) == 1 ? b : a;
132 }
133 
135 {
136  return av_cmp_q(a, b) == -1 ? b : a;
137 }
138 
140 {
141  uint64_t mask[4];
142  int shift[4];
143 
144  switch (op->op) {
145  case SWS_OP_READ:
146  case SWS_OP_WRITE:
147  return;
148  case SWS_OP_UNPACK: {
151  unsigned val = x[0].num;
152  for (int i = 0; i < 4; i++)
153  x[i] = Q((val >> shift[i]) & mask[i]);
154  return;
155  }
156  case SWS_OP_PACK: {
159  unsigned val = 0;
160  for (int i = 0; i < 4; i++)
161  val |= (x[i].num & mask[i]) << shift[i];
162  x[0] = Q(val);
163  return;
164  }
165  case SWS_OP_SWAP_BYTES:
167  switch (ff_sws_pixel_type_size(op->type)) {
168  case 2:
169  for (int i = 0; i < 4; i++)
170  x[i].num = av_bswap16(x[i].num);
171  break;
172  case 4:
173  for (int i = 0; i < 4; i++)
174  x[i].num = av_bswap32(x[i].num);
175  break;
176  }
177  return;
178  case SWS_OP_CLEAR:
179  for (int i = 0; i < 4; i++) {
180  if (op->c.q4[i].den)
181  x[i] = op->c.q4[i];
182  }
183  return;
184  case SWS_OP_LSHIFT: {
186  AVRational mult = Q(1 << op->c.u);
187  for (int i = 0; i < 4; i++)
188  x[i] = x[i].den ? av_mul_q(x[i], mult) : x[i];
189  return;
190  }
191  case SWS_OP_RSHIFT: {
193  for (int i = 0; i < 4; i++)
194  x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->c.u) : x[i];
195  return;
196  }
197  case SWS_OP_SWIZZLE: {
198  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
199  for (int i = 0; i < 4; i++)
200  x[i] = orig[op->swizzle.in[i]];
201  return;
202  }
203  case SWS_OP_CONVERT:
204  if (ff_sws_pixel_type_is_int(op->convert.to)) {
205  const AVRational scale = ff_sws_pixel_expand(op->type, op->convert.to);
206  for (int i = 0; i < 4; i++) {
207  x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
208  if (op->convert.expand)
209  x[i] = av_mul_q(x[i], scale);
210  }
211  }
212  return;
213  case SWS_OP_DITHER:
215  for (int i = 0; i < 4; i++) {
216  if (op->dither.y_offset[i] >= 0 && x[i].den)
217  x[i] = av_add_q(x[i], av_make_q(1, 2));
218  }
219  return;
220  case SWS_OP_MIN:
221  for (int i = 0; i < 4; i++)
222  x[i] = av_min_q(x[i], op->c.q4[i]);
223  return;
224  case SWS_OP_MAX:
225  for (int i = 0; i < 4; i++)
226  x[i] = av_max_q(x[i], op->c.q4[i]);
227  return;
228  case SWS_OP_LINEAR: {
230  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
231  for (int i = 0; i < 4; i++) {
232  AVRational sum = op->lin.m[i][4];
233  for (int j = 0; j < 4; j++)
234  sum = av_add_q(sum, av_mul_q(orig[j], op->lin.m[i][j]));
235  x[i] = sum;
236  }
237  return;
238  }
239  case SWS_OP_SCALE:
240  for (int i = 0; i < 4; i++)
241  x[i] = x[i].den ? av_mul_q(x[i], op->c.q) : x[i];
242  return;
243  case SWS_OP_FILTER_H:
244  case SWS_OP_FILTER_V:
245  /* Filters have normalized energy by definition, so they don't
246  * conceptually modify individual components */
247  return;
248  }
249 
250  av_unreachable("Invalid operation type!");
251 }
252 
253 /* merge_comp_flags() forms a monoid with flags_identity as the null element */
256 {
257  const SwsCompFlags flags_or = SWS_COMP_GARBAGE;
258  const SwsCompFlags flags_and = SWS_COMP_ZERO | SWS_COMP_EXACT;
259  return ((a & b) & flags_and) | ((a | b) & flags_or);
260 }
261 
262 /* Linearly propagate flags per component */
263 static void propagate_flags(SwsOp *op, const SwsComps *prev)
264 {
265  for (int i = 0; i < 4; i++)
266  op->comps.flags[i] = prev->flags[i];
267 }
268 
269 /* Clear undefined values in dst with src */
271 {
272  for (int i = 0; i < 4; i++) {
273  if (dst[i].den == 0)
274  dst[i] = src[i];
275  }
276 }
277 
278 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
279  const SwsFilterWeights *weights)
280 {
281  const AVRational posw = { weights->sum_positive, SWS_FILTER_SCALE };
282  const AVRational negw = { weights->sum_negative, SWS_FILTER_SCALE };
283  for (int i = 0; i < 4; i++) {
284  comps->flags[i] = prev->flags[i];
285  /* Only point sampling preserves exactness */
286  if (weights->filter_size != 1)
287  comps->flags[i] &= ~SWS_COMP_EXACT;
288  /* Update min/max assuming extremes */
289  comps->min[i] = av_add_q(av_mul_q(prev->min[i], posw),
290  av_mul_q(prev->max[i], negw));
291  comps->max[i] = av_add_q(av_mul_q(prev->min[i], negw),
292  av_mul_q(prev->max[i], posw));
293  }
294 }
295 
296 /* Infer + propagate known information about components */
298 {
299  SwsComps prev = { .flags = {
301  }};
302 
303  /* Forwards pass, propagates knowledge about the incoming pixel values */
304  for (int n = 0; n < ops->num_ops; n++) {
305  SwsOp *op = &ops->ops[n];
306 
307  switch (op->op) {
308  case SWS_OP_READ:
309  case SWS_OP_LINEAR:
310  case SWS_OP_DITHER:
311  case SWS_OP_SWAP_BYTES:
312  case SWS_OP_UNPACK:
313  case SWS_OP_FILTER_H:
314  case SWS_OP_FILTER_V:
315  break; /* special cases, handled below */
316  default:
317  memcpy(op->comps.min, prev.min, sizeof(prev.min));
318  memcpy(op->comps.max, prev.max, sizeof(prev.max));
319  ff_sws_apply_op_q(op, op->comps.min);
320  ff_sws_apply_op_q(op, op->comps.max);
321  break;
322  }
323 
324  switch (op->op) {
325  case SWS_OP_READ:
326  /* Active components are taken from the user-provided values,
327  * other components are explicitly stripped */
328  for (int i = 0; i < op->rw.elems; i++) {
329  const int idx = op->rw.packed ? i : ops->plane_src[i];
330  op->comps.flags[i] = ops->comps_src.flags[idx];
331  op->comps.min[i] = ops->comps_src.min[idx];
332  op->comps.max[i] = ops->comps_src.max[idx];
333  }
334  for (int i = op->rw.elems; i < 4; i++) {
335  op->comps.flags[i] = prev.flags[i];
336  op->comps.min[i] = prev.min[i];
337  op->comps.max[i] = prev.max[i];
338  }
339 
340  if (op->rw.filter) {
341  const SwsComps prev = op->comps;
342  apply_filter_weights(&op->comps, &prev, op->rw.kernel);
343  }
344  break;
345  case SWS_OP_SWAP_BYTES:
346  for (int i = 0; i < 4; i++) {
347  op->comps.flags[i] = prev.flags[i] ^ SWS_COMP_SWAPPED;
348  op->comps.min[i] = prev.min[i];
349  op->comps.max[i] = prev.max[i];
350  }
351  break;
352  case SWS_OP_WRITE:
353  for (int i = 0; i < op->rw.elems; i++)
354  av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
355  /* fall through */
356  case SWS_OP_LSHIFT:
357  case SWS_OP_RSHIFT:
358  propagate_flags(op, &prev);
359  break;
360  case SWS_OP_MIN:
361  propagate_flags(op, &prev);
362  clear_undefined_values(op->comps.max, op->c.q4);
363  break;
364  case SWS_OP_MAX:
365  propagate_flags(op, &prev);
366  clear_undefined_values(op->comps.min, op->c.q4);
367  break;
368  case SWS_OP_DITHER:
369  /* Strip zero flag because of the nonzero dithering offset */
370  for (int i = 0; i < 4; i++) {
371  op->comps.min[i] = prev.min[i];
372  op->comps.max[i] = prev.max[i];
373  if (op->dither.y_offset[i] < 0)
374  continue;
375  op->comps.flags[i] = prev.flags[i] & ~SWS_COMP_ZERO;
376  op->comps.min[i] = av_add_q(op->comps.min[i], op->dither.min);
377  op->comps.max[i] = av_add_q(op->comps.max[i], op->dither.max);
378  }
379  break;
380  case SWS_OP_UNPACK:
381  for (int i = 0; i < 4; i++) {
382  const int pattern = op->pack.pattern[i];
383  if (pattern) {
384  av_assert1(pattern < 32);
385  op->comps.flags[i] = prev.flags[0];
386  op->comps.min[i] = Q(0);
387  op->comps.max[i] = Q((1ULL << pattern) - 1);
388  } else
389  op->comps.flags[i] = SWS_COMP_GARBAGE;
390  }
391  break;
392  case SWS_OP_PACK: {
394  for (int i = 0; i < 4; i++) {
395  if (op->pack.pattern[i])
396  flags = merge_comp_flags(flags, prev.flags[i]);
397  if (i > 0) /* clear remaining comps for sanity */
398  op->comps.flags[i] = SWS_COMP_GARBAGE;
399  }
400  op->comps.flags[0] = flags;
401  break;
402  }
403  case SWS_OP_CLEAR:
404  for (int i = 0; i < 4; i++) {
405  if (op->c.q4[i].den) {
406  op->comps.flags[i] = 0;
407  if (op->c.q4[i].num == 0)
408  op->comps.flags[i] |= SWS_COMP_ZERO;
409  if (op->c.q4[i].den == 1)
410  op->comps.flags[i] |= SWS_COMP_EXACT;
411  } else {
412  op->comps.flags[i] = prev.flags[i];
413  }
414  }
415  break;
416  case SWS_OP_SWIZZLE:
417  for (int i = 0; i < 4; i++)
418  op->comps.flags[i] = prev.flags[op->swizzle.in[i]];
419  break;
420  case SWS_OP_CONVERT:
421  for (int i = 0; i < 4; i++) {
422  op->comps.flags[i] = prev.flags[i];
423  if (ff_sws_pixel_type_is_int(op->convert.to))
424  op->comps.flags[i] |= SWS_COMP_EXACT;
425  }
426  break;
427  case SWS_OP_LINEAR:
428  for (int i = 0; i < 4; i++) {
430  AVRational min = Q(0), max = Q(0);
431  for (int j = 0; j < 4; j++) {
432  const AVRational k = op->lin.m[i][j];
433  AVRational mink = av_mul_q(prev.min[j], k);
434  AVRational maxk = av_mul_q(prev.max[j], k);
435  if (k.num) {
436  flags = merge_comp_flags(flags, prev.flags[j]);
437  if (k.den != 1) /* fractional coefficient */
438  flags &= ~SWS_COMP_EXACT;
439  if (k.num < 0)
440  FFSWAP(AVRational, mink, maxk);
441  min = av_add_q(min, mink);
442  max = av_add_q(max, maxk);
443  }
444  }
445  if (op->lin.m[i][4].num) { /* nonzero offset */
446  flags &= ~SWS_COMP_ZERO;
447  if (op->lin.m[i][4].den != 1) /* fractional offset */
448  flags &= ~SWS_COMP_EXACT;
449  min = av_add_q(min, op->lin.m[i][4]);
450  max = av_add_q(max, op->lin.m[i][4]);
451  }
452  op->comps.flags[i] = flags;
453  op->comps.min[i] = min;
454  op->comps.max[i] = max;
455  }
456  break;
457  case SWS_OP_SCALE:
458  for (int i = 0; i < 4; i++) {
459  op->comps.flags[i] = prev.flags[i];
460  if (op->c.q.den != 1) /* fractional scale */
461  op->comps.flags[i] &= ~SWS_COMP_EXACT;
462  if (op->c.q.num < 0)
463  FFSWAP(AVRational, op->comps.min[i], op->comps.max[i]);
464  }
465  break;
466  case SWS_OP_FILTER_H:
467  case SWS_OP_FILTER_V: {
468  apply_filter_weights(&op->comps, &prev, op->filter.kernel);
469  break;
470  }
471 
472  case SWS_OP_INVALID:
473  case SWS_OP_TYPE_NB:
474  av_unreachable("Invalid operation type!");
475  }
476 
477  prev = op->comps;
478  }
479 
480  /* Backwards pass, solves for component dependencies */
481  bool need_out[4] = { false, false, false, false };
482  for (int n = ops->num_ops - 1; n >= 0; n--) {
483  SwsOp *op = &ops->ops[n];
484  bool need_in[4] = { false, false, false, false };
485 
486  for (int i = 0; i < 4; i++) {
487  if (!need_out[i]) {
488  op->comps.flags[i] = SWS_COMP_GARBAGE;
489  op->comps.min[i] = op->comps.max[i] = (AVRational) {0};
490  }
491  }
492 
493  switch (op->op) {
494  case SWS_OP_READ:
495  case SWS_OP_WRITE:
496  for (int i = 0; i < op->rw.elems; i++)
497  need_in[i] = op->op == SWS_OP_WRITE;
498  for (int i = op->rw.elems; i < 4; i++)
499  need_in[i] = need_out[i];
500  break;
501  case SWS_OP_SWAP_BYTES:
502  case SWS_OP_LSHIFT:
503  case SWS_OP_RSHIFT:
504  case SWS_OP_CONVERT:
505  case SWS_OP_DITHER:
506  case SWS_OP_MIN:
507  case SWS_OP_MAX:
508  case SWS_OP_SCALE:
509  case SWS_OP_FILTER_H:
510  case SWS_OP_FILTER_V:
511  for (int i = 0; i < 4; i++)
512  need_in[i] = need_out[i];
513  break;
514  case SWS_OP_UNPACK:
515  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
516  need_in[0] |= need_out[i];
517  break;
518  case SWS_OP_PACK:
519  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
520  need_in[i] = need_out[0];
521  break;
522  case SWS_OP_CLEAR:
523  for (int i = 0; i < 4; i++) {
524  if (!op->c.q4[i].den)
525  need_in[i] = need_out[i];
526  }
527  break;
528  case SWS_OP_SWIZZLE:
529  for (int i = 0; i < 4; i++)
530  need_in[op->swizzle.in[i]] |= need_out[i];
531  break;
532  case SWS_OP_LINEAR:
533  for (int i = 0; i < 4; i++) {
534  for (int j = 0; j < 4; j++) {
535  if (op->lin.m[i][j].num)
536  need_in[j] |= need_out[i];
537  }
538  }
539  break;
540  }
541 
542  for (int i = 0; i < 4; i++) {
543  need_out[i] = need_in[i];
544  op->comps.unused[i] = !need_in[i];
545  }
546  }
547 }
548 
549 static void op_uninit(SwsOp *op)
550 {
551  switch (op->op) {
552  case SWS_OP_READ:
553  av_refstruct_unref(&op->rw.kernel);
554  break;
555  case SWS_OP_DITHER:
556  av_refstruct_unref(&op->dither.matrix);
557  break;
558  case SWS_OP_FILTER_H:
559  case SWS_OP_FILTER_V:
560  av_refstruct_unref(&op->filter.kernel);
561  break;
562  }
563 
564  *op = (SwsOp) {0};
565 }
566 
568 {
569  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
570  if (!ops)
571  return NULL;
572 
573  for (int i = 0; i < 4; i++)
574  ops->plane_src[i] = ops->plane_dst[i] = i;
575  ff_fmt_clear(&ops->src);
576  ff_fmt_clear(&ops->dst);
577  return ops;
578 }
579 
581 {
582  SwsOpList *ops = *p_ops;
583  if (!ops)
584  return;
585 
586  for (int i = 0; i < ops->num_ops; i++)
587  op_uninit(&ops->ops[i]);
588 
589  av_freep(&ops->ops);
590  av_free(ops);
591  *p_ops = NULL;
592 }
593 
595 {
596  SwsOpList *copy = av_malloc(sizeof(*copy));
597  if (!copy)
598  return NULL;
599 
600  int num = ops->num_ops;
601  if (num)
602  num = 1 << av_ceil_log2(num);
603 
604  *copy = *ops;
605  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
606  if (!copy->ops) {
607  av_free(copy);
608  return NULL;
609  }
610 
611  for (int i = 0; i < copy->num_ops; i++) {
612  const SwsOp *op = &copy->ops[i];
613  switch (op->op) {
614  case SWS_OP_READ:
615  if (op->rw.kernel)
616  av_refstruct_ref(op->rw.kernel);
617  break;
618  case SWS_OP_DITHER:
619  av_refstruct_ref(op->dither.matrix);
620  break;
621  case SWS_OP_FILTER_H:
622  case SWS_OP_FILTER_V:
623  av_refstruct_ref(op->filter.kernel);
624  break;
625  }
626  }
627 
628  return copy;
629 }
630 
632 {
633  if (!ops->num_ops)
634  return NULL;
635 
636  const SwsOp *read = &ops->ops[0];
637  return read->op == SWS_OP_READ ? read : NULL;
638 }
639 
641 {
642  if (!ops->num_ops)
643  return NULL;
644 
645  const SwsOp *write = &ops->ops[ops->num_ops - 1];
646  return write->op == SWS_OP_WRITE ? write : NULL;
647 }
648 
649 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
650 {
651  const int end = ops->num_ops - count;
652  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
653  for (int i = 0; i < count; i++)
654  op_uninit(&ops->ops[index + i]);
655  for (int i = index; i < end; i++)
656  ops->ops[i] = ops->ops[i + count];
657  ops->num_ops = end;
658 }
659 
661 {
662  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
663  if (!ret) {
664  op_uninit(op);
665  return AVERROR(ENOMEM);
666  }
667 
668  for (int i = ops->num_ops - 1; i > index; i--)
669  ops->ops[i] = ops->ops[i - 1];
670  ops->ops[index] = *op;
671  return 0;
672 }
673 
675 {
676  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
677 }
678 
680 {
681  if (!ops->num_ops)
682  return true;
683 
684  const SwsOp *read = ff_sws_op_list_input(ops);
685  const SwsOp *write = ff_sws_op_list_output(ops);
686  if (!read || !write || ops->num_ops > 2 ||
687  read->type != write->type ||
688  read->rw.packed != write->rw.packed ||
689  read->rw.elems != write->rw.elems ||
690  read->rw.frac != write->rw.frac)
691  return false;
692 
693  /**
694  * Note that this check is unlikely to ever be hit in practice, since it
695  * would imply the existence of planar formats with different plane orders
696  * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
697  * However, the check is cheap and lets me sleep at night.
698  */
699  const int num_planes = read->rw.packed ? 1 : read->rw.elems;
700  for (int i = 0; i < num_planes; i++) {
701  if (ops->plane_src[i] != ops->plane_dst[i])
702  return false;
703  }
704 
705  return true;
706 }
707 
709 {
710  int max_size = 0;
711  for (int i = 0; i < ops->num_ops; i++) {
712  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
713  max_size = FFMAX(max_size, size);
714  }
715 
716  return max_size;
717 }
718 
720 {
721  uint32_t mask = 0;
722  for (int i = 0; i < 4; i++) {
723  for (int j = 0; j < 5; j++) {
724  if (av_cmp_q(c.m[i][j], Q(i == j)))
725  mask |= SWS_MASK(i, j);
726  }
727  }
728  return mask;
729 }
730 
731 static const char *describe_lin_mask(uint32_t mask)
732 {
733  /* Try to be fairly descriptive without assuming too much */
734  static const struct {
735  char name[24];
736  uint32_t mask;
737  } patterns[] = {
738  { "noop", 0 },
739  { "luma", SWS_MASK_LUMA },
740  { "alpha", SWS_MASK_ALPHA },
741  { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA },
742  { "dot3", 0x7 },
743  { "dot4", 0xF },
744  { "row0", SWS_MASK_ROW(0) },
745  { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA },
746  { "col0", SWS_MASK_COL(0) },
747  { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 },
748  { "off3", SWS_MASK_OFF3 },
749  { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA },
750  { "diag3", SWS_MASK_DIAG3 },
751  { "diag4", SWS_MASK_DIAG4 },
752  { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA },
753  { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 },
754  { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
755  { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 },
756  { "matrix3", SWS_MASK_MAT3 },
757  { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 },
758  { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
759  { "matrix4", SWS_MASK_MAT4 },
760  { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 },
761  };
762 
763  for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
764  if (!(mask & ~patterns[i].mask))
765  return patterns[i].name;
766  }
767 
768  av_unreachable("Invalid linear mask!");
769  return "ERR";
770 }
771 
773 {
774  if (flags & SWS_COMP_GARBAGE)
775  return 'X';
776  else if (flags & SWS_COMP_ZERO)
777  return '0';
778  else if (flags & SWS_COMP_SWAPPED)
779  return 'z';
780  else if (flags & SWS_COMP_EXACT)
781  return '+';
782  else
783  return '.';
784 }
785 
786 static void print_q(AVBPrint *bp, const AVRational q, bool ignore_den0)
787 {
788  if (!q.den && ignore_den0) {
789  av_bprintf(bp, "_");
790  } else if (!q.den) {
791  av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
792  } else if (q.den == 1) {
793  av_bprintf(bp, "%d", q.num);
794  } else if (abs(q.num) > 1000 || abs(q.den) > 1000) {
795  av_bprintf(bp, "%f", av_q2d(q));
796  } else {
797  av_bprintf(bp, "%d/%d", q.num, q.den);
798  }
799 }
800 
801 static void print_q4(AVBPrint *bp, const AVRational q4[4], bool ignore_den0,
802  const SwsCompFlags flags[4])
803 {
804  av_bprintf(bp, "{");
805  for (int i = 0; i < 4; i++) {
806  if (i)
807  av_bprintf(bp, " ");
808  if (flags[i] & SWS_COMP_GARBAGE) {
809  av_bprintf(bp, "_");
810  } else {
811  print_q(bp, q4[i], ignore_den0);
812  }
813  }
814  av_bprintf(bp, "}");
815 }
816 
817 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
818 {
819  const char *name = ff_sws_op_type_name(op->op);
820 
821  switch (op->op) {
822  case SWS_OP_INVALID:
823  case SWS_OP_SWAP_BYTES:
824  av_bprintf(bp, "%s", name);
825  break;
826  case SWS_OP_READ:
827  case SWS_OP_WRITE:
828  av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
829  op->rw.elems, op->rw.packed ? "packed" : "planar",
830  op->rw.frac);
831  if (!op->rw.filter)
832  break;
833  const SwsFilterWeights *kernel = op->rw.kernel;
834  av_bprintf(bp, " + %d tap %s filter (%c)",
835  kernel->filter_size, kernel->name,
836  op->rw.filter == SWS_OP_FILTER_H ? 'H' : 'V');
837  break;
838  case SWS_OP_LSHIFT:
839  av_bprintf(bp, "%-20s: << %u", name, op->c.u);
840  break;
841  case SWS_OP_RSHIFT:
842  av_bprintf(bp, "%-20s: >> %u", name, op->c.u);
843  break;
844  case SWS_OP_PACK:
845  case SWS_OP_UNPACK:
846  av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
847  op->pack.pattern[0], op->pack.pattern[1],
848  op->pack.pattern[2], op->pack.pattern[3]);
849  break;
850  case SWS_OP_CLEAR:
851  av_bprintf(bp, "%-20s: ", name);
852  print_q4(bp, op->c.q4, true, op->comps.flags);
853  break;
854  case SWS_OP_SWIZZLE:
855  av_bprintf(bp, "%-20s: %d%d%d%d", name,
856  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
857  break;
858  case SWS_OP_CONVERT:
859  av_bprintf(bp, "%-20s: %s -> %s%s", name,
860  ff_sws_pixel_type_name(op->type),
861  ff_sws_pixel_type_name(op->convert.to),
862  op->convert.expand ? " (expand)" : "");
863  break;
864  case SWS_OP_DITHER:
865  av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
866  1 << op->dither.size_log2, 1 << op->dither.size_log2,
867  op->dither.y_offset[0], op->dither.y_offset[1],
868  op->dither.y_offset[2], op->dither.y_offset[3]);
869  break;
870  case SWS_OP_MIN:
871  av_bprintf(bp, "%-20s: x <= ", name);
872  print_q4(bp, op->c.q4, true, op->comps.flags);
873  break;
874  case SWS_OP_MAX:
875  av_bprintf(bp, "%-20s: ", name);
876  print_q4(bp, op->c.q4, true, op->comps.flags);
877  av_bprintf(bp, " <= x");
878  break;
879  case SWS_OP_LINEAR:
880  av_bprintf(bp, "%-20s: %s [", name, describe_lin_mask(op->lin.mask));
881  for (int i = 0; i < 4; i++) {
882  av_bprintf(bp, "%s[", i ? " " : "");
883  for (int j = 0; j < 5; j++) {
884  av_bprintf(bp, j ? " " : "");
885  print_q(bp, op->lin.m[i][j], false);
886  }
887  av_bprintf(bp, "]");
888  }
889  av_bprintf(bp, "]");
890  break;
891  case SWS_OP_SCALE:
892  av_bprintf(bp, "%-20s: * %d", name, op->c.q.num);
893  if (op->c.q.den != 1)
894  av_bprintf(bp, "/%d", op->c.q.den);
895  break;
896  case SWS_OP_FILTER_H:
897  case SWS_OP_FILTER_V: {
898  const SwsFilterWeights *kernel = op->filter.kernel;
899  av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
900  kernel->src_size, kernel->dst_size,
901  kernel->name, kernel->filter_size);
902  break;
903  }
904  case SWS_OP_TYPE_NB:
905  break;
906  }
907 }
908 
909 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
910 {
911  bool inorder = true;
912  for (int i = 0; i < nb_planes; i++)
913  inorder &= order[i] == i;
914  if (inorder)
915  return;
916 
917  av_bprintf(bp, ", via {");
918  for (int i = 0; i < nb_planes; i++)
919  av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
920  av_bprintf(bp, "}");
921 }
922 
923 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
924  const SwsOpList *ops)
925 {
926  AVBPrint bp;
927  if (!ops->num_ops) {
928  av_log(log, lev, " (empty)\n");
929  return;
930  }
931 
933 
934  for (int i = 0; i < ops->num_ops; i++) {
935  const SwsOp *op = &ops->ops[i];
936  av_bprint_clear(&bp);
937  av_bprintf(&bp, " [%3s %c%c%c%c] ",
938  ff_sws_pixel_type_name(op->type),
939  describe_comp_flags(op->comps.flags[0]),
940  describe_comp_flags(op->comps.flags[1]),
941  describe_comp_flags(op->comps.flags[2]),
942  describe_comp_flags(op->comps.flags[3]));
943 
944  ff_sws_op_desc(&bp, op);
945 
946  if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
947  const int planes = op->rw.packed ? 1 : op->rw.elems;
949  op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
950  }
951 
953  av_log(log, lev, "%s\n", bp.str);
954 
955  if (op->comps.min[0].den || op->comps.min[1].den ||
956  op->comps.min[2].den || op->comps.min[3].den ||
957  op->comps.max[0].den || op->comps.max[1].den ||
958  op->comps.max[2].den || op->comps.max[3].den)
959  {
960  av_bprint_clear(&bp);
961  av_bprintf(&bp, " min: ");
962  print_q4(&bp, op->comps.min, false, op->comps.flags);
963  av_bprintf(&bp, ", max: ");
964  print_q4(&bp, op->comps.max, false, op->comps.flags);
966  av_log(log, lev_extra, "%s\n", bp.str);
967  }
968 
969  }
970 
971  av_log(log, lev, " (X = unused, z = byteswapped, + = exact, 0 = zero)\n");
972 }
973 
974 static int enum_ops_fmt(SwsContext *ctx, void *opaque,
975  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
976  int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
977 {
978  int ret;
981  if (!ops)
982  return AVERROR(ENOMEM);
983 
984  ff_fmt_from_pixfmt(src_fmt, &ops->src);
985  ff_fmt_from_pixfmt(dst_fmt, &ops->dst);
986  ops->src.width = ops->dst.width = 16;
987  ops->src.height = ops->dst.height = 16;
988 
989  bool incomplete = ff_infer_colors(&ops->src.color, &ops->dst.color);
990  if (ff_sws_decode_pixfmt(ops, src_fmt) < 0 ||
991  ff_sws_decode_colors(ctx, type, ops, &ops->src, &incomplete) < 0 ||
992  ff_sws_encode_colors(ctx, type, ops, &ops->src, &ops->dst, &incomplete) < 0 ||
993  ff_sws_encode_pixfmt(ops, dst_fmt) < 0)
994  {
995  ret = 0; /* silently skip unsupported formats */
996  goto fail;
997  }
998 
1000  if (ret < 0)
1001  goto fail;
1002 
1003  ret = cb(ctx, opaque, ops);
1004  if (ret < 0)
1005  goto fail;
1006 
1007 fail:
1008  ff_sws_op_list_free(&ops);
1009  return ret;
1010 }
1011 
1013  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1014  int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1015 {
1016  const AVPixFmtDescriptor *src_start = av_pix_fmt_desc_next(NULL);
1017  const AVPixFmtDescriptor *dst_start = src_start;
1018  if (src_fmt != AV_PIX_FMT_NONE)
1019  src_start = av_pix_fmt_desc_get(src_fmt);
1020  if (dst_fmt != AV_PIX_FMT_NONE)
1021  dst_start = av_pix_fmt_desc_get(dst_fmt);
1022 
1023  const AVPixFmtDescriptor *src, *dst;
1024  for (src = src_start; src; src = av_pix_fmt_desc_next(src)) {
1025  const enum AVPixelFormat src_f = av_pix_fmt_desc_get_id(src);
1026  for (dst = dst_start; dst; dst = av_pix_fmt_desc_next(dst)) {
1027  const enum AVPixelFormat dst_f = av_pix_fmt_desc_get_id(dst);
1028  int ret = enum_ops_fmt(ctx, opaque, src_f, dst_f, cb);
1029  if (ret < 0)
1030  return ret;
1031  if (dst_fmt != AV_PIX_FMT_NONE)
1032  break;
1033  }
1034  if (src_fmt != AV_PIX_FMT_NONE)
1035  break;
1036  }
1037 
1038  return 0;
1039 }
1040 
1041 struct EnumOpaque {
1042  void *opaque;
1043  int (*cb)(SwsContext *ctx, void *opaque, SwsOp *op);
1044 };
1045 
1046 static int enum_ops(SwsContext *ctx, void *opaque, SwsOpList *ops)
1047 {
1048  struct EnumOpaque *priv = opaque;
1049  for (int i = 0; i < ops->num_ops; i++) {
1050  int ret = priv->cb(ctx, priv->opaque, &ops->ops[i]);
1051  if (ret < 0)
1052  return ret;
1053  }
1054  return 0;
1055 }
1056 
1058  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1059  int (*cb)(SwsContext *ctx, void *opaque, SwsOp *op))
1060 {
1061  struct EnumOpaque priv = { opaque, cb };
1062  return ff_sws_enum_op_lists(ctx, &priv, src_fmt, dst_fmt, enum_ops);
1063 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:50
flags
const SwsFlags flags[]
Definition: swscale.c:71
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:1057
print_q
static void print_q(AVBPrint *bp, const AVRational q, bool ignore_den0)
Definition: ops.c:786
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:580
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:567
SWS_MASK_ALPHA
@ SWS_MASK_ALPHA
Definition: ops.h:192
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:594
apply_filter_weights
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition: ops.c:278
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:129
SwsOpList::comps_src
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition: ops.h:273
merge_comp_flags
static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
Definition: ops.c:255
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:631
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:84
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:719
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:708
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:1037
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:674
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:217
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...
backend_vulkan
const SwsOpBackend backend_vulkan
Definition: ops.c:417
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:772
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:42
desc_plane_order
static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
Definition: ops.c:909
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
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:974
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:1046
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:68
clear_undefined_values
static void clear_undefined_values(AVRational dst[4], const AVRational src[4])
Definition: ops.c:270
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:186
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:106
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:262
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:923
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:39
av_ceil_log2
#define av_ceil_log2
Definition: common.h:97
SWS_MASK_OFF3
@ SWS_MASK_OFF3
Definition: ops.h:195
fail
#define fail()
Definition: checkasm.h:223
SwsOpList::num_ops
int num_ops
Definition: ops.h:256
SwsCompFlags
SwsCompFlags
Definition: ops.h:81
SWS_MASK_COL
#define SWS_MASK_COL(J)
Definition: ops.h:187
SWS_MASK_DIAG3
@ SWS_MASK_DIAG3
Definition: ops.h:194
SWS_PIXEL_U8
@ SWS_PIXEL_U8
Definition: ops.h:35
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:83
SWS_MASK_OFF4
@ SWS_MASK_OFF4
Definition: ops.h:201
val
static double val(void *priv, double ch)
Definition: aeval.c:77
flags_identity
static const SwsCompFlags flags_identity
Definition: ops.c:254
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
AVRational::num
int num
Numerator.
Definition: rational.h:59
refstruct.h
SwsOp::op
SwsOpType op
Definition: ops.h:213
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:253
SwsFormat::height
int height
Definition: format.h:78
float
float
Definition: af_crystalizer.c:122
SwsComps::min
AVRational min[4]
Definition: ops.h:106
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:100
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:640
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:73
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpBackend
Definition: ops_internal.h:55
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:57
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
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:679
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:119
ff_infer_colors
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition: format.c:539
planes
static const struct @577 planes[]
SWS_COMP_GARBAGE
@ SWS_COMP_GARBAGE
Definition: ops.h:82
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:649
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:184
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:139
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
print_q4
static void print_q4(AVBPrint *bp, const AVRational q4[4], bool ignore_den0, const SwsCompFlags flags[4])
Definition: ops.c:801
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:214
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:660
SWS_MASK_DIAG4
@ SWS_MASK_DIAG4
Definition: ops.h:200
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:259
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:297
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:549
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:167
ff_sws_op_desc
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition: ops.c:817
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
EnumOpaque::opaque
void * opaque
Definition: ops.c:1042
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:333
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:482
bprint.h
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
av_max_q
static AVRational av_max_q(AVRational a, AVRational b)
Definition: ops.c:134
SwsOpList::ops
SwsOp * ops
Definition: ops.h:255
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
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
SWS_MASK_LUMA
@ SWS_MASK_LUMA
Definition: ops.h:191
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:1012
SWS_MASK_MAT4
@ SWS_MASK_MAT4
Definition: ops.h:202
lev
static LevelCodes lev[4+3+3]
Definition: clearvideo.c:80
SwsOp
Definition: ops.h:212
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:101
ret
ret
Definition: filter_design.txt:187
bswap.h
backend_murder
const SwsOpBackend backend_murder
Definition: ops_memcpy.c:130
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:259
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:100
EnumOpaque::cb
int(* cb)(SwsContext *ctx, void *opaque, SwsOp *op)
Definition: ops.c:1043
AVRational::den
int den
Denominator.
Definition: rational.h:60
SWS_COMP_SWAPPED
@ SWS_COMP_SWAPPED
Definition: ops.h:85
SwsReadWriteOp::packed
bool packed
Definition: ops.h:120
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:53
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:83
describe_lin_mask
static const char * describe_lin_mask(uint32_t mask)
Definition: ops.c:731
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:118
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:1041
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:63
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:263
SWS_MASK_MAT3
@ SWS_MASK_MAT3
Definition: ops.h:196
avstring.h
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:262
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:254
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:100
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