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