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 enum {
311 
313 };
314 
315 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
317 {
318  const SwsCompFlags flags_or = SWS_COMP_GARBAGE;
319  const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
320  return ((a & b) & flags_and) | ((a | b) & flags_or);
321 }
322 
323 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
324  const SwsFilterWeights *weights)
325 {
326  const AVRational posw = { weights->sum_positive, SWS_FILTER_SCALE };
327  const AVRational negw = { weights->sum_negative, SWS_FILTER_SCALE };
328  for (int i = 0; i < 4; i++) {
329  comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
330  /* Only point sampling preserves exactness */
331  if (weights->filter_size != 1)
332  comps->flags[i] &= ~SWS_COMP_EXACT;
333  /* Update min/max assuming extremes */
334  comps->min[i] = av_add_q(av_mul_q(prev->min[i], posw),
335  av_mul_q(prev->max[i], negw));
336  comps->max[i] = av_add_q(av_mul_q(prev->min[i], negw),
337  av_mul_q(prev->max[i], posw));
338  }
339 }
340 
341 /* Infer + propagate known information about components */
343 {
344  SwsComps prev = { .flags = {
346  }};
347 
348  /* Forwards pass, propagates knowledge about the incoming pixel values */
349  for (int n = 0; n < ops->num_ops; n++) {
350  SwsOp *op = &ops->ops[n];
351 
352  switch (op->op) {
353  case SWS_OP_LINEAR:
354  case SWS_OP_DITHER:
355  case SWS_OP_SWAP_BYTES:
356  case SWS_OP_UNPACK:
357  case SWS_OP_FILTER_H:
358  case SWS_OP_FILTER_V:
359  break; /* special cases, handled below */
360  default:
361  memcpy(op->comps.min, prev.min, sizeof(prev.min));
362  memcpy(op->comps.max, prev.max, sizeof(prev.max));
363  ff_sws_apply_op_q(op, op->comps.min);
364  ff_sws_apply_op_q(op, op->comps.max);
365  break;
366  }
367 
368  switch (op->op) {
369  case SWS_OP_READ:
370  /* Active components are taken from the user-provided values,
371  * other components are explicitly stripped */
372  for (int i = 0; i < op->rw.elems; i++) {
373  int idx = 0;
374  switch (op->rw.mode) {
375  case SWS_RW_PALETTE: idx = i; break;
376  case SWS_RW_PACKED: idx = i; break;
377  case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
378  }
379 
380  av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
381  op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
382  op->comps.min[i] = ops->comps_src.min[idx];
383  op->comps.max[i] = ops->comps_src.max[idx];
384 
385  /**
386  * Don't mark packed or fractional reads as a copy, because the
387  * read operation implicitly unpacks the data into separate
388  * components. The only case in which op lists involving such
389  * reads can be refcopies is in the case of a true noop, which
390  * is already covered by the no-op check.
391  */
392  if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
393  op->comps.flags[i] |= SWS_COMP_COPY;
394  }
395 
396  if (op->rw.filter.op) {
397  const SwsComps prev = op->comps;
398  apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
399  }
400  break;
401  case SWS_OP_SWAP_BYTES:
402  for (int i = 0; i < 4; i++) {
403  op->comps.flags[i] = (prev.flags[i] ^ SWS_COMP_SWAPPED) & SWS_COMP_DIRTY;
404  op->comps.min[i] = prev.min[i];
405  op->comps.max[i] = prev.max[i];
406  }
407  break;
408  case SWS_OP_WRITE:
409  for (int i = 0; i < op->rw.elems; i++)
410  av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
411  for (int i = 0; i < 4; i++)
412  op->comps.flags[i] = prev.flags[i];
413  break;
414  case SWS_OP_LSHIFT:
415  case SWS_OP_RSHIFT:
416  for (int i = 0; i < 4; i++)
417  op->comps.flags[i] = prev.flags[i] & SWS_COMP_DIRTY;
418  break;
419  case SWS_OP_MIN:
420  case SWS_OP_MAX: {
421  AVRational *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
422  for (int i = 0; i < 4; i++) {
423  op->comps.flags[i] = prev.flags[i];
424  if (op->clamp.limit[i].den)
425  op->comps.flags[i] &= SWS_COMP_DIRTY;
426  if (!bound[i].den) /* reset undefined bounds to known range */
427  bound[i] = op->clamp.limit[i];
428  }
429  break;
430  }
431  case SWS_OP_DITHER:
432  for (int i = 0; i < 4; i++) {
433  op->comps.flags[i] = prev.flags[i];
434  op->comps.min[i] = prev.min[i];
435  op->comps.max[i] = prev.max[i];
436  if (op->dither.y_offset[i] < 0)
437  continue;
438  /* Strip zero flag because of the nonzero dithering offset */
439  op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
440  op->comps.min[i] = av_add_q(op->comps.min[i], op->dither.min);
441  op->comps.max[i] = av_add_q(op->comps.max[i], op->dither.max);
442  }
443  break;
444  case SWS_OP_UNPACK:
445  for (int i = 0; i < 4; i++) {
446  const int pattern = op->pack.pattern[i];
447  if (pattern) {
448  av_assert1(pattern < 32);
449  op->comps.flags[i] = prev.flags[0] & SWS_COMP_DIRTY;
450  op->comps.min[i] = Q(0);
451  op->comps.max[i] = Q((1ULL << pattern) - 1);
452  } else
453  op->comps.flags[i] = SWS_COMP_GARBAGE;
454  }
455  break;
456  case SWS_OP_PACK: {
458  for (int i = 0; i < 4; i++) {
459  if (op->pack.pattern[i])
460  flags = merge_comp_flags(flags, prev.flags[i]);
461  if (i > 0) /* clear remaining comps for sanity */
462  op->comps.flags[i] = SWS_COMP_GARBAGE;
463  }
464  op->comps.flags[0] = flags & SWS_COMP_DIRTY;
465  break;
466  }
467  case SWS_OP_CLEAR:
468  for (int i = 0; i < 4; i++) {
469  if (SWS_COMP_TEST(op->clear.mask, i)) {
470  op->comps.flags[i] = SWS_COMP_CONST;
471  if (op->clear.value[i].num == 0)
472  op->comps.flags[i] |= SWS_COMP_ZERO;
473  if (op->clear.value[i].den == 1)
474  op->comps.flags[i] |= SWS_COMP_EXACT;
475  } else {
476  op->comps.flags[i] = prev.flags[i];
477  }
478  }
479  break;
480  case SWS_OP_SWIZZLE:
481  for (int i = 0; i < 4; i++)
482  op->comps.flags[i] = prev.flags[op->swizzle.in[i]];
483  break;
484  case SWS_OP_CONVERT:
485  for (int i = 0; i < 4; i++) {
486  op->comps.flags[i] = prev.flags[i];
487  if (!(prev.flags[i] & SWS_COMP_EXACT) || op->convert.expand)
488  op->comps.flags[i] &= SWS_COMP_DIRTY;
489  if (ff_sws_pixel_type_is_int(op->convert.to))
490  op->comps.flags[i] |= SWS_COMP_EXACT;
491  }
492  break;
493  case SWS_OP_LINEAR:
494  for (int i = 0; i < 4; i++) {
496  AVRational min = Q(0), max = Q(0);
497  bool first = true;
498  for (int j = 0; j < 4; j++) {
499  const AVRational k = op->lin.m[i][j];
500  AVRational mink = av_mul_q(prev.min[j], k);
501  AVRational maxk = av_mul_q(prev.max[j], k);
502  if (k.num) {
503  flags = merge_comp_flags(flags, prev.flags[j]);
504  if (k.den != 1) /* fractional coefficient */
505  flags &= ~SWS_COMP_EXACT;
506  if (k.num < 0)
507  FFSWAP(AVRational, mink, maxk);
508  min = av_add_q(min, mink);
509  max = av_add_q(max, maxk);
510  if (!first || av_cmp_q(k, Q(1)))
512  first = false;
513  }
514  }
515  if (op->lin.m[i][4].num) { /* nonzero offset */
517  if (op->lin.m[i][4].den != 1) /* fractional offset */
518  flags &= ~SWS_COMP_EXACT;
519  min = av_add_q(min, op->lin.m[i][4]);
520  max = av_add_q(max, op->lin.m[i][4]);
521  }
522  op->comps.flags[i] = flags;
523  op->comps.min[i] = min;
524  op->comps.max[i] = max;
525  }
526  break;
527  case SWS_OP_SCALE:
528  for (int i = 0; i < 4; i++) {
529  op->comps.flags[i] = prev.flags[i] & SWS_COMP_DIRTY;
530  if (op->scale.factor.den != 1) /* fractional scale */
531  op->comps.flags[i] &= ~SWS_COMP_EXACT;
532  if (op->scale.factor.num < 0)
533  FFSWAP(AVRational, op->comps.min[i], op->comps.max[i]);
534  }
535  break;
536  case SWS_OP_FILTER_H:
537  case SWS_OP_FILTER_V: {
538  apply_filter_weights(&op->comps, &prev, op->filter.kernel);
539  break;
540  }
541 
542  case SWS_OP_INVALID:
543  case SWS_OP_TYPE_NB:
544  av_unreachable("Invalid operation type!");
545  }
546 
547  prev = op->comps;
548  }
549 
550  /* Backwards pass, solves for component dependencies */
551  bool need_out[4] = { false, false, false, false };
552  for (int n = ops->num_ops - 1; n >= 0; n--) {
553  SwsOp *op = &ops->ops[n];
554  bool need_in[4] = { false, false, false, false };
555 
556  for (int i = 0; i < 4; i++) {
557  if (!need_out[i])
558  op->comps.flags[i] = SWS_COMP_GARBAGE;
559  }
560 
561  switch (op->op) {
562  case SWS_OP_READ:
563  case SWS_OP_WRITE:
564  for (int i = 0; i < op->rw.elems; i++)
565  need_in[i] = op->op == SWS_OP_WRITE;
566  for (int i = op->rw.elems; i < 4; i++)
567  need_in[i] = need_out[i];
568  break;
569  case SWS_OP_SWAP_BYTES:
570  case SWS_OP_LSHIFT:
571  case SWS_OP_RSHIFT:
572  case SWS_OP_CONVERT:
573  case SWS_OP_DITHER:
574  case SWS_OP_MIN:
575  case SWS_OP_MAX:
576  case SWS_OP_SCALE:
577  case SWS_OP_FILTER_H:
578  case SWS_OP_FILTER_V:
579  for (int i = 0; i < 4; i++)
580  need_in[i] = need_out[i];
581  break;
582  case SWS_OP_UNPACK:
583  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
584  need_in[0] |= need_out[i];
585  break;
586  case SWS_OP_PACK:
587  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
588  need_in[i] = need_out[0];
589  break;
590  case SWS_OP_CLEAR:
591  for (int i = 0; i < 4; i++) {
592  if (!SWS_COMP_TEST(op->clear.mask, i))
593  need_in[i] = need_out[i];
594  }
595  break;
596  case SWS_OP_SWIZZLE:
597  for (int i = 0; i < 4; i++)
598  need_in[op->swizzle.in[i]] |= need_out[i];
599  break;
600  case SWS_OP_LINEAR:
601  for (int i = 0; i < 4; i++) {
602  for (int j = 0; j < 4; j++) {
603  if (op->lin.m[i][j].num)
604  need_in[j] |= need_out[i];
605  }
606  }
607  break;
608  }
609 
610  memcpy(need_out, need_in, sizeof(need_in));
611  }
612 }
613 
614 static void op_uninit(SwsOp *op)
615 {
616  switch (op->op) {
617  case SWS_OP_READ:
618  av_refstruct_unref(&op->rw.filter.kernel);
619  break;
620  case SWS_OP_DITHER:
621  av_refstruct_unref(&op->dither.matrix);
622  break;
623  case SWS_OP_FILTER_H:
624  case SWS_OP_FILTER_V:
625  av_refstruct_unref(&op->filter.kernel);
626  break;
627  }
628 
629  *op = (SwsOp) {0};
630 }
631 
633 {
634  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
635  if (!ops)
636  return NULL;
637 
638  for (int i = 0; i < 4; i++)
639  ops->plane_src[i] = ops->plane_dst[i] = i;
640  ff_fmt_clear(&ops->src);
641  ff_fmt_clear(&ops->dst);
642  return ops;
643 }
644 
646 {
647  SwsOpList *ops = *p_ops;
648  if (!ops)
649  return;
650 
651  for (int i = 0; i < ops->num_ops; i++)
652  op_uninit(&ops->ops[i]);
653 
654  av_freep(&ops->ops);
655  av_free(ops);
656  *p_ops = NULL;
657 }
658 
660 {
661  SwsOpList *copy = av_malloc(sizeof(*copy));
662  if (!copy)
663  return NULL;
664 
665  int num = ops->num_ops;
666  if (num)
667  num = 1 << av_ceil_log2(num);
668 
669  *copy = *ops;
670  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
671  if (!copy->ops) {
672  av_free(copy);
673  return NULL;
674  }
675 
676  for (int i = 0; i < copy->num_ops; i++) {
677  const SwsOp *op = &copy->ops[i];
678  switch (op->op) {
679  case SWS_OP_READ:
680  if (op->rw.filter.kernel)
681  av_refstruct_ref(op->rw.filter.kernel);
682  break;
683  case SWS_OP_DITHER:
684  av_refstruct_ref(op->dither.matrix);
685  break;
686  case SWS_OP_FILTER_H:
687  case SWS_OP_FILTER_V:
688  av_refstruct_ref(op->filter.kernel);
689  break;
690  }
691  }
692 
693  return copy;
694 }
695 
697 {
698  if (!ops->num_ops)
699  return NULL;
700 
701  const SwsOp *read = &ops->ops[0];
702  return read->op == SWS_OP_READ ? read : NULL;
703 }
704 
706 {
707  if (!ops->num_ops)
708  return NULL;
709 
710  const SwsOp *write = &ops->ops[ops->num_ops - 1];
711  return write->op == SWS_OP_WRITE ? write : NULL;
712 }
713 
714 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
715 {
716  const int end = ops->num_ops - count;
717  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
718  for (int i = 0; i < count; i++)
719  op_uninit(&ops->ops[index + i]);
720  for (int i = index; i < end; i++)
721  ops->ops[i] = ops->ops[i + count];
722  ops->num_ops = end;
723 }
724 
726 {
727  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
728  if (!ret) {
729  op_uninit(op);
730  return AVERROR(ENOMEM);
731  }
732 
733  for (int i = ops->num_ops - 1; i > index; i--)
734  ops->ops[i] = ops->ops[i - 1];
735  ops->ops[index] = *op;
736  return 0;
737 }
738 
740 {
741  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
742 }
743 
745 {
746  if (!ops->num_ops)
747  return true;
748 
749  const SwsOp *read = ff_sws_op_list_input(ops);
750  const SwsOp *write = ff_sws_op_list_output(ops);
751  if (!read || !write || ops->num_ops > 2 ||
752  read->type != write->type ||
753  read->rw.mode != write->rw.mode ||
754  read->rw.elems != write->rw.elems ||
755  read->rw.frac != write->rw.frac ||
756  read->rw.filter.op || write->rw.filter.op)
757  return false;
758 
759  /**
760  * Note that this check is unlikely to ever be hit in practice, since it
761  * would imply the existence of planar formats with different plane orders
762  * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
763  * However, the check is cheap and lets me sleep at night.
764  */
765  const int num_planes = ff_sws_rw_op_planes(read);
766  for (int i = 0; i < num_planes; i++) {
767  if (ops->plane_src[i] != ops->plane_dst[i])
768  return false;
769  }
770 
771  return true;
772 }
773 
775 {
776  int max_size = 0;
777  for (int i = 0; i < ops->num_ops; i++) {
778  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
779  max_size = FFMAX(max_size, size);
780  }
781 
782  return max_size;
783 }
784 
786 {
787  uint32_t mask = 0;
788  for (int i = 0; i < 4; i++) {
789  for (int j = 0; j < 5; j++) {
790  if (av_cmp_q(c->m[i][j], Q(i == j)))
791  mask |= SWS_MASK(i, j);
792  }
793  }
794  return mask;
795 }
796 
797 static const char *describe_lin_mask(uint32_t mask)
798 {
799  /* Try to be fairly descriptive without assuming too much */
800  static const struct {
801  char name[24];
802  uint32_t mask;
803  } patterns[] = {
804  { "noop", 0 },
805  { "luma", SWS_MASK_LUMA },
806  { "alpha", SWS_MASK_ALPHA },
807  { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA },
808  { "dot3", 0x7 },
809  { "dot4", 0xF },
810  { "row0", SWS_MASK_ROW(0) },
811  { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA },
812  { "col0", SWS_MASK_COL(0) },
813  { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 },
814  { "off3", SWS_MASK_OFF3 },
815  { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA },
816  { "diag3", SWS_MASK_DIAG3 },
817  { "diag4", SWS_MASK_DIAG4 },
818  { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA },
819  { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 },
820  { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
821  { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 },
822  { "matrix3", SWS_MASK_MAT3 },
823  { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 },
824  { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
825  { "matrix4", SWS_MASK_MAT4 },
826  { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 },
827  };
828 
829  for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
830  if (!(mask & ~patterns[i].mask))
831  return patterns[i].name;
832  }
833 
834  av_unreachable("Invalid linear mask!");
835  return "ERR";
836 }
837 
839 {
840  if (flags & SWS_COMP_GARBAGE)
841  return 'X';
842  else if (flags & SWS_COMP_ZERO)
843  return '0';
844  else if (flags & SWS_COMP_SWAPPED)
845  return 'z';
846  else if (flags & SWS_COMP_CONST)
847  return '$';
848  else if (flags & SWS_COMP_COPY)
849  return '=';
850  else if (flags & SWS_COMP_EXACT)
851  return '+';
852  else
853  return '.';
854 }
855 
856 static void print_q(AVBPrint *bp, const AVRational q)
857 {
858  if (!q.den) {
859  av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
860  } else if (q.den == 1) {
861  av_bprintf(bp, "%d", q.num);
862  } else if (abs(q.num) > 1000 || abs(q.den) > 1000) {
863  av_bprintf(bp, "%f", av_q2d(q));
864  } else {
865  av_bprintf(bp, "%d/%d", q.num, q.den);
866  }
867 }
868 
869 static void print_q4(AVBPrint *bp, const AVRational q4[4], SwsCompMask mask)
870 {
871  av_bprintf(bp, "{");
872  for (int i = 0; i < 4; i++) {
873  if (i)
874  av_bprintf(bp, " ");
875  if (!SWS_COMP_TEST(mask, i)) {
876  av_bprintf(bp, "_");
877  } else {
878  print_q(bp, q4[i]);
879  }
880  }
881  av_bprintf(bp, "}");
882 }
883 
884 static const char *const rw_mode_names[] = {
885  [SWS_RW_PLANAR] = "planar",
886  [SWS_RW_PACKED] = "packed",
887  [SWS_RW_PALETTE] = "palette"
888 };
889 
890 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
891 {
892  const char *name = ff_sws_op_type_name(op->op);
894 
895  switch (op->op) {
896  case SWS_OP_INVALID:
897  case SWS_OP_SWAP_BYTES:
898  av_bprintf(bp, "%s", name);
899  break;
900  case SWS_OP_READ:
901  case SWS_OP_WRITE:
902  av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
903  op->rw.elems, rw_mode_names[op->rw.mode],
904  op->rw.frac);
905  if (!op->rw.filter.op)
906  break;
907  const SwsFilterWeights *kernel = op->rw.filter.kernel;
908  av_bprintf(bp, " + %d tap %s filter (%c)",
909  kernel->filter_size, kernel->name,
910  op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
911  break;
912  case SWS_OP_LSHIFT:
913  av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
914  break;
915  case SWS_OP_RSHIFT:
916  av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
917  break;
918  case SWS_OP_PACK:
919  case SWS_OP_UNPACK:
920  av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
921  op->pack.pattern[0], op->pack.pattern[1],
922  op->pack.pattern[2], op->pack.pattern[3]);
923  break;
924  case SWS_OP_CLEAR:
925  av_bprintf(bp, "%-20s: ", name);
926  print_q4(bp, op->clear.value, mask & op->clear.mask);
927  break;
928  case SWS_OP_SWIZZLE:
929  av_bprintf(bp, "%-20s: %d%d%d%d", name,
930  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
931  break;
932  case SWS_OP_CONVERT:
933  av_bprintf(bp, "%-20s: %s -> %s%s", name,
934  ff_sws_pixel_type_name(op->type),
935  ff_sws_pixel_type_name(op->convert.to),
936  op->convert.expand ? " (expand)" : "");
937  break;
938  case SWS_OP_DITHER:
939  av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
940  1 << op->dither.size_log2, 1 << op->dither.size_log2,
941  op->dither.y_offset[0], op->dither.y_offset[1],
942  op->dither.y_offset[2], op->dither.y_offset[3]);
943  break;
944  case SWS_OP_MIN:
945  av_bprintf(bp, "%-20s: x <= ", name);
946  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
947  break;
948  case SWS_OP_MAX:
949  av_bprintf(bp, "%-20s: ", name);
950  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
951  av_bprintf(bp, " <= x");
952  break;
953  case SWS_OP_LINEAR:
954  av_bprintf(bp, "%-20s: %s [", name, describe_lin_mask(op->lin.mask));
955  for (int i = 0; i < 4; i++) {
956  av_bprintf(bp, "%s[", i ? " " : "");
957  for (int j = 0; j < 5; j++) {
958  av_bprintf(bp, j ? " " : "");
959  print_q(bp, op->lin.m[i][j]);
960  }
961  av_bprintf(bp, "]");
962  }
963  av_bprintf(bp, "]");
964  break;
965  case SWS_OP_SCALE:
966  av_bprintf(bp, "%-20s: * %d", name, op->scale.factor.num);
967  if (op->scale.factor.den != 1)
968  av_bprintf(bp, "/%d", op->scale.factor.den);
969  break;
970  case SWS_OP_FILTER_H:
971  case SWS_OP_FILTER_V: {
972  const SwsFilterWeights *kernel = op->filter.kernel;
973  av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
974  kernel->src_size, kernel->dst_size,
975  kernel->name, kernel->filter_size);
976  break;
977  }
978  case SWS_OP_TYPE_NB:
979  break;
980  }
981 }
982 
983 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
984 {
985  bool inorder = true;
986  for (int i = 0; i < nb_planes; i++)
987  inorder &= order[i] == i;
988  if (inorder)
989  return;
990 
991  av_bprintf(bp, ", via {");
992  for (int i = 0; i < nb_planes; i++)
993  av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
994  av_bprintf(bp, "}");
995 }
996 
997 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
998  const SwsOpList *ops)
999 {
1000  AVBPrint bp;
1001  if (!ops->num_ops) {
1002  av_log(log, lev, " (empty)\n");
1003  return;
1004  }
1005 
1007 
1008  for (int i = 0; i < ops->num_ops; i++) {
1009  const SwsOp *op = &ops->ops[i];
1011  av_bprint_clear(&bp);
1012  av_bprintf(&bp, " [%3s %c%c%c%c] ",
1013  ff_sws_pixel_type_name(op->type),
1014  describe_comp_flags(op->comps.flags[0]),
1015  describe_comp_flags(op->comps.flags[1]),
1016  describe_comp_flags(op->comps.flags[2]),
1017  describe_comp_flags(op->comps.flags[3]));
1018 
1019  ff_sws_op_desc(&bp, op);
1020 
1021  if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
1022  const int planes = ff_sws_rw_op_planes(op);
1023  desc_plane_order(&bp, planes,
1024  op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
1025  }
1026 
1028  av_log(log, lev, "%s\n", bp.str);
1029 
1030  /* Only print value ranges if any are relevant */
1031  SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
1032  ff_sws_comp_mask_q4(op->comps.max);
1033  if (range_mask & mask) {
1034  av_bprint_clear(&bp);
1035  av_bprintf(&bp, " min: ");
1036  print_q4(&bp, op->comps.min, mask);
1037  av_bprintf(&bp, ", max: ");
1038  print_q4(&bp, op->comps.max, mask);
1040  av_log(log, lev_extra, "%s\n", bp.str);
1041  }
1042 
1043  }
1044 
1045  av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
1046 }
1047 
1048 #define DUMMY_SIZE 16
1049 
1050 static int enum_ops_fmt(SwsContext *ctx, void *opaque,
1051  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1052  int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1053 {
1054  int ret = 0;
1055  SwsOpList *ops = NULL;
1056  SwsFormat src, dst;
1057  ff_fmt_from_pixfmt(src_fmt, &src);
1058  ff_fmt_from_pixfmt(dst_fmt, &dst);
1059  bool incomplete = ff_infer_colors(&src.color, &dst.color);
1060  src.width = src.height = DUMMY_SIZE;
1061 
1062  static const int dst_sizes[][2] = {
1063  { DUMMY_SIZE, DUMMY_SIZE },
1064  { DUMMY_SIZE, DUMMY_SIZE * 2 },
1065  { DUMMY_SIZE * 2, DUMMY_SIZE },
1066  { DUMMY_SIZE * 2, DUMMY_SIZE * 2 },
1067  };
1068 
1069  for (int i = 0; i < FF_ARRAY_ELEMS(dst_sizes); i++) {
1070  dst.width = dst_sizes[i][0];
1071  dst.height = dst_sizes[i][1];
1072 
1073  ret = ff_sws_op_list_generate(ctx, &src, &dst, &ops, &incomplete);
1074  if (ret == AVERROR(ENOTSUP))
1075  return 0; /* silently skip unsupported formats */
1076  else if (ret < 0)
1077  return ret;
1078 
1080  if (ret < 0)
1081  goto fail;
1082 
1083  ret = cb(ctx, opaque, ops);
1084  if (ret < 0)
1085  goto fail;
1086 
1087  ff_sws_op_list_free(&ops);
1088  }
1089 
1090 fail:
1091  ff_sws_op_list_free(&ops);
1092  return ret;
1093 }
1094 
1096  enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1097  int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1098 {
1099  const AVPixFmtDescriptor *src_start = av_pix_fmt_desc_next(NULL);
1100  const AVPixFmtDescriptor *dst_start = src_start;
1101  if (src_fmt != AV_PIX_FMT_NONE)
1102  src_start = av_pix_fmt_desc_get(src_fmt);
1103  if (dst_fmt != AV_PIX_FMT_NONE)
1104  dst_start = av_pix_fmt_desc_get(dst_fmt);
1105 
1106  const AVPixFmtDescriptor *src, *dst;
1107  for (src = src_start; src; src = av_pix_fmt_desc_next(src)) {
1108  const enum AVPixelFormat src_f = av_pix_fmt_desc_get_id(src);
1109  for (dst = dst_start; dst; dst = av_pix_fmt_desc_next(dst)) {
1110  const enum AVPixelFormat dst_f = av_pix_fmt_desc_get_id(dst);
1111  int ret = enum_ops_fmt(ctx, opaque, src_f, dst_f, cb);
1112  if (ret < 0)
1113  return ret;
1114  if (dst_fmt != AV_PIX_FMT_NONE)
1115  break;
1116  }
1117  if (src_fmt != AV_PIX_FMT_NONE)
1118  break;
1119  }
1120 
1121  return 0;
1122 }
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:1048
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:645
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:632
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:659
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:99
SWS_MASK_OFF4
@ SWS_MASK_OFF4
Definition: ops.h:218
apply_filter_weights
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition: ops.c:323
rw_mode_names
static const char *const rw_mode_names[]
Definition: ops.c:884
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:304
merge_comp_flags
static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
Definition: ops.c:316
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:696
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:774
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:739
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:235
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:838
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:983
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:309
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:1050
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
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:203
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:86
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:293
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:997
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:287
SwsCompFlags
SwsCompFlags
Definition: ops.h:72
SWS_MASK_COL
#define SWS_MASK_COL(J)
Definition: ops.h:204
SwsSwizzleOp
Definition: ops.h:140
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:217
AVRational::num
int num
Numerator.
Definition: rational.h:59
refstruct.h
SwsOp::op
SwsOpType op
Definition: ops.h:231
SWS_RW_PACKED
@ SWS_RW_PACKED
Definition: ops.h:100
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
first
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But first
Definition: rate_distortion.txt:12
avassert.h
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:257
float
float
Definition: af_crystalizer.c:122
SWS_MASK_MAT3
@ SWS_MASK_MAT3
Definition: ops.h:213
print_q
static void print_q(AVBPrint *bp, const AVRational q)
Definition: ops.c:856
print_q4
static void print_q4(AVBPrint *bp, const AVRational q4[4], SwsCompMask mask)
Definition: ops.c:869
SwsComps::min
AVRational min[4]
Definition: ops.h:86
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:705
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:744
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:116
ff_infer_colors
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition: format.c:541
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:714
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:212
SWS_MASK
#define SWS_MASK(I, J)
Definition: ops.h:201
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:208
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:232
SWS_MASK_ALPHA
@ SWS_MASK_ALPHA
Definition: ops.h:209
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:725
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition: ops.c:785
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:290
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:342
SwsFormat
Definition: format.h:77
SWS_MASK_DIAG3
@ SWS_MASK_DIAG3
Definition: ops.h:211
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:614
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
SWS_COMP_CONST
@ SWS_COMP_CONST
Definition: ops.h:78
SwsLinearOp
Definition: ops.h:184
ff_sws_op_desc
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition: ops.c:890
SwsReadWriteOp::op
SwsOpType op
Definition: ops.h:126
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:286
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:1095
lev
static LevelCodes lev[4+3+3]
Definition: clearvideo.c:80
SwsOp
Definition: ops.h:230
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
bound
static double bound(const double threshold, const double val)
Definition: af_dynaudnorm.c:413
SwsComps::flags
SwsCompFlags flags[4]
Definition: ops.h:82
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:290
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:53
SwsReadWriteOp::filter
struct SwsReadWriteOp::@571 filter
Filter kernel to apply to each plane while sampling.
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
SWS_RW_PALETTE
@ SWS_RW_PALETTE
Definition: ops.h:101
SwsComps
Definition: ops.h:81
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
SWS_COMP_COPY
@ SWS_COMP_COPY
Definition: ops.h:77
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:797
SwsReadWriteOp::elems
uint8_t elems
Definition: ops.h:115
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:219
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:147
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:51
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
avstring.h
SwsReadWriteOp::mode
SwsReadWriteMode mode
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition: ops.h:114
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:293
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:285
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
SWS_COMP_DIRTY
@ SWS_COMP_DIRTY
Definition: ops.c:312