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/avassert.h"
22 #include "libavutil/bswap.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/rational.h"
25 #include "libavutil/refstruct.h"
26 
27 #include "ops.h"
28 #include "ops_internal.h"
29 
30 extern const SwsOpBackend backend_c;
31 extern const SwsOpBackend backend_murder;
32 extern const SwsOpBackend backend_x86;
33 
34 const SwsOpBackend * const ff_sws_op_backends[] = {
36 #if ARCH_X86_64 && HAVE_X86ASM
37  &backend_x86,
38 #endif
39  &backend_c,
40  NULL
41 };
42 
43 #define RET(x) \
44  do { \
45  if ((ret = (x)) < 0) \
46  return ret; \
47  } while (0)
48 
50 {
51  switch (type) {
52  case SWS_PIXEL_U8: return "u8";
53  case SWS_PIXEL_U16: return "u16";
54  case SWS_PIXEL_U32: return "u32";
55  case SWS_PIXEL_F32: return "f32";
56  case SWS_PIXEL_NONE: return "none";
57  case SWS_PIXEL_TYPE_NB: break;
58  }
59 
60  av_unreachable("Invalid pixel type!");
61  return "ERR";
62 }
63 
65 {
66  switch (type) {
67  case SWS_PIXEL_U8: return sizeof(uint8_t);
68  case SWS_PIXEL_U16: return sizeof(uint16_t);
69  case SWS_PIXEL_U32: return sizeof(uint32_t);
70  case SWS_PIXEL_F32: return sizeof(float);
71  case SWS_PIXEL_NONE: break;
72  case SWS_PIXEL_TYPE_NB: break;
73  }
74 
75  av_unreachable("Invalid pixel type!");
76  return 0;
77 }
78 
80 {
81  switch (type) {
82  case SWS_PIXEL_U8:
83  case SWS_PIXEL_U16:
84  case SWS_PIXEL_U32:
85  return true;
86  case SWS_PIXEL_F32:
87  return false;
88  case SWS_PIXEL_NONE:
89  case SWS_PIXEL_TYPE_NB: break;
90  }
91 
92  av_unreachable("Invalid pixel type!");
93  return false;
94 }
95 
96 /* biased towards `a` */
98 {
99  return av_cmp_q(a, b) == 1 ? b : a;
100 }
101 
103 {
104  return av_cmp_q(a, b) == -1 ? b : a;
105 }
106 
108 {
109  uint64_t mask[4];
110  int shift[4];
111 
112  switch (op->op) {
113  case SWS_OP_READ:
114  case SWS_OP_WRITE:
115  return;
116  case SWS_OP_UNPACK: {
117  unsigned val = x[0].num;
119  for (int i = 0; i < 4; i++)
120  x[i] = Q((val >> shift[i]) & mask[i]);
121  return;
122  }
123  case SWS_OP_PACK: {
124  unsigned val = 0;
126  for (int i = 0; i < 4; i++)
127  val |= (x[i].num & mask[i]) << shift[i];
128  x[0] = Q(val);
129  return;
130  }
131  case SWS_OP_SWAP_BYTES:
132  switch (ff_sws_pixel_type_size(op->type)) {
133  case 2:
134  for (int i = 0; i < 4; i++)
135  x[i].num = av_bswap16(x[i].num);
136  break;
137  case 4:
138  for (int i = 0; i < 4; i++)
139  x[i].num = av_bswap32(x[i].num);
140  break;
141  }
142  return;
143  case SWS_OP_CLEAR:
144  for (int i = 0; i < 4; i++) {
145  if (op->c.q4[i].den)
146  x[i] = op->c.q4[i];
147  }
148  return;
149  case SWS_OP_LSHIFT: {
150  AVRational mult = Q(1 << op->c.u);
151  for (int i = 0; i < 4; i++)
152  x[i] = x[i].den ? av_mul_q(x[i], mult) : x[i];
153  return;
154  }
155  case SWS_OP_RSHIFT: {
156  AVRational mult = Q(1 << op->c.u);
157  for (int i = 0; i < 4; i++)
158  x[i] = x[i].den ? av_div_q(x[i], mult) : x[i];
159  return;
160  }
161  case SWS_OP_SWIZZLE: {
162  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
163  for (int i = 0; i < 4; i++)
164  x[i] = orig[op->swizzle.in[i]];
165  return;
166  }
167  case SWS_OP_CONVERT:
168  if (ff_sws_pixel_type_is_int(op->convert.to)) {
169  const AVRational scale = ff_sws_pixel_expand(op->type, op->convert.to);
170  for (int i = 0; i < 4; i++) {
171  x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
172  if (op->convert.expand)
173  x[i] = av_mul_q(x[i], scale);
174  }
175  }
176  return;
177  case SWS_OP_DITHER:
178  for (int i = 0; i < 4; i++)
179  x[i] = x[i].den ? av_add_q(x[i], av_make_q(1, 2)) : x[i];
180  return;
181  case SWS_OP_MIN:
182  for (int i = 0; i < 4; i++)
183  x[i] = av_min_q(x[i], op->c.q4[i]);
184  return;
185  case SWS_OP_MAX:
186  for (int i = 0; i < 4; i++)
187  x[i] = av_max_q(x[i], op->c.q4[i]);
188  return;
189  case SWS_OP_LINEAR: {
190  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
191  for (int i = 0; i < 4; i++) {
192  AVRational sum = op->lin.m[i][4];
193  for (int j = 0; j < 4; j++)
194  sum = av_add_q(sum, av_mul_q(orig[j], op->lin.m[i][j]));
195  x[i] = sum;
196  }
197  return;
198  }
199  case SWS_OP_SCALE:
200  for (int i = 0; i < 4; i++)
201  x[i] = x[i].den ? av_mul_q(x[i], op->c.q) : x[i];
202  return;
203  }
204 
205  av_unreachable("Invalid operation type!");
206 }
207 
208 static void op_uninit(SwsOp *op)
209 {
210  switch (op->op) {
211  case SWS_OP_DITHER:
212  av_refstruct_unref(&op->dither.matrix);
213  break;
214  }
215 
216  *op = (SwsOp) {0};
217 }
218 
220 {
221  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
222  if (!ops)
223  return NULL;
224 
225  ff_fmt_clear(&ops->src);
226  ff_fmt_clear(&ops->dst);
227  return ops;
228 }
229 
231 {
232  SwsOpList *ops = *p_ops;
233  if (!ops)
234  return;
235 
236  for (int i = 0; i < ops->num_ops; i++)
237  op_uninit(&ops->ops[i]);
238 
239  av_freep(&ops->ops);
240  av_free(ops);
241  *p_ops = NULL;
242 }
243 
245 {
246  SwsOpList *copy = av_malloc(sizeof(*copy));
247  if (!copy)
248  return NULL;
249 
250  int num = ops->num_ops;
251  if (num)
252  num = 1 << av_ceil_log2(num);
253 
254  *copy = *ops;
255  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
256  if (!copy->ops) {
257  av_free(copy);
258  return NULL;
259  }
260 
261  for (int i = 0; i < ops->num_ops; i++) {
262  const SwsOp *op = &ops->ops[i];
263  switch (op->op) {
264  case SWS_OP_DITHER:
265  av_refstruct_ref(copy->ops[i].dither.matrix);
266  break;
267  }
268  }
269 
270  return copy;
271 }
272 
273 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
274 {
275  const int end = ops->num_ops - count;
276  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
277  op_uninit(&ops->ops[index]);
278  for (int i = index; i < end; i++)
279  ops->ops[i] = ops->ops[i + count];
280  ops->num_ops = end;
281 }
282 
284 {
285  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
286  if (!ret) {
287  op_uninit(op);
288  return AVERROR(ENOMEM);
289  }
290 
291  for (int i = ops->num_ops - 1; i > index; i--)
292  ops->ops[i] = ops->ops[i - 1];
293  ops->ops[index] = *op;
294  return 0;
295 }
296 
298 {
299  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
300 }
301 
303 {
304  int max_size = 0;
305  for (int i = 0; i < ops->num_ops; i++) {
306  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
307  max_size = FFMAX(max_size, size);
308  }
309 
310  return max_size;
311 }
312 
314 {
315  uint32_t mask = 0;
316  for (int i = 0; i < 4; i++) {
317  for (int j = 0; j < 5; j++) {
318  if (av_cmp_q(c.m[i][j], Q(i == j)))
319  mask |= SWS_MASK(i, j);
320  }
321  }
322  return mask;
323 }
324 
325 static const char *describe_lin_mask(uint32_t mask)
326 {
327  /* Try to be fairly descriptive without assuming too much */
328  static const struct {
329  char name[24];
330  uint32_t mask;
331  } patterns[] = {
332  { "noop", 0 },
333  { "luma", SWS_MASK_LUMA },
334  { "alpha", SWS_MASK_ALPHA },
335  { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA },
336  { "dot3", 0x7 },
337  { "dot4", 0xF },
338  { "row0", SWS_MASK_ROW(0) },
339  { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA },
340  { "col0", SWS_MASK_COL(0) },
341  { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 },
342  { "off3", SWS_MASK_OFF3 },
343  { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA },
344  { "diag3", SWS_MASK_DIAG3 },
345  { "diag4", SWS_MASK_DIAG4 },
346  { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA },
347  { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 },
348  { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
349  { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 },
350  { "matrix3", SWS_MASK_MAT3 },
351  { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 },
352  { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
353  { "matrix4", SWS_MASK_MAT4 },
354  { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 },
355  };
356 
357  for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
358  if (!(mask & ~patterns[i].mask))
359  return patterns[i].name;
360  }
361 
362  av_unreachable("Invalid linear mask!");
363  return "ERR";
364 }
365 
366 static char describe_comp_flags(unsigned flags)
367 {
368  if (flags & SWS_COMP_GARBAGE)
369  return 'X';
370  else if (flags & SWS_COMP_ZERO)
371  return '0';
372  else if (flags & SWS_COMP_EXACT)
373  return '+';
374  else
375  return '.';
376 }
377 
378 static const char *print_q(const AVRational q, char buf[], int buf_len)
379 {
380  if (!q.den) {
381  return q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan";
382  } else if (q.den == 1) {
383  snprintf(buf, buf_len, "%d", q.num);
384  return buf;
385  } else if (abs(q.num) > 1000 || abs(q.den) > 1000) {
386  snprintf(buf, buf_len, "%f", av_q2d(q));
387  return buf;
388  } else {
389  snprintf(buf, buf_len, "%d/%d", q.num, q.den);
390  return buf;
391  }
392 }
393 
394 #define PRINTQ(q) print_q(q, (char[32]){0}, sizeof(char[32]) - 1)
395 
396 void ff_sws_op_list_print(void *log, int lev, const SwsOpList *ops)
397 {
398  if (!ops->num_ops) {
399  av_log(log, lev, " (empty)\n");
400  return;
401  }
402 
403  for (int i = 0; i < ops->num_ops; i++) {
404  const SwsOp *op = &ops->ops[i];
405  av_log(log, lev, " [%3s %c%c%c%c -> %c%c%c%c] ",
406  ff_sws_pixel_type_name(op->type),
407  op->comps.unused[0] ? 'X' : '.',
408  op->comps.unused[1] ? 'X' : '.',
409  op->comps.unused[2] ? 'X' : '.',
410  op->comps.unused[3] ? 'X' : '.',
411  describe_comp_flags(op->comps.flags[0]),
412  describe_comp_flags(op->comps.flags[1]),
413  describe_comp_flags(op->comps.flags[2]),
414  describe_comp_flags(op->comps.flags[3]));
415 
416  switch (op->op) {
417  case SWS_OP_INVALID:
418  av_log(log, lev, "SWS_OP_INVALID\n");
419  break;
420  case SWS_OP_READ:
421  case SWS_OP_WRITE:
422  av_log(log, lev, "%-20s: %d elem(s) %s >> %d\n",
423  op->op == SWS_OP_READ ? "SWS_OP_READ"
424  : "SWS_OP_WRITE",
425  op->rw.elems, op->rw.packed ? "packed" : "planar",
426  op->rw.frac);
427  break;
428  case SWS_OP_SWAP_BYTES:
429  av_log(log, lev, "SWS_OP_SWAP_BYTES\n");
430  break;
431  case SWS_OP_LSHIFT:
432  av_log(log, lev, "%-20s: << %u\n", "SWS_OP_LSHIFT", op->c.u);
433  break;
434  case SWS_OP_RSHIFT:
435  av_log(log, lev, "%-20s: >> %u\n", "SWS_OP_RSHIFT", op->c.u);
436  break;
437  case SWS_OP_PACK:
438  case SWS_OP_UNPACK:
439  av_log(log, lev, "%-20s: {%d %d %d %d}\n",
440  op->op == SWS_OP_PACK ? "SWS_OP_PACK"
441  : "SWS_OP_UNPACK",
442  op->pack.pattern[0], op->pack.pattern[1],
443  op->pack.pattern[2], op->pack.pattern[3]);
444  break;
445  case SWS_OP_CLEAR:
446  av_log(log, lev, "%-20s: {%s %s %s %s}\n", "SWS_OP_CLEAR",
447  op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
448  op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
449  op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
450  op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
451  break;
452  case SWS_OP_SWIZZLE:
453  av_log(log, lev, "%-20s: %d%d%d%d\n", "SWS_OP_SWIZZLE",
454  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
455  break;
456  case SWS_OP_CONVERT:
457  av_log(log, lev, "%-20s: %s -> %s%s\n", "SWS_OP_CONVERT",
458  ff_sws_pixel_type_name(op->type),
459  ff_sws_pixel_type_name(op->convert.to),
460  op->convert.expand ? " (expand)" : "");
461  break;
462  case SWS_OP_DITHER:
463  av_log(log, lev, "%-20s: %dx%d matrix\n", "SWS_OP_DITHER",
464  1 << op->dither.size_log2, 1 << op->dither.size_log2);
465  break;
466  case SWS_OP_MIN:
467  av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", "SWS_OP_MIN",
468  op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
469  op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
470  op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
471  op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
472  break;
473  case SWS_OP_MAX:
474  av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", "SWS_OP_MAX",
475  op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
476  op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
477  op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
478  op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
479  break;
480  case SWS_OP_LINEAR:
481  av_log(log, lev, "%-20s: %s [[%s %s %s %s %s] "
482  "[%s %s %s %s %s] "
483  "[%s %s %s %s %s] "
484  "[%s %s %s %s %s]]\n",
485  "SWS_OP_LINEAR", describe_lin_mask(op->lin.mask),
486  PRINTQ(op->lin.m[0][0]), PRINTQ(op->lin.m[0][1]), PRINTQ(op->lin.m[0][2]), PRINTQ(op->lin.m[0][3]), PRINTQ(op->lin.m[0][4]),
487  PRINTQ(op->lin.m[1][0]), PRINTQ(op->lin.m[1][1]), PRINTQ(op->lin.m[1][2]), PRINTQ(op->lin.m[1][3]), PRINTQ(op->lin.m[1][4]),
488  PRINTQ(op->lin.m[2][0]), PRINTQ(op->lin.m[2][1]), PRINTQ(op->lin.m[2][2]), PRINTQ(op->lin.m[2][3]), PRINTQ(op->lin.m[2][4]),
489  PRINTQ(op->lin.m[3][0]), PRINTQ(op->lin.m[3][1]), PRINTQ(op->lin.m[3][2]), PRINTQ(op->lin.m[3][3]), PRINTQ(op->lin.m[3][4]));
490  break;
491  case SWS_OP_SCALE:
492  av_log(log, lev, "%-20s: * %s\n", "SWS_OP_SCALE",
493  PRINTQ(op->c.q));
494  break;
495  case SWS_OP_TYPE_NB:
496  break;
497  }
498 
499  if (op->comps.min[0].den || op->comps.min[1].den ||
500  op->comps.min[2].den || op->comps.min[3].den ||
501  op->comps.max[0].den || op->comps.max[1].den ||
502  op->comps.max[2].den || op->comps.max[3].den)
503  {
504  av_log(log, AV_LOG_TRACE, " min: {%s, %s, %s, %s}, max: {%s, %s, %s, %s}\n",
505  PRINTQ(op->comps.min[0]), PRINTQ(op->comps.min[1]),
506  PRINTQ(op->comps.min[2]), PRINTQ(op->comps.min[3]),
507  PRINTQ(op->comps.max[0]), PRINTQ(op->comps.max[1]),
508  PRINTQ(op->comps.max[2]), PRINTQ(op->comps.max[3]));
509  }
510 
511  }
512 
513  av_log(log, lev, " (X = unused, + = exact, 0 = zero)\n");
514 }
515 
517  const SwsOpList *ops, SwsCompiledOp *out)
518 {
519  SwsOpList *copy, rest;
520  SwsCompiledOp compiled = {0};
521  int ret = 0;
522 
524  if (!copy)
525  return AVERROR(ENOMEM);
526 
527  /* Ensure these are always set during compilation */
529 
530  /* Make an on-stack copy of `ops` to ensure we can still properly clean up
531  * the copy afterwards */
532  rest = *copy;
533 
534  ret = backend->compile(ctx, &rest, &compiled);
535  if (ret < 0) {
536  int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR;
537  av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n",
538  backend->name, av_err2str(ret));
539  if (rest.num_ops != ops->num_ops) {
540  av_log(ctx, msg_lev, "Uncompiled remainder:\n");
541  ff_sws_op_list_print(ctx, msg_lev, &rest);
542  }
543  } else {
544  *out = compiled;
545  }
546 
548  return ret;
549 }
550 
552 {
553  for (int n = 0; ff_sws_op_backends[n]; n++) {
554  const SwsOpBackend *backend = ff_sws_op_backends[n];
555  if (ff_sws_ops_compile_backend(ctx, backend, ops, out) < 0)
556  continue;
557 
558  av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': "
559  "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n",
560  backend->name, out->block_size, out->over_read, out->over_write,
561  out->cpu_flags);
562  return 0;
563  }
564 
565  av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n");
567  return AVERROR(ENOTSUP);
568 }
569 
570 typedef struct SwsOpPass {
572  SwsOpExec exec_base;
573  int num_blocks;
574  int tail_off_in;
575  int tail_off_out;
576  int tail_size_in;
577  int tail_size_out;
578  int planes_in;
579  int planes_out;
580  int pixel_bits_in;
581  int pixel_bits_out;
582  bool memcpy_in;
583  bool memcpy_out;
584 } SwsOpPass;
585 
586 static void op_pass_free(void *ptr)
587 {
588  SwsOpPass *p = ptr;
589  if (!p)
590  return;
591 
592  if (p->comp.free)
593  p->comp.free(p->comp.priv);
594 
595  av_free(p);
596 }
597 
598 static void op_pass_setup(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
599 {
600  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->fmt);
601  const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->fmt);
602 
603  SwsOpPass *p = pass->priv;
604  SwsOpExec *exec = &p->exec_base;
605  const SwsCompiledOp *comp = &p->comp;
606  const int block_size = comp->block_size;
607  p->num_blocks = (pass->width + block_size - 1) / block_size;
608 
609  /* Set up main loop parameters */
610  const int aligned_w = p->num_blocks * block_size;
611  const int safe_width = (p->num_blocks - 1) * block_size;
612  const int tail_size = pass->width - safe_width;
613  p->tail_off_in = safe_width * p->pixel_bits_in >> 3;
614  p->tail_off_out = safe_width * p->pixel_bits_out >> 3;
615  p->tail_size_in = tail_size * p->pixel_bits_in >> 3;
616  p->tail_size_out = tail_size * p->pixel_bits_out >> 3;
617  p->memcpy_in = false;
618  p->memcpy_out = false;
619 
620  for (int i = 0; i < p->planes_in; i++) {
621  const int sub_x = (i == 1 || i == 2) ? indesc->log2_chroma_w : 0;
622  const int plane_w = (aligned_w + sub_x) >> sub_x;
623  const int plane_pad = (comp->over_read + sub_x) >> sub_x;
624  const int plane_size = plane_w * p->pixel_bits_in >> 3;
625  p->memcpy_in |= plane_size + plane_pad > in->linesize[i];
626  exec->in_stride[i] = in->linesize[i];
627  }
628 
629  for (int i = 0; i < p->planes_out; i++) {
630  const int sub_x = (i == 1 || i == 2) ? outdesc->log2_chroma_w : 0;
631  const int plane_w = (aligned_w + sub_x) >> sub_x;
632  const int plane_pad = (comp->over_write + sub_x) >> sub_x;
633  const int plane_size = plane_w * p->pixel_bits_out >> 3;
634  p->memcpy_out |= plane_size + plane_pad > out->linesize[i];
635  exec->out_stride[i] = out->linesize[i];
636  }
637 
638  /* Pre-fill pointer bump for the main section only; this value does not
639  * matter at all for the tail / last row handlers because they only ever
640  * process a single line */
641  const int blocks_main = p->num_blocks - p->memcpy_out;
642  for (int i = 0; i < 4; i++) {
643  exec->in_bump[i] = in->linesize[i] - blocks_main * exec->block_size_in;
644  exec->out_bump[i] = out->linesize[i] - blocks_main * exec->block_size_out;
645  }
646 }
647 
648 /* Dispatch kernel over the last column of the image using memcpy */
649 static av_always_inline void
650 handle_tail(const SwsOpPass *p, SwsOpExec *exec,
651  const SwsImg *out_base, const bool copy_out,
652  const SwsImg *in_base, const bool copy_in,
653  int y, const int h)
654 {
655  DECLARE_ALIGNED_64(uint8_t, tmp)[2][4][sizeof(uint32_t[128])];
656 
657  const SwsCompiledOp *comp = &p->comp;
658  const int tail_size_in = p->tail_size_in;
659  const int tail_size_out = p->tail_size_out;
660  const int bx = p->num_blocks - 1;
661 
662  SwsImg in = ff_sws_img_shift(in_base, y);
663  SwsImg out = ff_sws_img_shift(out_base, y);
664  for (int i = 0; i < p->planes_in; i++) {
665  in.data[i] += p->tail_off_in;
666  if (copy_in) {
667  exec->in[i] = (void *) tmp[0][i];
668  exec->in_stride[i] = sizeof(tmp[0][i]);
669  } else {
670  exec->in[i] = in.data[i];
671  }
672  }
673 
674  for (int i = 0; i < p->planes_out; i++) {
675  out.data[i] += p->tail_off_out;
676  if (copy_out) {
677  exec->out[i] = (void *) tmp[1][i];
678  exec->out_stride[i] = sizeof(tmp[1][i]);
679  } else {
680  exec->out[i] = out.data[i];
681  }
682  }
683 
684  for (int y_end = y + h; y < y_end; y++) {
685  if (copy_in) {
686  for (int i = 0; i < p->planes_in; i++) {
687  av_assert2(tmp[0][i] + tail_size_in < (uint8_t *) tmp[1]);
688  memcpy(tmp[0][i], in.data[i], tail_size_in);
689  in.data[i] += in.linesize[i];
690  }
691  }
692 
693  comp->func(exec, comp->priv, bx, y, p->num_blocks, y + 1);
694 
695  if (copy_out) {
696  for (int i = 0; i < p->planes_out; i++) {
697  av_assert2(tmp[1][i] + tail_size_out < (uint8_t *) tmp[2]);
698  memcpy(out.data[i], tmp[1][i], tail_size_out);
699  out.data[i] += out.linesize[i];
700  }
701  }
702 
703  for (int i = 0; i < 4; i++) {
704  if (!copy_in)
705  exec->in[i] += in.linesize[i];
706  if (!copy_out)
707  exec->out[i] += out.linesize[i];
708  }
709  }
710 }
711 
712 static void op_pass_run(const SwsImg *out_base, const SwsImg *in_base,
713  const int y, const int h, const SwsPass *pass)
714 {
715  const SwsOpPass *p = pass->priv;
716  const SwsCompiledOp *comp = &p->comp;
717  const SwsImg in = ff_sws_img_shift(in_base, y);
718  const SwsImg out = ff_sws_img_shift(out_base, y);
719 
720  /* Fill exec metadata for this slice */
721  DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base;
722  exec.slice_y = y;
723  exec.slice_h = h;
724  for (int i = 0; i < 4; i++) {
725  exec.in[i] = in.data[i];
726  exec.out[i] = out.data[i];
727  }
728 
729  /**
730  * To ensure safety, we need to consider the following:
731  *
732  * 1. We can overread the input, unless this is the last line of an
733  * unpadded buffer. All defined operations can handle arbitrary pixel
734  * input, so overread of arbitrary data is fine.
735  *
736  * 2. We can overwrite the output, as long as we don't write more than the
737  * amount of pixels that fit into one linesize. So we always need to
738  * memcpy the last column on the output side if unpadded.
739  *
740  * 3. For the last row, we also need to memcpy the remainder of the input,
741  * to avoid reading past the end of the buffer. Note that since we know
742  * the run() function is called on stripes of the same buffer, we don't
743  * need to worry about this for the end of a slice.
744  */
745 
746  const int last_slice = y + h == pass->height;
747  const bool memcpy_in = last_slice && p->memcpy_in;
748  const bool memcpy_out = p->memcpy_out;
749  const int num_blocks = p->num_blocks;
750  const int blocks_main = num_blocks - memcpy_out;
751  const int h_main = h - memcpy_in;
752 
753  /* Handle main section */
754  comp->func(&exec, comp->priv, 0, y, blocks_main, y + h_main);
755 
756  if (memcpy_in) {
757  /* Safe part of last row */
758  for (int i = 0; i < 4; i++) {
759  exec.in[i] += h_main * in.linesize[i];
760  exec.out[i] += h_main * out.linesize[i];
761  }
762  comp->func(&exec, comp->priv, 0, y + h_main, num_blocks - 1, y + h);
763  }
764 
765  /* Handle last column via memcpy, takes over `exec` so call these last */
766  if (memcpy_out)
767  handle_tail(p, &exec, out_base, true, in_base, false, y, h_main);
768  if (memcpy_in)
769  handle_tail(p, &exec, out_base, memcpy_out, in_base, true, y + h_main, 1);
770 }
771 
772 static int rw_planes(const SwsOp *op)
773 {
774  return op->rw.packed ? 1 : op->rw.elems;
775 }
776 
777 static int rw_pixel_bits(const SwsOp *op)
778 {
779  const int elems = op->rw.packed ? op->rw.elems : 1;
780  const int size = ff_sws_pixel_type_size(op->type);
781  const int bits = 8 >> op->rw.frac;
782  av_assert1(bits >= 1);
783  return elems * size * bits;
784 }
785 
788 {
789  SwsContext *ctx = graph->ctx;
790  SwsOpPass *p = NULL;
791  const SwsOp *read = &ops->ops[0];
792  const SwsOp *write = &ops->ops[ops->num_ops - 1];
793  SwsPass *pass;
794  int ret;
795 
796  if (ops->num_ops < 2) {
797  av_log(ctx, AV_LOG_ERROR, "Need at least two operations.\n");
798  return AVERROR(EINVAL);
799  }
800 
801  if (read->op != SWS_OP_READ || write->op != SWS_OP_WRITE) {
802  av_log(ctx, AV_LOG_ERROR, "First and last operations must be a read "
803  "and write, respectively.\n");
804  return AVERROR(EINVAL);
805  }
806 
809  else
811 
812  p = av_mallocz(sizeof(*p));
813  if (!p)
814  return AVERROR(ENOMEM);
815 
816  ret = ff_sws_ops_compile(ctx, ops, &p->comp);
817  if (ret < 0)
818  goto fail;
819 
820  p->planes_in = rw_planes(read);
821  p->planes_out = rw_planes(write);
822  p->pixel_bits_in = rw_pixel_bits(read);
823  p->pixel_bits_out = rw_pixel_bits(write);
824  p->exec_base = (SwsOpExec) {
825  .width = dst.width,
826  .height = dst.height,
827  .block_size_in = p->comp.block_size * p->pixel_bits_in >> 3,
828  .block_size_out = p->comp.block_size * p->pixel_bits_out >> 3,
829  };
830 
831  pass = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height, input,
832  1, p, op_pass_run);
833  if (!pass) {
834  ret = AVERROR(ENOMEM);
835  goto fail;
836  }
837  pass->setup = op_pass_setup;
838  pass->free = op_pass_free;
839 
840  *output = pass;
841  return 0;
842 
843 fail:
844  op_pass_free(p);
845  return ret;
846 }
SWS_OP_READ
@ SWS_OP_READ
Definition: ops.h:47
flags
const SwsFlags flags[]
Definition: swscale.c:61
SWS_PIXEL_U16
@ SWS_PIXEL_U16
Definition: ops.h:33
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:230
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
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_MASK_LUMA
@ SWS_MASK_LUMA
Definition: ops.h:161
SWS_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:57
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:109
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:68
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:219
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
SWS_OP_LSHIFT
@ SWS_OP_LSHIFT
Definition: ops.h:55
SWS_OP_UNPACK
@ SWS_OP_UNPACK
Definition: ops.h:50
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:244
out
FILE * out
Definition: movenc.c:55
av_min_q
static AVRational av_min_q(AVRational a, AVRational b)
Definition: ops.c:97
comp
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:79
SwsOpExec::in_bump
ptrdiff_t in_bump[4]
Definition: ops_internal.h:66
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:73
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:54
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp c)
Definition: ops.c:313
SwsOpExec::in
const uint8_t * in[4]
Definition: ops_internal.h:58
SwsOpExec::out_stride
ptrdiff_t out_stride[4]
Definition: ops_internal.h:63
av_div_q
AVRational av_div_q(AVRational b, AVRational c)
Divide one rational by another.
Definition: rational.c:88
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:302
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:720
rational.h
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:226
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:297
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:59
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
SwsOpExec::block_size_in
int32_t block_size_in
Definition: ops_internal.h:72
b
#define b
Definition: input.c:42
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
SWS_PIXEL_U32
@ SWS_PIXEL_U32
Definition: ops.h:34
SWS_OP_TYPE_NB
@ SWS_OP_TYPE_NB
Definition: ops.h:67
SwsPass::free
void(* free)(void *priv)
Optional private state and associated free() function.
Definition: graph.h:101
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
SwsOpExec::in_stride
ptrdiff_t in_stride[4]
Definition: ops_internal.h:62
SwsImg
Represents a view into a single field of frame data.
Definition: graph.h:33
SwsOpBackend::name
const char * name
Definition: ops_internal.h:104
SWS_MASK_DIAG4
@ SWS_MASK_DIAG4
Definition: ops.h:170
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:64
describe_comp_flags
static char describe_comp_flags(unsigned flags)
Definition: ops.c:366
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:156
av_memdup
void * av_memdup(const void *p, size_t size)
Duplicate a buffer with av_malloc().
Definition: mem.c:304
DECLARE_ALIGNED_64
#define DECLARE_ALIGNED_64(t, v)
Definition: mem_internal.h:114
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:30
SwsPass::width
int width
Definition: graph.h:78
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:35
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:34
av_ceil_log2
#define av_ceil_log2
Definition: common.h:97
fail
#define fail()
Definition: checkasm.h:207
SwsOpList::num_ops
int num_ops
Definition: ops.h:210
SWS_MASK_COL
#define SWS_MASK_COL(J)
Definition: ops.h:157
SwsOpBackend::compile
int(* compile)(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
Compile an operation list to an implementation chain.
Definition: ops_internal.h:112
SWS_PIXEL_U8
@ SWS_PIXEL_U8
Definition: ops.h:32
ff_sws_pixel_type_is_int
bool ff_sws_pixel_type_is_int(SwsPixelType type)
Definition: ops.c:79
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
AVRational::num
int num
Numerator.
Definition: rational.h:59
ff_sws_ops_compile_backend
int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Attempt to compile a list of operations using a specific backend.
refstruct.h
RET
#define RET(x)
Definition: ops.c:43
SwsOp::op
SwsOpType op
Definition: ops.h:179
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:63
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
SwsPass::priv
void * priv
Definition: graph.h:102
float
float
Definition: af_crystalizer.c:122
SWS_MASK_MAT4
@ SWS_MASK_MAT4
Definition: ops.h:172
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
SWS_MASK_ALPHA
@ SWS_MASK_ALPHA
Definition: ops.h:162
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
backend_c
const SwsOpBackend backend_c
Copyright (C) 2025 Niklas Haas.
Definition: ops_backend.c:106
SwsPass::setup
void(* setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Called once from the main thread before running the filter.
Definition: graph.h:96
bits
uint8_t bits
Definition: vp3data.h:128
SWS_OP_MIN
@ SWS_OP_MIN
Definition: ops.h:64
ctx
AVFormatContext * ctx
Definition: movenc.c:49
ff_sws_pixel_expand
static AVRational ff_sws_pixel_expand(SwsPixelType from, SwsPixelType to)
Definition: ops_internal.h:30
SWS_OP_LINEAR
@ SWS_OP_LINEAR
Definition: ops.h:62
AVPixFmtDescriptor::log2_chroma_w
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:80
PRINTQ
#define PRINTQ(q)
Definition: ops.c:394
SwsOpBackend
Definition: ops_internal.h:103
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
SWS_OP_PACK
@ SWS_OP_PACK
Definition: ops.h:51
SwsOpExec
Global execution context for all compiled functions.
Definition: ops_internal.h:56
ff_sws_graph_add_pass
SwsPass * ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int align, void *priv, sws_filter_run_t run)
Allocate and add a new pass to the filter graph.
Definition: graph.c:48
rw_pixel_bits
static int rw_pixel_bits(const SwsOp *op)
Definition: sw_ops.c:55
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:108
SWS_COMP_GARBAGE
@ SWS_COMP_GARBAGE
Definition: ops.h:71
abs
#define abs(x)
Definition: cuda_runtime.h:35
ff_sws_op_list_remove_at
void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
Definition: ops.c:273
SwsOpExec::slice_h
int32_t slice_h
Definition: ops_internal.h:71
print_q
static const char * print_q(const AVRational q, char buf[], int buf_len)
Definition: ops.c:378
SWS_MASK
#define SWS_MASK(I, J)
Definition: ops.h:154
SWS_PIXEL_NONE
@ SWS_PIXEL_NONE
Definition: ops.h:31
index
int index
Definition: gxfenc.c:90
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
ff_sws_apply_op_q
void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
Apply an operation to an AVRational.
Definition: ops.c:107
SwsPass::height
int height
Definition: graph.h:78
SwsImg::linesize
int linesize[4]
Definition: graph.h:36
SwsOpExec::block_size_out
int32_t block_size_out
Definition: ops_internal.h:73
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
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:122
SwsOp::type
SwsPixelType type
Definition: ops.h:180
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:283
size
int size
Definition: twinvq_data.h:10344
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
SWS_OP_RSHIFT
@ SWS_OP_RSHIFT
Definition: ops.h:56
SwsOpList::src
SwsFormat src
Definition: ops.h:213
SWS_OP_INVALID
@ SWS_OP_INVALID
Definition: ops.h:44
SWS_MASK_OFF4
@ SWS_MASK_OFF4
Definition: ops.h:171
SwsFormat
Definition: format.h:77
SWS_OP_WRITE
@ SWS_OP_WRITE
Definition: ops.h:48
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:208
SWS_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops.h:256
SwsLinearOp
Definition: ops.h:137
SWS_MASK_DIAG3
@ SWS_MASK_DIAG3
Definition: ops.h:164
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops_optimizer.c:75
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
SwsOpExec::out
uint8_t * out[4]
Definition: ops_internal.h:59
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:412
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:68
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
av_max_q
static AVRational av_max_q(AVRational a, AVRational b)
Definition: ops.c:102
SwsOpList::ops
SwsOp * ops
Definition: ops.h:209
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:57
av_always_inline
#define av_always_inline
Definition: attributes.h:63
DECLARE_ALIGNED_32
#define DECLARE_ALIGNED_32(t, v)
Definition: mem_internal.h:113
ops_internal.h
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
ff_sws_ops_compile
int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Compile a list of operations using the best available backend.
lev
static LevelCodes lev[4+3+3]
Definition: clearvideo.c:80
SwsOp
Definition: ops.h:178
ff_sws_img_shift
static av_const SwsImg ff_sws_img_shift(const SwsImg *base, const int y)
Definition: graph.h:45
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
ret
ret
Definition: filter_design.txt:187
bswap.h
backend_murder
const SwsOpBackend backend_murder
Definition: ops_memcpy.c:129
SwsOpList::dst
SwsFormat dst
Definition: ops.h:213
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:65
SwsCompiledOp
Definition: ops_internal.h:90
SWS_MASK_OFF3
@ SWS_MASK_OFF3
Definition: ops.h:165
SWS_PIXEL_TYPE_NB
@ SWS_PIXEL_TYPE_NB
Definition: ops.h:36
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, SwsFormat dst, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
AVRational::den
int den
Denominator.
Definition: rational.h:60
ff_sws_pixel_type_name
const char * ff_sws_pixel_type_name(SwsPixelType type)
Definition: ops.c:49
SWS_OP_SWAP_BYTES
@ SWS_OP_SWAP_BYTES
Definition: ops.h:49
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
SWS_COMP_EXACT
@ SWS_COMP_EXACT
Definition: ops.h:72
describe_lin_mask
static const char * describe_lin_mask(uint32_t mask)
Definition: ops.c:325
mem.h
SWS_MASK_MAT3
@ SWS_MASK_MAT3
Definition: ops.h:166
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:108
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
SwsImg::fmt
enum AVPixelFormat fmt
Definition: graph.h:34
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:273
av_add_q
AVRational av_add_q(AVRational b, AVRational c)
Add two rationals.
Definition: rational.c:93
ff_sws_pack_op_decode
static void ff_sws_pack_op_decode(const SwsOp *op, uint64_t mask[4], int shift[4])
Definition: ops_internal.h:40
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
SWS_OP_CONVERT
@ SWS_OP_CONVERT
Definition: ops.h:58
ff_sws_op_list_print
void ff_sws_op_list_print(void *log, int lev, const SwsOpList *ops)
Print out the contents of an operation list.
Definition: ops.c:396
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2070
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:208
av_bswap16
#define av_bswap16
Definition: bswap.h:28
SwsOpExec::slice_y
int32_t slice_y
Definition: ops_internal.h:71
SwsContext
Main external API structure.
Definition: swscale.h:189
snprintf
#define snprintf
Definition: snprintf.h:34
SwsOpExec::out_bump
ptrdiff_t out_bump[4]
Definition: ops_internal.h:67
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
SwsImg::data
uint8_t * data[4]
Definition: graph.h:35
ff_fmt_clear
static void ff_fmt_clear(SwsFormat *fmt)
Definition: format.h:88