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: {
119  unsigned val = x[0].num;
120  for (int i = 0; i < 4; i++)
121  x[i] = Q((val >> shift[i]) & mask[i]);
122  return;
123  }
124  case SWS_OP_PACK: {
127  unsigned val = 0;
128  for (int i = 0; i < 4; i++)
129  val |= (x[i].num & mask[i]) << shift[i];
130  x[0] = Q(val);
131  return;
132  }
133  case SWS_OP_SWAP_BYTES:
135  switch (ff_sws_pixel_type_size(op->type)) {
136  case 2:
137  for (int i = 0; i < 4; i++)
138  x[i].num = av_bswap16(x[i].num);
139  break;
140  case 4:
141  for (int i = 0; i < 4; i++)
142  x[i].num = av_bswap32(x[i].num);
143  break;
144  }
145  return;
146  case SWS_OP_CLEAR:
147  for (int i = 0; i < 4; i++) {
148  if (op->c.q4[i].den)
149  x[i] = op->c.q4[i];
150  }
151  return;
152  case SWS_OP_LSHIFT: {
154  AVRational mult = Q(1 << op->c.u);
155  for (int i = 0; i < 4; i++)
156  x[i] = x[i].den ? av_mul_q(x[i], mult) : x[i];
157  return;
158  }
159  case SWS_OP_RSHIFT: {
161  for (int i = 0; i < 4; i++)
162  x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->c.u) : x[i];
163  return;
164  }
165  case SWS_OP_SWIZZLE: {
166  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
167  for (int i = 0; i < 4; i++)
168  x[i] = orig[op->swizzle.in[i]];
169  return;
170  }
171  case SWS_OP_CONVERT:
172  if (ff_sws_pixel_type_is_int(op->convert.to)) {
173  const AVRational scale = ff_sws_pixel_expand(op->type, op->convert.to);
174  for (int i = 0; i < 4; i++) {
175  x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
176  if (op->convert.expand)
177  x[i] = av_mul_q(x[i], scale);
178  }
179  }
180  return;
181  case SWS_OP_DITHER:
183  for (int i = 0; i < 4; i++)
184  x[i] = x[i].den ? av_add_q(x[i], av_make_q(1, 2)) : x[i];
185  return;
186  case SWS_OP_MIN:
187  for (int i = 0; i < 4; i++)
188  x[i] = av_min_q(x[i], op->c.q4[i]);
189  return;
190  case SWS_OP_MAX:
191  for (int i = 0; i < 4; i++)
192  x[i] = av_max_q(x[i], op->c.q4[i]);
193  return;
194  case SWS_OP_LINEAR: {
196  const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
197  for (int i = 0; i < 4; i++) {
198  AVRational sum = op->lin.m[i][4];
199  for (int j = 0; j < 4; j++)
200  sum = av_add_q(sum, av_mul_q(orig[j], op->lin.m[i][j]));
201  x[i] = sum;
202  }
203  return;
204  }
205  case SWS_OP_SCALE:
206  for (int i = 0; i < 4; i++)
207  x[i] = x[i].den ? av_mul_q(x[i], op->c.q) : x[i];
208  return;
209  }
210 
211  av_unreachable("Invalid operation type!");
212 }
213 
214 static void op_uninit(SwsOp *op)
215 {
216  switch (op->op) {
217  case SWS_OP_DITHER:
218  av_refstruct_unref(&op->dither.matrix);
219  break;
220  }
221 
222  *op = (SwsOp) {0};
223 }
224 
226 {
227  SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
228  if (!ops)
229  return NULL;
230 
231  ff_fmt_clear(&ops->src);
232  ff_fmt_clear(&ops->dst);
233  return ops;
234 }
235 
237 {
238  SwsOpList *ops = *p_ops;
239  if (!ops)
240  return;
241 
242  for (int i = 0; i < ops->num_ops; i++)
243  op_uninit(&ops->ops[i]);
244 
245  av_freep(&ops->ops);
246  av_free(ops);
247  *p_ops = NULL;
248 }
249 
251 {
252  SwsOpList *copy = av_malloc(sizeof(*copy));
253  if (!copy)
254  return NULL;
255 
256  int num = ops->num_ops;
257  if (num)
258  num = 1 << av_ceil_log2(num);
259 
260  *copy = *ops;
261  copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
262  if (!copy->ops) {
263  av_free(copy);
264  return NULL;
265  }
266 
267  for (int i = 0; i < ops->num_ops; i++) {
268  const SwsOp *op = &ops->ops[i];
269  switch (op->op) {
270  case SWS_OP_DITHER:
271  av_refstruct_ref(copy->ops[i].dither.matrix);
272  break;
273  }
274  }
275 
276  return copy;
277 }
278 
279 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
280 {
281  const int end = ops->num_ops - count;
282  av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
283  op_uninit(&ops->ops[index]);
284  for (int i = index; i < end; i++)
285  ops->ops[i] = ops->ops[i + count];
286  ops->num_ops = end;
287 }
288 
290 {
291  void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
292  if (!ret) {
293  op_uninit(op);
294  return AVERROR(ENOMEM);
295  }
296 
297  for (int i = ops->num_ops - 1; i > index; i--)
298  ops->ops[i] = ops->ops[i - 1];
299  ops->ops[index] = *op;
300  return 0;
301 }
302 
304 {
305  return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
306 }
307 
309 {
310  int max_size = 0;
311  for (int i = 0; i < ops->num_ops; i++) {
312  const int size = ff_sws_pixel_type_size(ops->ops[i].type);
313  max_size = FFMAX(max_size, size);
314  }
315 
316  return max_size;
317 }
318 
320 {
321  uint32_t mask = 0;
322  for (int i = 0; i < 4; i++) {
323  for (int j = 0; j < 5; j++) {
324  if (av_cmp_q(c.m[i][j], Q(i == j)))
325  mask |= SWS_MASK(i, j);
326  }
327  }
328  return mask;
329 }
330 
331 static const char *describe_lin_mask(uint32_t mask)
332 {
333  /* Try to be fairly descriptive without assuming too much */
334  static const struct {
335  char name[24];
336  uint32_t mask;
337  } patterns[] = {
338  { "noop", 0 },
339  { "luma", SWS_MASK_LUMA },
340  { "alpha", SWS_MASK_ALPHA },
341  { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA },
342  { "dot3", 0x7 },
343  { "dot4", 0xF },
344  { "row0", SWS_MASK_ROW(0) },
345  { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA },
346  { "col0", SWS_MASK_COL(0) },
347  { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 },
348  { "off3", SWS_MASK_OFF3 },
349  { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA },
350  { "diag3", SWS_MASK_DIAG3 },
351  { "diag4", SWS_MASK_DIAG4 },
352  { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA },
353  { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 },
354  { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
355  { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 },
356  { "matrix3", SWS_MASK_MAT3 },
357  { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 },
358  { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
359  { "matrix4", SWS_MASK_MAT4 },
360  { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 },
361  };
362 
363  for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
364  if (!(mask & ~patterns[i].mask))
365  return patterns[i].name;
366  }
367 
368  av_unreachable("Invalid linear mask!");
369  return "ERR";
370 }
371 
372 static char describe_comp_flags(unsigned flags)
373 {
374  if (flags & SWS_COMP_GARBAGE)
375  return 'X';
376  else if (flags & SWS_COMP_ZERO)
377  return '0';
378  else if (flags & SWS_COMP_EXACT)
379  return '+';
380  else
381  return '.';
382 }
383 
384 static const char *print_q(const AVRational q, char buf[], int buf_len)
385 {
386  if (!q.den) {
387  return q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan";
388  } else if (q.den == 1) {
389  snprintf(buf, buf_len, "%d", q.num);
390  return buf;
391  } else if (abs(q.num) > 1000 || abs(q.den) > 1000) {
392  snprintf(buf, buf_len, "%f", av_q2d(q));
393  return buf;
394  } else {
395  snprintf(buf, buf_len, "%d/%d", q.num, q.den);
396  return buf;
397  }
398 }
399 
400 #define PRINTQ(q) print_q(q, (char[32]){0}, sizeof(char[32]) - 1)
401 
402 void ff_sws_op_list_print(void *log, int lev, const SwsOpList *ops)
403 {
404  if (!ops->num_ops) {
405  av_log(log, lev, " (empty)\n");
406  return;
407  }
408 
409  for (int i = 0; i < ops->num_ops; i++) {
410  const SwsOp *op = &ops->ops[i];
411  av_log(log, lev, " [%3s %c%c%c%c -> %c%c%c%c] ",
412  ff_sws_pixel_type_name(op->type),
413  op->comps.unused[0] ? 'X' : '.',
414  op->comps.unused[1] ? 'X' : '.',
415  op->comps.unused[2] ? 'X' : '.',
416  op->comps.unused[3] ? 'X' : '.',
417  describe_comp_flags(op->comps.flags[0]),
418  describe_comp_flags(op->comps.flags[1]),
419  describe_comp_flags(op->comps.flags[2]),
420  describe_comp_flags(op->comps.flags[3]));
421 
422  switch (op->op) {
423  case SWS_OP_INVALID:
424  av_log(log, lev, "SWS_OP_INVALID\n");
425  break;
426  case SWS_OP_READ:
427  case SWS_OP_WRITE:
428  av_log(log, lev, "%-20s: %d elem(s) %s >> %d\n",
429  op->op == SWS_OP_READ ? "SWS_OP_READ"
430  : "SWS_OP_WRITE",
431  op->rw.elems, op->rw.packed ? "packed" : "planar",
432  op->rw.frac);
433  break;
434  case SWS_OP_SWAP_BYTES:
435  av_log(log, lev, "SWS_OP_SWAP_BYTES\n");
436  break;
437  case SWS_OP_LSHIFT:
438  av_log(log, lev, "%-20s: << %u\n", "SWS_OP_LSHIFT", op->c.u);
439  break;
440  case SWS_OP_RSHIFT:
441  av_log(log, lev, "%-20s: >> %u\n", "SWS_OP_RSHIFT", op->c.u);
442  break;
443  case SWS_OP_PACK:
444  case SWS_OP_UNPACK:
445  av_log(log, lev, "%-20s: {%d %d %d %d}\n",
446  op->op == SWS_OP_PACK ? "SWS_OP_PACK"
447  : "SWS_OP_UNPACK",
448  op->pack.pattern[0], op->pack.pattern[1],
449  op->pack.pattern[2], op->pack.pattern[3]);
450  break;
451  case SWS_OP_CLEAR:
452  av_log(log, lev, "%-20s: {%s %s %s %s}\n", "SWS_OP_CLEAR",
453  op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
454  op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
455  op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
456  op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
457  break;
458  case SWS_OP_SWIZZLE:
459  av_log(log, lev, "%-20s: %d%d%d%d\n", "SWS_OP_SWIZZLE",
460  op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
461  break;
462  case SWS_OP_CONVERT:
463  av_log(log, lev, "%-20s: %s -> %s%s\n", "SWS_OP_CONVERT",
464  ff_sws_pixel_type_name(op->type),
465  ff_sws_pixel_type_name(op->convert.to),
466  op->convert.expand ? " (expand)" : "");
467  break;
468  case SWS_OP_DITHER:
469  av_log(log, lev, "%-20s: %dx%d matrix + {%d %d %d %d}\n", "SWS_OP_DITHER",
470  1 << op->dither.size_log2, 1 << op->dither.size_log2,
471  op->dither.y_offset[0], op->dither.y_offset[1],
472  op->dither.y_offset[2], op->dither.y_offset[3]);
473  break;
474  case SWS_OP_MIN:
475  av_log(log, lev, "%-20s: x <= {%s %s %s %s}\n", "SWS_OP_MIN",
476  op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
477  op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
478  op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
479  op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
480  break;
481  case SWS_OP_MAX:
482  av_log(log, lev, "%-20s: {%s %s %s %s} <= x\n", "SWS_OP_MAX",
483  op->c.q4[0].den ? PRINTQ(op->c.q4[0]) : "_",
484  op->c.q4[1].den ? PRINTQ(op->c.q4[1]) : "_",
485  op->c.q4[2].den ? PRINTQ(op->c.q4[2]) : "_",
486  op->c.q4[3].den ? PRINTQ(op->c.q4[3]) : "_");
487  break;
488  case SWS_OP_LINEAR:
489  av_log(log, lev, "%-20s: %s [[%s %s %s %s %s] "
490  "[%s %s %s %s %s] "
491  "[%s %s %s %s %s] "
492  "[%s %s %s %s %s]]\n",
493  "SWS_OP_LINEAR", describe_lin_mask(op->lin.mask),
494  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]),
495  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]),
496  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]),
497  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]));
498  break;
499  case SWS_OP_SCALE:
500  av_log(log, lev, "%-20s: * %s\n", "SWS_OP_SCALE",
501  PRINTQ(op->c.q));
502  break;
503  case SWS_OP_TYPE_NB:
504  break;
505  }
506 
507  if (op->comps.min[0].den || op->comps.min[1].den ||
508  op->comps.min[2].den || op->comps.min[3].den ||
509  op->comps.max[0].den || op->comps.max[1].den ||
510  op->comps.max[2].den || op->comps.max[3].den)
511  {
512  av_log(log, AV_LOG_TRACE, " min: {%s, %s, %s, %s}, max: {%s, %s, %s, %s}\n",
513  PRINTQ(op->comps.min[0]), PRINTQ(op->comps.min[1]),
514  PRINTQ(op->comps.min[2]), PRINTQ(op->comps.min[3]),
515  PRINTQ(op->comps.max[0]), PRINTQ(op->comps.max[1]),
516  PRINTQ(op->comps.max[2]), PRINTQ(op->comps.max[3]));
517  }
518 
519  }
520 
521  av_log(log, lev, " (X = unused, + = exact, 0 = zero)\n");
522 }
523 
525  const SwsOpList *ops, SwsCompiledOp *out)
526 {
527  SwsOpList *copy, rest;
528  SwsCompiledOp compiled = {0};
529  int ret = 0;
530 
532  if (!copy)
533  return AVERROR(ENOMEM);
534 
535  /* Ensure these are always set during compilation */
537 
538  /* Make an on-stack copy of `ops` to ensure we can still properly clean up
539  * the copy afterwards */
540  rest = *copy;
541 
542  ret = backend->compile(ctx, &rest, &compiled);
543  if (ret < 0) {
544  int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR;
545  av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n",
546  backend->name, av_err2str(ret));
547  if (rest.num_ops != ops->num_ops) {
548  av_log(ctx, msg_lev, "Uncompiled remainder:\n");
549  ff_sws_op_list_print(ctx, msg_lev, &rest);
550  }
551  } else {
552  *out = compiled;
553  }
554 
556  return ret;
557 }
558 
560 {
561  for (int n = 0; ff_sws_op_backends[n]; n++) {
562  const SwsOpBackend *backend = ff_sws_op_backends[n];
563  if (ff_sws_ops_compile_backend(ctx, backend, ops, out) < 0)
564  continue;
565 
566  av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': "
567  "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n",
568  backend->name, out->block_size, out->over_read, out->over_write,
569  out->cpu_flags);
570  return 0;
571  }
572 
573  av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n");
575  return AVERROR(ENOTSUP);
576 }
577 
578 typedef struct SwsOpPass {
580  SwsOpExec exec_base;
581  int num_blocks;
582  int tail_off_in;
583  int tail_off_out;
584  int tail_size_in;
585  int tail_size_out;
586  int planes_in;
587  int planes_out;
588  int pixel_bits_in;
589  int pixel_bits_out;
590  bool memcpy_in;
591  bool memcpy_out;
592 } SwsOpPass;
593 
594 static void op_pass_free(void *ptr)
595 {
596  SwsOpPass *p = ptr;
597  if (!p)
598  return;
599 
600  if (p->comp.free)
601  p->comp.free(p->comp.priv);
602 
603  av_free(p);
604 }
605 
606 static void op_pass_setup(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
607 {
608  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->fmt);
609  const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->fmt);
610 
611  SwsOpPass *p = pass->priv;
612  SwsOpExec *exec = &p->exec_base;
613  const SwsCompiledOp *comp = &p->comp;
614  const int block_size = comp->block_size;
615  p->num_blocks = (pass->width + block_size - 1) / block_size;
616 
617  /* Set up main loop parameters */
618  const int aligned_w = p->num_blocks * block_size;
619  const int safe_width = (p->num_blocks - 1) * block_size;
620  const int tail_size = pass->width - safe_width;
621  p->tail_off_in = safe_width * p->pixel_bits_in >> 3;
622  p->tail_off_out = safe_width * p->pixel_bits_out >> 3;
623  p->tail_size_in = tail_size * p->pixel_bits_in >> 3;
624  p->tail_size_out = tail_size * p->pixel_bits_out >> 3;
625  p->memcpy_in = false;
626  p->memcpy_out = false;
627 
628  for (int i = 0; i < p->planes_in; i++) {
629  const int sub_x = (i == 1 || i == 2) ? indesc->log2_chroma_w : 0;
630  const int plane_w = (aligned_w + sub_x) >> sub_x;
631  const int plane_pad = (comp->over_read + sub_x) >> sub_x;
632  const int plane_size = plane_w * p->pixel_bits_in >> 3;
633  p->memcpy_in |= plane_size + plane_pad > in->linesize[i];
634  exec->in_stride[i] = in->linesize[i];
635  }
636 
637  for (int i = 0; i < p->planes_out; i++) {
638  const int sub_x = (i == 1 || i == 2) ? outdesc->log2_chroma_w : 0;
639  const int plane_w = (aligned_w + sub_x) >> sub_x;
640  const int plane_pad = (comp->over_write + sub_x) >> sub_x;
641  const int plane_size = plane_w * p->pixel_bits_out >> 3;
642  p->memcpy_out |= plane_size + plane_pad > out->linesize[i];
643  exec->out_stride[i] = out->linesize[i];
644  }
645 
646  /* Pre-fill pointer bump for the main section only; this value does not
647  * matter at all for the tail / last row handlers because they only ever
648  * process a single line */
649  const int blocks_main = p->num_blocks - p->memcpy_out;
650  for (int i = 0; i < 4; i++) {
651  exec->in_bump[i] = in->linesize[i] - blocks_main * exec->block_size_in;
652  exec->out_bump[i] = out->linesize[i] - blocks_main * exec->block_size_out;
653  }
654 }
655 
656 /* Dispatch kernel over the last column of the image using memcpy */
657 static av_always_inline void
658 handle_tail(const SwsOpPass *p, SwsOpExec *exec,
659  const SwsImg *out_base, const bool copy_out,
660  const SwsImg *in_base, const bool copy_in,
661  int y, const int h)
662 {
663  DECLARE_ALIGNED_64(uint8_t, tmp)[2][4][sizeof(uint32_t[128])];
664 
665  const SwsCompiledOp *comp = &p->comp;
666  const int tail_size_in = p->tail_size_in;
667  const int tail_size_out = p->tail_size_out;
668  const int bx = p->num_blocks - 1;
669 
670  SwsImg in = ff_sws_img_shift(in_base, y);
671  SwsImg out = ff_sws_img_shift(out_base, y);
672  for (int i = 0; i < p->planes_in; i++) {
673  in.data[i] += p->tail_off_in;
674  if (copy_in) {
675  exec->in[i] = (void *) tmp[0][i];
676  exec->in_stride[i] = sizeof(tmp[0][i]);
677  } else {
678  exec->in[i] = in.data[i];
679  }
680  }
681 
682  for (int i = 0; i < p->planes_out; i++) {
683  out.data[i] += p->tail_off_out;
684  if (copy_out) {
685  exec->out[i] = (void *) tmp[1][i];
686  exec->out_stride[i] = sizeof(tmp[1][i]);
687  } else {
688  exec->out[i] = out.data[i];
689  }
690  }
691 
692  for (int y_end = y + h; y < y_end; y++) {
693  if (copy_in) {
694  for (int i = 0; i < p->planes_in; i++) {
695  av_assert2(tmp[0][i] + tail_size_in < (uint8_t *) tmp[1]);
696  memcpy(tmp[0][i], in.data[i], tail_size_in);
697  in.data[i] += in.linesize[i];
698  }
699  }
700 
701  comp->func(exec, comp->priv, bx, y, p->num_blocks, y + 1);
702 
703  if (copy_out) {
704  for (int i = 0; i < p->planes_out; i++) {
705  av_assert2(tmp[1][i] + tail_size_out < (uint8_t *) tmp[2]);
706  memcpy(out.data[i], tmp[1][i], tail_size_out);
707  out.data[i] += out.linesize[i];
708  }
709  }
710 
711  for (int i = 0; i < 4; i++) {
712  if (!copy_in)
713  exec->in[i] += in.linesize[i];
714  if (!copy_out)
715  exec->out[i] += out.linesize[i];
716  }
717  }
718 }
719 
720 static void op_pass_run(const SwsImg *out_base, const SwsImg *in_base,
721  const int y, const int h, const SwsPass *pass)
722 {
723  const SwsOpPass *p = pass->priv;
724  const SwsCompiledOp *comp = &p->comp;
725  const SwsImg in = ff_sws_img_shift(in_base, y);
726  const SwsImg out = ff_sws_img_shift(out_base, y);
727 
728  /* Fill exec metadata for this slice */
729  DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base;
730  exec.slice_y = y;
731  exec.slice_h = h;
732  for (int i = 0; i < 4; i++) {
733  exec.in[i] = in.data[i];
734  exec.out[i] = out.data[i];
735  }
736 
737  /**
738  * To ensure safety, we need to consider the following:
739  *
740  * 1. We can overread the input, unless this is the last line of an
741  * unpadded buffer. All defined operations can handle arbitrary pixel
742  * input, so overread of arbitrary data is fine.
743  *
744  * 2. We can overwrite the output, as long as we don't write more than the
745  * amount of pixels that fit into one linesize. So we always need to
746  * memcpy the last column on the output side if unpadded.
747  *
748  * 3. For the last row, we also need to memcpy the remainder of the input,
749  * to avoid reading past the end of the buffer. Note that since we know
750  * the run() function is called on stripes of the same buffer, we don't
751  * need to worry about this for the end of a slice.
752  */
753 
754  const int last_slice = y + h == pass->height;
755  const bool memcpy_in = last_slice && p->memcpy_in;
756  const bool memcpy_out = p->memcpy_out;
757  const int num_blocks = p->num_blocks;
758  const int blocks_main = num_blocks - memcpy_out;
759  const int h_main = h - memcpy_in;
760 
761  /* Handle main section */
762  comp->func(&exec, comp->priv, 0, y, blocks_main, y + h_main);
763 
764  if (memcpy_in) {
765  /* Safe part of last row */
766  for (int i = 0; i < 4; i++) {
767  exec.in[i] += h_main * in.linesize[i];
768  exec.out[i] += h_main * out.linesize[i];
769  }
770  comp->func(&exec, comp->priv, 0, y + h_main, num_blocks - 1, y + h);
771  }
772 
773  /* Handle last column via memcpy, takes over `exec` so call these last */
774  if (memcpy_out)
775  handle_tail(p, &exec, out_base, true, in_base, false, y, h_main);
776  if (memcpy_in)
777  handle_tail(p, &exec, out_base, memcpy_out, in_base, true, y + h_main, 1);
778 }
779 
780 static int rw_planes(const SwsOp *op)
781 {
782  return op->rw.packed ? 1 : op->rw.elems;
783 }
784 
785 static int rw_pixel_bits(const SwsOp *op)
786 {
787  const int elems = op->rw.packed ? op->rw.elems : 1;
788  const int size = ff_sws_pixel_type_size(op->type);
789  const int bits = 8 >> op->rw.frac;
790  av_assert1(bits >= 1);
791  return elems * size * bits;
792 }
793 
796 {
797  SwsContext *ctx = graph->ctx;
798  SwsOpPass *p = NULL;
799  const SwsOp *read = &ops->ops[0];
800  const SwsOp *write = &ops->ops[ops->num_ops - 1];
801  SwsPass *pass;
802  int ret;
803 
804  if (ops->num_ops < 2) {
805  av_log(ctx, AV_LOG_ERROR, "Need at least two operations.\n");
806  return AVERROR(EINVAL);
807  }
808 
809  if (read->op != SWS_OP_READ || write->op != SWS_OP_WRITE) {
810  av_log(ctx, AV_LOG_ERROR, "First and last operations must be a read "
811  "and write, respectively.\n");
812  return AVERROR(EINVAL);
813  }
814 
817  else
819 
820  p = av_mallocz(sizeof(*p));
821  if (!p)
822  return AVERROR(ENOMEM);
823 
824  ret = ff_sws_ops_compile(ctx, ops, &p->comp);
825  if (ret < 0)
826  goto fail;
827 
828  p->planes_in = rw_planes(read);
829  p->planes_out = rw_planes(write);
830  p->pixel_bits_in = rw_pixel_bits(read);
831  p->pixel_bits_out = rw_pixel_bits(write);
832  p->exec_base = (SwsOpExec) {
833  .width = dst.width,
834  .height = dst.height,
835  .block_size_in = p->comp.block_size * p->pixel_bits_in >> 3,
836  .block_size_out = p->comp.block_size * p->pixel_bits_out >> 3,
837  };
838 
839  pass = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height, input,
840  1, p, op_pass_run);
841  if (!pass) {
842  ret = AVERROR(ENOMEM);
843  goto fail;
844  }
845  pass->setup = op_pass_setup;
846  pass->free = op_pass_free;
847 
848  *output = pass;
849  return 0;
850 
851 fail:
852  op_pass_free(p);
853  return ret;
854 }
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:236
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_OP_SWIZZLE
@ SWS_OP_SWIZZLE
Definition: ops.h:50
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:225
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:53
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:250
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
SWS_MASK_DIAG3
@ SWS_MASK_DIAG3
Definition: ops.h:167
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:75
SWS_OP_CLEAR
@ SWS_OP_CLEAR
Definition: ops.h:59
ff_sws_linear_mask
uint32_t ff_sws_linear_mask(const SwsLinearOp c)
Definition: ops.c:319
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
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:308
backend_x86
const SwsOpBackend backend_x86
Definition: ops.c:743
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:303
normalize.log
log
Definition: normalize.py:21
mask
int mask
Definition: mediacodecdec_common.c:154
SWS_MASK_OFF3
@ SWS_MASK_OFF3
Definition: ops.h:168
ops.h
SWS_OP_DITHER
@ SWS_OP_DITHER
Definition: ops.h:67
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
SWS_MASK_LUMA
@ SWS_MASK_LUMA
Definition: ops.h:164
SWS_MASK_ALPHA
@ SWS_MASK_ALPHA
Definition: ops.h:165
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:69
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
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:372
SWS_MASK_ROW
#define SWS_MASK_ROW(I)
Definition: ops.h:159
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
SWS_MASK_OFF4
@ SWS_MASK_OFF4
Definition: ops.h:174
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:214
SwsOpList::num_ops
int num_ops
Definition: ops.h:213
SWS_MASK_COL
#define SWS_MASK_COL(J)
Definition: ops.h:160
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:182
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
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_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:61
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:66
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:400
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
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:54
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
SWS_MASK_DIAG4
@ SWS_MASK_DIAG4
Definition: ops.h:173
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:73
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:279
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:384
SWS_MASK
#define SWS_MASK(I, J)
Definition: ops.h:157
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:183
ff_sws_op_list_insert_at
int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
Definition: ops.c:289
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:216
SWS_OP_INVALID
@ SWS_OP_INVALID
Definition: ops.h:44
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:214
SWS_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops.h:259
SwsLinearOp
Definition: ops.h:140
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:159
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:496
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:212
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
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:181
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
SWS_MASK_MAT4
@ SWS_MASK_MAT4
Definition: ops.h:175
av_malloc
void * av_malloc(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:98
SwsOpList::dst
SwsFormat dst
Definition: ops.h:216
SWS_OP_MAX
@ SWS_OP_MAX
Definition: ops.h:62
SwsCompiledOp
Definition: ops_internal.h:90
SWS_MASK_MAT3
@ SWS_MASK_MAT3
Definition: ops.h:169
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:74
describe_lin_mask
static const char * describe_lin_mask(uint32_t mask)
Definition: ops.c:331
mem.h
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:60
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:402
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:211
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