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