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