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/mem.h"
24 #include "libavutil/mem_internal.h"
25 #include "libavutil/refstruct.h"
26 
27 #include "ops.h"
28 #include "ops_internal.h"
29 #include "ops_dispatch.h"
30 
31 typedef struct SwsOpPass {
40  int planes_in;
44  int idx_in[4];
45  int idx_out[4];
46  int *offsets_y;
50  bool memcpy_out;
51  uint8_t *tail_buf; /* extra memory for fixing unpadded tails */
52  unsigned int tail_buf_size;
53 } SwsOpPass;
54 
56  const SwsOpList *ops, SwsCompiledOp *out)
57 {
58  SwsOpList *copy;
59  SwsCompiledOp compiled = {0};
60  int ret = 0;
61 
63  if (!copy)
64  return AVERROR(ENOMEM);
65 
66  /* Ensure these are always set during compilation */
68 
69  ret = backend->compile(ctx, copy, &compiled);
70  if (ret < 0) {
71  int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR;
72  av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n",
73  backend->name, av_err2str(ret));
74  } else {
75  *out = compiled;
76  }
77 
79  return ret;
80 }
81 
83 {
84  for (int n = 0; ff_sws_op_backends[n]; n++) {
85  const SwsOpBackend *backend = ff_sws_op_backends[n];
86  if (ops->src.hw_format != backend->hw_format ||
87  ops->dst.hw_format != backend->hw_format)
88  continue;
89  if (ff_sws_ops_compile_backend(ctx, backend, ops, out) < 0)
90  continue;
91 
92  av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': "
93  "block size = %d, over-read = %d, over-write = %d, cpu flags = 0x%x\n",
94  backend->name, out->block_size, out->over_read, out->over_write,
95  out->cpu_flags);
96 
98  return 0;
99  }
100 
101  return AVERROR(ENOTSUP);
102 }
103 
105 {
106  if (comp->free)
107  comp->free(comp->priv);
108 
109  *comp = (SwsCompiledOp) {0};
110 }
111 
112 static void op_pass_free(void *ptr)
113 {
114  SwsOpPass *p = ptr;
115  if (!p)
116  return;
117 
118  ff_sws_compiled_op_unref(&p->comp);
119  av_refstruct_unref(&p->offsets_y);
120  av_free(p->exec_base.in_bump_y);
121  av_free(p->exec_base.in_offset_x);
122  av_free(p->tail_buf);
123  av_free(p);
124 }
125 
126 static inline void get_row_data(const SwsOpPass *p, const int y_dst,
127  const uint8_t *in[4], uint8_t *out[4])
128 {
129  const SwsOpExec *base = &p->exec_base;
130  const int y_src = p->offsets_y ? p->offsets_y[y_dst] : y_dst;
131  for (int i = 0; i < p->planes_in; i++)
132  in[i] = base->in[i] + (y_src >> base->in_sub_y[i]) * base->in_stride[i];
133  for (int i = 0; i < p->planes_out; i++)
134  out[i] = base->out[i] + (y_dst >> base->out_sub_y[i]) * base->out_stride[i];
135 }
136 
137 static int op_pass_setup(const SwsFrame *out, const SwsFrame *in,
138  const SwsPass *pass)
139 {
140  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->format);
141  const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format);
142 
143  SwsOpPass *p = pass->priv;
144  SwsOpExec *exec = &p->exec_base;
145  const SwsCompiledOp *comp = &p->comp;
146 
147  /* Set up main loop parameters */
148  const int block_size = comp->block_size;
149  const int num_blocks = (pass->width + block_size - 1) / block_size;
150  const int aligned_w = num_blocks * block_size;
151  p->num_blocks = num_blocks;
152  p->memcpy_first = false;
153  p->memcpy_last = false;
154  p->memcpy_out = false;
155 
156  for (int i = 0; i < p->planes_in; i++) {
157  const int idx = p->idx_in[i];
158  const int chroma = idx == 1 || idx == 2;
159  const int sub_x = chroma ? indesc->log2_chroma_w : 0;
160  const int sub_y = chroma ? indesc->log2_chroma_h : 0;
161  const int plane_w = AV_CEIL_RSHIFT(aligned_w, sub_x);
162  const int plane_pad = AV_CEIL_RSHIFT(comp->over_read, sub_x);
163  const int plane_size = plane_w * p->pixel_bits_in >> 3;
164  const int total_size = plane_size + plane_pad;
165  const int loop_size = num_blocks * exec->block_size_in;
166  if (in->linesize[idx] >= 0) {
167  p->memcpy_last |= total_size > in->linesize[idx];
168  } else {
169  p->memcpy_first |= total_size > -in->linesize[idx];
170  }
171  exec->in[i] = in->data[idx];
172  exec->in_stride[i] = in->linesize[idx];
173  exec->in_bump[i] = in->linesize[idx] - loop_size;
174  exec->in_sub_y[i] = sub_y;
175  exec->in_sub_x[i] = sub_x;
176  }
177 
178  for (int i = 0; i < p->planes_out; i++) {
179  const int idx = p->idx_out[i];
180  const int chroma = idx == 1 || idx == 2;
181  const int sub_x = chroma ? outdesc->log2_chroma_w : 0;
182  const int sub_y = chroma ? outdesc->log2_chroma_h : 0;
183  const int plane_w = AV_CEIL_RSHIFT(aligned_w, sub_x);
184  const int plane_pad = AV_CEIL_RSHIFT(comp->over_write, sub_x);
185  const int plane_size = plane_w * p->pixel_bits_out >> 3;
186  const int loop_size = num_blocks * exec->block_size_out;
187  p->memcpy_out |= plane_size + plane_pad > FFABS(out->linesize[idx]);
188  exec->out[i] = out->data[idx];
189  exec->out_stride[i] = out->linesize[idx];
190  exec->out_bump[i] = out->linesize[idx] - loop_size;
191  exec->out_sub_y[i] = sub_y;
192  exec->out_sub_x[i] = sub_x;
193  }
194 
195  const bool memcpy_in = p->memcpy_first || p->memcpy_last;
196  if (!memcpy_in && !p->memcpy_out)
197  return 0;
198 
199  /* Set-up tail section parameters and buffers */
200  SwsOpExec *tail = &p->exec_tail;
201  const int align = av_cpu_max_align();
202  size_t alloc_size = 0;
203  *tail = *exec;
204 
205  const int safe_width = (num_blocks - 1) * block_size;
206  const int tail_size = pass->width - safe_width;
207  p->tail_off_out = safe_width * p->pixel_bits_out >> 3;
208  p->tail_size_out = (tail_size * p->pixel_bits_out + 7) >> 3;
209 
210  if (exec->in_offset_x) {
211  p->tail_off_in = exec->in_offset_x[safe_width];
212  p->tail_size_in = exec->in_offset_x[pass->width - 1] - p->tail_off_in;
213  p->tail_size_in += (p->filter_size * p->pixel_bits_in + 7) >> 3;
214  } else {
215  p->tail_off_in = safe_width * p->pixel_bits_in >> 3;
216  p->tail_size_in = (tail_size * p->pixel_bits_in + 7) >> 3;
217  }
218 
219  for (int i = 0; memcpy_in && i < p->planes_in; i++) {
220  size_t block_size = (comp->block_size * p->pixel_bits_in + 7) >> 3;
221  block_size += comp->over_read;
222  block_size = FFMAX(block_size, p->tail_size_in);
223  tail->in_stride[i] = FFALIGN(block_size, align);
224  tail->in_bump[i] = tail->in_stride[i] - exec->block_size_in;
225  alloc_size += tail->in_stride[i] * in->height;
226  }
227 
228  for (int i = 0; p->memcpy_out && i < p->planes_out; i++) {
229  size_t block_size = (comp->block_size * p->pixel_bits_out + 7) >> 3;
230  block_size += comp->over_write;
231  block_size = FFMAX(block_size, p->tail_size_out);
232  tail->out_stride[i] = FFALIGN(block_size, align);
233  tail->out_bump[i] = tail->out_stride[i] - exec->block_size_out;
234  alloc_size += tail->out_stride[i] * out->height;
235  }
236 
237  if (memcpy_in && exec->in_offset_x) {
238  /* `in_offset_x` is indexed relative to the line start, not the start
239  * of the section being processed; so we need to over-allocate this
240  * array to the full width of the image, even though we will only
241  * partially fill in the offsets relevant to the tail region */
242  alloc_size += aligned_w * sizeof(*exec->in_offset_x);
243  }
244 
245  uint8_t *tail_buf = av_fast_realloc(p->tail_buf, &p->tail_buf_size, alloc_size);
246  if (!tail_buf)
247  return AVERROR(ENOMEM);
248  p->tail_buf = tail_buf;
249 
250  for (int i = 0; memcpy_in && i < p->planes_in; i++) {
251  tail->in[i] = tail_buf;
252  tail_buf += tail->in_stride[i] * in->height;
253  }
254 
255  for (int i = 0; p->memcpy_out && i < p->planes_out; i++) {
256  tail->out[i] = tail_buf;
257  tail_buf += tail->out_stride[i] * out->height;
258  }
259 
260  if (memcpy_in && exec->in_offset_x) {
261  tail->in_offset_x = (int32_t *) tail_buf;
262  for (int i = safe_width; i < aligned_w; i++)
263  tail->in_offset_x[i] = exec->in_offset_x[i] - p->tail_off_in;
264  }
265 
266  return 0;
267 }
268 
269 static void copy_lines(uint8_t *dst, const size_t dst_stride,
270  const uint8_t *src, const size_t src_stride,
271  const int h, const size_t bytes)
272 {
273  for (int y = 0; y < h; y++) {
274  memcpy(dst, src, bytes);
275  dst += dst_stride;
276  src += src_stride;
277  }
278 }
279 
280 static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y,
281  const int h, const SwsPass *pass)
282 {
283  const SwsOpPass *p = pass->priv;
284  const SwsCompiledOp *comp = &p->comp;
285 
286  /* Fill exec metadata for this slice */
287  DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base;
288  exec.slice_y = y;
289  exec.slice_h = h;
290 
291  /**
292  * To ensure safety, we need to consider the following:
293  *
294  * 1. We can overread the input, unless this is the last line of an
295  * unpadded buffer. All defined operations can handle arbitrary pixel
296  * input, so overread of arbitrary data is fine. For flipped images,
297  * this condition is actually *inverted* to where the first line is
298  * the one at the end of the buffer.
299  *
300  * 2. We can overwrite the output, as long as we don't write more than the
301  * amount of pixels that fit into one linesize. So we always need to
302  * memcpy the last column on the output side if unpadded.
303  */
304 
305  const bool memcpy_in = p->memcpy_last && y + h == pass->height ||
306  p->memcpy_first && y == 0;
307  const bool memcpy_out = p->memcpy_out;
308  const int num_blocks = p->num_blocks;
309 
310  get_row_data(p, y, exec.in, exec.out);
311  if (!memcpy_in && !memcpy_out) {
312  /* Fast path (fully aligned/padded inputs and outputs) */
313  comp->func(&exec, comp->priv, 0, y, num_blocks, y + h);
314  return;
315  }
316 
317  /* Non-aligned case (slow path); process num_blocks - 1 main blocks and
318  * a separate tail (via memcpy into an appropriately padded buffer) */
319  for (int i = 0; i < 4; i++) {
320  /* We process one fewer block, so the in_bump needs to be increased
321  * to reflect that the plane pointers are left on the last block,
322  * not the end of the processed line, after each loop iteration */
323  exec.in_bump[i] += exec.block_size_in;
324  exec.out_bump[i] += exec.block_size_out;
325  }
326 
327  comp->func(&exec, comp->priv, 0, y, num_blocks - 1, y + h);
328 
329  DECLARE_ALIGNED_32(SwsOpExec, tail) = p->exec_tail;
330  tail.slice_y = y;
331  tail.slice_h = h;
332 
333  for (int i = 0; i < p->planes_in; i++) {
334  /* Input offsets are relative to the base pointer */
335  if (!exec.in_offset_x || memcpy_in)
336  exec.in[i] += p->tail_off_in;
337  tail.in[i] += y * tail.in_stride[i];
338  }
339  for (int i = 0; i < p->planes_out; i++) {
340  exec.out[i] += p->tail_off_out;
341  tail.out[i] += y * tail.out_stride[i];
342  }
343 
344  for (int i = 0; i < p->planes_in; i++) {
345  if (memcpy_in) {
346  copy_lines((uint8_t *) tail.in[i], tail.in_stride[i],
347  exec.in[i], exec.in_stride[i], h, p->tail_size_in);
348  } else {
349  /* Reuse input pointers directly */
350  tail.in[i] = exec.in[i];
351  tail.in_stride[i] = exec.in_stride[i];
352  tail.in_bump[i] = exec.in_stride[i] - exec.block_size_in;
353  }
354  }
355 
356  for (int i = 0; !memcpy_out && i < p->planes_out; i++) {
357  /* Reuse output pointers directly */
358  tail.out[i] = exec.out[i];
359  tail.out_stride[i] = exec.out_stride[i];
360  tail.out_bump[i] = exec.out_stride[i] - exec.block_size_out;
361  }
362 
363  /* Dispatch kernel over tail */
364  comp->func(&tail, comp->priv, num_blocks - 1, y, num_blocks, y + h);
365 
366  for (int i = 0; memcpy_out && i < p->planes_out; i++) {
367  copy_lines(exec.out[i], exec.out_stride[i],
368  tail.out[i], tail.out_stride[i], h, p->tail_size_out);
369  }
370 }
371 
372 static int rw_planes(const SwsOp *op)
373 {
374  return op->rw.packed ? 1 : op->rw.elems;
375 }
376 
377 static int rw_pixel_bits(const SwsOp *op)
378 {
379  const int elems = op->rw.packed ? op->rw.elems : 1;
380  const int size = ff_sws_pixel_type_size(op->type);
381  const int bits = 8 >> op->rw.frac;
382  av_assert1(bits >= 1);
383  return elems * size * bits;
384 }
385 
386 static int compile(SwsGraph *graph, const SwsOpList *ops, SwsPass *input,
387  SwsPass **output)
388 {
389  SwsContext *ctx = graph->ctx;
390  SwsOpPass *p = av_mallocz(sizeof(*p));
391  if (!p)
392  return AVERROR(ENOMEM);
393 
394  int ret = ff_sws_ops_compile(ctx, ops, &p->comp);
395  if (ret < 0)
396  goto fail;
397 
398  const SwsFormat *dst = &ops->dst;
399  if (p->comp.opaque) {
400  SwsCompiledOp c = p->comp;
401  av_free(p);
402  return ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
403  input, c.slice_align, c.func_opaque,
404  NULL, c.priv, c.free, output);
405  }
406 
407  const SwsOp *read = ff_sws_op_list_input(ops);
408  const SwsOp *write = ff_sws_op_list_output(ops);
409  p->planes_in = rw_planes(read);
410  p->planes_out = rw_planes(write);
411  p->pixel_bits_in = rw_pixel_bits(read);
412  p->pixel_bits_out = rw_pixel_bits(write);
413  p->exec_base = (SwsOpExec) {
414  .width = dst->width,
415  .height = dst->height,
416  .block_size_in = p->comp.block_size * p->pixel_bits_in >> 3,
417  .block_size_out = p->comp.block_size * p->pixel_bits_out >> 3,
418  };
419 
420  for (int i = 0; i < 4; i++) {
421  p->idx_in[i] = i < p->planes_in ? ops->plane_src[i] : -1;
422  p->idx_out[i] = i < p->planes_out ? ops->plane_dst[i] : -1;
423  }
424 
425  const SwsFilterWeights *filter = read->rw.kernel;
426  if (read->rw.filter == SWS_OP_FILTER_V) {
427  p->offsets_y = av_refstruct_ref(filter->offsets);
428 
429  /* Compute relative pointer bumps for each output line */
430  int32_t *bump = av_malloc_array(filter->dst_size, sizeof(*bump));
431  if (!bump) {
432  ret = AVERROR(ENOMEM);
433  goto fail;
434  }
435 
436  int line = filter->offsets[0];
437  for (int y = 0; y < filter->dst_size - 1; y++) {
438  int next = filter->offsets[y + 1];
439  bump[y] = next - line - 1;
440  line = next;
441  }
442  bump[filter->dst_size - 1] = 0;
443  p->exec_base.in_bump_y = bump;
444  } else if (read->rw.filter == SWS_OP_FILTER_H) {
445  /* Compute pixel offset map for each output line */
446  const int pixels = FFALIGN(filter->dst_size, p->comp.block_size);
447  int32_t *offset = av_malloc_array(pixels, sizeof(*offset));
448  if (!offset) {
449  ret = AVERROR(ENOMEM);
450  goto fail;
451  }
452 
453  for (int x = 0; x < filter->dst_size; x++)
454  offset[x] = filter->offsets[x] * p->pixel_bits_in >> 3;
455  for (int x = filter->dst_size; x < pixels; x++)
456  offset[x] = offset[filter->dst_size - 1];
457  p->exec_base.in_offset_x = offset;
458  p->exec_base.block_size_in = 0; /* ptr does not advance */
459  p->filter_size = filter->filter_size;
460  }
461 
462  return ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
463  input, p->comp.slice_align, op_pass_run,
465 
466 fail:
467  op_pass_free(p);
468  return ret;
469 }
470 
471 int ff_sws_compile_pass(SwsGraph *graph, SwsOpList **pops, int flags,
473 {
474  const int passes_orig = graph->num_passes;
475  SwsContext *ctx = graph->ctx;
476  SwsOpList *ops = *pops;
477  int ret = 0;
478 
479  /* Check if the whole operation graph is an end-to-end no-op */
480  if (ff_sws_op_list_is_noop(ops)) {
481  *output = input;
482  goto out;
483  }
484 
485  const SwsOp *read = ff_sws_op_list_input(ops);
486  const SwsOp *write = ff_sws_op_list_output(ops);
487  if (!read || !write) {
488  av_log(ctx, AV_LOG_ERROR, "First and last operations must be a read "
489  "and write, respectively.\n");
490  ret = AVERROR(EINVAL);
491  goto out;
492  }
493 
494  if (flags & SWS_OP_FLAG_OPTIMIZE) {
496  if (ret < 0)
497  goto out;
498  av_log(ctx, AV_LOG_DEBUG, "Operation list after optimizing:\n");
500  }
501 
502  ret = compile(graph, ops, input, output);
503  if (ret != AVERROR(ENOTSUP))
504  goto out;
505 
506  av_log(ctx, AV_LOG_DEBUG, "Retrying with separated filter passes.\n");
507  SwsPass *prev = input;
508  while (ops) {
509  SwsOpList *rest;
510  ret = ff_sws_op_list_subpass(ops, &rest);
511  if (ret < 0)
512  goto out;
513 
514  if (prev == input && !rest) {
515  /* No point in compiling an unsplit pass again */
516  ret = AVERROR(ENOTSUP);
517  goto out;
518  }
519 
520  ret = compile(graph, ops, prev, &prev);
521  if (ret < 0) {
522  ff_sws_op_list_free(&rest);
523  goto out;
524  }
525 
526  ff_sws_op_list_free(&ops);
527  ops = rest;
528  }
529 
530  /* Return last subpass successfully compiled */
531  av_log(ctx, AV_LOG_VERBOSE, "Using %d separate passes.\n",
532  graph->num_passes - passes_orig);
533  *output = prev;
534 
535 out:
536  if (ret == AVERROR(ENOTSUP)) {
537  av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n");
539  }
540  if (ret < 0)
541  ff_sws_graph_rollback(graph, passes_orig);
542  ff_sws_op_list_free(&ops);
543  *pops = NULL;
544  return ret;
545 }
flags
const SwsFlags flags[]
Definition: swscale.c:71
SwsOpPass::tail_buf
uint8_t * tail_buf
Definition: ops_dispatch.c:51
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:269
SwsOpPass::filter_size
int filter_size
Definition: ops_dispatch.c:47
SwsOpPass::tail_buf_size
unsigned int tail_buf_size
Definition: ops_dispatch.c:52
rw_planes
static int rw_planes(const SwsOp *op)
Definition: ops_dispatch.c:372
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:580
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:113
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:71
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:44
SwsOpPass::tail_size_out
int tail_size_out
Definition: ops_dispatch.c:39
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:594
mem_internal.h
out
static FILE * out
Definition: movenc.c:55
SwsOpPass::exec_tail
SwsOpExec exec_tail
Definition: ops_dispatch.c:34
comp
static void comp(unsigned char *dst, ptrdiff_t dst_stride, unsigned char *src, ptrdiff_t src_stride, int add)
Definition: eamad.c:79
SwsOpExec::in_bump
ptrdiff_t in_bump[4]
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:631
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
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
SwsOpPass::num_blocks
int num_blocks
Definition: ops_dispatch.c:35
ff_sws_ops_compile
int ff_sws_ops_compile(SwsContext *ctx, const SwsOpList *ops, SwsCompiledOp *out)
Compile a list of operations using the best available backend.
Definition: ops_dispatch.c:82
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
ops.h
SwsFilterWeights
Represents a computed filter kernel.
Definition: filters.h:64
SwsOpExec::block_size_in
int32_t block_size_in
Definition: ops_dispatch.h:57
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_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
ops_dispatch.h
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
compile
static int compile(SwsGraph *graph, const SwsOpList *ops, SwsPass *input, SwsPass **output)
Definition: ops_dispatch.c:386
SwsOpExec::in_stride
ptrdiff_t in_stride[4]
Definition: ops_dispatch.h:41
SwsOpBackend::name
const char * name
Definition: ops_internal.h:56
SwsOpPass::idx_out
int idx_out[4]
Definition: ops_dispatch.c:45
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:68
SwsPass::width
int width
Definition: graph.h:81
ff_sws_op_list_subpass
int ff_sws_op_list_subpass(SwsOpList *ops, SwsOpList **out_rest)
Eliminate SWS_OP_FILTER_* operations by merging them with prior SWS_OP_READ operations.
Definition: ops_optimizer.c:927
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:262
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:923
ff_sws_op_backends
const SwsOpBackend *const ff_sws_op_backends[]
Definition: ops.c:39
SwsFrame::data
uint8_t * data[4]
Definition: format.h:195
fail
#define fail()
Definition: checkasm.h:223
SwsOpBackend::compile
int(* compile)(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
Compile an operation list to an implementation chain.
Definition: ops_internal.h:64
SwsOpBackend::hw_format
enum AVPixelFormat hw_format
If NONE, backend only supports software frames.
Definition: ops_internal.h:71
SwsOpPass::memcpy_last
bool memcpy_last
Definition: ops_dispatch.c:49
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:126
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, SwsOpList **pops, int flags, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
Definition: ops_dispatch.c:471
SwsFrame
Represents a view into a single field of frame data.
Definition: format.h:193
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:202
SwsPass::priv
void * priv
Definition: graph.h:106
av_fast_realloc
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition: mem.c:497
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_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:123
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
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:640
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:73
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
SwsOpPass::comp
SwsCompiledOp comp
Definition: ops_dispatch.c:32
SwsOpBackend
Definition: ops_internal.h:55
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:74
SwsOpExec
Copyright (C) 2026 Niklas Haas.
Definition: ops_dispatch.h:35
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:679
op_pass_free
static void op_pass_free(void *ptr)
Definition: ops_dispatch.c:112
NULL
#define NULL
Definition: coverity.c:32
ff_sws_compiled_op_unref
void ff_sws_compiled_op_unref(SwsCompiledOp *comp)
Definition: ops_dispatch.c:104
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:74
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
rw_pixel_bits
static int rw_pixel_bits(const SwsOp *op)
Definition: ops_dispatch.c:377
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
SwsPass::height
int height
Definition: graph.h:81
SwsOpExec::block_size_out
int32_t block_size_out
Definition: ops_dispatch.h:58
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
SwsFrame::height
int height
Definition: format.h:201
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
cpu.h
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:137
SwsOpPass::offsets_y
int * offsets_y
Definition: ops_dispatch.c:46
SwsOpList::src
SwsFormat src
Definition: ops.h:259
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:297
SwsFormat
Definition: format.h:77
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
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_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops.h:338
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:40
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
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:333
SwsOpPass::pixel_bits_out
int pixel_bits_out
Definition: ops_dispatch.c:43
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:41
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:38
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
DECLARE_ALIGNED_32
#define DECLARE_ALIGNED_32(t, v)
Definition: mem_internal.h:113
ops_internal.h
SwsOpPass
Copyright (C) 2025 Niklas Haas.
Definition: ops_dispatch.c:31
SwsOp
Definition: ops.h:212
SwsOpExec::out_sub_y
uint8_t out_sub_y[4]
Definition: ops_dispatch.h:61
SwsOpExec::out_sub_x
uint8_t out_sub_x[4]
Definition: ops_dispatch.h:62
SwsOpPass::memcpy_first
bool memcpy_first
Definition: ops_dispatch.c:48
ff_sws_graph_add_pass
int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, 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:115
ret
ret
Definition: filter_design.txt:187
SwsOpList::dst
SwsFormat dst
Definition: ops.h:259
SwsCompiledOp
Definition: ops_dispatch.h:100
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:81
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
ff_sws_ops_compile_backend
int ff_sws_ops_compile_backend(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Attempt to compile a list of operations using a specific backend.
Definition: ops_dispatch.c:55
SwsOpPass::exec_base
SwsOpExec exec_base
Definition: ops_dispatch.c:33
SwsOpExec::in_sub_y
uint8_t in_sub_y[4]
Definition: ops_dispatch.h:61
SwsOpPass::pixel_bits_in
int pixel_bits_in
Definition: ops_dispatch.c:42
SwsOpPass::tail_off_in
int tail_off_in
Definition: ops_dispatch.c:36
SwsOpPass::memcpy_out
bool memcpy_out
Definition: ops_dispatch.c:50
mem.h
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:112
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:280
int32_t
int32_t
Definition: audioconvert.c:56
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
h
h
Definition: vp9dsp_template.c:2070
SwsOpList::plane_src
uint8_t plane_src[4]
Definition: ops.h:262
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:254
SwsContext
Main external API structure.
Definition: swscale.h:206
SwsOpPass::tail_off_out
int tail_off_out
Definition: ops_dispatch.c:37
SwsFrame::linesize
int linesize[4]
Definition: format.h:196
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
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_graph_rollback
void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
Remove all passes added since the given index.
Definition: graph.c:884