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 
42 const SwsOpBackend * const ff_sws_op_backends[] = {
44 #if ARCH_AARCH64 && HAVE_NEON
46 #elif ARCH_X86_64 && HAVE_X86ASM
47  &backend_x86,
48 #endif
49  &backend_c,
50 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
51  &backend_spirv,
52 #endif
53  NULL
54 };
55 
57 {
58  switch (type) {
59  case SWS_PIXEL_U8: return "u8";
60  case SWS_PIXEL_U16: return "u16";
61  case SWS_PIXEL_U32: return "u32";
62  case SWS_PIXEL_F32: return "f32";
63  case SWS_PIXEL_NONE: return "none";
64  case SWS_PIXEL_TYPE_NB: break;
65  }
66 
67  av_unreachable("Invalid pixel type!");
68  return "ERR";
69 }
70 
72 {
73  switch (op) {
74  case SWS_OP_READ: return "SWS_OP_READ";
75  case SWS_OP_WRITE: return "SWS_OP_WRITE";
76  case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
77  case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
78  case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
79  case SWS_OP_PACK: return "SWS_OP_PACK";
80  case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
81  case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
82  case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
83  case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
84  case SWS_OP_MIN: return "SWS_OP_MIN";
85  case SWS_OP_MAX: return "SWS_OP_MAX";
86  case SWS_OP_SCALE: return "SWS_OP_SCALE";
87  case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
88  case SWS_OP_DITHER: return "SWS_OP_DITHER";
89  case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
90  case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
91  case SWS_OP_INVALID: return "SWS_OP_INVALID";
92  case SWS_OP_TYPE_NB: break;
93  }
94 
95  av_unreachable("Invalid operation type!");
96  return "ERR";
97 }
98 
100 {
101  SwsCompMask mask = 0;
102  for (int i = 0; i < 4; i++) {
103  if (q[i].den)
104  mask |= SWS_COMP(i);
105  }
106  return mask;
107 }
108 
110 {
111  const SwsCompMask orig = *mask;
112  SwsCompMask res = 0;
113  for (int i = 0; i < 4; i++) {
114  const int src = swiz->in[i];
115  if (SWS_COMP_TEST(orig, src))
116  res |= SWS_COMP(i);
117  }
118 
119  *mask = res;
120 }
121 
123 {
124  SwsCompMask mask = 0;
125  for (int i = 0; i < 4; i++) {
126  if (SWS_OP_NEEDED(op, i))
127  mask |= SWS_COMP(i);
128  }
129  return mask;
130 }
131 
133 {
134  av_assert2(op->op == SWS_OP_READ || op->op == SWS_OP_WRITE);
135  switch (op->rw.mode) {
136  case SWS_RW_PLANAR: return op->rw.elems;
137  case SWS_RW_PACKED: return 1;
138  case SWS_RW_PALETTE: return 2;
139  }
140 
141  av_unreachable("Invalid read/write mode!");
142  return 0;
143 }
144 
145 /* biased towards `a` */
147 {
148  return av_cmp_q64(a, b) == 1 ? b : a;
149 }
150 
152 {
153  return av_cmp_q64(a, b) == -1 ? b : a;
154 }
155 
157 {
158  uint64_t mask[4];
159  int shift[4];
160 
161  switch (op->op) {
162  case SWS_OP_READ:
163  case SWS_OP_WRITE:
164  return;
165  case SWS_OP_UNPACK: {
168  unsigned val = x[0].num;
169  for (int i = 0; i < 4; i++)
170  x[i] = Q((val >> shift[i]) & mask[i]);
171  return;
172  }
173  case SWS_OP_PACK: {
176  unsigned val = 0;
177  for (int i = 0; i < 4; i++)
178  val |= (x[i].num & mask[i]) << shift[i];
179  x[0] = Q(val);
180  return;
181  }
182  case SWS_OP_SWAP_BYTES:
183  switch (op->type) {
184  case SWS_PIXEL_U16:
185  for (int i = 0; i < 4; i++) {
186  av_assert2(x[i].num >= 0 && x[i].num <= UINT16_MAX);
187  x[i].num = av_bswap16(x[i].num);
188  }
189  return;
190  case SWS_PIXEL_U32:
191  for (int i = 0; i < 4; i++) {
192  av_assert2(x[i].num >= 0 && x[i].num <= UINT32_MAX);
193  x[i].num = av_bswap32(x[i].num);
194  }
195  return;
196  }
197  av_unreachable("Invalid pixel type for SWS_OP_SWAP_BYTES!");
198  return;
199  case SWS_OP_CLEAR:
200  for (int i = 0; i < 4; i++) {
201  if (SWS_COMP_TEST(op->clear.mask, i))
202  x[i] = op->clear.value[i];
203  }
204  return;
205  case SWS_OP_LSHIFT: {
207  AVRational64 mult = Q(1 << op->shift.amount);
208  for (int i = 0; i < 4; i++)
209  x[i] = x[i].den ? av_mul_q64(x[i], mult) : x[i];
210  return;
211  }
212  case SWS_OP_RSHIFT: {
214  for (int i = 0; i < 4; i++)
215  x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->shift.amount) : x[i];
216  return;
217  }
218  case SWS_OP_SWIZZLE: {
219  const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
220  for (int i = 0; i < 4; i++)
221  x[i] = orig[op->swizzle.in[i]];
222  return;
223  }
224  case SWS_OP_CONVERT:
225  if (ff_sws_pixel_type_is_int(op->convert.to)) {
226  const AVRational64 scale = ff_sws_pixel_expand(op->type, op->convert.to);
227  for (int i = 0; i < 4; i++) {
228  x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
229  if (op->convert.expand)
230  x[i] = av_mul_q64(x[i], scale);
231  }
232  }
233  return;
234  case SWS_OP_DITHER:
236  for (int i = 0; i < 4; i++) {
237  if (op->dither.y_offset[i] >= 0 && x[i].den)
238  x[i] = av_add_q64(x[i], av_make_q64(1, 2));
239  }
240  return;
241  case SWS_OP_MIN:
242  for (int i = 0; i < 4; i++)
243  x[i] = av_min_q64(x[i], op->clamp.limit[i]);
244  return;
245  case SWS_OP_MAX:
246  for (int i = 0; i < 4; i++)
247  x[i] = av_max_q64(x[i], op->clamp.limit[i]);
248  return;
249  case SWS_OP_LINEAR: {
251  const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
252  for (int i = 0; i < 4; i++) {
253  AVRational64 sum = op->lin.m[i][4];
254  for (int j = 0; j < 4; j++)
255  sum = av_add_q64(sum, av_mul_q64(orig[j], op->lin.m[i][j]));
256  x[i] = sum;
257  }
258  return;
259  }
260  case SWS_OP_SCALE:
261  for (int i = 0; i < 4; i++)
262  x[i] = x[i].den ? av_mul_q64(x[i], op->scale.factor) : x[i];
263  return;
264  case SWS_OP_FILTER_H:
265  case SWS_OP_FILTER_V:
266  /* Filters have normalized energy by definition, so they don't
267  * conceptually modify individual components */
268  return;
269  }
270 
271  av_unreachable("Invalid operation type!");
272 }
273 
274 enum {
277 
279 };
280 
281 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
283 {
284  const SwsCompFlags flags_or = SWS_COMP_GARBAGE;
285  const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
286  return ((a & b) & flags_and) | ((a | b) & flags_or);
287 }
288 
289 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
290  const SwsFilterWeights *weights)
291 {
292  const AVRational64 posw = { weights->sum_positive, SWS_FILTER_SCALE };
293  const AVRational64 negw = { weights->sum_negative, SWS_FILTER_SCALE };
294  for (int i = 0; i < 4; i++) {
295  comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
296  /* Only point sampling preserves exactness */
297  if (weights->filter_size != 1)
298  comps->flags[i] &= ~SWS_COMP_EXACT;
299  /* Update min/max assuming extremes */
300  comps->min[i] = av_add_q64(av_mul_q64(prev->min[i], posw),
301  av_mul_q64(prev->max[i], negw));
302  comps->max[i] = av_add_q64(av_mul_q64(prev->min[i], negw),
303  av_mul_q64(prev->max[i], posw));
304  }
305 }
306 
307 /* Infer + propagate known information about components */
309 {
310  SwsComps prev = { .flags = {
312  }};
313 
314  /* Forwards pass, propagates knowledge about the incoming pixel values */
315  for (int n = 0; n < ops->num_ops; n++) {
316  SwsOp *op = &ops->ops[n];
317 
318  switch (op->op) {
319  case SWS_OP_LINEAR:
320  case SWS_OP_DITHER:
321  case SWS_OP_SWAP_BYTES:
322  case SWS_OP_UNPACK:
323  case SWS_OP_FILTER_H:
324  case SWS_OP_FILTER_V:
325  break; /* special cases, handled below */
326  default:
327  memcpy(op->comps.min, prev.min, sizeof(prev.min));
328  memcpy(op->comps.max, prev.max, sizeof(prev.max));
329  ff_sws_apply_op_q(op, op->comps.min);
330  ff_sws_apply_op_q(op, op->comps.max);
331  break;
332  }
333 
334  switch (op->op) {
335  case SWS_OP_READ:
336  /* Active components are taken from the user-provided values,
337  * other components are explicitly stripped */
338  for (int i = 0; i < op->rw.elems; i++) {
339  int idx = 0;
340  switch (op->rw.mode) {
341  case SWS_RW_PALETTE: idx = i; break;
342  case SWS_RW_PACKED: idx = i; break;
343  case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
344  }
345 
346  av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
347  op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
348  op->comps.min[i] = ops->comps_src.min[idx];
349  op->comps.max[i] = ops->comps_src.max[idx];
350 
351  /**
352  * Don't mark packed or fractional reads as a copy, because the
353  * read operation implicitly unpacks the data into separate
354  * components. The only case in which op lists involving such
355  * reads can be refcopies is in the case of a true noop, which
356  * is already covered by the no-op check.
357  */
358  if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
359  op->comps.flags[i] |= SWS_COMP_COPY;
360  }
361 
362  if (op->rw.filter.op) {
363  const SwsComps prev = op->comps;
364  apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
365  }
366  break;
367  case SWS_OP_SWAP_BYTES:
368  for (int i = 0; i < 4; i++) {
369  op->comps.flags[i] = (prev.flags[i] ^ SWS_COMP_SWAPPED) & SWS_COMP_DIRTY;
370  op->comps.min[i] = prev.min[i];
371  op->comps.max[i] = prev.max[i];
372  }
373  break;
374  case SWS_OP_WRITE:
375  for (int i = 0; i < op->rw.elems; i++)
376  av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
377  for (int i = 0; i < 4; i++)
378  op->comps.flags[i] = prev.flags[i];
379  break;
380  case SWS_OP_LSHIFT:
381  case SWS_OP_RSHIFT:
382  for (int i = 0; i < 4; i++)
383  op->comps.flags[i] = prev.flags[i] & SWS_COMP_DIRTY;
384  break;
385  case SWS_OP_MIN:
386  case SWS_OP_MAX: {
387  AVRational64 *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
388  for (int i = 0; i < 4; i++) {
389  op->comps.flags[i] = prev.flags[i];
390  if (op->clamp.limit[i].den)
391  op->comps.flags[i] &= SWS_COMP_DIRTY;
392  if (!bound[i].den) /* reset undefined bounds to known range */
393  bound[i] = op->clamp.limit[i];
394  }
395  break;
396  }
397  case SWS_OP_DITHER:
398  for (int i = 0; i < 4; i++) {
399  op->comps.flags[i] = prev.flags[i];
400  op->comps.min[i] = prev.min[i];
401  op->comps.max[i] = prev.max[i];
402  if (op->dither.y_offset[i] < 0)
403  continue;
404  /* Strip zero flag because of the nonzero dithering offset */
405  op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
406  op->comps.min[i] = av_add_q64(op->comps.min[i], op->dither.min);
407  op->comps.max[i] = av_add_q64(op->comps.max[i], op->dither.max);
408  }
409  break;
410  case SWS_OP_UNPACK:
411  for (int i = 0; i < 4; i++) {
412  const int pattern = op->pack.pattern[i];
413  if (pattern) {
414  av_assert1(pattern < 32);
415  op->comps.flags[i] = prev.flags[0] & SWS_COMP_DIRTY;
416  op->comps.min[i] = Q(0);
417  op->comps.max[i] = Q((1ULL << pattern) - 1);
418  } else
419  op->comps.flags[i] = SWS_COMP_GARBAGE;
420  }
421  break;
422  case SWS_OP_PACK: {
424  for (int i = 0; i < 4; i++) {
425  if (op->pack.pattern[i])
426  flags = merge_comp_flags(flags, prev.flags[i]);
427  if (i > 0) /* clear remaining comps for sanity */
428  op->comps.flags[i] = SWS_COMP_GARBAGE;
429  }
430  op->comps.flags[0] = flags & SWS_COMP_DIRTY;
431  break;
432  }
433  case SWS_OP_CLEAR:
434  for (int i = 0; i < 4; i++) {
435  if (SWS_COMP_TEST(op->clear.mask, i)) {
436  op->comps.flags[i] = SWS_COMP_CONST;
437  if (op->clear.value[i].num == 0)
438  op->comps.flags[i] |= SWS_COMP_ZERO;
439  if (op->clear.value[i].den == 1)
440  op->comps.flags[i] |= SWS_COMP_EXACT;
441  } else {
442  op->comps.flags[i] = prev.flags[i];
443  }
444  }
445  break;
446  case SWS_OP_SWIZZLE:
447  for (int i = 0; i < 4; i++)
448  op->comps.flags[i] = prev.flags[op->swizzle.in[i]];
449  break;
450  case SWS_OP_CONVERT:
451  for (int i = 0; i < 4; i++) {
452  op->comps.flags[i] = prev.flags[i];
453  if (!(prev.flags[i] & SWS_COMP_EXACT) || op->convert.expand)
454  op->comps.flags[i] &= SWS_COMP_DIRTY;
455  if (ff_sws_pixel_type_is_int(op->convert.to))
456  op->comps.flags[i] |= SWS_COMP_EXACT;
457  }
458  break;
459  case SWS_OP_LINEAR:
460  for (int i = 0; i < 4; i++) {
462  AVRational64 min = Q(0), max = Q(0);
463  bool first = true;
464  for (int j = 0; j < 4; j++) {
465  const AVRational64 k = op->lin.m[i][j];
466  AVRational64 mink = av_mul_q64(prev.min[j], k);
467  AVRational64 maxk = av_mul_q64(prev.max[j], k);
468  if (k.num) {
469  flags = merge_comp_flags(flags, prev.flags[j]);
470  if (k.den != 1) /* fractional coefficient */
471  flags &= ~SWS_COMP_EXACT;
472  if (k.num < 0)
473  FFSWAP(AVRational64, mink, maxk);
474  min = av_add_q64(min, mink);
475  max = av_add_q64(max, maxk);
476  if (!first || av_cmp_q64(k, Q(1)))
478  first = false;
479  }
480  }
481  if (op->lin.m[i][4].num) { /* nonzero offset */
483  if (op->lin.m[i][4].den != 1) /* fractional offset */
484  flags &= ~SWS_COMP_EXACT;
485  min = av_add_q64(min, op->lin.m[i][4]);
486  max = av_add_q64(max, op->lin.m[i][4]);
487  }
488  op->comps.flags[i] = flags;
489  op->comps.min[i] = min;
490  op->comps.max[i] = max;
491  }
492  break;
493  case SWS_OP_SCALE:
494  for (int i = 0; i < 4; i++) {
495  op->comps.flags[i] = prev.flags[i] & SWS_COMP_DIRTY;
496  if (op->scale.factor.den != 1) /* fractional scale */
497  op->comps.flags[i] &= ~SWS_COMP_EXACT;
498  if (op->scale.factor.num < 0)
499  FFSWAP(AVRational64, op->comps.min[i], op->comps.max[i]);
500  }
501  break;
502  case SWS_OP_FILTER_H:
503  case SWS_OP_FILTER_V: {
504  apply_filter_weights(&op->comps, &prev, op->filter.kernel);
505  break;
506  }
507 
508  case SWS_OP_INVALID:
509  case SWS_OP_TYPE_NB:
510  av_unreachable("Invalid operation type!");
511  }
512 
513  prev = op->comps;
514  }
515 
516  /* Backwards pass, solves for component dependencies */
517  bool need_out[4] = { false, false, false, false };
518  for (int n = ops->num_ops - 1; n >= 0; n--) {
519  SwsOp *op = &ops->ops[n];
520  bool need_in[4] = { false, false, false, false };
521 
522  for (int i = 0; i < 4; i++) {
523  if (!need_out[i])
524  op->comps.flags[i] = SWS_COMP_GARBAGE;
525  }
526 
527  switch (op->op) {
528  case SWS_OP_READ:
529  case SWS_OP_WRITE:
530  for (int i = 0; i < op->rw.elems; i++)
531  need_in[i] = op->op == SWS_OP_WRITE;
532  for (int i = op->rw.elems; i < 4; i++)
533  need_in[i] = need_out[i];
534  break;
535  case SWS_OP_SWAP_BYTES:
536  case SWS_OP_LSHIFT:
537  case SWS_OP_RSHIFT:
538  case SWS_OP_CONVERT:
539  case SWS_OP_DITHER:
540  case SWS_OP_MIN:
541  case SWS_OP_MAX:
542  case SWS_OP_SCALE:
543  case SWS_OP_FILTER_H:
544  case SWS_OP_FILTER_V:
545  for (int i = 0; i < 4; i++)
546  need_in[i] = need_out[i];
547  break;
548  case SWS_OP_UNPACK:
549  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
550  need_in[0] |= need_out[i];
551  break;
552  case SWS_OP_PACK:
553  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
554  need_in[i] = need_out[0];
555  break;
556  case SWS_OP_CLEAR:
557  for (int i = 0; i < 4; i++) {
558  if (!SWS_COMP_TEST(op->clear.mask, i))
559  need_in[i] = need_out[i];
560  }
561  break;
562  case SWS_OP_SWIZZLE:
563  for (int i = 0; i < 4; i++)
564  need_in[op->swizzle.in[i]] |= need_out[i];
565  break;
566  case SWS_OP_LINEAR:
567  for (int i = 0; i < 4; i++) {
568  for (int j = 0; j < 4; j++) {
569  if (op->lin.m[i][j].num)
570  need_in[j] |= need_out[i];
571  }
572  }
573  break;
574  }
575 
576  memcpy(need_out, need_in, sizeof(need_in));
577  }
578 }
579 
580 static void op_uninit(SwsOp *op)
581 {
582  switch (op->op) {
583  case SWS_OP_READ:
584  av_refstruct_unref(&op->rw.filter.kernel);
585  break;
586  case SWS_OP_DITHER:
587  av_refstruct_unref(&op->dither.matrix);
588  break;
589  case SWS_OP_FILTER_H:
590  case SWS_OP_FILTER_V:
591  av_refstruct_unref(&op->filter.kernel);
592  break;
593  }
594 
595  *op = (SwsOp) {0};
596 }
597 
599 {
600  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
601  if (!ops)
602  return NULL;
603 
604  for (int i = 0; i < 4; i++)
605  ops->plane_src[i] = ops->plane_dst[i] = i;
606  ff_fmt_clear(&ops->src);
607  ff_fmt_clear(&ops->dst);
608  return ops;
609 }
610 
612 {
613  SwsOpList *ops = *p_ops;
614  if (!ops)
615  return;
616 
617  for (int i = 0; i < ops->num_ops; i++)
618  op_uninit(&ops->ops[i]);
619 
620  av_freep(&ops->ops);
621  av_free(ops);
622  *p_ops = NULL;
623 }
624 
626 {
627  SwsOpList *copy = av_malloc(sizeof(*copy));
628  if (!copy)
629  return NULL;
630 
631  int num = ops->num_ops;
632  if (num)
633  num = 1 << av_ceil_log2(num);
634 
635  *copy = *ops;
636  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
637  if (!copy->ops) {
638  av_free(copy);
639  return NULL;
640  }
641 
642  for (int i = 0; i < copy->num_ops; i++) {
643  const SwsOp *op = &copy->ops[i];
644  switch (op->op) {
645  case SWS_OP_READ:
646  if (op->rw.filter.kernel)
647  av_refstruct_ref(op->rw.filter.kernel);
648  break;
649  case SWS_OP_DITHER:
650  av_refstruct_ref(op->dither.matrix);
651  break;
652  case SWS_OP_FILTER_H:
653  case SWS_OP_FILTER_V:
654  av_refstruct_ref(op->filter.kernel);
655  break;
656  }
657  }
658 
659  return copy;
660 }
661 
663 {
664  if (!ops->num_ops)
665  return NULL;
666 
667  const SwsOp *read = &ops->ops[0];
668  return read->op == SWS_OP_READ ? read : NULL;
669 }
670 
672 {
673  if (!ops->num_ops)
674  return NULL;
675 
676  const SwsOp *write = &ops->ops[ops->num_ops - 1];
677  return write->op == SWS_OP_WRITE ? write : NULL;
678 }
679 
680 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
681 {
682  const int end = ops->num_ops - count;
683  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
684  for (int i = 0; i < count; i++)
685  op_uninit(&ops->ops[index + i]);
686  for (int i = index; i < end; i++)
687  ops->ops[i] = ops->ops[i + count];
688  ops->num_ops = end;
689 }
690 
692 {
693  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
694  if (!ret) {
695  op_uninit(op);
696  return AVERROR(ENOMEM);
697  }
698 
699  for (int i = ops->num_ops - 1; i > index; i--)
700  ops->ops[i] = ops->ops[i - 1];
701  ops->ops[index] = *op;
702  return 0;
703 }
704 
706 {
707  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
708 }
709 
711 {
712  if (!ops->num_ops)
713  return true;
714 
715  const SwsOp *read = ff_sws_op_list_input(ops);
716  const SwsOp *write = ff_sws_op_list_output(ops);
717  if (!read || !write || ops->num_ops > 2 ||
718  read->type != write->type ||
719  read->rw.mode != write->rw.mode ||
720  read->rw.elems != write->rw.elems ||
721  read->rw.frac != write->rw.frac ||
722  read->rw.filter.op || write->rw.filter.op)
723  return false;
724 
725  /**
726  * Note that this check is unlikely to ever be hit in practice, since it
727  * would imply the existence of planar formats with different plane orders
728  * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
729  * However, the check is cheap and lets me sleep at night.
730  */
731  const int num_planes = ff_sws_rw_op_planes(read);
732  for (int i = 0; i < num_planes; i++) {
733  if (ops->plane_src[i] != ops->plane_dst[i])
734  return false;
735  }
736 
737  return true;
738 }
739 
741 {
742  int max_size = 0;
743  for (int i = 0; i < ops->num_ops; i++) {
744  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
745  max_size = FFMAX(max_size, size);
746  }
747 
748  return max_size;
749 }
750 
752 {
753  uint32_t mask = 0;
754  for (int i = 0; i < 4; i++) {
755  for (int j = 0; j < 5; j++) {
756  if (av_cmp_q64(c->m[i][j], Q(i == j)))
757  mask |= SWS_MASK(i, j);
758  }
759  }
760  return mask;
761 }
762 
764 {
765  if (flags & SWS_COMP_GARBAGE)
766  return 'X';
767  else if (flags & SWS_COMP_ZERO)
768  return '0';
769  else if (flags & SWS_COMP_SWAPPED)
770  return 'z';
771  else if (flags & SWS_COMP_CONST)
772  return '$';
773  else if (flags & SWS_COMP_COPY)
774  return '=';
775  else if (flags & SWS_COMP_EXACT)
776  return '+';
777  else
778  return '.';
779 }
780 
781 static void print_q(AVBPrint *bp, const AVRational64 q)
782 {
783  if (!q.den) {
784  av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
785  } else if (q.den == 1) {
786  av_bprintf(bp, "%"PRId64, q.num);
787  } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) {
788  av_bprintf(bp, "%f", av_q2d_64(q));
789  } else {
790  av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den);
791  }
792 }
793 
794 static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
795 {
796  av_bprintf(bp, "{");
797  for (int i = 0; i < 4; i++) {
798  if (i)
799  av_bprintf(bp, " ");
800  if (!SWS_COMP_TEST(mask, i)) {
801  av_bprintf(bp, "_");
802  } else {
803  print_q(bp, q4[i]);
804  }
805  }
806  av_bprintf(bp, "}");
807 }
808 
809 static const char *const rw_mode_names[] = {
810  [SWS_RW_PLANAR] = "planar",
811  [SWS_RW_PACKED] = "packed",
812  [SWS_RW_PALETTE] = "palette"
813 };
814 
815 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
816 {
817  const char *name = ff_sws_op_type_name(op->op);
819 
820  switch (op->op) {
821  case SWS_OP_INVALID:
822  case SWS_OP_SWAP_BYTES:
823  av_bprintf(bp, "%s", name);
824  break;
825  case SWS_OP_READ:
826  case SWS_OP_WRITE:
827  av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
828  op->rw.elems, rw_mode_names[op->rw.mode],
829  op->rw.frac);
830  if (!op->rw.filter.op)
831  break;
832  const SwsFilterWeights *kernel = op->rw.filter.kernel;
833  av_bprintf(bp, " + %d tap %s filter (%c)",
834  kernel->filter_size, kernel->name,
835  op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
836  break;
837  case SWS_OP_LSHIFT:
838  av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
839  break;
840  case SWS_OP_RSHIFT:
841  av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
842  break;
843  case SWS_OP_PACK:
844  case SWS_OP_UNPACK:
845  av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
846  op->pack.pattern[0], op->pack.pattern[1],
847  op->pack.pattern[2], op->pack.pattern[3]);
848  break;
849  case SWS_OP_CLEAR:
850  av_bprintf(bp, "%-20s: ", name);
851  print_q4(bp, op->clear.value, mask & op->clear.mask);
852  break;
853  case SWS_OP_SWIZZLE:
854  av_bprintf(bp, "%-20s: %d%d%d%d", name,
855  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
856  break;
857  case SWS_OP_CONVERT:
858  av_bprintf(bp, "%-20s: %s -> %s%s", name,
859  ff_sws_pixel_type_name(op->type),
860  ff_sws_pixel_type_name(op->convert.to),
861  op->convert.expand ? " (expand)" : "");
862  break;
863  case SWS_OP_DITHER:
864  av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
865  1 << op->dither.size_log2, 1 << op->dither.size_log2,
866  op->dither.y_offset[0], op->dither.y_offset[1],
867  op->dither.y_offset[2], op->dither.y_offset[3]);
868  break;
869  case SWS_OP_MIN:
870  av_bprintf(bp, "%-20s: x <= ", name);
871  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
872  break;
873  case SWS_OP_MAX:
874  av_bprintf(bp, "%-20s: ", name);
875  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
876  av_bprintf(bp, " <= x");
877  break;
878  case SWS_OP_LINEAR:
879  av_bprintf(bp, "%-20s: [", name);
880  for (int i = 0; i < 4; i++) {
881  av_bprintf(bp, "%s[", i ? " " : "");
882  for (int j = 0; j < 5; j++) {
883  av_bprintf(bp, j ? " " : "");
884  print_q(bp, op->lin.m[i][j]);
885  }
886  av_bprintf(bp, "]");
887  }
888  av_bprintf(bp, "]");
889  break;
890  case SWS_OP_SCALE:
891  av_bprintf(bp, "%-20s: * %"PRId64, name, op->scale.factor.num);
892  if (op->scale.factor.den != 1)
893  av_bprintf(bp, "/%"PRId64, op->scale.factor.den);
894  break;
895  case SWS_OP_FILTER_H:
896  case SWS_OP_FILTER_V: {
897  const SwsFilterWeights *kernel = op->filter.kernel;
898  av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
899  kernel->src_size, kernel->dst_size,
900  kernel->name, kernel->filter_size);
901  break;
902  }
903  case SWS_OP_TYPE_NB:
904  break;
905  }
906 }
907 
908 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
909 {
910  bool inorder = true;
911  for (int i = 0; i < nb_planes; i++)
912  inorder &= order[i] == i;
913  if (inorder)
914  return;
915 
916  av_bprintf(bp, ", via {");
917  for (int i = 0; i < nb_planes; i++)
918  av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
919  av_bprintf(bp, "}");
920 }
921 
922 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
923  const SwsOpList *ops)
924 {
925  AVBPrint bp;
926  if (!ops->num_ops) {
927  av_log(log, lev, " (empty)\n");
928  return;
929  }
930 
932 
933  for (int i = 0; i < ops->num_ops; i++) {
934  const SwsOp *op = &ops->ops[i];
936  av_bprint_clear(&bp);
937  av_bprintf(&bp, " [%3s %c%c%c%c] ",
938  ff_sws_pixel_type_name(op->type),
939  describe_comp_flags(op->comps.flags[0]),
940  describe_comp_flags(op->comps.flags[1]),
941  describe_comp_flags(op->comps.flags[2]),
942  describe_comp_flags(op->comps.flags[3]));
943 
944  ff_sws_op_desc(&bp, op);
945 
946  if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
947  const int planes = ff_sws_rw_op_planes(op);
949  op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
950  }
951 
953  av_log(log, lev, "%s\n", bp.str);
954 
955  /* Only print value ranges if any are relevant */
956  SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
957  ff_sws_comp_mask_q4(op->comps.max);
958  if (range_mask & mask) {
959  av_bprint_clear(&bp);
960  av_bprintf(&bp, " min: ");
961  print_q4(&bp, op->comps.min, mask);
962  av_bprintf(&bp, ", max: ");
963  print_q4(&bp, op->comps.max, mask);
965  av_log(log, lev_extra, "%s\n", bp.str);
966  }
967 
968  }
969 
970  av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
971 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:39
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:611
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:132
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:42
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:598
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:47
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:45
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:625
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:100
apply_filter_weights
static void apply_filter_weights(SwsComps *comps, const SwsComps *prev, const SwsFilterWeights *weights)
Definition: ops.c:289
rw_mode_names
static const char *const rw_mode_names[]
Definition: ops.c:809
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
SwsOpList::comps_src
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition: ops.h:284
merge_comp_flags
static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
Definition: ops.c:282
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:662
SWS_COMP_ZERO
@ SWS_COMP_ZERO
Definition: ops.h:76
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:51
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:740
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:705
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:705
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
ff_sws_comp_mask_q4
SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
Definition: ops.c:99
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:215
ops.h
ff_sws_pixel_type_is_int
static av_const bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: uops.h:62
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:59
SwsFilterWeights
Represents a computed filter kernel.
Definition: filters.h:85
describe_comp_flags
static char describe_comp_flags(SwsCompFlags flags)
Definition: ops.c:763
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:341
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:908
SWS_FILTER_SCALE
@ SWS_FILTER_SCALE
14-bit coefficients are picked to fit comfortably within int16_t for efficient SIMD processing (e....
Definition: filters.h:40
max
#define max(a, b)
Definition: cuda_runtime.h:33
SWS_OP_TYPE_NB
@ SWS_OP_TYPE_NB
Definition: ops.h:65
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_min_q64
static AVRational64 av_min_q64(AVRational64 a, AVRational64 b)
Definition: ops.c:146
format.h
ff_sws_comp_mask_needed
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition: ops.c:122
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:302
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:273
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:922
print_q4
static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
Definition: ops.c:794
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: uops.h:97
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:42
av_ceil_log2
#define av_ceil_log2
Definition: common.h:97
SwsOpList::num_ops
int num_ops
Definition: ops.h:267
SwsCompFlags
SwsCompFlags
Definition: ops.h:73
print_q
static void print_q(AVBPrint *bp, const AVRational64 q)
Definition: ops.c:781
SwsSwizzleOp
Definition: ops.h:141
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
SWS_COMP_IDENTITY
@ SWS_COMP_IDENTITY
Definition: ops.c:275
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
refstruct.h
SwsOp::op
SwsOpType op
Definition: ops.h:211
SWS_RW_PACKED
@ SWS_RW_PACKED
Definition: ops.h:101
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:55
planes
static const struct @603 planes[]
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
backend_aarch64
const SwsOpBackend backend_aarch64
Definition: ops.c:268
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:237
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:504
ff_sws_pixel_expand
static AVRational64 ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
Definition: ops_internal.h:31
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
backend_c
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
Definition: uops_backend.c:198
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
av_cmp_q64
int av_cmp_q64(AVRational64 a, AVRational64 b)
Compare two 64-bit rationals.
Definition: rational64.c:108
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:53
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: uops.h:87
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:58
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:671
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:62
av_mul_q64
AVRational64 av_mul_q64(AVRational64 b, AVRational64 c)
Multiply two 64-bit rationals.
Definition: rational64.c:124
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpBackend
Definition: ops_dispatch.h:134
ff_sws_pixel_type_size
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition: uops.h:49
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:46
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:710
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
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:117
SWS_COMP_GARBAGE
@ SWS_COMP_GARBAGE
Definition: ops.h:74
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:63
SwsOpType
SwsOpType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:35
ff_sws_op_list_remove_at
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
Definition: ops.c:680
attributes.h
ff_sws_apply_op_q
void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4])
Apply an operation to an AVRational64.
Definition: ops.c:156
SwsFilterWeights::src_size
int src_size
Copy of the parameters used to generate this filter, for reference.
Definition: filters.h:110
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_comp_mask_swizzle
void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz)
Definition: ops.c:109
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
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:212
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:691
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition: ops.c:751
size
int size
Definition: twinvq_data.h:10344
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:48
SwsOpList::src
SwsFormat src
Definition: ops.h:270
SWS_OP_INVALID
@ SWS_OP_INVALID
Definition: ops.h:36
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:308
AVRational64
64-bit Rational number (pair of numerator and denominator).
Definition: rational64.h:52
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:40
SWS_COMP
#define SWS_COMP(X)
Definition: uops.h:96
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:580
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:79
SwsLinearOp
Definition: ops.h:185
ff_sws_op_desc
void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
Describe an operation in human-readable form.
Definition: ops.c:815
SwsReadWriteOp::op
SwsOpType op
Definition: ops.h:127
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
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:68
bprint.h
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
SwsOpList::ops
SwsOp * ops
Definition: ops.h:266
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
lev
static LevelCodes lev[4+3+3]
Definition: clearvideo.c:80
SwsOp
Definition: ops.h:210
SwsReadWriteOp::filter
struct SwsReadWriteOp::@580 filter
Filter kernel to apply to each plane while sampling.
AVRational64::den
int64_t den
Denominator.
Definition: rational64.h:54
bound
static double bound(const double threshold, const double val)
Definition: af_dynaudnorm.c:413
SwsComps::flags
SwsCompFlags flags[4]
Definition: ops.h:83
ret
ret
Definition: filter_design.txt:187
bswap.h
backend_murder
const SwsOpBackend backend_murder
Definition: ops_memcpy.c:144
SwsComps::min
AVRational64 min[4]
Definition: ops.h:87
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:270
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:54
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
av_q2d_64
static double av_q2d_64(AVRational64 a)
Convert an AVRational64 to a double.
Definition: rational64.h:90
SWS_RW_PALETTE
@ SWS_RW_PALETTE
Definition: ops.h:102
av_make_q64
static AVRational64 av_make_q64(int64_t num, int64_t den)
Create an AVRational64.
Definition: rational64.h:64
SwsComps
Definition: ops.h:82
SWS_COMP_SWAPPED
@ SWS_COMP_SWAPPED
Definition: ops.h:77
ff_sws_pixel_type_name
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition: ops.c:56
av_max_q64
static AVRational64 av_max_q64(AVRational64 a, AVRational64 b)
Definition: ops.c:151
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:41
SWS_COMP_COPY
@ SWS_COMP_COPY
Definition: ops.h:78
SWS_COMP_EXACT
@ SWS_COMP_EXACT
Definition: ops.h:75
SwsReadWriteOp::elems
uint8_t elems
Definition: ops.h:116
mem.h
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: uops.h:43
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
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
AVRational64::num
int64_t num
Numerator.
Definition: rational64.h:53
SwsComps::max
AVRational64 max[4]
Definition: ops.h:87
SwsSwizzleOp::in
uint8_t in[4]
Definition: ops.h:148
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:52
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:115
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:273
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:265
SWS_COMP_DIRTY
@ SWS_COMP_DIRTY
Definition: ops.c:278
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:71
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: uops.h:41
SWS_MASK
#define SWS_MASK(I, J)
Definition: uops.h:229
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
av_add_q64
AVRational64 av_add_q64(AVRational64 b, AVRational64 c)
Add two 64-bit rationals.
Definition: rational64.c:135
min
float min
Definition: vorbis_enc_data.h:429