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 /* Updates the plane copy (no-op) map for this operation list */
479 static void op_list_get_plane_copy(const SwsOpList *ops, SwsPass *pass)
480 {
481  const SwsOp *write = ff_sws_op_list_output(ops);
482  const SwsOp *read = ff_sws_op_list_input(ops);
483  if (!write || write->rw.mode != SWS_RW_PLANAR ||
484  !read || read->rw.mode != SWS_RW_PLANAR ||
485  read->type != write->type ||
486  read->rw.frac != write->rw.frac)
487  return; /* only regular planes can be directly ref'd */
488 
489  const SwsOp *prev = &ops->ops[ops->num_ops - 2];
490  int *plane_copy = pass->output->plane_copy;
491  for (int i = 0; i < write->rw.elems; i++) {
492  SwsCompFlags flags = prev->comps.flags[i];
493  if (!(flags & SWS_COMP_COPY))
494  continue;
495 
496  const int out_idx = ops->plane_dst[i];
497  switch (prev->comps.dep_in[i]) {
498  case SWS_COMP(0): plane_copy[out_idx] = ops->plane_src[0]; break;
499  case SWS_COMP(1): plane_copy[out_idx] = ops->plane_src[1]; break;
500  case SWS_COMP(2): plane_copy[out_idx] = ops->plane_src[2]; break;
501  case SWS_COMP(3): plane_copy[out_idx] = ops->plane_src[3]; break;
502  }
503  }
504 }
505 
506 static int rw_data_planes(const SwsOp *op)
507 {
508  /* Exclude the palette plane from the plane count, since it does not need
509  * to be directly processed/adjusted by the dispatch layer */
510  return op->rw.mode == SWS_RW_PALETTE ? 1 : ff_sws_rw_op_planes(op);
511 }
512 
513 static int rw_pixel_bits(const SwsOp *op)
514 {
515  if (op->rw.mode == SWS_RW_PALETTE)
516  return 8; /* index size */
517 
518  int elems = 0;
519  switch (op->rw.mode) {
520  case SWS_RW_PLANAR: elems = 1; break;
521  case SWS_RW_PACKED: elems = op->rw.elems; break;
522  }
523 
524  const int size = ff_sws_pixel_type_size(op->type);
525  const int bits = 8 >> op->rw.frac;
526  av_assert1(bits >= 1);
527  return elems * size * bits;
528 }
529 
530 static void align_pass(SwsPass *pass, int block_size, const int *over_rw,
531  int pixel_bits)
532 {
533  if (!pass || pixel_bits <= 0)
534  return;
535 
536  /* Add at least as many pixels as needed to cover the padding requirement */
537  int pad_max = 0;
538  for (int i = 0; i < 4; i++) {
539  const int pad = (over_rw[i] * 8 + pixel_bits - 1) / pixel_bits;
540  pad_max = FFMAX(pad_max, pad);
541  }
542 
543  SwsPassBuffer *buf = pass->output;
544  buf->width_align = FFMAX(buf->width_align, block_size);
545  buf->width_pad = FFMAX(buf->width_pad, pad_max);
546 }
547 
548 /* Unchanging part of parameter list */
549 typedef struct CompileArgs {
552  int flags;
553 } CompileArgs;
554 
555 static int compile_single(const CompileArgs *args, const SwsOpList *ops,
557 {
558  SwsGraph *graph = args->graph;
559  SwsContext *ctx = graph->ctx;
560  SwsOpPass *p = av_mallocz(sizeof(*p));
561  if (!p)
562  return AVERROR(ENOMEM);
563 
564  int ret = ff_sws_ops_compile(ctx, args->backend, ops, &p->comp);
565  if (ret < 0)
566  goto fail;
567  else if (args->flags & SWS_OP_FLAG_DRY_RUN)
568  goto fail; /* nothing to do, just return */
569 
570  const SwsCompiledOp *comp = &p->comp;
571  const SwsFormat *src = &ops->src;
572  const SwsFormat *dst = &ops->dst;
573  av_assert0(!link || link->format == dst->format);
574  if (p->comp.opaque) {
575  SwsCompiledOp c = *comp;
576  av_free(p);
577  ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
578  input, 0, c.slice_align, c.func_opaque,
579  NULL, c.priv, c.free, output);
580  if (ret >= 0) {
581  (*output)->backend = c.backend->flags;
584  }
585  return ret;
586  }
587 
588  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(src->format);
589  const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(dst->format);
590  const SwsOp *write = ff_sws_op_list_output(ops);
591  p->planes_out = rw_data_planes(write);
592  p->pixel_bits_out = rw_pixel_bits(write);
593  p->palette_idx = -1;
594  p->exec_base = (SwsOpExec) {
595  .width = dst->width,
596  .height = dst->height,
597  };
598 
599  const SwsOp *read = ff_sws_op_list_input(ops);
600  if (read) {
601  p->planes_in = rw_data_planes(read);
602  p->pixel_bits_in = rw_pixel_bits(read);
603  if (read->rw.mode == SWS_RW_PALETTE)
604  p->palette_idx = ops->plane_src[1];
605  }
606 
607  const int64_t block_bits_in = (int64_t) comp->block_size * p->pixel_bits_in;
608  const int64_t block_bits_out = (int64_t) comp->block_size * p->pixel_bits_out;
609  if (block_bits_in & 0x7 || block_bits_out & 0x7) {
610  av_log(ctx, AV_LOG_ERROR, "Block size must be byte-aligned.\n");
611  ret = AVERROR(EINVAL);
612  goto fail;
613  }
614 
615  for (int i = 0; i < 4; i++)
616  p->idx_in[i] = p->idx_out[i] = -1;
617 
618  for (int i = 0; i < p->planes_in; i++) {
619  const int idx = ops->plane_src[i];
620  const int chroma = idx == 1 || idx == 2;
621  const int sub_x = chroma ? indesc->log2_chroma_w : 0;
622  const int sub_y = chroma ? indesc->log2_chroma_h : 0;
623  p->exec_base.in_sub_x[i] = sub_x;
624  p->exec_base.in_sub_y[i] = sub_y;
625  p->exec_base.block_size_in[i] = block_bits_in >> 3;
626  p->idx_in[i] = idx;
627  }
628 
629  for (int i = 0; i < p->planes_out; i++) {
630  const int idx = ops->plane_dst[i];
631  const int chroma = idx == 1 || idx == 2;
632  const int sub_x = chroma ? outdesc->log2_chroma_w : 0;
633  const int sub_y = chroma ? outdesc->log2_chroma_h : 0;
634  p->exec_base.out_sub_x[i] = sub_x;
635  p->exec_base.out_sub_y[i] = sub_y;
636  p->exec_base.block_size_out[i] = block_bits_out >> 3;
637  p->idx_out[i] = idx;
638  }
639 
640  const SwsFilterWeights *filter = read ? read->rw.filter.kernel : NULL;
641  if (read && read->rw.filter.op == SWS_OP_FILTER_V) {
642  p->offsets_y = av_refstruct_ref(filter->offsets);
643 
644  /* Compute relative pointer bumps for each output line */
645  int32_t *bump = av_malloc_array(filter->dst_size, sizeof(*bump));
646  if (!bump) {
647  ret = AVERROR(ENOMEM);
648  goto fail;
649  }
650 
651  int line = filter->offsets[0];
652  for (int y = 0; y < filter->dst_size - 1; y++) {
653  int next = filter->offsets[y + 1];
654  bump[y] = next - line - 1;
655  line = next;
656  }
657  bump[filter->dst_size - 1] = 0;
658  p->exec_base.in_bump_y = bump;
659  } else if (read && read->rw.filter.op == SWS_OP_FILTER_H) {
660  /* Compute pixel offset map for each output line */
661  const int pixels = FFALIGN(filter->dst_size, p->comp.block_size);
662  int32_t *offset = av_malloc_array(pixels, sizeof(*offset));
663  if (!offset) {
664  ret = AVERROR(ENOMEM);
665  goto fail;
666  }
667  p->exec_base.in_offset_x = offset;
668 
669  for (int x = 0; x < filter->dst_size; x++) {
670  /* Sanity check; if the tap would land on a half-pixel, we cannot
671  * reasonably expect the implementation to know about this. Just
672  * error out in such (theoretical) cases. */
673  int64_t bits = (int64_t) filter->offsets[x] * p->pixel_bits_in;
674  if ((bits & 0x7) || (bits >> 3) > INT32_MAX) {
675  ret = AVERROR(EINVAL);
676  goto fail;
677  }
678  offset[x] = bits >> 3;
679  }
680  for (int x = filter->dst_size; x < pixels; x++)
681  offset[x] = offset[filter->dst_size - 1];
682  for (int i = 0; i < 4; i++)
683  p->exec_base.block_size_in[i] = 0; /* ptr does not advance */
684  p->filter_size_h = filter->filter_size;
685  }
686 
687  ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
688  input, 0, comp->slice_align, op_pass_run,
690  if (ret < 0)
691  return ret;
692 
693  (*output)->backend = comp->backend->flags;
696  align_pass(*output, comp->block_size, comp->over_write, p->pixel_bits_out);
697  if (read)
698  align_pass(input, comp->block_size, comp->over_read, p->pixel_bits_in);
699  return 0;
700 
701 fail:
702  op_pass_free(p);
703  return ret;
704 }
705 
706 /* Return a mask of all planes matching any flag in `flags` */
708 {
709  SwsCompMask planes = 0;
710  for (int c = 0; c < 4; c++) {
711  if (op->comps.flags[c] & flags)
712  planes |= SWS_COMP(c);
713  }
714 
715  return planes;
716 }
717 
718 /* Takes over ownership of *pops, even on failure */
719 static int compile_subpass(const CompileArgs *args, SwsOpList **pops,
721 {
722  int ret;
723  SwsContext *ctx = args->graph->ctx;
724  SwsOpList *ops = *pops;
725  SwsOpList *rest = NULL;
726  SwsPass *tmp = NULL;
727  *pops = NULL;
728 
729  if (args->flags & SWS_OP_FLAG_SPLIT_MEMCPY) {
730  /* Split off copied and constant planes into a separate subpass,
731  * since these are likely to be handled by the memcpy backend */
732  av_assert0(ops->num_ops >= 2);
733  const SwsOp *prev = &ops->ops[ops->num_ops - 2];
735  RET(ff_sws_op_list_split_planes(ops, &rest, planes));
736  if (rest) {
737  /* Parallel split: share input and link all outputs together */
738  av_log(ctx, AV_LOG_DEBUG, "Splitting const/memcpy planes: %s\n",
740  RET(compile_subpass(args, &ops, link, input, &tmp));
741  RET(compile_subpass(args, &rest, tmp, input, output));
742  return 0;
743  }
744  }
745 
746  ret = compile_single(args, ops, link, input, output);
747  if (ret != AVERROR(ENOTSUP))
748  goto fail; /* either success or a hard error */
749 
750  /* Find any unresolved filter */
751  for (int idx = 1; idx < ops->num_ops - 1; idx++) {
752  const SwsOp *op = &ops->ops[idx];
753  if (op->op == SWS_OP_FILTER_H || op->op == SWS_OP_FILTER_V) {
754  RET(ff_sws_op_list_split_at(ops, &rest, idx));
755  if (ff_sws_op_list_is_noop(ops)) {
756  /* Prevent infinite recursion by avoiding splitting in a way
757  * that does not meaningfully reduce the number of operations
758  * performed in the second part. */
759  FFSWAP(SwsOpList *, ops, rest);
760  break;
761  }
762  /* Serial split: feed first pass into second */
763  RET(compile_subpass(args, &ops, NULL, input, &tmp));
764  RET(compile_subpass(args, &rest, link, tmp, output));
765  return 0;
766  }
767  }
768 
769  /* If we didn't find any more operations to eliminate, then this ops list
770  * is simply unsupported by any of the available backends */
771  av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n");
773  ret = AVERROR(ENOTSUP);
774 
775 fail:
776  ff_sws_op_list_free(&ops);
777  ff_sws_op_list_free(&rest);
778  return ret;
779 }
780 
781 int ff_sws_compile_pass(SwsGraph *graph, const SwsOpBackend *backend,
782  SwsOpList **pops, int flags, SwsPass *input,
783  SwsPass **output)
784 {
785  const int passes_orig = graph->num_passes;
786  SwsContext *ctx = graph->ctx;
787  SwsOpList *ops = *pops;
788  int ret = 0;
789 
790  const SwsOp *write = ff_sws_op_list_output(ops);
791  if (!write) {
792  av_log(ctx, AV_LOG_ERROR, "Last operation must be SWS_OP_WRITE.\n");
793  ret = AVERROR(EINVAL);
794  goto out;
795  }
796 
797  if (flags & SWS_OP_FLAG_OPTIMIZE) {
799  if (ret < 0)
800  goto out;
801  av_log(ctx, AV_LOG_DEBUG, "Operation list after optimizing:\n");
803  }
804 
805  /* Check if the whole operation graph is an end-to-end no-op */
806  if (ff_sws_op_list_is_noop(ops)) {
807  if (output)
808  *output = input;
809  goto out;
810  }
811 
812  const CompileArgs args = {
813  .backend = backend,
814  .graph = graph,
815  .flags = flags,
816  };
817 
818  ret = compile_subpass(&args, &ops, NULL, input, output);
819  if (ret < 0)
820  goto out;
821 
822  const int num_passes = graph->num_passes - passes_orig;
823  if (num_passes > 1)
824  av_log(ctx, AV_LOG_VERBOSE, "Using %d separate passes.\n", num_passes);
825 
826 out:
827  if (ret < 0)
828  ff_sws_graph_rollback(graph, passes_orig);
829  ff_sws_op_list_free(&ops);
830  *pops = NULL;
831  return ret;
832 }
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:191
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:659
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:133
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:133
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:85
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:249
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:673
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:107
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:136
SwsOpExec::in_bump
ptrdiff_t in_bump[4]
Pointer bump, difference between stride and processed line size.
Definition: ops_dispatch.h:52
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:713
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3460
SwsPass::lines
int lines
Definition: graph.h:96
SwsOpExec::out_stride
ptrdiff_t out_stride[4]
Definition: ops_dispatch.h:43
SwsOpExec::in
const uint8_t * in[4]
Definition: ops_dispatch.h:38
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
SwsOp::rw
SwsReadWriteOp rw
Definition: ops.h:242
compile_subpass
static int compile_subpass(const CompileArgs *args, SwsOpList **pops, SwsPass *link, SwsPass *input, SwsPass **output)
Definition: ops_dispatch.c:719
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:59
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
SwsFrame::width
int width
Dimensions and format.
Definition: format.h:244
mathematics.h
ops_dispatch.h
CompileArgs::backend
const SwsOpBackend * backend
Definition: ops_dispatch.c:550
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
SwsOpExec::in_stride
ptrdiff_t in_stride[4]
Definition: ops_dispatch.h:42
SwsOpPass::tail_blocks
size_t tail_blocks
Definition: ops_dispatch.c:60
SwsOpBackend::name
const char * name
Definition: ops_dispatch.h:135
SwsOpPass::idx_out
int idx_out[4]
Definition: ops_dispatch.c:53
cpu.h
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:301
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:987
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:42
SwsFrame::data
uint8_t * data[4]
Definition: format.h:238
SwsOpList::num_ops
int num_ops
Definition: ops.h:295
SwsCompFlags
SwsCompFlags
Definition: ops.h:77
SwsOpExec::block_size_in
int32_t block_size_in[4]
Definition: ops_dispatch.h:58
rw_data_planes
static int rw_data_planes(const SwsOp *op)
Definition: ops_dispatch.c:506
SwsOpBackend::hw_format
enum AVPixelFormat hw_format
If NONE, backend only supports software frames.
Definition: ops_dispatch.h:155
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:108
SwsFrame
Represents a view into a single field of frame data.
Definition: format.h:236
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
SwsFrame::format
enum AVPixelFormat format
Definition: format.h:245
SwsPass::priv
void * priv
Definition: graph.h:121
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:504
SwsPassBuffer::plane_copy
int plane_copy[4]
Map of planes which are directly copied from the pass input.
Definition: graph.h:77
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:154
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
SwsCompMask
uint8_t SwsCompMask
Bit-mask of components.
Definition: uops.h:88
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:722
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:63
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:134
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
ff_sws_pixel_type_size
static av_const int ff_sws_pixel_type_size(SwsPixelType type)
Definition: uops.h:50
SwsOpExec
Copyright (C) 2026 Niklas Haas.
Definition: ops_dispatch.h:36
fail
#define fail
Definition: test.h:479
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:761
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
op_list_get_plane_copy
static void op_list_get_plane_copy(const SwsOpList *ops, SwsPass *pass)
Definition: ops_dispatch.c:479
av_unreachable
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition: avassert.h:116
SwsReadWriteOp::frac
uint8_t frac
Definition: ops.h:124
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:560
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:1113
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:64
rw_pixel_bits
static int rw_pixel_bits(const SwsOp *op)
Definition: ops_dispatch.c:513
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:178
ff_sws_enabled_backends
SwsBackend ff_sws_enabled_backends(const SwsContext *ctx)
Definition: utils.c:60
SwsFrame::height
int height
Definition: format.h:244
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:63
filter
void(* filter)(uint8_t *src, ptrdiff_t stride, int qscale)
Definition: h263dsp.c:29
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
SwsOp::type
SwsPixelType type
Definition: ops.h:239
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:298
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:315
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:559
SWS_COMP
#define SWS_COMP(X)
Definition: uops.h:97
SwsCompiledOp::backend
const struct SwsOpBackend * backend
Definition: ops_dispatch.h:116
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:836
SwsPass::output
SwsPassBuffer * output
Filter output buffer.
Definition: graph.h:109
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
SwsOp::comps
SwsComps comps
Metadata about the operation's input/output components.
Definition: ops.h:262
SWS_COMP_CONST
@ SWS_COMP_CONST
Definition: ops.h:83
align_pass
static void align_pass(SwsPass *pass, int block_size, const int *over_rw, int pixel_bits)
Definition: ops_dispatch.c:530
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:39
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:342
SwsPassBuffer::width_align
int width_align
Definition: graph.h:67
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:81
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
av_malloc_array
#define av_malloc_array(a, b)
Definition: tableprint_vlc.h:32
SwsOpList::ops
SwsOp * ops
Definition: ops.h:294
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:551
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:552
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:237
SwsOpPass::memcpy_first
bool memcpy_first
Definition: ops_dispatch.c:57
SwsComps::flags
SwsCompFlags flags[4]
Definition: ops.h:87
ret
ret
Definition: filter_design.txt:187
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
SwsOpList::dst
SwsFormat dst
Definition: ops.h:298
SwsCompiledOp
Definition: ops_dispatch.h:101
SwsPassBuffer::width_pad
int width_pad
Definition: graph.h:68
SWS_RW_PALETTE
@ SWS_RW_PALETTE
Definition: ops.h:109
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:82
SWS_COMP_COPY
@ SWS_COMP_COPY
Definition: ops.h:82
SwsComps::dep_in
SwsCompMask dep_in[4]
Definition: ops.h:94
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:781
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
SwsReadWriteOp::elems
uint8_t elems
Definition: ops.h:123
CompileArgs
Definition: ops_dispatch.c:549
mem.h
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:132
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:172
plane_mask_flags
static SwsCompMask plane_mask_flags(const SwsOp *op, SwsCompFlags flags)
Definition: ops_dispatch.c:707
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
planes
static const struct @609 planes[]
SwsPassBuffer
Represents an output buffer for a filter pass.
Definition: graph.h:60
h
h
Definition: vp9dsp_template.c:2070
SwsReadWriteOp::mode
SwsReadWriteMode mode
Examples: rgba = 4x u8 packed yuv444p = 3x u8 rgb565 = 1x u16 <- use SWS_OP_UNPACK to unpack monow = ...
Definition: ops.h:122
width
#define width
Definition: dsp.h:89
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:301
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:293
compile_single
static int compile_single(const CompileArgs *args, const SwsOpList *ops, SwsPass *link, SwsPass *input, SwsPass **output)
Definition: ops_dispatch.c:555
SwsContext
Main external API structure.
Definition: swscale.h:227
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:175
SwsFrame::linesize
int linesize[4]
Definition: format.h:239
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:53
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:935
ff_sws_comp_mask_str
#define ff_sws_comp_mask_str(mask)
Definition: uops.h:110