FFmpeg
ops_optimizer.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/bswap.h"
24 #include "libavutil/rational.h"
25 
26 #include "ops.h"
27 #include "ops_internal.h"
28 
29 #define RET(x) \
30  do { \
31  if ((ret = (x)) < 0) \
32  return ret; \
33  } while (0)
34 
35 /**
36  * Try to commute a clear op with the next operation. Makes any adjustments
37  * to the operations as needed, but does not perform the actual commutation.
38  *
39  * Returns whether successful.
40  */
41 static bool op_commute_clear(SwsOp *op, SwsOp *next)
42 {
43  SwsClearOp tmp = {0};
44 
45  av_assert1(op->op == SWS_OP_CLEAR);
46  switch (next->op) {
47  case SWS_OP_CONVERT:
48  op->type = next->convert.to;
50  case SWS_OP_LSHIFT:
51  case SWS_OP_RSHIFT:
52  case SWS_OP_DITHER:
53  case SWS_OP_MIN:
54  case SWS_OP_MAX:
55  case SWS_OP_SCALE:
56  case SWS_OP_READ:
57  case SWS_OP_FILTER_H:
58  case SWS_OP_FILTER_V:
59  ff_sws_apply_op_q(next, op->clear.value);
60  return true;
61  case SWS_OP_SWIZZLE:
62  op->clear.mask = ff_sws_comp_mask_swizzle(op->clear.mask, next->swizzle);
63  ff_sws_apply_op_q(next, op->clear.value);
64  return true;
65  case SWS_OP_SWAP_BYTES:
66  switch (next->type) {
67  case SWS_PIXEL_U16:
68  ff_sws_apply_op_q(next, op->clear.value); /* always works */
69  return true;
70  case SWS_PIXEL_U32:
71  for (int i = 0; i < 4; i++) {
72  if (!SWS_COMP_TEST(op->clear.mask, i))
73  continue;
74  uint32_t v = av_bswap32(op->clear.value[i].num);
75  if (v > INT_MAX)
76  return false; /* can't represent as AVRational anymore */
77  tmp.value[i] = Q(v);
78  }
79  op->clear = tmp;
80  return true;
81  default:
82  return false;
83  }
84  case SWS_OP_INVALID:
85  case SWS_OP_WRITE:
86  case SWS_OP_LINEAR:
87  case SWS_OP_PACK:
88  case SWS_OP_UNPACK:
89  case SWS_OP_CLEAR:
90  return false;
91  case SWS_OP_TYPE_NB:
92  break;
93  }
94 
95  av_unreachable("Invalid operation type!");
96  return false;
97 }
98 
99  /**
100  * Try to commute a swizzle op with the next operation. Makes any adjustments
101  * to the operations as needed, but does not perform the actual commutation.
102  *
103  * Returns whether successful.
104  */
105 static bool op_commute_swizzle(SwsOp *op, SwsOp *next)
106 {
107  bool seen[4] = {0};
108 
109  av_assert1(op->op == SWS_OP_SWIZZLE);
110  switch (next->op) {
111  case SWS_OP_CONVERT:
112  op->type = next->convert.to;
114  case SWS_OP_SWAP_BYTES:
115  case SWS_OP_LSHIFT:
116  case SWS_OP_RSHIFT:
117  case SWS_OP_SCALE:
118  case SWS_OP_FILTER_H:
119  case SWS_OP_FILTER_V:
120  return true;
121 
122  /**
123  * We can commute per-channel ops only if the per-channel constants are the
124  * same for all duplicated channels; e.g.:
125  * SWIZZLE {0, 0, 0, 3}
126  * NEXT {x, x, x, w}
127  * ->
128  * NEXT {x, _, _, w}
129  * SWIZZLE {0, 0, 0, 3}
130  */
131  case SWS_OP_MIN:
132  case SWS_OP_MAX: {
133  const SwsClampOp c = next->clamp;
134  for (int i = 0; i < 4; i++) {
135  if (!SWS_OP_NEEDED(op, i))
136  continue;
137  const int j = op->swizzle.in[i];
138  if (seen[j] && av_cmp_q(next->clamp.limit[j], c.limit[i]))
139  return false;
140  next->clamp.limit[j] = c.limit[i];
141  seen[j] = true;
142  }
143  return true;
144  }
145 
146  case SWS_OP_DITHER: {
147  const SwsDitherOp d = next->dither;
148  for (int i = 0; i < 4; i++) {
149  if (!SWS_OP_NEEDED(op, i))
150  continue;
151  const int j = op->swizzle.in[i];
152  if (seen[j] && next->dither.y_offset[j] != d.y_offset[i])
153  return false;
154  next->dither.y_offset[j] = d.y_offset[i];
155  seen[j] = true;
156  }
157  return true;
158  }
159 
160  case SWS_OP_INVALID:
161  case SWS_OP_READ:
162  case SWS_OP_WRITE:
163  case SWS_OP_SWIZZLE:
164  case SWS_OP_CLEAR:
165  case SWS_OP_LINEAR:
166  case SWS_OP_PACK:
167  case SWS_OP_UNPACK:
168  return false;
169  case SWS_OP_TYPE_NB:
170  break;
171  }
172 
173  av_unreachable("Invalid operation type!");
174  return false;
175 }
176 
177 /**
178  * Try to commute a filter op with the previous operation. Makes any
179  * adjustments to the operations as needed, but does not perform the actual
180  * commutation.
181  *
182  * Returns whether successful.
183  */
184 static bool op_commute_filter(SwsOp *op, SwsOp *prev)
185 {
186  switch (prev->op) {
187  case SWS_OP_SWIZZLE:
188  case SWS_OP_SCALE:
189  case SWS_OP_LINEAR:
190  case SWS_OP_DITHER:
191  prev->type = SWS_PIXEL_F32;
192  return true;
193  case SWS_OP_CONVERT:
194  if (prev->convert.to == SWS_PIXEL_F32) {
195  av_assert0(!prev->convert.expand);
196  FFSWAP(SwsPixelType, op->type, prev->type);
197  return true;
198  }
199  return false;
200  case SWS_OP_INVALID:
201  case SWS_OP_READ:
202  case SWS_OP_WRITE:
203  case SWS_OP_SWAP_BYTES:
204  case SWS_OP_UNPACK:
205  case SWS_OP_PACK:
206  case SWS_OP_LSHIFT:
207  case SWS_OP_RSHIFT:
208  case SWS_OP_CLEAR:
209  case SWS_OP_MIN:
210  case SWS_OP_MAX:
211  case SWS_OP_FILTER_H:
212  case SWS_OP_FILTER_V:
213  return false;
214  case SWS_OP_TYPE_NB:
215  break;
216  }
217 
218  av_unreachable("Invalid operation type!");
219  return false;
220 }
221 
222 /* returns log2(x) only if x is a power of two, or 0 otherwise */
223 static int exact_log2(const int x)
224 {
225  int p;
226  if (x <= 0)
227  return 0;
228  p = av_log2(x);
229  return (1 << p) == x ? p : 0;
230 }
231 
232 static int exact_log2_q(const AVRational x)
233 {
234  if (x.den == 1)
235  return exact_log2(x.num);
236  else if (x.num == 1)
237  return -exact_log2(x.den);
238  else
239  return 0;
240 }
241 
242 /**
243  * If a linear operation can be reduced to a scalar multiplication, returns
244  * the corresponding scaling factor, or 0 otherwise.
245  */
246 static bool extract_scalar(const SwsLinearOp *c, SwsComps comps, SwsComps prev,
247  SwsScaleOp *out_scale)
248 {
249  SwsScaleOp scale = {0};
250 
251  /* There are components not on the main diagonal */
252  if (c->mask & ~SWS_MASK_DIAG4)
253  return false;
254 
255  for (int i = 0; i < 4; i++) {
256  const AVRational s = c->m[i][i];
257  if ((prev.flags[i] & SWS_COMP_ZERO) ||
258  (comps.flags[i] & SWS_COMP_GARBAGE))
259  continue;
260  if (scale.factor.den && av_cmp_q(s, scale.factor))
261  return false;
262  scale.factor = s;
263  }
264 
265  if (scale.factor.den)
266  *out_scale = scale;
267  return scale.factor.den;
268 }
269 
270 /* Extracts an integer clear operation (subset) from the given linear op. */
272  SwsClearOp *out_clear)
273 {
274  SwsClearOp clear = {0};
275  bool ret = false;
276 
277  for (int i = 0; i < 4; i++) {
278  bool const_row = c->m[i][4].den == 1; /* offset is integer */
279  for (int j = 0; j < 4; j++) {
280  const_row &= c->m[i][j].num == 0 || /* scalar is zero */
281  (prev.flags[j] & SWS_COMP_ZERO); /* input is zero */
282  }
283  if (const_row && (c->mask & SWS_MASK_ROW(i))) {
284  clear.mask |= SWS_COMP(i);
285  clear.value[i] = c->m[i][4];
286  for (int j = 0; j < 5; j++)
287  c->m[i][j] = Q(i == j);
288  c->mask &= ~SWS_MASK_ROW(i);
289  ret = true;
290  }
291  }
292 
293  if (ret)
294  *out_clear = clear;
295  return ret;
296 }
297 
298 /* Unswizzle a linear operation by aligning single-input rows with
299  * their corresponding diagonal */
300 static bool extract_swizzle(SwsLinearOp *op, SwsComps prev, SwsSwizzleOp *out_swiz)
301 {
302  SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
303  SwsLinearOp c = *op;
304 
305  /* Find non-zero coefficients in the main 4x4 matrix */
306  uint32_t nonzero = 0;
307  for (int i = 0; i < 4; i++) {
308  for (int j = 0; j < 4; j++) {
309  if (!c.m[i][j].num || (prev.flags[j] & SWS_COMP_ZERO))
310  continue;
311  nonzero |= SWS_MASK(i, j);
312  }
313  }
314 
315  /* If a value is unique in its row and the target column is
316  * empty, move it there and update the input swizzle */
317  for (int i = 0; i < 4; i++) {
318  if (nonzero & SWS_MASK_COL(i))
319  continue; /* target column is not empty */
320  for (int j = 0; j < 4; j++) {
321  if ((nonzero & SWS_MASK_ROW(i)) == SWS_MASK(i, j)) {
322  /* Move coefficient to the diagonal */
323  c.m[i][i] = c.m[i][j];
324  c.m[i][j] = Q(0);
325  swiz.in[i] = j;
326  break;
327  }
328  }
329  }
330 
331  if (swiz.mask == SWS_SWIZZLE(0, 1, 2, 3).mask)
332  return false; /* no swizzle was identified */
333 
334  c.mask = ff_sws_linear_mask(c);
335  *out_swiz = swiz;
336  *op = c;
337  return true;
338 }
339 
340 static int op_result_is_exact(const SwsOp *op)
341 {
342  for (int i = 0; i < 4; i++) {
343  if (SWS_OP_NEEDED(op, i) && !(op->comps.flags[i] & SWS_COMP_EXACT))
344  return false;
345  }
346 
347  return true;
348 }
349 
351 {
352  int ret;
353 
354 retry:
356 
357  /* Try to push filters towards the input; do this first to unblock
358  * in-place optimizations like linear op fusion */
359  for (int n = 1; n < ops->num_ops; n++) {
360  SwsOp *op = &ops->ops[n];
361  SwsOp *prev = &ops->ops[n - 1];
362 
363  switch (op->op) {
364  case SWS_OP_FILTER_H:
365  case SWS_OP_FILTER_V:
366  if (op_commute_filter(op, prev)) {
367  FFSWAP(SwsOp, *op, *prev);
368  goto retry;
369  }
370  break;
371  }
372  }
373 
374  /* Apply all in-place optimizations (that do not re-order the list) */
375  for (int n = 0; n < ops->num_ops; n++) {
376  SwsOp dummy = {0};
377  SwsOp *op = &ops->ops[n];
378  SwsOp *prev = n ? &ops->ops[n - 1] : &dummy;
379  SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : &dummy;
380 
381  /* common helper variable */
382  bool noop = true;
383 
384  if (!SWS_OP_NEEDED(op, 0) && !SWS_OP_NEEDED(op, 1) &&
385  !SWS_OP_NEEDED(op, 2) && !SWS_OP_NEEDED(op, 3) &&
386  op->op != SWS_OP_WRITE)
387  {
388  /* Remove any operation whose output is not needed */
389  ff_sws_op_list_remove_at(ops, n, 1);
390  goto retry;
391  }
392 
393  switch (op->op) {
394  case SWS_OP_READ:
395  /* "Compress" planar reads where not all components are needed */
396  if (!op->rw.packed) {
397  SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
398  int nb_planes = 0;
399  for (int i = 0; i < op->rw.elems; i++) {
400  if (!SWS_OP_NEEDED(op, i)) {
401  swiz.in[i] = 3 - (i - nb_planes); /* map to unused plane */
402  continue;
403  }
404 
405  const int idx = nb_planes++;
406  av_assert1(idx <= i);
407  ops->plane_src[idx] = ops->plane_src[i];
408  swiz.in[i] = idx;
409  }
410 
411  if (nb_planes < op->rw.elems) {
412  op->rw.elems = nb_planes;
413  RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
414  .op = SWS_OP_SWIZZLE,
415  .type = op->rw.filter ? SWS_PIXEL_F32 : op->type,
416  .swizzle = swiz,
417  }));
418  goto retry;
419  }
420  }
421  break;
422 
423  case SWS_OP_SWAP_BYTES:
424  /* Redundant (double) swap */
425  if (next->op == SWS_OP_SWAP_BYTES) {
426  ff_sws_op_list_remove_at(ops, n, 2);
427  goto retry;
428  }
429  break;
430 
431  case SWS_OP_UNPACK:
432  /* Redundant unpack+pack */
433  if (next->op == SWS_OP_PACK && next->type == op->type &&
434  next->pack.pattern[0] == op->pack.pattern[0] &&
435  next->pack.pattern[1] == op->pack.pattern[1] &&
436  next->pack.pattern[2] == op->pack.pattern[2] &&
437  next->pack.pattern[3] == op->pack.pattern[3])
438  {
439  ff_sws_op_list_remove_at(ops, n, 2);
440  goto retry;
441  }
442  break;
443 
444  case SWS_OP_LSHIFT:
445  case SWS_OP_RSHIFT:
446  /* Two shifts in the same direction */
447  if (next->op == op->op) {
448  op->shift.amount += next->shift.amount;
449  ff_sws_op_list_remove_at(ops, n + 1, 1);
450  goto retry;
451  }
452 
453  /* No-op shift */
454  if (!op->shift.amount) {
455  ff_sws_op_list_remove_at(ops, n, 1);
456  goto retry;
457  }
458  break;
459 
460  case SWS_OP_CLEAR:
461  for (int i = 0; i < 4; i++) {
462  if (!SWS_COMP_TEST(op->clear.mask, i))
463  continue;
464 
465  if ((prev->comps.flags[i] & SWS_COMP_ZERO) &&
466  !(prev->comps.flags[i] & SWS_COMP_GARBAGE) &&
467  op->clear.value[i].num == 0)
468  {
469  /* Redundant clear-to-zero of zero component */
470  op->clear.mask ^= SWS_COMP(i);
471  } else if (!SWS_OP_NEEDED(op, i)) {
472  /* Unnecessary clear of unused component */
473  op->clear.mask ^= SWS_COMP(i);
474  } else {
475  noop = false;
476  }
477  }
478 
479  if (noop) {
480  ff_sws_op_list_remove_at(ops, n, 1);
481  goto retry;
482  }
483 
484  /* Transitive clear */
485  if (next->op == SWS_OP_CLEAR) {
486  for (int i = 0; i < 4; i++) {
487  if (SWS_COMP_TEST(next->clear.mask, i))
488  op->clear.value[i] = next->clear.value[i];
489  }
490  op->clear.mask |= next->clear.mask;
491  ff_sws_op_list_remove_at(ops, n + 1, 1);
492  goto retry;
493  }
494  break;
495 
496  case SWS_OP_SWIZZLE:
497  for (int i = 0; i < 4; i++) {
498  if (!SWS_OP_NEEDED(op, i))
499  continue;
500  if (op->swizzle.in[i] != i)
501  noop = false;
502  }
503 
504  /* Identity swizzle */
505  if (noop) {
506  ff_sws_op_list_remove_at(ops, n, 1);
507  goto retry;
508  }
509 
510  /* Transitive swizzle */
511  if (next->op == SWS_OP_SWIZZLE) {
512  const SwsSwizzleOp orig = op->swizzle;
513  for (int i = 0; i < 4; i++)
514  op->swizzle.in[i] = orig.in[next->swizzle.in[i]];
515  ff_sws_op_list_remove_at(ops, n + 1, 1);
516  goto retry;
517  }
518 
519  /* Swizzle planes instead of components, if possible */
520  if (prev->op == SWS_OP_READ && !prev->rw.packed) {
521  for (int dst = 0; dst < prev->rw.elems; dst++) {
522  const int src = op->swizzle.in[dst];
523  if (src > dst && src < prev->rw.elems) {
524  FFSWAP(int, ops->plane_src[dst], ops->plane_src[src]);
525  for (int i = dst; i < 4; i++) {
526  if (op->swizzle.in[i] == dst)
527  op->swizzle.in[i] = src;
528  else if (op->swizzle.in[i] == src)
529  op->swizzle.in[i] = dst;
530  }
531  goto retry;
532  }
533  }
534  }
535 
536  if (next->op == SWS_OP_WRITE && !next->rw.packed) {
537  for (int dst = 0; dst < next->rw.elems; dst++) {
538  const int src = op->swizzle.in[dst];
539  if (src > dst && src < next->rw.elems) {
540  FFSWAP(int, ops->plane_dst[dst], ops->plane_dst[src]);
541  FFSWAP(int, op->swizzle.in[dst], op->swizzle.in[src]);
542  goto retry;
543  }
544  }
545  }
546  break;
547 
548  case SWS_OP_CONVERT:
549  /* No-op conversion */
550  if (op->type == op->convert.to) {
551  ff_sws_op_list_remove_at(ops, n, 1);
552  goto retry;
553  }
554 
555  /* Transitive conversion */
556  if (next->op == SWS_OP_CONVERT &&
557  op->convert.expand == next->convert.expand)
558  {
559  av_assert1(op->convert.to == next->type);
560  op->convert.to = next->convert.to;
561  ff_sws_op_list_remove_at(ops, n + 1, 1);
562  goto retry;
563  }
564 
565  /* Conversion followed by integer expansion */
566  if (next->op == SWS_OP_SCALE && !op->convert.expand &&
567  ff_sws_pixel_type_is_int(op->type) &&
568  ff_sws_pixel_type_is_int(op->convert.to) &&
569  !av_cmp_q(next->scale.factor,
570  ff_sws_pixel_expand(op->type, op->convert.to)))
571  {
572  op->convert.expand = true;
573  ff_sws_op_list_remove_at(ops, n + 1, 1);
574  goto retry;
575  }
576  break;
577 
578  case SWS_OP_MIN:
579  for (int i = 0; i < 4; i++) {
580  if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
581  continue;
582  if (av_cmp_q(op->clamp.limit[i], prev->comps.max[i]) < 0)
583  noop = false;
584  }
585 
586  if (noop) {
587  ff_sws_op_list_remove_at(ops, n, 1);
588  goto retry;
589  }
590  break;
591 
592  case SWS_OP_MAX:
593  for (int i = 0; i < 4; i++) {
594  if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
595  continue;
596  if (av_cmp_q(prev->comps.min[i], op->clamp.limit[i]) < 0)
597  noop = false;
598  }
599 
600  if (noop) {
601  ff_sws_op_list_remove_at(ops, n, 1);
602  goto retry;
603  }
604  break;
605 
606  case SWS_OP_DITHER:
607  for (int i = 0; i < 4; i++) {
608  if (op->dither.y_offset[i] < 0)
609  continue;
610  if (!SWS_OP_NEEDED(op, i) || (prev->comps.flags[i] & SWS_COMP_EXACT)) {
611  op->dither.y_offset[i] = -1; /* unnecessary dither */
612  goto retry;
613  } else {
614  noop = false;
615  }
616  }
617 
618  if (noop) {
619  ff_sws_op_list_remove_at(ops, n, 1);
620  goto retry;
621  }
622  break;
623 
624  case SWS_OP_LINEAR: {
625  SwsSwizzleOp swizzle;
626  SwsClearOp clear;
628 
629  /* No-op (identity) linear operation */
630  if (!op->lin.mask) {
631  ff_sws_op_list_remove_at(ops, n, 1);
632  goto retry;
633  }
634 
635  if (next->op == SWS_OP_LINEAR) {
636  /* 5x5 matrix multiplication after appending [ 0 0 0 0 1 ] */
637  const SwsLinearOp m1 = op->lin;
638  const SwsLinearOp m2 = next->lin;
639  for (int i = 0; i < 4; i++) {
640  for (int j = 0; j < 5; j++) {
641  AVRational sum = Q(0);
642  for (int k = 0; k < 4; k++)
643  sum = av_add_q(sum, av_mul_q(m2.m[i][k], m1.m[k][j]));
644  if (j == 4) /* m1.m[4][j] == 1 */
645  sum = av_add_q(sum, m2.m[i][4]);
646  op->lin.m[i][j] = sum;
647  }
648  }
649  op->lin.mask = ff_sws_linear_mask(op->lin);
650  ff_sws_op_list_remove_at(ops, n + 1, 1);
651  goto retry;
652  }
653 
654  /* Optimize away zero columns */
655  for (int j = 0; j < 4; j++) {
656  const uint32_t col = SWS_MASK_COL(j);
657  if (!(prev->comps.flags[j] & SWS_COMP_ZERO) || !(op->lin.mask & col))
658  continue;
659  for (int i = 0; i < 4; i++)
660  op->lin.m[i][j] = Q(i == j);
661  op->lin.mask &= ~col;
662  goto retry;
663  }
664 
665  /* Optimize away unused rows */
666  for (int i = 0; i < 4; i++) {
667  const uint32_t row = SWS_MASK_ROW(i);
668  if (SWS_OP_NEEDED(op, i) || !(op->lin.mask & row))
669  continue;
670  for (int j = 0; j < 5; j++)
671  op->lin.m[i][j] = Q(i == j);
672  op->lin.mask &= ~row;
673  goto retry;
674  }
675 
676  /* Convert constant rows to explicit clear instruction */
677  if (extract_constant_rows(&op->lin, prev->comps, &clear)) {
678  RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
679  .op = SWS_OP_CLEAR,
680  .type = op->type,
681  .comps = op->comps,
682  .clear = clear,
683  }));
684  goto retry;
685  }
686 
687  /* Multiplication by scalar constant */
688  if (extract_scalar(&op->lin, op->comps, prev->comps, &scale)) {
689  op->op = SWS_OP_SCALE;
690  op->scale = scale;
691  goto retry;
692  }
693 
694  /* Swizzle by fixed pattern */
695  if (extract_swizzle(&op->lin, prev->comps, &swizzle)) {
696  RET(ff_sws_op_list_insert_at(ops, n, &(SwsOp) {
697  .op = SWS_OP_SWIZZLE,
698  .type = op->type,
699  .swizzle = swizzle,
700  }));
701  goto retry;
702  }
703  break;
704  }
705 
706  case SWS_OP_SCALE: {
707  const int factor2 = exact_log2_q(op->scale.factor);
708 
709  /* No-op scaling */
710  if (op->scale.factor.num == 1 && op->scale.factor.den == 1) {
711  ff_sws_op_list_remove_at(ops, n, 1);
712  goto retry;
713  }
714 
715  /* Merge consecutive scaling operations (that don't overflow) */
716  if (next->op == SWS_OP_SCALE) {
717  int64_t p = op->scale.factor.num * (int64_t) next->scale.factor.num;
718  int64_t q = op->scale.factor.den * (int64_t) next->scale.factor.den;
719  if (FFABS(p) <= INT_MAX && FFABS(q) <= INT_MAX) {
720  av_reduce(&op->scale.factor.num, &op->scale.factor.den, p, q, INT_MAX);
721  ff_sws_op_list_remove_at(ops, n + 1, 1);
722  goto retry;
723  }
724  }
725 
726  /* Scaling by exact power of two */
727  if (factor2 && ff_sws_pixel_type_is_int(op->type)) {
728  op->op = factor2 > 0 ? SWS_OP_LSHIFT : SWS_OP_RSHIFT;
729  op->shift.amount = FFABS(factor2);
730  goto retry;
731  }
732  break;
733  }
734 
735  case SWS_OP_FILTER_H:
736  case SWS_OP_FILTER_V:
737  /* Merge with prior simple planar read */
738  if (prev->op == SWS_OP_READ && !prev->rw.filter &&
739  !prev->rw.packed && !prev->rw.frac) {
740  prev->rw.filter = op->op;
741  prev->rw.kernel = av_refstruct_ref(op->filter.kernel);
742  ff_sws_op_list_remove_at(ops, n, 1);
743  goto retry;
744  }
745  break;
746  }
747  }
748 
749  /* Push clears to the back to void any unused components */
750  for (int n = 0; n < ops->num_ops - 1; n++) {
751  SwsOp *op = &ops->ops[n];
752  SwsOp *next = &ops->ops[n + 1];
753 
754  switch (op->op) {
755  case SWS_OP_CLEAR:
756  if (op_commute_clear(op, next)) {
757  FFSWAP(SwsOp, *op, *next);
758  goto retry;
759  }
760  break;
761  }
762  }
763 
764  /* Apply any remaining preferential re-ordering optimizations; do these
765  * last because they are more likely to block other optimizations if done
766  * too aggressively */
767  for (int n = 0; n < ops->num_ops - 1; n++) {
768  SwsOp *op = &ops->ops[n];
769  SwsOp *next = &ops->ops[n + 1];
770 
771  switch (op->op) {
772  case SWS_OP_SWIZZLE: {
773  /* Try to push swizzles towards the output */
774  if (op_commute_swizzle(op, next)) {
775  FFSWAP(SwsOp, *op, *next);
776  goto retry;
777  }
778  break;
779  }
780 
781  case SWS_OP_SCALE:
782  /* Exact integer multiplication */
783  if (op->scale.factor.den == 1 && next->op == SWS_OP_CONVERT &&
786  {
787  op->type = next->convert.to;
788  FFSWAP(SwsOp, *op, *next);
789  goto retry;
790  }
791  break;
792  }
793  }
794 
795  return 0;
796 }
797 
798 int ff_sws_solve_shuffle(const SwsOpList *const ops, uint8_t shuffle[],
799  int size, uint8_t clear_val,
800  int *read_bytes, int *write_bytes)
801 {
802  if (!ops->num_ops)
803  return AVERROR(EINVAL);
804 
805  const SwsOp *read = ff_sws_op_list_input(ops);
806  if (!read || read->rw.frac || read->rw.filter ||
807  (!read->rw.packed && read->rw.elems > 1))
808  return AVERROR(ENOTSUP);
809 
810  const int read_size = ff_sws_pixel_type_size(read->type);
811  uint32_t mask[4] = {0};
812  for (int i = 0; i < read->rw.elems; i++)
813  mask[i] = 0x01010101 * i * read_size + 0x03020100;
814 
815  for (int opidx = 1; opidx < ops->num_ops; opidx++) {
816  const SwsOp *op = &ops->ops[opidx];
817  switch (op->op) {
818  case SWS_OP_SWIZZLE: {
819  uint32_t orig[4] = { mask[0], mask[1], mask[2], mask[3] };
820  for (int i = 0; i < 4; i++)
821  mask[i] = orig[op->swizzle.in[i]];
822  break;
823  }
824 
825  case SWS_OP_SWAP_BYTES:
826  for (int i = 0; i < 4; i++) {
827  switch (ff_sws_pixel_type_size(op->type)) {
828  case 2: mask[i] = av_bswap16(mask[i]); break;
829  case 4: mask[i] = av_bswap32(mask[i]); break;
830  }
831  }
832  break;
833 
834  case SWS_OP_CLEAR:
835  for (int i = 0; i < 4; i++) {
836  if (!SWS_COMP_TEST(op->clear.mask, i))
837  continue;
838  if (op->clear.value[i].num != 0 || !clear_val)
839  return AVERROR(ENOTSUP);
840  mask[i] = 0x1010101ul * clear_val;
841  }
842  break;
843 
844  case SWS_OP_CONVERT: {
845  if (!op->convert.expand)
846  return AVERROR(ENOTSUP);
847  for (int i = 0; i < 4; i++) {
848  switch (ff_sws_pixel_type_size(op->type)) {
849  case 1: mask[i] = 0x01010101 * (mask[i] & 0xFF); break;
850  case 2: mask[i] = 0x00010001 * (mask[i] & 0xFFFF); break;
851  }
852  }
853  break;
854  }
855 
856  case SWS_OP_WRITE: {
857  if (op->rw.frac || op->rw.filter ||
858  (!op->rw.packed && op->rw.elems > 1))
859  return AVERROR(ENOTSUP);
860 
861  /* Initialize to no-op */
862  memset(shuffle, clear_val, size);
863 
864  const int write_size = ff_sws_pixel_type_size(op->type);
865  const int read_chunk = read->rw.elems * read_size;
866  const int write_chunk = op->rw.elems * write_size;
867  const int num_groups = size / FFMAX(read_chunk, write_chunk);
868  for (int n = 0; n < num_groups; n++) {
869  const int base_in = n * read_chunk;
870  const int base_out = n * write_chunk;
871  for (int i = 0; i < op->rw.elems; i++) {
872  const int offset = base_out + i * write_size;
873  for (int b = 0; b < write_size; b++) {
874  const uint8_t idx = mask[i] >> (b * 8);
875  if (idx != clear_val)
876  shuffle[offset + b] = base_in + idx;
877  }
878  }
879  }
880 
881  *read_bytes = num_groups * read_chunk;
882  *write_bytes = num_groups * write_chunk;
883  return num_groups;
884  }
885 
886  default:
887  return AVERROR(ENOTSUP);
888  }
889  }
890 
891  return AVERROR(EINVAL);
892 }
893 
894 /**
895  * Determine a suitable intermediate buffer format for a given combination
896  * of pixel types and number of planes. The exact interpretation of these
897  * formats does not matter at all; since they will only ever be used as
898  * temporary intermediate buffers. We still need to pick *some* format as
899  * a consequence of ff_sws_graph_add_pass() taking an AVPixelFormat for the
900  * output buffer.
901  */
902 static enum AVPixelFormat get_planar_fmt(SwsPixelType type, int nb_planes)
903 {
904  switch (ff_sws_pixel_type_size(type)) {
905  case 1:
906  switch (nb_planes) {
907  case 1: return AV_PIX_FMT_GRAY8;
908  case 2: return AV_PIX_FMT_YUV444P; // FIXME: no 2-plane planar fmt
909  case 3: return AV_PIX_FMT_YUV444P;
910  case 4: return AV_PIX_FMT_YUVA444P;
911  }
912  break;
913  case 2:
914  switch (nb_planes) {
915  case 1: return AV_PIX_FMT_GRAY16;
916  case 2: return AV_PIX_FMT_YUV444P16; // FIXME: no 2-plane planar fmt
917  case 3: return AV_PIX_FMT_YUV444P16;
918  case 4: return AV_PIX_FMT_YUVA444P16;
919  }
920  break;
921  case 4:
922  switch (nb_planes) {
923  case 1: return AV_PIX_FMT_GRAYF32;
924  case 2: return AV_PIX_FMT_GBRPF32; // FIXME: no 2-plane planar fmt
925  case 3: return AV_PIX_FMT_GBRPF32;
926  case 4: return AV_PIX_FMT_GBRAPF32;
927  }
928  break;
929  }
930 
931  av_unreachable("Invalid pixel type or number of planes?");
932  return AV_PIX_FMT_NONE;
933 }
934 
935 static void get_input_size(const SwsOpList *ops, SwsFormat *fmt)
936 {
937  fmt->width = ops->src.width;
938  fmt->height = ops->src.height;
939 
940  const SwsOp *read = ff_sws_op_list_input(ops);
941  if (read && read->rw.filter == SWS_OP_FILTER_V) {
942  fmt->height = read->rw.kernel->dst_size;
943  } else if (read && read->rw.filter == SWS_OP_FILTER_H) {
944  fmt->width = read->rw.kernel->dst_size;
945  }
946 }
947 
949 {
950  const SwsOp *op;
951  int ret, idx;
952 
953  for (idx = 0; idx < ops1->num_ops; idx++) {
954  op = &ops1->ops[idx];
955  if (op->op == SWS_OP_FILTER_H || op->op == SWS_OP_FILTER_V)
956  break;
957  }
958 
959  if (idx == ops1->num_ops) {
960  *out_rest = NULL;
961  return 0;
962  }
963 
964  av_assert0(idx > 0);
965  const SwsOp *prev = &ops1->ops[idx - 1];
966 
967  SwsOpList *ops2 = ff_sws_op_list_duplicate(ops1);
968  if (!ops2)
969  return AVERROR(ENOMEM);
970 
971  /**
972  * Not all components may be needed; but we need the ones that *are*
973  * used to be contiguous for the write/read operations. So, first
974  * compress them into a linearly ascending list of components
975  */
976  int nb_planes = 0;
977  SwsSwizzleOp swiz_wr = SWS_SWIZZLE(0, 1, 2, 3);
978  SwsSwizzleOp swiz_rd = SWS_SWIZZLE(0, 1, 2, 3);
979  for (int i = 0; i < 4; i++) {
980  if (SWS_OP_NEEDED(prev, i)) {
981  const int o = nb_planes++;
982  swiz_wr.in[o] = i;
983  swiz_rd.in[i] = o;
984  }
985  }
986 
987  /* Determine metadata for the intermediate format */
988  const SwsPixelType type = op->type;
989  ops2->src.format = get_planar_fmt(type, nb_planes);
990  ops2->src.desc = av_pix_fmt_desc_get(ops2->src.format);
991  get_input_size(ops1, &ops2->src);
992  ops1->dst = ops2->src;
993 
994  for (int i = 0; i < nb_planes; i++) {
995  ops1->plane_dst[i] = ops2->plane_src[i] = i;
996  ops2->comps_src.flags[i] = prev->comps.flags[swiz_wr.in[i]];
997  }
998 
999  ff_sws_op_list_remove_at(ops1, idx, ops1->num_ops - idx);
1000  ff_sws_op_list_remove_at(ops2, 0, idx);
1001  op = NULL; /* the above command may invalidate op */
1002 
1003  if (swiz_wr.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1004  ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1005  .op = SWS_OP_SWIZZLE,
1006  .type = type,
1007  .swizzle = swiz_wr,
1008  });
1009  if (ret < 0)
1010  goto fail;
1011  }
1012 
1013  ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1014  .op = SWS_OP_WRITE,
1015  .type = type,
1016  .rw.elems = nb_planes,
1017  });
1018  if (ret < 0)
1019  goto fail;
1020 
1021  ret = ff_sws_op_list_insert_at(ops2, 0, &(SwsOp) {
1022  .op = SWS_OP_READ,
1023  .type = type,
1024  .rw.elems = nb_planes,
1025  });
1026  if (ret < 0)
1027  goto fail;
1028 
1029  if (swiz_rd.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1030  ret = ff_sws_op_list_insert_at(ops2, 1, &(SwsOp) {
1031  .op = SWS_OP_SWIZZLE,
1032  .type = type,
1033  .swizzle = swiz_rd,
1034  });
1035  if (ret < 0)
1036  goto fail;
1037  }
1038 
1039  ret = ff_sws_op_list_optimize(ops1);
1040  if (ret < 0)
1041  goto fail;
1042 
1043  ret = ff_sws_op_list_optimize(ops2);
1044  if (ret < 0)
1045  goto fail;
1046 
1047  *out_rest = ops2;
1048  return 0;
1049 
1050 fail:
1051  ff_sws_op_list_free(&ops2);
1052  return ret;
1053 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:50
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: ops.h:36
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:620
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:53
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
SwsClearOp::value
AVRational value[4]
Definition: ops.h:170
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:58
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:56
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:634
SwsClearOp
Definition: ops.h:168
SwsSwizzleOp::mask
uint32_t mask
Definition: ops.h:155
SwsOpList::comps_src
SwsComps comps_src
Source component metadata associated with pixel values from each corresponding component (in plane/me...
Definition: ops.h:307
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:671
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:105
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:62
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp c)
Definition: ops.c:759
SwsOp::swizzle
SwsSwizzleOp swizzle
Definition: ops.h:245
SwsLinearOp::m
AVRational m[4][5]
Generalized 5x5 affine transformation: [ Out.x ] = [ A B C D E ] [ Out.y ] = [ F G H I J ] * [ x y z ...
Definition: ops.h:206
SwsOp::convert
SwsConvertOp convert
Definition: ops.h:248
rational.h
int64_t
long long int64_t
Definition: coverity.c:34
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:714
mask
int mask
Definition: mediacodecdec_common.c:154
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:243
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:70
read_bytes
static void read_bytes(const uint8_t *src, float *dst, int src_stride, int dst_stride, int width, int height, float scale)
Definition: vf_nnedi.c:442
b
#define b
Definition: input.c:43
get_input_size
static void get_input_size(const SwsOpList *ops, SwsFormat *fmt)
Definition: ops_optimizer.c:935
ff_sws_op_list_optimize
int ff_sws_op_list_optimize(SwsOpList *ops)
Fuse compatible and eliminate redundant operations, as well as replacing some operations with more ef...
Definition: ops_optimizer.c:350
SwsClampOp::limit
AVRational limit[4]
Definition: ops.h:179
extract_constant_rows
static bool extract_constant_rows(SwsLinearOp *c, SwsComps prev, SwsClearOp *out_clear)
Definition: ops_optimizer.c:271
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: ops.h:37
SWS_OP_TYPE_NB
@ SWS_OP_TYPE_NB
Definition: ops.h:76
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:77
dummy
static int dummy
Definition: ffplay.c:3751
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:212
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:33
SwsComps::max
AVRational max[4]
Definition: ops.h:114
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:296
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
SwsClearOp::mask
SwsCompMask mask
Definition: ops.h:169
fail
#define fail()
Definition: checkasm.h:225
SwsOpList::num_ops
int num_ops
Definition: ops.h:290
SWS_MASK_COL
#define SWS_MASK_COL(J)
Definition: ops.h:213
SwsDitherOp
Definition: ops.h:186
AV_PIX_FMT_YUVA444P16
#define AV_PIX_FMT_YUVA444P16
Definition: pixfmt.h:597
SwsSwizzleOp
Definition: ops.h:149
SWS_COMP_TEST
#define SWS_COMP_TEST(mask, X)
Definition: ops.h:89
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:92
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
AV_PIX_FMT_GRAY16
#define AV_PIX_FMT_GRAY16
Definition: pixfmt.h:522
av_reduce
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition: rational.c:35
AVRational::num
int num
Numerator.
Definition: rational.h:59
SwsOp::op
SwsOpType op
Definition: ops.h:239
Q
#define Q(q)
SWS_OP_SCALE
@ SWS_OP_SCALE
Definition: ops.h:66
avassert.h
SwsOp::clear
SwsClearOp clear
Definition: ops.h:247
SwsFormat::height
int height
Definition: format.h:78
SWS_OP_NEEDED
#define SWS_OP_NEEDED(op, idx)
Definition: ops.h:265
SwsScaleOp::factor
AVRational factor
Definition: ops.h:183
s
#define s(width, name)
Definition: cbs_vp9.c:198
AV_PIX_FMT_YUV444P16
#define AV_PIX_FMT_YUV444P16
Definition: pixfmt.h:552
SWS_SWIZZLE
#define SWS_SWIZZLE(X, Y, Z, W)
Definition: ops.h:161
SwsComps::min
AVRational min[4]
Definition: ops.h:114
read_chunk
static int read_chunk(AVFormatContext *s)
Definition: dhav.c:173
op
static int op(uint8_t **dst, const uint8_t *dst_end, GetByteContext *gb, int pixel, int count, int *x, int width, int linesize)
Perform decode operation.
Definition: anm.c:76
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:64
exact_log2_q
static int exact_log2_q(const AVRational x)
Definition: ops_optimizer.c:232
extract_scalar
static bool extract_scalar(const SwsLinearOp *c, SwsComps comps, SwsComps prev, SwsScaleOp *out_scale)
If a linear operation can be reduced to a scalar multiplication, returns the corresponding scaling fa...
Definition: ops_optimizer.c:246
ff_sws_pixel_expand
static AVRational ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
Definition: ops_internal.h:31
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:69
op_commute_filter
static bool op_commute_filter(SwsOp *op, SwsOp *prev)
Try to commute a filter op with the previous operation.
Definition: ops_optimizer.c:184
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:73
AV_PIX_FMT_GRAYF32
#define AV_PIX_FMT_GRAYF32
Definition: pixfmt.h:582
av_fallthrough
#define av_fallthrough
Definition: attributes.h:67
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:74
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:57
SwsOp::dither
SwsDitherOp dither
Definition: ops.h:251
SwsReadWriteOp::kernel
SwsFilterWeights * kernel
Definition: ops.h:138
NULL
#define NULL
Definition: coverity.c:32
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_unreachable
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition: avassert.h:116
SwsReadWriteOp::frac
uint8_t frac
Definition: ops.h:127
SWS_COMP_GARBAGE
@ SWS_COMP_GARBAGE
Definition: ops.h:103
SwsConvertOp::to
SwsPixelType to
Definition: ops.h:174
ff_sws_op_list_subpass
int ff_sws_op_list_subpass(SwsOpList *ops1, SwsOpList **out_rest)
Eliminate SWS_OP_FILTER_* operations by merging them with prior SWS_OP_READ operations.
Definition: ops_optimizer.c:948
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:74
SwsOp::clamp
SwsClampOp clamp
Definition: ops.h:249
ff_sws_op_list_remove_at
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
Definition: ops.c:689
RET
#define RET(x)
Copyright (C) 2025 Niklas Haas.
Definition: ops_optimizer.c:29
SWS_COMP
#define SWS_COMP(X)
Definition: ops.h:88
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:81
SWS_MASK
#define SWS_MASK(I, J)
Definition: ops.h:210
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
ff_sws_apply_op_q
void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
Apply an operation to an AVRational.
Definition: ops.c:180
SwsConvertOp::expand
bool expand
Definition: ops.h:175
SWS_MASK_DIAG4
@ SWS_MASK_DIAG4
Definition: ops.h:226
SwsPackOp::pattern
uint8_t pattern[4]
Packed bits are assumed to be LSB-aligned within the underlying integer type; i.e.
Definition: ops.h:146
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
SwsClampOp
Definition: ops.h:178
av_bswap32
#define av_bswap32
Definition: bswap.h:47
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
SwsOp::type
SwsPixelType type
Definition: ops.h:240
AV_PIX_FMT_GBRPF32
#define AV_PIX_FMT_GBRPF32
Definition: pixfmt.h:578
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:700
size
int size
Definition: twinvq_data.h:10344
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:59
SwsOp::lin
SwsLinearOp lin
Definition: ops.h:242
SwsOpList::src
SwsFormat src
Definition: ops.h:293
SWS_OP_INVALID
@ SWS_OP_INVALID
Definition: ops.h:47
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:341
SwsFormat
Definition: format.h:77
SwsShiftOp::amount
uint8_t amount
Definition: ops.h:165
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:51
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
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:174
offset
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 offset
Definition: writing_filters.txt:86
attributes.h
SwsOp::comps
SwsComps comps
Metadata about the operation's input/output components.
Definition: ops.h:262
SwsScaleOp
Definition: ops.h:182
SwsLinearOp
Definition: ops.h:193
get_planar_fmt
static enum AVPixelFormat get_planar_fmt(SwsPixelType type, int nb_planes)
Determine a suitable intermediate buffer format for a given combination of pixel types and number of ...
Definition: ops_optimizer.c:902
ff_sws_comp_mask_swizzle
SwsCompMask ff_sws_comp_mask_swizzle(const SwsCompMask mask, const SwsSwizzleOp swiz)
Definition: ops.c:147
noop
#define noop(a)
Definition: h264chroma_template.c:71
SwsFormat::format
enum AVPixelFormat format
Definition: format.h:80
extract_swizzle
static bool extract_swizzle(SwsLinearOp *op, SwsComps prev, SwsSwizzleOp *out_swiz)
Definition: ops_optimizer.c:300
SwsOpList::ops
SwsOp * ops
Definition: ops.h:289
SwsFormat::desc
const AVPixFmtDescriptor * desc
Definition: format.h:85
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
ops_internal.h
SwsFormat::width
int width
Definition: format.h:78
SwsOp
Definition: ops.h:238
write_bytes
static void write_bytes(const float *src, uint8_t *dst, int src_stride, int dst_stride, int width, int height, int depth, float scale)
Definition: vf_nnedi.c:484
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
SwsComps::flags
SwsCompFlags flags[4]
Definition: ops.h:110
ret
ret
Definition: filter_design.txt:187
bswap.h
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:293
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:65
op_commute_swizzle
static bool op_commute_swizzle(SwsOp *op, SwsOp *next)
Try to commute a swizzle op with the next operation.
Definition: ops_optimizer.c:105
SwsReadWriteOp::filter
SwsOpType filter
Filter kernel to apply to each plane while sampling.
Definition: ops.h:137
SwsComps
Definition: ops.h:109
AVRational::den
int den
Denominator.
Definition: rational.h:60
SwsReadWriteOp::packed
bool packed
Definition: ops.h:128
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
AV_PIX_FMT_GBRAPF32
#define AV_PIX_FMT_GBRAPF32
Definition: pixfmt.h:579
SWS_OP_SWAP_BYTES
@ SWS_OP_SWAP_BYTES
Definition: ops.h:52
op_result_is_exact
static int op_result_is_exact(const SwsOp *op)
Definition: ops_optimizer.c:340
SwsOp::shift
SwsShiftOp shift
Definition: ops.h:246
ff_sws_solve_shuffle
int ff_sws_solve_shuffle(const SwsOpList *const ops, uint8_t shuffle[], int size, uint8_t clear_val, int *read_bytes, int *write_bytes)
"Solve" an op list into a fixed shuffle mask, with an optional ability to also directly clear the out...
Definition: ops_optimizer.c:798
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
av_mul_q
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:78
SWS_COMP_EXACT
@ SWS_COMP_EXACT
Definition: ops.h:104
SwsReadWriteOp::elems
uint8_t elems
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition: ops.h:126
SwsDitherOp::y_offset
int8_t y_offset[4]
Definition: ops.h:190
scale
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Definition: intra.c:278
av_add_q
AVRational av_add_q(AVRational b, AVRational c)
Add two rationals.
Definition: rational.c:93
SwsSwizzleOp::in
uint8_t in[4]
Definition: ops.h:156
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:63
SwsOp::scale
SwsScaleOp scale
Definition: ops.h:250
op_commute_clear
static bool op_commute_clear(SwsOp *op, SwsOp *next)
Try to commute a clear op with the next operation.
Definition: ops_optimizer.c:41
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:296
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:288
av_bswap16
#define av_bswap16
Definition: bswap.h:28
SwsOp::pack
SwsPackOp pack
Definition: ops.h:244
shuffle
static uint64_t shuffle(uint64_t in, const uint8_t *shuffle, int shuffle_len)
Definition: des.c:179
av_log2
int av_log2(unsigned v)
Definition: intmath.c:26
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
exact_log2
static int exact_log2(const int x)
Definition: ops_optimizer.c:223