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