FFmpeg
ops_dispatch.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/cpu.h"
23 #include "libavutil/mathematics.h"
24 #include "libavutil/mem.h"
25 #include "libavutil/mem_internal.h"
26 #include "libavutil/refstruct.h"
27 
28 #include "ops.h"
29 #include "ops_internal.h"
30 #include "ops_dispatch.h"
31 #include "swscale_internal.h"
32 
33 #define RET(x) \
34  do { \
35  if ((ret = (x)) < 0) \
36  goto fail; \
37  } while (0)
38 
39 typedef struct SwsOpPass {
43  size_t num_blocks;
48  int planes_in;
52  int idx_in[4];
53  int idx_out[4];
55  int *offsets_y;
59  bool memcpy_out;
60  size_t tail_blocks;
61  uint8_t *tail_buf; /* extra memory for fixing unpadded tails */
62  unsigned int tail_buf_size;
63 } SwsOpPass;
64 
65 static int compile_backend(SwsContext *ctx, const SwsOpBackend *backend,
66  const SwsOpList *ops, SwsCompiledOp *out)
67 {
68  SwsOpList *copy;
69  SwsCompiledOp compiled = {0};
70  int ret = 0;
71 
73  if (!copy)
74  return AVERROR(ENOMEM);
75 
76  /* Ensure these are always set during compilation */
78 
79  ret = backend->compile(ctx, copy, &compiled);
80  if (ret < 0) {
81  int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR;
82  av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n",
83  backend->name, av_err2str(ret));
84  goto fail;
85  }
86 
87  compiled.backend = backend;
88  *out = compiled;
89 
90  av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': "
91  "block size = %d, over-read = {%d %d %d %d}, over-write = {%d %d %d %d}, "
92  "cpu flags = 0x%x\n", backend->name, out->block_size,
93  out->over_read[0], out->over_read[1],
94  out->over_read[2], out->over_read[3],
95  out->over_write[0], out->over_write[1],
96  out->over_write[2], out->over_write[3],
97  out->cpu_flags);
98 
100 
101 fail:
103  return ret;
104 }
105 
107  const SwsOpList *ops, SwsCompiledOp *out)
108 {
109  if (backend)
110  return compile_backend(ctx, backend, ops, out);
111 
112  const SwsBackend enabled = ff_sws_enabled_backends(ctx);
113  for (int n = 0; ff_sws_op_backends[n]; n++) {
114  const SwsOpBackend *backend = ff_sws_op_backends[n];
115  if (ops->src.hw_format != backend->hw_format ||
116  ops->dst.hw_format != backend->hw_format ||
117  !(enabled & backend->flags))
118  continue;
119  if (compile_backend(ctx, backend, ops, out) < 0)
120  continue;
121 
122  return 0;
123  }
124 
125  return AVERROR(ENOTSUP);
126 }
127 
129 {
130  if (comp->free)
131  comp->free(comp->priv);
132 
133  *comp = (SwsCompiledOp) {0};
134 }
135 
136 static void op_pass_free(void *ptr)
137 {
138  SwsOpPass *p = ptr;
139  if (!p)
140  return;
141 
142  ff_sws_compiled_op_unref(&p->comp);
143  av_refstruct_unref(&p->offsets_y);
144  av_free(p->exec_base.in_bump_y);
145  av_free(p->exec_base.in_offset_x);
146  av_free(p->tail_buf);
147  av_free(p);
148 }
149 
150 static inline void get_row_data(const SwsOpPass *p, const int y_dst,
151  const uint8_t *in[4], uint8_t *out[4])
152 {
153  const SwsOpExec *base = &p->exec_base;
154  const int y_src = p->offsets_y ? p->offsets_y[y_dst] : y_dst;
155  for (int i = 0; i < p->planes_in; i++)
156  in[i] = base->in[i] + (y_src >> base->in_sub_y[i]) * base->in_stride[i];
157  for (int i = 0; i < p->planes_out; i++)
158  out[i] = base->out[i] + (y_dst >> base->out_sub_y[i]) * base->out_stride[i];
159 }
160 
161 static inline int get_lines_in(const SwsOpPass *p, const int y, const int h,
162  const int plane)
163 {
164  const SwsOpExec *base = &p->exec_base;
165  if (!p->offsets_y)
166  return h >> base->in_sub_y[plane];
167 
168  const int y0 = p->offsets_y[y] >> base->in_sub_y[plane];
169  const int y1 = p->offsets_y[y + h - 1] >> base->in_sub_y[plane];
170  return y1 - y0 + 1;
171 }
172 
173 static inline size_t pixel_bytes(size_t pixels, int pixel_bits,
174  enum AVRounding rounding)
175 {
176  const uint64_t bits = (uint64_t) pixels * pixel_bits;
177  switch (rounding) {
178  case AV_ROUND_ZERO:
179  case AV_ROUND_DOWN:
180  return bits >> 3;
181  case AV_ROUND_INF:
182  case AV_ROUND_UP:
183  return (bits + 7) >> 3;
184  default:
185  av_unreachable("Invalid rounding mode");
186  return (size_t) -1;
187  }
188 }
189 
190 static size_t safe_bytes_pad(int linesize, int plane_pad)
191 {
192  av_assert1(linesize);
193  int64_t safe_bytes = FFABS((int64_t) linesize) - plane_pad;
194  return FFMAX(safe_bytes, 0);
195 }
196 
197 static size_t safe_blocks_offset(size_t num_blocks, unsigned block_size,
198  ptrdiff_t safe_offset,
199  const int32_t *offset_bytes)
200 {
201  size_t safe_blocks = num_blocks;
202  while (safe_blocks && offset_bytes[safe_blocks * block_size - 1] > safe_offset)
203  safe_blocks--;
204  return safe_blocks;
205 }
206 
207 static int op_pass_setup(const SwsFrame *out, const SwsFrame *in,
208  const SwsPass *pass)
209 {
210  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->format);
211  const bool float_in = indesc->flags & AV_PIX_FMT_FLAG_FLOAT;
212  const int width = out->width;
213 
214  SwsOpPass *p = pass->priv;
215  SwsOpExec *exec = &p->exec_base;
216  const SwsCompiledOp *comp = &p->comp;
217 
218  /* Set up main loop parameters */
219  const unsigned block_size = comp->block_size;
220  const size_t num_blocks = (width + block_size - 1) / block_size;
221  const size_t aligned_w = num_blocks * block_size;
222  if (aligned_w < width) /* overflow */
223  return AVERROR(EINVAL);
224  p->num_blocks = num_blocks;
225  p->memcpy_first = false;
226  p->memcpy_last = false;
227  p->memcpy_out = false;
228 
229  size_t safe_blocks = num_blocks;
230  for (int i = 0; i < p->planes_in; i++) {
231  const int idx = p->idx_in[i];
232  size_t input_bytes = in->linesize[idx];
233  if (p->filter_size_h && float_in) {
234  /* Floating point inputs may contain NaN / Infinity in the padding */
235  const int plane_w = AV_CEIL_RSHIFT(in->width, exec->in_sub_x[i]);
236  input_bytes = pixel_bytes(plane_w, p->pixel_bits_in, AV_ROUND_UP);
237  }
238 
239  size_t safe_bytes = safe_bytes_pad(input_bytes, comp->over_read[i]);
240  size_t safe_blocks_in;
241  if (exec->in_offset_x) {
242  size_t filter_size = pixel_bytes(p->filter_size_h, p->pixel_bits_in,
243  AV_ROUND_UP);
244  safe_blocks_in = safe_blocks_offset(num_blocks, block_size,
245  safe_bytes - filter_size,
246  exec->in_offset_x);
247  } else {
248  safe_blocks_in = safe_bytes / exec->block_size_in[i];
249  }
250 
251  if (safe_blocks_in < num_blocks) {
252  p->memcpy_first |= in->linesize[idx] < 0;
253  p->memcpy_last |= in->linesize[idx] > 0;
254  safe_blocks = FFMIN(safe_blocks, safe_blocks_in);
255  }
256 
257  size_t loop_size = num_blocks * exec->block_size_in[i];
258  exec->in[i] = in->data[idx];
259  exec->in_stride[i] = in->linesize[idx];
260  exec->in_bump[i] = in->linesize[idx] - loop_size;
261  }
262 
263  for (int i = 0; i < p->planes_out; i++) {
264  const int idx = p->idx_out[i];
265  size_t safe_bytes = safe_bytes_pad(out->linesize[idx], comp->over_write[i]);
266  size_t safe_blocks_out = safe_bytes / exec->block_size_out[i];
267  if (safe_blocks_out < num_blocks) {
268  p->memcpy_out = true;
269  safe_blocks = FFMIN(safe_blocks, safe_blocks_out);
270  }
271 
272  size_t loop_size = num_blocks * exec->block_size_out[i];
273  exec->out[i] = out->data[idx];
274  exec->out_stride[i] = out->linesize[idx];
275  exec->out_bump[i] = out->linesize[idx] - loop_size;
276  }
277 
278  if (p->palette_idx >= 0) {
279  exec->in[1] = in->data[p->palette_idx];
280  exec->in_stride[1] = exec->in_bump[1] = 0;
281  }
282 
283  const bool memcpy_in = p->memcpy_first || p->memcpy_last;
284  if (!memcpy_in && !p->memcpy_out) {
285  av_assert0(safe_blocks == num_blocks);
286  return 0;
287  }
288 
289  /* Set-up tail section parameters and buffers */
290  SwsOpExec *tail = &p->exec_tail;
291  const int align = av_cpu_max_align();
292  size_t alloc_size = 0;
293  *tail = *exec;
294 
295  const size_t safe_width = safe_blocks * block_size;
296  const size_t tail_size = width - safe_width;
297  p->tail_off_out = pixel_bytes(safe_width, p->pixel_bits_out, AV_ROUND_DOWN);
298  p->tail_size_out = pixel_bytes(tail_size, p->pixel_bits_out, AV_ROUND_UP);
299  p->tail_blocks = num_blocks - safe_blocks;
300 
301  if (exec->in_offset_x) {
302  p->tail_off_in = exec->in_offset_x[safe_width];
303  p->tail_size_in = exec->in_offset_x[width - 1] - p->tail_off_in;
304  p->tail_size_in += pixel_bytes(p->filter_size_h, p->pixel_bits_in, AV_ROUND_UP);
305  } else {
306  p->tail_off_in = pixel_bytes(safe_width, p->pixel_bits_in, AV_ROUND_DOWN);
307  p->tail_size_in = pixel_bytes(tail_size, p->pixel_bits_in, AV_ROUND_UP);
308  }
309 
310  const size_t alloc_width = aligned_w - safe_width;
311  for (int i = 0; memcpy_in && i < p->planes_in; i++) {
312  size_t needed_size;
313  if (exec->in_offset_x) {
314  /* The input offset map is already padded to multiples of the block
315  * size, and clamps the input offsets to the image boundaries; so
316  * we just need to compensate for the comp->over_read */
317  needed_size = p->tail_size_in;
318  } else {
319  needed_size = pixel_bytes(alloc_width, p->pixel_bits_in, AV_ROUND_UP);
320  }
321  size_t loop_size = p->tail_blocks * exec->block_size_in[i];
322  tail->in_stride[i] = FFALIGN(needed_size + comp->over_read[i], align);
323  tail->in_bump[i] = tail->in_stride[i] - loop_size;
324  alloc_size += tail->in_stride[i] * in->height;
325  }
326 
327  for (int i = 0; p->memcpy_out && i < p->planes_out; i++) {
328  size_t needed_size = pixel_bytes(alloc_width, p->pixel_bits_out, AV_ROUND_UP);
329  size_t loop_size = p->tail_blocks * exec->block_size_out[i];
330  tail->out_stride[i] = FFALIGN(needed_size + comp->over_write[i], align);
331  tail->out_bump[i] = tail->out_stride[i] - loop_size;
332  alloc_size += tail->out_stride[i] * out->height;
333  }
334 
335  if (memcpy_in && exec->in_offset_x) {
336  /* `in_offset_x` is indexed relative to the line start, not the start
337  * of the section being processed; so we need to over-allocate this
338  * array to the full width of the image, even though we will only
339  * partially fill in the offsets relevant to the tail region */
340  alloc_size += aligned_w * sizeof(*exec->in_offset_x);
341  }
342 
343  av_fast_mallocz(&p->tail_buf, &p->tail_buf_size, alloc_size);
344  if (!p->tail_buf)
345  return AVERROR(ENOMEM);
346 
347  uint8_t *tail_buf = p->tail_buf;
348  for (int i = 0; memcpy_in && i < p->planes_in; i++) {
349  tail->in[i] = tail_buf;
350  tail_buf += tail->in_stride[i] * in->height;
351  }
352 
353  for (int i = 0; p->memcpy_out && i < p->planes_out; i++) {
354  tail->out[i] = tail_buf;
355  tail_buf += tail->out_stride[i] * out->height;
356  }
357 
358  if (memcpy_in && exec->in_offset_x) {
359  tail->in_offset_x = (int32_t *) tail_buf;
360  for (int i = safe_width; i < aligned_w; i++)
361  tail->in_offset_x[i] = exec->in_offset_x[i] - p->tail_off_in;
362  }
363 
364  return 0;
365 }
366 
367 static void copy_lines(uint8_t *dst, const size_t dst_stride,
368  const uint8_t *src, const size_t src_stride,
369  const int h, const size_t bytes)
370 {
371  for (int y = 0; y < h; y++) {
372  memcpy(dst, src, bytes);
373  dst += dst_stride;
374  src += src_stride;
375  }
376 }
377 
378 static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y,
379  const int h, const SwsPass *pass)
380 {
381  const SwsOpPass *p = pass->priv;
382  const SwsCompiledOp *comp = &p->comp;
383 
384  /* Fill exec metadata for this slice */
385  DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base;
386  exec.slice_y = y;
387  exec.slice_h = h;
388 
389  /**
390  * To ensure safety, we need to consider the following:
391  *
392  * 1. We can overread the input, unless this is the last line of an
393  * unpadded buffer. All defined operations can handle arbitrary pixel
394  * input, so overread of arbitrary data is fine. For flipped images,
395  * this condition is actually *inverted* to where the first line is
396  * the one at the end of the buffer.
397  *
398  * 2. We can overwrite the output, as long as we don't write more than the
399  * amount of pixels that fit into one linesize. So we always need to
400  * memcpy the last column on the output side if unpadded.
401  */
402 
403  const bool memcpy_in = p->memcpy_last && y + h == pass->lines ||
404  p->memcpy_first && y == 0;
405  const bool memcpy_out = p->memcpy_out;
406  const size_t num_blocks = p->num_blocks;
407  const size_t tail_blocks = p->tail_blocks;
408 
409  get_row_data(p, y, exec.in, exec.out);
410  if (!memcpy_in && !memcpy_out) {
411  /* Fast path (fully aligned/padded inputs and outputs) */
412  comp->func(&exec, comp->priv, 0, y, num_blocks, y + h);
413  return;
414  }
415 
416  /* Non-aligned case (slow path); process main blocks as normal, and
417  * a separate tail (via memcpy into an appropriately padded buffer) */
418  if (num_blocks > tail_blocks) {
419  for (int i = 0; i < 4; i++) {
420  /* We process fewer blocks, so the in_bump needs to be increased
421  * to reflect that the plane pointers are left on the last block,
422  * not the end of the processed line, after each loop iteration */
423  exec.in_bump[i] += exec.block_size_in[i] * tail_blocks;
424  exec.out_bump[i] += exec.block_size_out[i] * tail_blocks;
425  }
426 
427  comp->func(&exec, comp->priv, 0, y, num_blocks - tail_blocks, y + h);
428  }
429 
430  DECLARE_ALIGNED_32(SwsOpExec, tail) = p->exec_tail;
431  tail.slice_y = y;
432  tail.slice_h = h;
433 
434  for (int i = 0; i < p->planes_in; i++) {
435  /* Input offsets are relative to the base pointer */
436  if (!exec.in_offset_x || memcpy_in)
437  exec.in[i] += p->tail_off_in;
438  tail.in[i] += y * tail.in_stride[i];
439  }
440  for (int i = 0; i < p->planes_out; i++) {
441  exec.out[i] += p->tail_off_out;
442  tail.out[i] += y * tail.out_stride[i];
443  }
444 
445  for (int i = 0; i < p->planes_in; i++) {
446  if (memcpy_in) {
447  const int lines = get_lines_in(p, y, h, i);
448  copy_lines((uint8_t *) tail.in[i], tail.in_stride[i],
449  exec.in[i], exec.in_stride[i], lines, p->tail_size_in);
450  } else {
451  /* Reuse input pointers directly */
452  const size_t loop_size = tail_blocks * exec.block_size_in[i];
453  tail.in[i] = exec.in[i];
454  tail.in_stride[i] = exec.in_stride[i];
455  tail.in_bump[i] = exec.in_stride[i] - loop_size;
456  }
457  }
458 
459  for (int i = 0; !memcpy_out && i < p->planes_out; i++) {
460  /* Reuse output pointers directly */
461  const size_t loop_size = tail_blocks * exec.block_size_out[i];
462  tail.out[i] = exec.out[i];
463  tail.out_stride[i] = exec.out_stride[i];
464  tail.out_bump[i] = exec.out_stride[i] - loop_size;
465  }
466 
467  /* Dispatch kernel over tail */
468  av_assert1(tail_blocks > 0);
469  comp->func(&tail, comp->priv, num_blocks - tail_blocks, y, num_blocks, y + h);
470 
471  for (int i = 0; memcpy_out && i < p->planes_out; i++) {
472  const int lines = h >> tail.out_sub_y[i];
473  copy_lines(exec.out[i], exec.out_stride[i],
474  tail.out[i], tail.out_stride[i], lines, p->tail_size_out);
475  }
476 }
477 
478 static int rw_data_planes(const SwsOp *op)
479 {
480  /* Exclude the palette plane from the plane count, since it does not need
481  * to be directly processed/adjusted by the dispatch layer */
482  return op->rw.mode == SWS_RW_PALETTE ? 1 : ff_sws_rw_op_planes(op);
483 }
484 
485 static int rw_pixel_bits(const SwsOp *op)
486 {
487  if (op->rw.mode == SWS_RW_PALETTE)
488  return 8; /* index size */
489 
490  int elems = 0;
491  switch (op->rw.mode) {
492  case SWS_RW_PLANAR: elems = 1; break;
493  case SWS_RW_PACKED: elems = op->rw.elems; break;
494  }
495 
496  const int size = ff_sws_pixel_type_size(op->type);
497  const int bits = 8 >> op->rw.frac;
498  av_assert1(bits >= 1);
499  return elems * size * bits;
500 }
501 
502 static void align_pass(SwsPass *pass, int block_size, const int *over_rw,
503  int pixel_bits)
504 {
505  if (!pass || pixel_bits <= 0)
506  return;
507 
508  /* Add at least as many pixels as needed to cover the padding requirement */
509  int pad_max = 0;
510  for (int i = 0; i < 4; i++) {
511  const int pad = (over_rw[i] * 8 + pixel_bits - 1) / pixel_bits;
512  pad_max = FFMAX(pad_max, pad);
513  }
514 
515  SwsPassBuffer *buf = pass->output;
516  buf->width_align = FFMAX(buf->width_align, block_size);
517  buf->width_pad = FFMAX(buf->width_pad, pad_max);
518 }
519 
520 /* Unchanging part of parameter list */
521 typedef struct CompileArgs {
524  int flags;
525 } CompileArgs;
526 
527 static int compile_single(const CompileArgs *args, const SwsOpList *ops,
529 {
530  SwsGraph *graph = args->graph;
531  SwsContext *ctx = graph->ctx;
532  SwsOpPass *p = av_mallocz(sizeof(*p));
533  if (!p)
534  return AVERROR(ENOMEM);
535 
536  int ret = ff_sws_ops_compile(ctx, args->backend, ops, &p->comp);
537  if (ret < 0)
538  goto fail;
539  else if (args->flags & SWS_OP_FLAG_DRY_RUN)
540  goto fail; /* nothing to do, just return */
541 
542  const SwsCompiledOp *comp = &p->comp;
543  const SwsFormat *src = &ops->src;
544  const SwsFormat *dst = &ops->dst;
545  av_assert0(!link || link->format == dst->format);
546  if (p->comp.opaque) {
547  SwsCompiledOp c = *comp;
548  av_free(p);
549  ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
550  input, 0, c.slice_align, c.func_opaque,
551  NULL, c.priv, c.free, output);
552  if (ret >= 0) {
553  (*output)->backend = comp->backend->flags;
555  }
556  return ret;
557  }
558 
559  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(src->format);
560  const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(dst->format);
561  const SwsOp *write = ff_sws_op_list_output(ops);
562  p->planes_out = rw_data_planes(write);
563  p->pixel_bits_out = rw_pixel_bits(write);
564  p->palette_idx = -1;
565  p->exec_base = (SwsOpExec) {
566  .width = dst->width,
567  .height = dst->height,
568  };
569 
570  const SwsOp *read = ff_sws_op_list_input(ops);
571  if (read) {
572  p->planes_in = rw_data_planes(read);
573  p->pixel_bits_in = rw_pixel_bits(read);
574  if (read->rw.mode == SWS_RW_PALETTE)
575  p->palette_idx = ops->plane_src[1];
576  }
577 
578  const int64_t block_bits_in = (int64_t) comp->block_size * p->pixel_bits_in;
579  const int64_t block_bits_out = (int64_t) comp->block_size * p->pixel_bits_out;
580  if (block_bits_in & 0x7 || block_bits_out & 0x7) {
581  av_log(ctx, AV_LOG_ERROR, "Block size must be byte-aligned.\n");
582  ret = AVERROR(EINVAL);
583  goto fail;
584  }
585 
586  for (int i = 0; i < 4; i++)
587  p->idx_in[i] = p->idx_out[i] = -1;
588 
589  for (int i = 0; i < p->planes_in; i++) {
590  const int idx = ops->plane_src[i];
591  const int chroma = idx == 1 || idx == 2;
592  const int sub_x = chroma ? indesc->log2_chroma_w : 0;
593  const int sub_y = chroma ? indesc->log2_chroma_h : 0;
594  p->exec_base.in_sub_x[i] = sub_x;
595  p->exec_base.in_sub_y[i] = sub_y;
596  p->exec_base.block_size_in[i] = block_bits_in >> 3;
597  p->idx_in[i] = idx;
598  }
599 
600  for (int i = 0; i < p->planes_out; i++) {
601  const int idx = ops->plane_dst[i];
602  const int chroma = idx == 1 || idx == 2;
603  const int sub_x = chroma ? outdesc->log2_chroma_w : 0;
604  const int sub_y = chroma ? outdesc->log2_chroma_h : 0;
605  p->exec_base.out_sub_x[i] = sub_x;
606  p->exec_base.out_sub_y[i] = sub_y;
607  p->exec_base.block_size_out[i] = block_bits_out >> 3;
608  p->idx_out[i] = idx;
609  }
610 
611  const SwsFilterWeights *filter = read ? read->rw.filter.kernel : NULL;
612  if (read && read->rw.filter.op == SWS_OP_FILTER_V) {
613  p->offsets_y = av_refstruct_ref(filter->offsets);
614 
615  /* Compute relative pointer bumps for each output line */
616  int32_t *bump = av_malloc_array(filter->dst_size, sizeof(*bump));
617  if (!bump) {
618  ret = AVERROR(ENOMEM);
619  goto fail;
620  }
621 
622  int line = filter->offsets[0];
623  for (int y = 0; y < filter->dst_size - 1; y++) {
624  int next = filter->offsets[y + 1];
625  bump[y] = next - line - 1;
626  line = next;
627  }
628  bump[filter->dst_size - 1] = 0;
629  p->exec_base.in_bump_y = bump;
630  } else if (read && read->rw.filter.op == SWS_OP_FILTER_H) {
631  /* Compute pixel offset map for each output line */
632  const int pixels = FFALIGN(filter->dst_size, p->comp.block_size);
633  int32_t *offset = av_malloc_array(pixels, sizeof(*offset));
634  if (!offset) {
635  ret = AVERROR(ENOMEM);
636  goto fail;
637  }
638  p->exec_base.in_offset_x = offset;
639 
640  for (int x = 0; x < filter->dst_size; x++) {
641  /* Sanity check; if the tap would land on a half-pixel, we cannot
642  * reasonably expect the implementation to know about this. Just
643  * error out in such (theoretical) cases. */
644  int64_t bits = (int64_t) filter->offsets[x] * p->pixel_bits_in;
645  if ((bits & 0x7) || (bits >> 3) > INT32_MAX) {
646  ret = AVERROR(EINVAL);
647  goto fail;
648  }
649  offset[x] = bits >> 3;
650  }
651  for (int x = filter->dst_size; x < pixels; x++)
652  offset[x] = offset[filter->dst_size - 1];
653  for (int i = 0; i < 4; i++)
654  p->exec_base.block_size_in[i] = 0; /* ptr does not advance */
655  p->filter_size_h = filter->filter_size;
656  }
657 
658  ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
659  input, 0, comp->slice_align, op_pass_run,
661  if (ret < 0)
662  return ret;
663 
664  (*output)->backend = comp->backend->flags;
666  align_pass(*output, comp->block_size, comp->over_write, p->pixel_bits_out);
667  if (read)
668  align_pass(input, comp->block_size, comp->over_read, p->pixel_bits_in);
669  return 0;
670 
671 fail:
672  op_pass_free(p);
673  return ret;
674 }
675 
676 /* Return a mask of all planes matching any flag in `flags` */
678 {
679  SwsCompMask planes = 0;
680  for (int c = 0; c < 4; c++) {
681  if (op->comps.flags[c] & flags)
682  planes |= SWS_COMP(c);
683  }
684 
685  return planes;
686 }
687 
688 /* Takes over ownership of *pops, even on failure */
689 static int compile_subpass(const CompileArgs *args, SwsOpList **pops,
691 {
692  int ret;
693  SwsContext *ctx = args->graph->ctx;
694  SwsOpList *ops = *pops;
695  SwsOpList *rest = NULL;
696  SwsPass *tmp = NULL;
697  *pops = NULL;
698 
699  if (args->flags & SWS_OP_FLAG_SPLIT_MEMCPY) {
700  /* Split off copied and constant planes into a separate subpass,
701  * since these are likely to be handled by the memcpy backend */
702  av_assert0(ops->num_ops >= 2);
703  const SwsOp *prev = &ops->ops[ops->num_ops - 2];
705  RET(ff_sws_op_list_split_planes(ops, &rest, planes));
706  if (rest) {
707  /* Parallel split: share input and link all outputs together */
708  av_log(ctx, AV_LOG_DEBUG, "Splitting const/memcpy planes: %s\n",
710  RET(compile_subpass(args, &ops, link, input, &tmp));
711  RET(compile_subpass(args, &rest, tmp, input, output));
712  return 0;
713  }
714  }
715 
716  ret = compile_single(args, ops, link, input, output);
717  if (ret != AVERROR(ENOTSUP))
718  goto fail; /* either success or a hard error */
719 
720  /* Find any unresolved filter */
721  for (int idx = 1; idx < ops->num_ops - 1; idx++) {
722  const SwsOp *op = &ops->ops[idx];
723  if (op->op == SWS_OP_FILTER_H || op->op == SWS_OP_FILTER_V) {
724  RET(ff_sws_op_list_split_at(ops, &rest, idx));
725  if (ff_sws_op_list_is_noop(ops)) {
726  /* Prevent infinite recursion by avoiding splitting in a way
727  * that does not meaningfully reduce the number of operations
728  * performed in the second part. */
729  FFSWAP(SwsOpList *, ops, rest);
730  break;
731  }
732  /* Serial split: feed first pass into second */
733  RET(compile_subpass(args, &ops, NULL, input, &tmp));
734  RET(compile_subpass(args, &rest, link, tmp, output));
735  return 0;
736  }
737  }
738 
739  /* If we didn't find any more operations to eliminate, then this ops list
740  * is simply unsupported by any of the available backends */
741  av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n");
743  ret = AVERROR(ENOTSUP);
744 
745 fail:
746  ff_sws_op_list_free(&ops);
747  ff_sws_op_list_free(&rest);
748  return ret;
749 }
750 
751 int ff_sws_compile_pass(SwsGraph *graph, const SwsOpBackend *backend,
752  SwsOpList **pops, int flags, SwsPass *input,
753  SwsPass **output)
754 {
755  const int passes_orig = graph->num_passes;
756  SwsContext *ctx = graph->ctx;
757  SwsOpList *ops = *pops;
758  int ret = 0;
759 
760  const SwsOp *write = ff_sws_op_list_output(ops);
761  if (!write) {
762  av_log(ctx, AV_LOG_ERROR, "Last operation must be SWS_OP_WRITE.\n");
763  ret = AVERROR(EINVAL);
764  goto out;
765  }
766 
767  if (flags & SWS_OP_FLAG_OPTIMIZE) {
769  if (ret < 0)
770  goto out;
771  av_log(ctx, AV_LOG_DEBUG, "Operation list after optimizing:\n");
773  }
774 
775  /* Check if the whole operation graph is an end-to-end no-op */
776  if (ff_sws_op_list_is_noop(ops)) {
777  if (output)
778  *output = input;
779  goto out;
780  }
781 
782  const CompileArgs args = {
783  .backend = backend,
784  .graph = graph,
785  .flags = flags,
786  };
787 
788  ret = compile_subpass(&args, &ops, NULL, input, output);
789  if (ret < 0)
790  goto out;
791 
792  const int num_passes = graph->num_passes - passes_orig;
793  if (num_passes > 1)
794  av_log(ctx, AV_LOG_VERBOSE, "Using %d separate passes.\n", num_passes);
795 
796 out:
797  if (ret < 0)
798  ff_sws_graph_rollback(graph, passes_orig);
799  ff_sws_op_list_free(&ops);
800  *pops = NULL;
801  return ret;
802 }
flags
const SwsFlags flags[]
Definition: swscale.c:85
SwsOpPass::tail_buf
uint8_t * tail_buf
Definition: ops_dispatch.c:61
copy_lines
static void copy_lines(uint8_t *dst, const size_t dst_stride, const uint8_t *src, const size_t src_stride, const int h, const size_t bytes)
Definition: ops_dispatch.c:367
AV_ROUND_UP
@ AV_ROUND_UP
Round toward +infinity.
Definition: mathematics.h:134
SwsOpPass::tail_buf_size
unsigned int tail_buf_size
Definition: ops_dispatch.c:62
ff_sws_graph_add_pass
int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int lines, int align, SwsPassFunc run, SwsPassSetup setup, void *priv, void(*free_cb)(void *priv), SwsPass **out_pass)
Allocate and add a new pass to the filter graph.
Definition: graph.c:175
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:645
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
ff_sws_rw_op_planes
int ff_sws_rw_op_planes(const SwsOp *op)
Return the number of planes involved in a read/write operation.
Definition: ops.c:170
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:123
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:75
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
SwsOpPass::idx_in
int idx_in[4]
Definition: ops_dispatch.c:52
SwsOpPass::tail_size_out
int tail_size_out
Definition: ops_dispatch.c:47
ff_sws_pass_link_output
void ff_sws_pass_link_output(SwsPass *dst, const SwsPass *src)
Link the output buffers to a different pass, rather than allocating new image buffers.
Definition: graph.c:232
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:659
SWS_RW_PLANAR
@ SWS_RW_PLANAR
Note: 1-component reads are either SWS_RW_PLANAR or SWS_RW_PACKED, depending on the underlying interp...
Definition: ops.h:99
mem_internal.h
out
static FILE * out
Definition: movenc.c:55
SwsOpPass::exec_tail
SwsOpExec exec_tail
Definition: ops_dispatch.c:42
comp
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:79
SwsOpBackend::flags
SwsBackend flags
Definition: ops_dispatch.h:135
SwsOpExec::in_bump
ptrdiff_t in_bump[4]
Pointer bump, difference between stride and processed line size.
Definition: ops_dispatch.h:51
ff_sws_op_list_input
const SwsOp * ff_sws_op_list_input(const SwsOpList *ops)
Returns the input operation for a given op list, or NULL if there is none (e.g.
Definition: ops.c:696
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
SwsPass::lines
int lines
Definition: graph.h:86
SwsOpExec::out_stride
ptrdiff_t out_stride[4]
Definition: ops_dispatch.h:42
SwsOpExec::in
const uint8_t * in[4]
Definition: ops_dispatch.h:37
int64_t
long long int64_t
Definition: coverity.c:34
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
AV_PIX_FMT_FLAG_FLOAT
#define AV_PIX_FMT_FLAG_FLOAT
The pixel format contains IEEE-754 floating point values.
Definition: pixdesc.h:158
compile_subpass
static int compile_subpass(const CompileArgs *args, SwsOpList **pops, SwsPass *link, SwsPass *input, SwsPass **output)
Definition: ops_dispatch.c:689
ops.h
SwsFilterWeights
Represents a computed filter kernel.
Definition: filters.h:85
SwsOpExec::block_size_out
int32_t block_size_out[4]
Definition: ops_dispatch.h:58
chroma
static av_always_inline void chroma(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, int column, int mirror, int jobnr, int nb_jobs)
Definition: vf_waveform.c:1639
AV_ROUND_ZERO
@ AV_ROUND_ZERO
Round toward zero.
Definition: mathematics.h:131
AVRounding
AVRounding
Rounding methods.
Definition: mathematics.h:130
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
base
uint8_t base
Definition: vp3data.h:128
filter
void(* filter)(uint8_t *src, int stride, int qscale)
Definition: h263dsp.c:29
SwsFrame::width
int width
Dimensions and format.
Definition: format.h:232
mathematics.h
ops_dispatch.h
CompileArgs::backend
const SwsOpBackend * backend
Definition: ops_dispatch.c:522
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
SwsOpExec::in_stride
ptrdiff_t in_stride[4]
Definition: ops_dispatch.h:41
SwsOpPass::tail_blocks
size_t tail_blocks
Definition: ops_dispatch.c:60
SwsOpBackend::name
const char * name
Definition: ops_dispatch.h:134
SwsOpPass::idx_out
int idx_out[4]
Definition: ops_dispatch.c:53
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:77
cpu.h
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:293
ff_sws_op_list_print
void ff_sws_op_list_print(void *log, int lev, int lev_extra, const SwsOpList *ops)
Print out the contents of an operation list.
Definition: ops.c:997
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:45
SwsFrame::data
uint8_t * data[4]
Definition: format.h:226
SwsOpList::num_ops
int num_ops
Definition: ops.h:287
SwsCompFlags
SwsCompFlags
Definition: ops.h:72
SwsOpExec::block_size_in
int32_t block_size_in[4]
Definition: ops_dispatch.h:57
rw_data_planes
static int rw_data_planes(const SwsOp *op)
Definition: ops_dispatch.c:478
SwsOpBackend::hw_format
enum AVPixelFormat hw_format
If NONE, backend only supports software frames.
Definition: ops_dispatch.h:150
SwsOpPass::memcpy_last
bool memcpy_last
Definition: ops_dispatch.c:58
refstruct.h
get_row_data
static void get_row_data(const SwsOpPass *p, const int y_dst, const uint8_t *in[4], uint8_t *out[4])
Definition: ops_dispatch.c:150
safe_blocks_offset
static size_t safe_blocks_offset(size_t num_blocks, unsigned block_size, ptrdiff_t safe_offset, const int32_t *offset_bytes)
Definition: ops_dispatch.c:197
SWS_RW_PACKED
@ SWS_RW_PACKED
Definition: ops.h:100
SwsFrame
Represents a view into a single field of frame data.
Definition: format.h:224
SwsBackend
SwsBackend
Definition: swscale.h:110
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
planes
static const struct @594 planes[]
SwsFrame::format
enum AVPixelFormat format
Definition: format.h:233
SwsPass::priv
void * priv
Definition: graph.h:111
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:60
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
bits
uint8_t bits
Definition: vp3data.h:128
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
SwsGraph::num_passes
int num_passes
Definition: graph.h:134
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: uops.h:61
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
ff_sws_op_list_output
const SwsOp * ff_sws_op_list_output(const SwsOpList *ops)
Returns the output operation for a given op list, or NULL if there is none.
Definition: ops.c:705
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:61
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpPass::comp
SwsCompiledOp comp
Definition: ops_dispatch.c:40
SwsOpBackend
Definition: ops_dispatch.h:133
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
link
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 link
Definition: filter_design.txt:23
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:74
if
if(ret)
Definition: filter_design.txt:179
SwsOpExec
Copyright (C) 2026 Niklas Haas.
Definition: ops_dispatch.h:35
fail
#define fail
Definition: test.h:478
ff_sws_op_list_is_noop
bool ff_sws_op_list_is_noop(const SwsOpList *ops)
Returns whether an op list represents a true no-op operation, i.e.
Definition: ops.c:744
op_pass_free
static void op_pass_free(void *ptr)
Definition: ops_dispatch.c:136
NULL
#define NULL
Definition: coverity.c:32
ff_sws_compiled_op_unref
void ff_sws_compiled_op_unref(SwsCompiledOp *comp)
Definition: ops_dispatch.c:128
av_unreachable
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition: avassert.h:116
av_fast_mallocz
void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size)
Allocate and clear a buffer, reusing the given one if large enough.
Definition: mem.c:562
ff_sws_op_list_split_at
int ff_sws_op_list_split_at(SwsOpList *ops1, SwsOpList **ops2, int index)
Split an op list into two at the given index.
Definition: ops_optimizer.c:1021
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:62
rw_pixel_bits
static int rw_pixel_bits(const SwsOp *op)
Definition: ops_dispatch.c:485
AVPixFmtDescriptor::flags
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:94
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
SwsOpPass::filter_size_h
int filter_size_h
Definition: ops_dispatch.c:56
SwsOpBackend::compile
int(* compile)(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Compile an operation list to an implementation chain.
Definition: ops_dispatch.h:143
AV_ROUND_DOWN
@ AV_ROUND_DOWN
Round toward -infinity.
Definition: mathematics.h:133
SwsOpPass::palette_idx
int palette_idx
Definition: ops_dispatch.c:54
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
SWS_OP_FLAG_SPLIT_MEMCPY
@ SWS_OP_FLAG_SPLIT_MEMCPY
Definition: ops_dispatch.h:173
ff_sws_enabled_backends
SwsBackend ff_sws_enabled_backends(const SwsContext *ctx)
Definition: utils.c:71
SwsFrame::height
int height
Definition: format.h:232
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
SwsOpExec::in_sub_x
uint8_t in_sub_x[4]
Definition: ops_dispatch.h:62
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
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
for
for(k=2;k<=8;++k)
Definition: h264pred_template.c:424
size
int size
Definition: twinvq_data.h:10344
op_pass_setup
static int op_pass_setup(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: ops_dispatch.c:207
SwsOpPass::offsets_y
int * offsets_y
Definition: ops_dispatch.c:55
SwsOpList::src
SwsFormat src
Definition: ops.h:290
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:342
compile_backend
static int compile_backend(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Definition: ops_dispatch.c:65
SwsFormat
Definition: format.h:77
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:553
SWS_COMP
#define SWS_COMP(X)
Definition: uops.h:70
SwsCompiledOp::backend
const struct SwsOpBackend * backend
Definition: ops_dispatch.h:115
align
static const uint8_t *BS_FUNC() align(BSCTX *bc)
Skip bits to a byte boundary.
Definition: bitstream_template.h:419
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
ff_sws_op_list_split_planes
int ff_sws_op_list_split_planes(SwsOpList *ops1, SwsOpList **ops2, SwsCompMask planes)
Reduce an op list into a reduced subset that operates only on a given subset of planes.
Definition: ops_optimizer.c:840
SwsPass::output
SwsPassBuffer * output
Filter output buffer.
Definition: graph.h:99
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
line
Definition: graph2dot.c:48
SWS_COMP_CONST
@ SWS_COMP_CONST
Definition: ops.h:78
align_pass
static void align_pass(SwsPass *pass, int block_size, const int *over_rw, int pixel_bits)
Definition: ops_dispatch.c:502
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
SwsOpPass::planes_in
int planes_in
Definition: ops_dispatch.c:48
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_dispatch.h:38
get_lines_in
static int get_lines_in(const SwsOpPass *p, const int y, const int h, const int plane)
Definition: ops_dispatch.c:161
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:352
SwsPassBuffer::width_align
int width_align
Definition: graph.h:66
SwsOpPass::pixel_bits_out
int pixel_bits_out
Definition: ops_dispatch.c:51
SwsOpExec::in_offset_x
int32_t * in_offset_x
Pixel offset map; for horizontal scaling, in bytes.
Definition: ops_dispatch.h:80
SwsOpPass::planes_out
int planes_out
Definition: ops_dispatch.c:49
AV_ROUND_INF
@ AV_ROUND_INF
Round away from zero.
Definition: mathematics.h:132
SwsOpList::ops
SwsOp * ops
Definition: ops.h:286
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
SwsOpPass::tail_size_in
int tail_size_in
Definition: ops_dispatch.c:46
av_cpu_max_align
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
Definition: cpu.c:287
CompileArgs::graph
SwsGraph * graph
Definition: ops_dispatch.c:523
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
swscale_internal.h
DECLARE_ALIGNED_32
#define DECLARE_ALIGNED_32(t, v)
Definition: mem_internal.h:113
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
ops_internal.h
SwsOpPass
Definition: ops_dispatch.c:39
CompileArgs::flags
int flags
Definition: ops_dispatch.c:524
pixel_bytes
static size_t pixel_bytes(size_t pixels, int pixel_bits, enum AVRounding rounding)
Definition: ops_dispatch.c:173
SwsOp
Definition: ops.h:230
SwsOpPass::memcpy_first
bool memcpy_first
Definition: ops_dispatch.c:57
ret
ret
Definition: filter_design.txt:187
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:290
SwsCompiledOp
Definition: ops_dispatch.h:100
SwsPassBuffer::width_pad
int width_pad
Definition: graph.h:67
SWS_RW_PALETTE
@ SWS_RW_PALETTE
Definition: ops.h:101
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:82
SWS_COMP_COPY
@ SWS_COMP_COPY
Definition: ops.h:77
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
SwsOpPass::num_blocks
size_t num_blocks
Definition: ops_dispatch.c:43
safe_bytes_pad
static size_t safe_bytes_pad(int linesize, int plane_pad)
Definition: ops_dispatch.c:190
SwsOpPass::exec_base
SwsOpExec exec_base
Definition: ops_dispatch.c:41
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, const SwsOpBackend *backend, SwsOpList **pops, int flags, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
Definition: ops_dispatch.c:751
SwsOpPass::pixel_bits_in
int pixel_bits_in
Definition: ops_dispatch.c:50
SwsOpPass::tail_off_in
int tail_off_in
Definition: ops_dispatch.c:44
SwsOpPass::memcpy_out
bool memcpy_out
Definition: ops_dispatch.c:59
CompileArgs
Definition: ops_dispatch.c:521
mem.h
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:122
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
op_pass_run
static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y, const int h, const SwsPass *pass)
Definition: ops_dispatch.c:378
int32_t
int32_t
Definition: audioconvert.c:56
SWS_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops_dispatch.h:167
plane_mask_flags
static SwsCompMask plane_mask_flags(const SwsOp *op, SwsCompFlags flags)
Definition: ops_dispatch.c:677
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
SwsPassBuffer
Represents an output buffer for a filter pass.
Definition: graph.h:59
h
h
Definition: vp9dsp_template.c:2070
width
#define width
Definition: dsp.h:89
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:293
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:285
compile_single
static int compile_single(const CompileArgs *args, const SwsOpList *ops, SwsPass *link, SwsPass *input, SwsPass **output)
Definition: ops_dispatch.c:527
SwsContext
Main external API structure.
Definition: swscale.h:229
SwsOpPass::tail_off_out
int tail_off_out
Definition: ops_dispatch.c:45
SWS_OP_FLAG_DRY_RUN
@ SWS_OP_FLAG_DRY_RUN
Definition: ops_dispatch.h:170
SwsFrame::linesize
int linesize[4]
Definition: format.h:227
AVPixFmtDescriptor::log2_chroma_h
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:89
src
#define src
Definition: vp8dsp.c:248
SwsOpExec::out_bump
ptrdiff_t out_bump[4]
Definition: ops_dispatch.h:52
RET
#define RET(x)
Copyright (C) 2025 Niklas Haas.
Definition: ops_dispatch.c:33
read
static uint32_t BS_FUNC() read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
Definition: bitstream_template.h:239
ff_sws_ops_compile
int ff_sws_ops_compile(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Attempt to compile a list of operations using a specific backend, or the best available backend if ba...
Definition: ops_dispatch.c:106
ff_sws_graph_rollback
void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
Remove all passes added since the given index.
Definition: graph.c:900
ff_sws_comp_mask_str
#define ff_sws_comp_mask_str(mask)
Definition: uops.h:82