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 (type) {
74  case SWS_PIXEL_U8: return sizeof(uint8_t);
75  case SWS_PIXEL_U16: return sizeof(uint16_t);
76  case SWS_PIXEL_U32: return sizeof(uint32_t);
77  case SWS_PIXEL_F32: return sizeof(float);
78  case SWS_PIXEL_NONE: break;
79  case SWS_PIXEL_TYPE_NB: break;
80  }
81 
82  av_unreachable("Invalid pixel type!");
83  return 0;
84 }
85 
87 {
88  switch (type) {
89  case SWS_PIXEL_U8:
90  case SWS_PIXEL_U16:
91  case SWS_PIXEL_U32:
92  return true;
93  case SWS_PIXEL_F32:
94  return false;
95  case SWS_PIXEL_NONE:
96  case SWS_PIXEL_TYPE_NB: break;
97  }
98 
99  av_unreachable("Invalid pixel type!");
100  return false;
101 }
102 
104 {
105  switch (op) {
106  case SWS_OP_READ: return "SWS_OP_READ";
107  case SWS_OP_WRITE: return "SWS_OP_WRITE";
108  case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
109  case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
110  case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
111  case SWS_OP_PACK: return "SWS_OP_PACK";
112  case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
113  case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
114  case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
115  case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
116  case SWS_OP_MIN: return "SWS_OP_MIN";
117  case SWS_OP_MAX: return "SWS_OP_MAX";
118  case SWS_OP_SCALE: return "SWS_OP_SCALE";
119  case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
120  case SWS_OP_DITHER: return "SWS_OP_DITHER";
121  case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
122  case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
123  case SWS_OP_INVALID: return "SWS_OP_INVALID";
124  case SWS_OP_TYPE_NB: break;
125  }
126 
127  av_unreachable("Invalid operation type!");
128  return "ERR";
129 }
130 
132 {
133  SwsCompMask mask = 0;
134  for (int i = 0; i < 4; i++) {
135  if (q[i].den)
136  mask |= SWS_COMP(i);
137  }
138  return mask;
139 }
140 
142 {
143  const SwsCompMask orig = *mask;
144  SwsCompMask res = 0;
145  for (int i = 0; i < 4; i++) {
146  const int src = swiz->in[i];
147  if (SWS_COMP_TEST(orig, src))
148  res |= SWS_COMP(i);
149  }
150 
151  *mask = res;
152 }
153 
155 {
156  SwsCompMask mask = 0;
157  for (int i = 0; i < 4; i++) {
158  if (SWS_OP_NEEDED(op, i))
159  mask |= SWS_COMP(i);
160  }
161  return mask;
162 }
163 
165 {
166  av_assert2(op->op == SWS_OP_READ || op->op == SWS_OP_WRITE);
167  switch (op->rw.mode) {
168  case SWS_RW_PLANAR: return op->rw.elems;
169  case SWS_RW_PACKED: return 1;
170  case SWS_RW_PALETTE: return 2;
171  }
172 
173  av_unreachable("Invalid read/write mode!");
174  return 0;
175 }
176 
177 /* biased towards `a` */
179 {
180  return av_cmp_q64(a, b) == 1 ? b : a;
181 }
182 
184 {
185  return av_cmp_q64(a, b) == -1 ? b : a;
186 }
187 
189 {
190  uint64_t mask[4];
191  int shift[4];
192 
193  switch (op->op) {
194  case SWS_OP_READ:
195  case SWS_OP_WRITE:
196  return;
197  case SWS_OP_UNPACK: {
200  unsigned val = x[0].num;
201  for (int i = 0; i < 4; i++)
202  x[i] = Q((val >> shift[i]) & mask[i]);
203  return;
204  }
205  case SWS_OP_PACK: {
208  unsigned val = 0;
209  for (int i = 0; i < 4; i++)
210  val |= (x[i].num & mask[i]) << shift[i];
211  x[0] = Q(val);
212  return;
213  }
214  case SWS_OP_SWAP_BYTES:
215  switch (op->type) {
216  case SWS_PIXEL_U16:
217  for (int i = 0; i < 4; i++) {
218  av_assert2(x[i].num >= 0 && x[i].num <= UINT16_MAX);
219  x[i].num = av_bswap16(x[i].num);
220  }
221  return;
222  case SWS_PIXEL_U32:
223  for (int i = 0; i < 4; i++) {
224  av_assert2(x[i].num >= 0 && x[i].num <= UINT32_MAX);
225  x[i].num = av_bswap32(x[i].num);
226  }
227  return;
228  }
229  av_unreachable("Invalid pixel type for SWS_OP_SWAP_BYTES!");
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  AVRational64 mult = Q(1 << op->shift.amount);
240  for (int i = 0; i < 4; i++)
241  x[i] = x[i].den ? av_mul_q64(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 AVRational64 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 AVRational64 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_q64(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_q64(x[i], av_make_q64(1, 2));
271  }
272  return;
273  case SWS_OP_MIN:
274  for (int i = 0; i < 4; i++)
275  x[i] = av_min_q64(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_q64(x[i], op->clamp.limit[i]);
280  return;
281  case SWS_OP_LINEAR: {
283  const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
284  for (int i = 0; i < 4; i++) {
285  AVRational64 sum = op->lin.m[i][4];
286  for (int j = 0; j < 4; j++)
287  sum = av_add_q64(sum, av_mul_q64(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_q64(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 enum {
309 
311 };
312 
313 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
315 {
316  const SwsCompFlags flags_or = SWS_COMP_GARBAGE;
317  const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
318  return ((a & b) & flags_and) | ((a | b) & flags_or);
319 }
320 
321 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
322  const SwsFilterWeights *weights)
323 {
324  const AVRational64 posw = { weights->sum_positive, SWS_FILTER_SCALE };
325  const AVRational64 negw = { weights->sum_negative, SWS_FILTER_SCALE };
326  for (int i = 0; i < 4; i++) {
327  comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
328  /* Only point sampling preserves exactness */
329  if (weights->filter_size != 1)
330  comps->flags[i] &= ~SWS_COMP_EXACT;
331  /* Update min/max assuming extremes */
332  comps->min[i] = av_add_q64(av_mul_q64(prev->min[i], posw),
333  av_mul_q64(prev->max[i], negw));
334  comps->max[i] = av_add_q64(av_mul_q64(prev->min[i], negw),
335  av_mul_q64(prev->max[i], posw));
336  }
337 }
338 
339 /* Infer + propagate known information about components */
341 {
342  SwsComps prev = { .flags = {
344  }};
345 
346  /* Forwards pass, propagates knowledge about the incoming pixel values */
347  for (int n = 0; n < ops->num_ops; n++) {
348  SwsOp *op = &ops->ops[n];
349 
350  switch (op->op) {
351  case SWS_OP_LINEAR:
352  case SWS_OP_DITHER:
353  case SWS_OP_SWAP_BYTES:
354  case SWS_OP_UNPACK:
355  case SWS_OP_FILTER_H:
356  case SWS_OP_FILTER_V:
357  break; /* special cases, handled below */
358  default:
359  memcpy(op->comps.min, prev.min, sizeof(prev.min));
360  memcpy(op->comps.max, prev.max, sizeof(prev.max));
361  ff_sws_apply_op_q(op, op->comps.min);
362  ff_sws_apply_op_q(op, op->comps.max);
363  break;
364  }
365 
366  switch (op->op) {
367  case SWS_OP_READ:
368  /* Active components are taken from the user-provided values,
369  * other components are explicitly stripped */
370  for (int i = 0; i < op->rw.elems; i++) {
371  int idx = 0;
372  switch (op->rw.mode) {
373  case SWS_RW_PALETTE: idx = i; break;
374  case SWS_RW_PACKED: idx = i; break;
375  case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
376  }
377 
378  av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
379  op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
380  op->comps.min[i] = ops->comps_src.min[idx];
381  op->comps.max[i] = ops->comps_src.max[idx];
382 
383  /**
384  * Don't mark packed or fractional reads as a copy, because the
385  * read operation implicitly unpacks the data into separate
386  * components. The only case in which op lists involving such
387  * reads can be refcopies is in the case of a true noop, which
388  * is already covered by the no-op check.
389  */
390  if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
391  op->comps.flags[i] |= SWS_COMP_COPY;
392  }
393 
394  if (op->rw.filter.op) {
395  const SwsComps prev = op->comps;
396  apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
397  }
398  break;
399  case SWS_OP_SWAP_BYTES:
400  for (int i = 0; i < 4; i++) {
401  op->comps.flags[i] = (prev.flags[i] ^ SWS_COMP_SWAPPED) & SWS_COMP_DIRTY;
402  op->comps.min[i] = prev.min[i];
403  op->comps.max[i] = prev.max[i];
404  }
405  break;
406  case SWS_OP_WRITE:
407  for (int i = 0; i < op->rw.elems; i++)
408  av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
409  for (int i = 0; i < 4; i++)
410  op->comps.flags[i] = prev.flags[i];
411  break;
412  case SWS_OP_LSHIFT:
413  case SWS_OP_RSHIFT:
414  for (int i = 0; i < 4; i++)
415  op->comps.flags[i] = prev.flags[i] & SWS_COMP_DIRTY;
416  break;
417  case SWS_OP_MIN:
418  case SWS_OP_MAX: {
419  AVRational64 *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
420  for (int i = 0; i < 4; i++) {
421  op->comps.flags[i] = prev.flags[i];
422  if (op->clamp.limit[i].den)
423  op->comps.flags[i] &= SWS_COMP_DIRTY;
424  if (!bound[i].den) /* reset undefined bounds to known range */
425  bound[i] = op->clamp.limit[i];
426  }
427  break;
428  }
429  case SWS_OP_DITHER:
430  for (int i = 0; i < 4; i++) {
431  op->comps.flags[i] = prev.flags[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] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
438  op->comps.min[i] = av_add_q64(op->comps.min[i], op->dither.min);
439  op->comps.max[i] = av_add_q64(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] & SWS_COMP_DIRTY;
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 & SWS_COMP_DIRTY;
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] = SWS_COMP_CONST;
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 (!(prev.flags[i] & SWS_COMP_EXACT) || op->convert.expand)
486  op->comps.flags[i] &= SWS_COMP_DIRTY;
487  if (ff_sws_pixel_type_is_int(op->convert.to))
488  op->comps.flags[i] |= SWS_COMP_EXACT;
489  }
490  break;
491  case SWS_OP_LINEAR:
492  for (int i = 0; i < 4; i++) {
494  AVRational64 min = Q(0), max = Q(0);
495  bool first = true;
496  for (int j = 0; j < 4; j++) {
497  const AVRational64 k = op->lin.m[i][j];
498  AVRational64 mink = av_mul_q64(prev.min[j], k);
499  AVRational64 maxk = av_mul_q64(prev.max[j], k);
500  if (k.num) {
501  flags = merge_comp_flags(flags, prev.flags[j]);
502  if (k.den != 1) /* fractional coefficient */
503  flags &= ~SWS_COMP_EXACT;
504  if (k.num < 0)
505  FFSWAP(AVRational64, mink, maxk);
506  min = av_add_q64(min, mink);
507  max = av_add_q64(max, maxk);
508  if (!first || av_cmp_q64(k, Q(1)))
510  first = false;
511  }
512  }
513  if (op->lin.m[i][4].num) { /* nonzero offset */
515  if (op->lin.m[i][4].den != 1) /* fractional offset */
516  flags &= ~SWS_COMP_EXACT;
517  min = av_add_q64(min, op->lin.m[i][4]);
518  max = av_add_q64(max, op->lin.m[i][4]);
519  }
520  op->comps.flags[i] = flags;
521  op->comps.min[i] = min;
522  op->comps.max[i] = max;
523  }
524  break;
525  case SWS_OP_SCALE:
526  for (int i = 0; i < 4; i++) {
527  op->comps.flags[i] = prev.flags[i] & SWS_COMP_DIRTY;
528  if (op->scale.factor.den != 1) /* fractional scale */
529  op->comps.flags[i] &= ~SWS_COMP_EXACT;
530  if (op->scale.factor.num < 0)
531  FFSWAP(AVRational64, op->comps.min[i], op->comps.max[i]);
532  }
533  break;
534  case SWS_OP_FILTER_H:
535  case SWS_OP_FILTER_V: {
536  apply_filter_weights(&op->comps, &prev, op->filter.kernel);
537  break;
538  }
539 
540  case SWS_OP_INVALID:
541  case SWS_OP_TYPE_NB:
542  av_unreachable("Invalid operation type!");
543  }
544 
545  prev = op->comps;
546  }
547 
548  /* Backwards pass, solves for component dependencies */
549  bool need_out[4] = { false, false, false, false };
550  for (int n = ops->num_ops - 1; n >= 0; n--) {
551  SwsOp *op = &ops->ops[n];
552  bool need_in[4] = { false, false, false, false };
553 
554  for (int i = 0; i < 4; i++) {
555  if (!need_out[i])
556  op->comps.flags[i] = SWS_COMP_GARBAGE;
557  }
558 
559  switch (op->op) {
560  case SWS_OP_READ:
561  case SWS_OP_WRITE:
562  for (int i = 0; i < op->rw.elems; i++)
563  need_in[i] = op->op == SWS_OP_WRITE;
564  for (int i = op->rw.elems; i < 4; i++)
565  need_in[i] = need_out[i];
566  break;
567  case SWS_OP_SWAP_BYTES:
568  case SWS_OP_LSHIFT:
569  case SWS_OP_RSHIFT:
570  case SWS_OP_CONVERT:
571  case SWS_OP_DITHER:
572  case SWS_OP_MIN:
573  case SWS_OP_MAX:
574  case SWS_OP_SCALE:
575  case SWS_OP_FILTER_H:
576  case SWS_OP_FILTER_V:
577  for (int i = 0; i < 4; i++)
578  need_in[i] = need_out[i];
579  break;
580  case SWS_OP_UNPACK:
581  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
582  need_in[0] |= need_out[i];
583  break;
584  case SWS_OP_PACK:
585  for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
586  need_in[i] = need_out[0];
587  break;
588  case SWS_OP_CLEAR:
589  for (int i = 0; i < 4; i++) {
590  if (!SWS_COMP_TEST(op->clear.mask, i))
591  need_in[i] = need_out[i];
592  }
593  break;
594  case SWS_OP_SWIZZLE:
595  for (int i = 0; i < 4; i++)
596  need_in[op->swizzle.in[i]] |= need_out[i];
597  break;
598  case SWS_OP_LINEAR:
599  for (int i = 0; i < 4; i++) {
600  for (int j = 0; j < 4; j++) {
601  if (op->lin.m[i][j].num)
602  need_in[j] |= need_out[i];
603  }
604  }
605  break;
606  }
607 
608  memcpy(need_out, need_in, sizeof(need_in));
609  }
610 }
611 
612 static void op_uninit(SwsOp *op)
613 {
614  switch (op->op) {
615  case SWS_OP_READ:
616  av_refstruct_unref(&op->rw.filter.kernel);
617  break;
618  case SWS_OP_DITHER:
619  av_refstruct_unref(&op->dither.matrix);
620  break;
621  case SWS_OP_FILTER_H:
622  case SWS_OP_FILTER_V:
623  av_refstruct_unref(&op->filter.kernel);
624  break;
625  }
626 
627  *op = (SwsOp) {0};
628 }
629 
631 {
632  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
633  if (!ops)
634  return NULL;
635 
636  for (int i = 0; i < 4; i++)
637  ops->plane_src[i] = ops->plane_dst[i] = i;
638  ff_fmt_clear(&ops->src);
639  ff_fmt_clear(&ops->dst);
640  return ops;
641 }
642 
644 {
645  SwsOpList *ops = *p_ops;
646  if (!ops)
647  return;
648 
649  for (int i = 0; i < ops->num_ops; i++)
650  op_uninit(&ops->ops[i]);
651 
652  av_freep(&ops->ops);
653  av_free(ops);
654  *p_ops = NULL;
655 }
656 
658 {
659  SwsOpList *copy = av_malloc(sizeof(*copy));
660  if (!copy)
661  return NULL;
662 
663  int num = ops->num_ops;
664  if (num)
665  num = 1 << av_ceil_log2(num);
666 
667  *copy = *ops;
668  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
669  if (!copy->ops) {
670  av_free(copy);
671  return NULL;
672  }
673 
674  for (int i = 0; i < copy->num_ops; i++) {
675  const SwsOp *op = &copy->ops[i];
676  switch (op->op) {
677  case SWS_OP_READ:
678  if (op->rw.filter.kernel)
679  av_refstruct_ref(op->rw.filter.kernel);
680  break;
681  case SWS_OP_DITHER:
682  av_refstruct_ref(op->dither.matrix);
683  break;
684  case SWS_OP_FILTER_H:
685  case SWS_OP_FILTER_V:
686  av_refstruct_ref(op->filter.kernel);
687  break;
688  }
689  }
690 
691  return copy;
692 }
693 
695 {
696  if (!ops->num_ops)
697  return NULL;
698 
699  const SwsOp *read = &ops->ops[0];
700  return read->op == SWS_OP_READ ? read : NULL;
701 }
702 
704 {
705  if (!ops->num_ops)
706  return NULL;
707 
708  const SwsOp *write = &ops->ops[ops->num_ops - 1];
709  return write->op == SWS_OP_WRITE ? write : NULL;
710 }
711 
712 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
713 {
714  const int end = ops->num_ops - count;
715  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
716  for (int i = 0; i < count; i++)
717  op_uninit(&ops->ops[index + i]);
718  for (int i = index; i < end; i++)
719  ops->ops[i] = ops->ops[i + count];
720  ops->num_ops = end;
721 }
722 
724 {
725  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
726  if (!ret) {
727  op_uninit(op);
728  return AVERROR(ENOMEM);
729  }
730 
731  for (int i = ops->num_ops - 1; i > index; i--)
732  ops->ops[i] = ops->ops[i - 1];
733  ops->ops[index] = *op;
734  return 0;
735 }
736 
738 {
739  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
740 }
741 
743 {
744  if (!ops->num_ops)
745  return true;
746 
747  const SwsOp *read = ff_sws_op_list_input(ops);
748  const SwsOp *write = ff_sws_op_list_output(ops);
749  if (!read || !write || ops->num_ops > 2 ||
750  read->type != write->type ||
751  read->rw.mode != write->rw.mode ||
752  read->rw.elems != write->rw.elems ||
753  read->rw.frac != write->rw.frac ||
754  read->rw.filter.op || write->rw.filter.op)
755  return false;
756 
757  /**
758  * Note that this check is unlikely to ever be hit in practice, since it
759  * would imply the existence of planar formats with different plane orders
760  * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
761  * However, the check is cheap and lets me sleep at night.
762  */
763  const int num_planes = ff_sws_rw_op_planes(read);
764  for (int i = 0; i < num_planes; i++) {
765  if (ops->plane_src[i] != ops->plane_dst[i])
766  return false;
767  }
768 
769  return true;
770 }
771 
773 {
774  int max_size = 0;
775  for (int i = 0; i < ops->num_ops; i++) {
776  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
777  max_size = FFMAX(max_size, size);
778  }
779 
780  return max_size;
781 }
782 
784 {
785  uint32_t mask = 0;
786  for (int i = 0; i < 4; i++) {
787  for (int j = 0; j < 5; j++) {
788  if (av_cmp_q64(c->m[i][j], Q(i == j)))
789  mask |= SWS_MASK(i, j);
790  }
791  }
792  return mask;
793 }
794 
796 {
797  if (flags & SWS_COMP_GARBAGE)
798  return 'X';
799  else if (flags & SWS_COMP_ZERO)
800  return '0';
801  else if (flags & SWS_COMP_SWAPPED)
802  return 'z';
803  else if (flags & SWS_COMP_CONST)
804  return '$';
805  else if (flags & SWS_COMP_COPY)
806  return '=';
807  else if (flags & SWS_COMP_EXACT)
808  return '+';
809  else
810  return '.';
811 }
812 
813 static void print_q(AVBPrint *bp, const AVRational64 q)
814 {
815  if (!q.den) {
816  av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
817  } else if (q.den == 1) {
818  av_bprintf(bp, "%"PRId64, q.num);
819  } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) {
820  av_bprintf(bp, "%f", av_q2d_64(q));
821  } else {
822  av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den);
823  }
824 }
825 
826 static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
827 {
828  av_bprintf(bp, "{");
829  for (int i = 0; i < 4; i++) {
830  if (i)
831  av_bprintf(bp, " ");
832  if (!SWS_COMP_TEST(mask, i)) {
833  av_bprintf(bp, "_");
834  } else {
835  print_q(bp, q4[i]);
836  }
837  }
838  av_bprintf(bp, "}");
839 }
840 
841 static const char *const rw_mode_names[] = {
842  [SWS_RW_PLANAR] = "planar",
843  [SWS_RW_PACKED] = "packed",
844  [SWS_RW_PALETTE] = "palette"
845 };
846 
847 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
848 {
849  const char *name = ff_sws_op_type_name(op->op);
851 
852  switch (op->op) {
853  case SWS_OP_INVALID:
854  case SWS_OP_SWAP_BYTES:
855  av_bprintf(bp, "%s", name);
856  break;
857  case SWS_OP_READ:
858  case SWS_OP_WRITE:
859  av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
860  op->rw.elems, rw_mode_names[op->rw.mode],
861  op->rw.frac);
862  if (!op->rw.filter.op)
863  break;
864  const SwsFilterWeights *kernel = op->rw.filter.kernel;
865  av_bprintf(bp, " + %d tap %s filter (%c)",
866  kernel->filter_size, kernel->name,
867  op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
868  break;
869  case SWS_OP_LSHIFT:
870  av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
871  break;
872  case SWS_OP_RSHIFT:
873  av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
874  break;
875  case SWS_OP_PACK:
876  case SWS_OP_UNPACK:
877  av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
878  op->pack.pattern[0], op->pack.pattern[1],
879  op->pack.pattern[2], op->pack.pattern[3]);
880  break;
881  case SWS_OP_CLEAR:
882  av_bprintf(bp, "%-20s: ", name);
883  print_q4(bp, op->clear.value, mask & op->clear.mask);
884  break;
885  case SWS_OP_SWIZZLE:
886  av_bprintf(bp, "%-20s: %d%d%d%d", name,
887  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
888  break;
889  case SWS_OP_CONVERT:
890  av_bprintf(bp, "%-20s: %s -> %s%s", name,
891  ff_sws_pixel_type_name(op->type),
892  ff_sws_pixel_type_name(op->convert.to),
893  op->convert.expand ? " (expand)" : "");
894  break;
895  case SWS_OP_DITHER:
896  av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
897  1 << op->dither.size_log2, 1 << op->dither.size_log2,
898  op->dither.y_offset[0], op->dither.y_offset[1],
899  op->dither.y_offset[2], op->dither.y_offset[3]);
900  break;
901  case SWS_OP_MIN:
902  av_bprintf(bp, "%-20s: x <= ", name);
903  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
904  break;
905  case SWS_OP_MAX:
906  av_bprintf(bp, "%-20s: ", name);
907  print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
908  av_bprintf(bp, " <= x");
909  break;
910  case SWS_OP_LINEAR:
911  av_bprintf(bp, "%-20s: [", name);
912  for (int i = 0; i < 4; i++) {
913  av_bprintf(bp, "%s[", i ? " " : "");
914  for (int j = 0; j < 5; j++) {
915  av_bprintf(bp, j ? " " : "");
916  print_q(bp, op->lin.m[i][j]);
917  }
918  av_bprintf(bp, "]");
919  }
920  av_bprintf(bp, "]");
921  break;
922  case SWS_OP_SCALE:
923  av_bprintf(bp, "%-20s: * %"PRId64, name, op->scale.factor.num);
924  if (op->scale.factor.den != 1)
925  av_bprintf(bp, "/%"PRId64, op->scale.factor.den);
926  break;
927  case SWS_OP_FILTER_H:
928  case SWS_OP_FILTER_V: {
929  const SwsFilterWeights *kernel = op->filter.kernel;
930  av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
931  kernel->src_size, kernel->dst_size,
932  kernel->name, kernel->filter_size);
933  break;
934  }
935  case SWS_OP_TYPE_NB:
936  break;
937  }
938 }
939 
940 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
941 {
942  bool inorder = true;
943  for (int i = 0; i < nb_planes; i++)
944  inorder &= order[i] == i;
945  if (inorder)
946  return;
947 
948  av_bprintf(bp, ", via {");
949  for (int i = 0; i < nb_planes; i++)
950  av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
951  av_bprintf(bp, "}");
952 }
953 
954 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
955  const SwsOpList *ops)
956 {
957  AVBPrint bp;
958  if (!ops->num_ops) {
959  av_log(log, lev, " (empty)\n");
960  return;
961  }
962 
964 
965  for (int i = 0; i < ops->num_ops; i++) {
966  const SwsOp *op = &ops->ops[i];
968  av_bprint_clear(&bp);
969  av_bprintf(&bp, " [%3s %c%c%c%c] ",
970  ff_sws_pixel_type_name(op->type),
971  describe_comp_flags(op->comps.flags[0]),
972  describe_comp_flags(op->comps.flags[1]),
973  describe_comp_flags(op->comps.flags[2]),
974  describe_comp_flags(op->comps.flags[3]));
975 
976  ff_sws_op_desc(&bp, op);
977 
978  if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
979  const int planes = ff_sws_rw_op_planes(op);
981  op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
982  }
983 
985  av_log(log, lev, "%s\n", bp.str);
986 
987  /* Only print value ranges if any are relevant */
988  SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
989  ff_sws_comp_mask_q4(op->comps.max);
990  if (range_mask & mask) {
991  av_bprint_clear(&bp);
992  av_bprintf(&bp, " min: ");
993  print_q4(&bp, op->comps.min, mask);
994  av_bprintf(&bp, ", max: ");
995  print_q4(&bp, op->comps.max, mask);
997  av_log(log, lev_extra, "%s\n", bp.str);
998  }
999 
1000  }
1001 
1002  av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
1003 }
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:643
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:164
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:630
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:657
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:321
rw_mode_names
static const char *const rw_mode_names[]
Definition: ops.c:841
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:314
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:694
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:772
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:693
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:737
SWS_COMP_IDENTITY
@ SWS_COMP_IDENTITY
Definition: ops.c:307
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:131
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:215
ops.h
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:795
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:940
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:178
format.h
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:71
ff_sws_comp_mask_needed
SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
Definition: ops.c:154
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:954
print_q4
static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
Definition: ops.c:826
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: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:813
SwsSwizzleOp
Definition: ops.h:141
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:86
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
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:252
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:237
SwsReadWriteOp::filter
struct SwsReadWriteOp::@581 filter
Filter kernel to apply to each plane while sampling.
float
float
Definition: af_crystalizer.c:122
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:504
planes
static const struct @604 planes[]
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:61
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:703
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
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:742
SWS_COMP_DIRTY
@ SWS_COMP_DIRTY
Definition: ops.c:310
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:712
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:188
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:141
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:723
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
Definition: ops.c:783
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:340
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: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:612
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:847
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
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:183
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
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:103
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: uops.h:41
SWS_MASK
#define SWS_MASK(I, J)
Definition: uops.h:188
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
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