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