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 typedef struct SwsOpPass {
37  size_t num_blocks;
42  int planes_in;
46  int idx_in[4];
47  int idx_out[4];
49  int *offsets_y;
53  bool memcpy_out;
54  size_t tail_blocks;
55  uint8_t *tail_buf; /* extra memory for fixing unpadded tails */
56  unsigned int tail_buf_size;
57 } SwsOpPass;
58 
59 static int compile_backend(SwsContext *ctx, const SwsOpBackend *backend,
60  const SwsOpList *ops, SwsCompiledOp *out)
61 {
62  SwsOpList *copy;
63  SwsCompiledOp compiled = {0};
64  int ret = 0;
65 
67  if (!copy)
68  return AVERROR(ENOMEM);
69 
70  /* Ensure these are always set during compilation */
72 
73  ret = backend->compile(ctx, copy, &compiled);
74  if (ret < 0) {
75  int msg_lev = ret == AVERROR(ENOTSUP) ? AV_LOG_TRACE : AV_LOG_ERROR;
76  av_log(ctx, msg_lev, "Backend '%s' failed to compile operations: %s\n",
77  backend->name, av_err2str(ret));
78  goto fail;
79  }
80 
81  compiled.backend = backend;
82  *out = compiled;
83 
84  av_log(ctx, AV_LOG_VERBOSE, "Compiled using backend '%s': "
85  "block size = %d, over-read = {%d %d %d %d}, over-write = {%d %d %d %d}, "
86  "cpu flags = 0x%x\n", backend->name, out->block_size,
87  out->over_read[0], out->over_read[1],
88  out->over_read[2], out->over_read[3],
89  out->over_write[0], out->over_write[1],
90  out->over_write[2], out->over_write[3],
91  out->cpu_flags);
92 
94 
95 fail:
97  return ret;
98 }
99 
101  const SwsOpList *ops, SwsCompiledOp *out)
102 {
103  if (backend)
104  return compile_backend(ctx, backend, ops, out);
105 
106  const SwsBackend enabled = ff_sws_enabled_backends(ctx);
107  for (int n = 0; ff_sws_op_backends[n]; n++) {
108  const SwsOpBackend *backend = ff_sws_op_backends[n];
109  if (ops->src.hw_format != backend->hw_format ||
110  ops->dst.hw_format != backend->hw_format ||
111  !(enabled & backend->flags))
112  continue;
113  if (compile_backend(ctx, backend, ops, out) < 0)
114  continue;
115 
116  return 0;
117  }
118 
119  return AVERROR(ENOTSUP);
120 }
121 
123 {
124  if (comp->free)
125  comp->free(comp->priv);
126 
127  *comp = (SwsCompiledOp) {0};
128 }
129 
130 static void op_pass_free(void *ptr)
131 {
132  SwsOpPass *p = ptr;
133  if (!p)
134  return;
135 
136  ff_sws_compiled_op_unref(&p->comp);
137  av_refstruct_unref(&p->offsets_y);
138  av_free(p->exec_base.in_bump_y);
139  av_free(p->exec_base.in_offset_x);
140  av_free(p->tail_buf);
141  av_free(p);
142 }
143 
144 static inline void get_row_data(const SwsOpPass *p, const int y_dst,
145  const uint8_t *in[4], uint8_t *out[4])
146 {
147  const SwsOpExec *base = &p->exec_base;
148  const int y_src = p->offsets_y ? p->offsets_y[y_dst] : y_dst;
149  for (int i = 0; i < p->planes_in; i++)
150  in[i] = base->in[i] + (y_src >> base->in_sub_y[i]) * base->in_stride[i];
151  for (int i = 0; i < p->planes_out; i++)
152  out[i] = base->out[i] + (y_dst >> base->out_sub_y[i]) * base->out_stride[i];
153 }
154 
155 static inline int get_lines_in(const SwsOpPass *p, const int y, const int h,
156  const int plane)
157 {
158  const SwsOpExec *base = &p->exec_base;
159  if (!p->offsets_y)
160  return h >> base->in_sub_y[plane];
161 
162  const int y0 = p->offsets_y[y] >> base->in_sub_y[plane];
163  const int y1 = p->offsets_y[y + h - 1] >> base->in_sub_y[plane];
164  return y1 - y0 + 1;
165 }
166 
167 static inline size_t pixel_bytes(size_t pixels, int pixel_bits,
168  enum AVRounding rounding)
169 {
170  const uint64_t bits = (uint64_t) pixels * pixel_bits;
171  switch (rounding) {
172  case AV_ROUND_ZERO:
173  case AV_ROUND_DOWN:
174  return bits >> 3;
175  case AV_ROUND_INF:
176  case AV_ROUND_UP:
177  return (bits + 7) >> 3;
178  default:
179  av_unreachable("Invalid rounding mode");
180  return (size_t) -1;
181  }
182 }
183 
184 static size_t safe_bytes_pad(int linesize, int plane_pad)
185 {
186  av_assert1(linesize);
187  int64_t safe_bytes = FFABS((int64_t) linesize) - plane_pad;
188  return FFMAX(safe_bytes, 0);
189 }
190 
191 static size_t safe_blocks_offset(size_t num_blocks, unsigned block_size,
192  ptrdiff_t safe_offset,
193  const int32_t *offset_bytes)
194 {
195  size_t safe_blocks = num_blocks;
196  while (safe_blocks && offset_bytes[safe_blocks * block_size - 1] > safe_offset)
197  safe_blocks--;
198  return safe_blocks;
199 }
200 
201 static int op_pass_setup(const SwsFrame *out, const SwsFrame *in,
202  const SwsPass *pass)
203 {
204  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(in->format);
205  const bool float_in = indesc->flags & AV_PIX_FMT_FLAG_FLOAT;
206  const int width = out->width;
207 
208  SwsOpPass *p = pass->priv;
209  SwsOpExec *exec = &p->exec_base;
210  const SwsCompiledOp *comp = &p->comp;
211 
212  /* Set up main loop parameters */
213  const unsigned block_size = comp->block_size;
214  const size_t num_blocks = (width + block_size - 1) / block_size;
215  const size_t aligned_w = num_blocks * block_size;
216  if (aligned_w < width) /* overflow */
217  return AVERROR(EINVAL);
218  p->num_blocks = num_blocks;
219  p->memcpy_first = false;
220  p->memcpy_last = false;
221  p->memcpy_out = false;
222 
223  size_t safe_blocks = num_blocks;
224  for (int i = 0; i < p->planes_in; i++) {
225  const int idx = p->idx_in[i];
226  size_t input_bytes = in->linesize[idx];
227  if (p->filter_size_h && float_in) {
228  /* Floating point inputs may contain NaN / Infinity in the padding */
229  const int plane_w = AV_CEIL_RSHIFT(in->width, exec->in_sub_x[i]);
230  input_bytes = pixel_bytes(plane_w, p->pixel_bits_in, AV_ROUND_UP);
231  }
232 
233  size_t safe_bytes = safe_bytes_pad(input_bytes, comp->over_read[i]);
234  size_t safe_blocks_in;
235  if (exec->in_offset_x) {
236  size_t filter_size = pixel_bytes(p->filter_size_h, p->pixel_bits_in,
237  AV_ROUND_UP);
238  safe_blocks_in = safe_blocks_offset(num_blocks, block_size,
239  safe_bytes - filter_size,
240  exec->in_offset_x);
241  } else {
242  safe_blocks_in = safe_bytes / exec->block_size_in[i];
243  }
244 
245  if (safe_blocks_in < num_blocks) {
246  p->memcpy_first |= in->linesize[idx] < 0;
247  p->memcpy_last |= in->linesize[idx] > 0;
248  safe_blocks = FFMIN(safe_blocks, safe_blocks_in);
249  }
250 
251  size_t loop_size = num_blocks * exec->block_size_in[i];
252  exec->in[i] = in->data[idx];
253  exec->in_stride[i] = in->linesize[idx];
254  exec->in_bump[i] = in->linesize[idx] - loop_size;
255  }
256 
257  for (int i = 0; i < p->planes_out; i++) {
258  const int idx = p->idx_out[i];
259  size_t safe_bytes = safe_bytes_pad(out->linesize[idx], comp->over_write[i]);
260  size_t safe_blocks_out = safe_bytes / exec->block_size_out[i];
261  if (safe_blocks_out < num_blocks) {
262  p->memcpy_out = true;
263  safe_blocks = FFMIN(safe_blocks, safe_blocks_out);
264  }
265 
266  size_t loop_size = num_blocks * exec->block_size_out[i];
267  exec->out[i] = out->data[idx];
268  exec->out_stride[i] = out->linesize[idx];
269  exec->out_bump[i] = out->linesize[idx] - loop_size;
270  }
271 
272  if (p->palette_idx >= 0) {
273  exec->in[1] = in->data[p->palette_idx];
274  exec->in_stride[1] = exec->in_bump[1] = 0;
275  }
276 
277  const bool memcpy_in = p->memcpy_first || p->memcpy_last;
278  if (!memcpy_in && !p->memcpy_out) {
279  av_assert0(safe_blocks == num_blocks);
280  return 0;
281  }
282 
283  /* Set-up tail section parameters and buffers */
284  SwsOpExec *tail = &p->exec_tail;
285  const int align = av_cpu_max_align();
286  size_t alloc_size = 0;
287  *tail = *exec;
288 
289  const size_t safe_width = safe_blocks * block_size;
290  const size_t tail_size = width - safe_width;
291  p->tail_off_out = pixel_bytes(safe_width, p->pixel_bits_out, AV_ROUND_DOWN);
292  p->tail_size_out = pixel_bytes(tail_size, p->pixel_bits_out, AV_ROUND_UP);
293  p->tail_blocks = num_blocks - safe_blocks;
294 
295  if (exec->in_offset_x) {
296  p->tail_off_in = exec->in_offset_x[safe_width];
297  p->tail_size_in = exec->in_offset_x[width - 1] - p->tail_off_in;
298  p->tail_size_in += pixel_bytes(p->filter_size_h, p->pixel_bits_in, AV_ROUND_UP);
299  } else {
300  p->tail_off_in = pixel_bytes(safe_width, p->pixel_bits_in, AV_ROUND_DOWN);
301  p->tail_size_in = pixel_bytes(tail_size, p->pixel_bits_in, AV_ROUND_UP);
302  }
303 
304  const size_t alloc_width = aligned_w - safe_width;
305  for (int i = 0; memcpy_in && i < p->planes_in; i++) {
306  size_t needed_size;
307  if (exec->in_offset_x) {
308  /* The input offset map is already padded to multiples of the block
309  * size, and clamps the input offsets to the image boundaries; so
310  * we just need to compensate for the comp->over_read */
311  needed_size = p->tail_size_in;
312  } else {
313  needed_size = pixel_bytes(alloc_width, p->pixel_bits_in, AV_ROUND_UP);
314  }
315  size_t loop_size = p->tail_blocks * exec->block_size_in[i];
316  tail->in_stride[i] = FFALIGN(needed_size + comp->over_read[i], align);
317  tail->in_bump[i] = tail->in_stride[i] - loop_size;
318  alloc_size += tail->in_stride[i] * in->height;
319  }
320 
321  for (int i = 0; p->memcpy_out && i < p->planes_out; i++) {
322  size_t needed_size = pixel_bytes(alloc_width, p->pixel_bits_out, AV_ROUND_UP);
323  size_t loop_size = p->tail_blocks * exec->block_size_out[i];
324  tail->out_stride[i] = FFALIGN(needed_size + comp->over_write[i], align);
325  tail->out_bump[i] = tail->out_stride[i] - loop_size;
326  alloc_size += tail->out_stride[i] * out->height;
327  }
328 
329  if (memcpy_in && exec->in_offset_x) {
330  /* `in_offset_x` is indexed relative to the line start, not the start
331  * of the section being processed; so we need to over-allocate this
332  * array to the full width of the image, even though we will only
333  * partially fill in the offsets relevant to the tail region */
334  alloc_size += aligned_w * sizeof(*exec->in_offset_x);
335  }
336 
337  av_fast_mallocz(&p->tail_buf, &p->tail_buf_size, alloc_size);
338  if (!p->tail_buf)
339  return AVERROR(ENOMEM);
340 
341  uint8_t *tail_buf = p->tail_buf;
342  for (int i = 0; memcpy_in && i < p->planes_in; i++) {
343  tail->in[i] = tail_buf;
344  tail_buf += tail->in_stride[i] * in->height;
345  }
346 
347  for (int i = 0; p->memcpy_out && i < p->planes_out; i++) {
348  tail->out[i] = tail_buf;
349  tail_buf += tail->out_stride[i] * out->height;
350  }
351 
352  if (memcpy_in && exec->in_offset_x) {
353  tail->in_offset_x = (int32_t *) tail_buf;
354  for (int i = safe_width; i < aligned_w; i++)
355  tail->in_offset_x[i] = exec->in_offset_x[i] - p->tail_off_in;
356  }
357 
358  return 0;
359 }
360 
361 static void copy_lines(uint8_t *dst, const size_t dst_stride,
362  const uint8_t *src, const size_t src_stride,
363  const int h, const size_t bytes)
364 {
365  for (int y = 0; y < h; y++) {
366  memcpy(dst, src, bytes);
367  dst += dst_stride;
368  src += src_stride;
369  }
370 }
371 
372 static void op_pass_run(const SwsFrame *out, const SwsFrame *in, const int y,
373  const int h, const SwsPass *pass)
374 {
375  const SwsOpPass *p = pass->priv;
376  const SwsCompiledOp *comp = &p->comp;
377 
378  /* Fill exec metadata for this slice */
379  DECLARE_ALIGNED_32(SwsOpExec, exec) = p->exec_base;
380  exec.slice_y = y;
381  exec.slice_h = h;
382 
383  /**
384  * To ensure safety, we need to consider the following:
385  *
386  * 1. We can overread the input, unless this is the last line of an
387  * unpadded buffer. All defined operations can handle arbitrary pixel
388  * input, so overread of arbitrary data is fine. For flipped images,
389  * this condition is actually *inverted* to where the first line is
390  * the one at the end of the buffer.
391  *
392  * 2. We can overwrite the output, as long as we don't write more than the
393  * amount of pixels that fit into one linesize. So we always need to
394  * memcpy the last column on the output side if unpadded.
395  */
396 
397  const bool memcpy_in = p->memcpy_last && y + h == pass->lines ||
398  p->memcpy_first && y == 0;
399  const bool memcpy_out = p->memcpy_out;
400  const size_t num_blocks = p->num_blocks;
401  const size_t tail_blocks = p->tail_blocks;
402 
403  get_row_data(p, y, exec.in, exec.out);
404  if (!memcpy_in && !memcpy_out) {
405  /* Fast path (fully aligned/padded inputs and outputs) */
406  comp->func(&exec, comp->priv, 0, y, num_blocks, y + h);
407  return;
408  }
409 
410  /* Non-aligned case (slow path); process main blocks as normal, and
411  * a separate tail (via memcpy into an appropriately padded buffer) */
412  if (num_blocks > tail_blocks) {
413  for (int i = 0; i < 4; i++) {
414  /* We process fewer blocks, so the in_bump needs to be increased
415  * to reflect that the plane pointers are left on the last block,
416  * not the end of the processed line, after each loop iteration */
417  exec.in_bump[i] += exec.block_size_in[i] * tail_blocks;
418  exec.out_bump[i] += exec.block_size_out[i] * tail_blocks;
419  }
420 
421  comp->func(&exec, comp->priv, 0, y, num_blocks - tail_blocks, y + h);
422  }
423 
424  DECLARE_ALIGNED_32(SwsOpExec, tail) = p->exec_tail;
425  tail.slice_y = y;
426  tail.slice_h = h;
427 
428  for (int i = 0; i < p->planes_in; i++) {
429  /* Input offsets are relative to the base pointer */
430  if (!exec.in_offset_x || memcpy_in)
431  exec.in[i] += p->tail_off_in;
432  tail.in[i] += y * tail.in_stride[i];
433  }
434  for (int i = 0; i < p->planes_out; i++) {
435  exec.out[i] += p->tail_off_out;
436  tail.out[i] += y * tail.out_stride[i];
437  }
438 
439  for (int i = 0; i < p->planes_in; i++) {
440  if (memcpy_in) {
441  const int lines = get_lines_in(p, y, h, i);
442  copy_lines((uint8_t *) tail.in[i], tail.in_stride[i],
443  exec.in[i], exec.in_stride[i], lines, p->tail_size_in);
444  } else {
445  /* Reuse input pointers directly */
446  const size_t loop_size = tail_blocks * exec.block_size_in[i];
447  tail.in[i] = exec.in[i];
448  tail.in_stride[i] = exec.in_stride[i];
449  tail.in_bump[i] = exec.in_stride[i] - loop_size;
450  }
451  }
452 
453  for (int i = 0; !memcpy_out && i < p->planes_out; i++) {
454  /* Reuse output pointers directly */
455  const size_t loop_size = tail_blocks * exec.block_size_out[i];
456  tail.out[i] = exec.out[i];
457  tail.out_stride[i] = exec.out_stride[i];
458  tail.out_bump[i] = exec.out_stride[i] - loop_size;
459  }
460 
461  /* Dispatch kernel over tail */
462  av_assert1(tail_blocks > 0);
463  comp->func(&tail, comp->priv, num_blocks - tail_blocks, y, num_blocks, y + h);
464 
465  for (int i = 0; memcpy_out && i < p->planes_out; i++) {
466  const int lines = h >> tail.out_sub_y[i];
467  copy_lines(exec.out[i], exec.out_stride[i],
468  tail.out[i], tail.out_stride[i], lines, p->tail_size_out);
469  }
470 }
471 
472 static int rw_data_planes(const SwsOp *op)
473 {
474  /* Exclude the palette plane from the plane count, since it does not need
475  * to be directly processed/adjusted by the dispatch layer */
476  return op->rw.mode == SWS_RW_PALETTE ? 1 : ff_sws_rw_op_planes(op);
477 }
478 
479 static int rw_pixel_bits(const SwsOp *op)
480 {
481  if (op->rw.mode == SWS_RW_PALETTE)
482  return 8; /* index size */
483 
484  int elems = 0;
485  switch (op->rw.mode) {
486  case SWS_RW_PLANAR: elems = 1; break;
487  case SWS_RW_PACKED: elems = op->rw.elems; break;
488  }
489 
490  const int size = ff_sws_pixel_type_size(op->type);
491  const int bits = 8 >> op->rw.frac;
492  av_assert1(bits >= 1);
493  return elems * size * bits;
494 }
495 
496 static void align_pass(SwsPass *pass, int block_size, const int *over_rw,
497  int pixel_bits)
498 {
499  if (!pass)
500  return;
501 
502  /* Add at least as many pixels as needed to cover the padding requirement */
503  int pad_max = 0;
504  for (int i = 0; i < 4; i++) {
505  const int pad = (over_rw[i] * 8 + pixel_bits - 1) / pixel_bits;
506  pad_max = FFMAX(pad_max, pad);
507  }
508 
509  SwsPassBuffer *buf = pass->output;
510  buf->width_align = FFMAX(buf->width_align, block_size);
511  buf->width_pad = FFMAX(buf->width_pad, pad_max);
512 }
513 
514 static int compile(SwsGraph *graph, const SwsOpBackend *backend,
515  const SwsOpList *ops, SwsPass *input, SwsPass **output)
516 {
517  SwsContext *ctx = graph->ctx;
518  SwsOpPass *p = av_mallocz(sizeof(*p));
519  if (!p)
520  return AVERROR(ENOMEM);
521 
522  int ret = ff_sws_ops_compile(ctx, backend, ops, &p->comp);
523  if (ret < 0)
524  goto fail;
525  else if (!output)
526  goto fail; /* nothing to do, just return */
527 
528  const SwsCompiledOp *comp = &p->comp;
529  const SwsFormat *src = &ops->src;
530  const SwsFormat *dst = &ops->dst;
531  if (p->comp.opaque) {
532  SwsCompiledOp c = *comp;
533  av_free(p);
534  ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
535  input, 0, c.slice_align, c.func_opaque,
536  NULL, c.priv, c.free, output);
537  if (ret >= 0)
538  (*output)->backend = comp->backend->flags;
539  return ret;
540  }
541 
542  const AVPixFmtDescriptor *indesc = av_pix_fmt_desc_get(src->format);
543  const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(dst->format);
544  const SwsOp *read = ff_sws_op_list_input(ops);
545  const SwsOp *write = ff_sws_op_list_output(ops);
546  p->palette_idx = read->rw.mode == SWS_RW_PALETTE ? ops->plane_src[1] : -1;
547  p->planes_in = rw_data_planes(read);
548  p->planes_out = rw_data_planes(write);
549  p->pixel_bits_in = rw_pixel_bits(read);
550  p->pixel_bits_out = rw_pixel_bits(write);
551  p->exec_base = (SwsOpExec) {
552  .width = dst->width,
553  .height = dst->height,
554  };
555 
556  const int64_t block_bits_in = (int64_t) comp->block_size * p->pixel_bits_in;
557  const int64_t block_bits_out = (int64_t) comp->block_size * p->pixel_bits_out;
558  if (block_bits_in & 0x7 || block_bits_out & 0x7) {
559  av_log(ctx, AV_LOG_ERROR, "Block size must be byte-aligned.\n");
560  ret = AVERROR(EINVAL);
561  goto fail;
562  }
563 
564  for (int i = 0; i < 4; i++)
565  p->idx_in[i] = p->idx_out[i] = -1;
566 
567  for (int i = 0; i < p->planes_in; i++) {
568  const int idx = ops->plane_src[i];
569  const int chroma = idx == 1 || idx == 2;
570  const int sub_x = chroma ? indesc->log2_chroma_w : 0;
571  const int sub_y = chroma ? indesc->log2_chroma_h : 0;
572  p->exec_base.in_sub_x[i] = sub_x;
573  p->exec_base.in_sub_y[i] = sub_y;
574  p->exec_base.block_size_in[i] = block_bits_in >> 3;
575  p->idx_in[i] = idx;
576  }
577 
578  for (int i = 0; i < p->planes_out; i++) {
579  const int idx = ops->plane_dst[i];
580  const int chroma = idx == 1 || idx == 2;
581  const int sub_x = chroma ? outdesc->log2_chroma_w : 0;
582  const int sub_y = chroma ? outdesc->log2_chroma_h : 0;
583  p->exec_base.out_sub_x[i] = sub_x;
584  p->exec_base.out_sub_y[i] = sub_y;
585  p->exec_base.block_size_out[i] = block_bits_out >> 3;
586  p->idx_out[i] = idx;
587  }
588 
589  const SwsFilterWeights *filter = read->rw.filter.kernel;
590  if (read->rw.filter.op == SWS_OP_FILTER_V) {
591  p->offsets_y = av_refstruct_ref(filter->offsets);
592 
593  /* Compute relative pointer bumps for each output line */
594  int32_t *bump = av_malloc_array(filter->dst_size, sizeof(*bump));
595  if (!bump) {
596  ret = AVERROR(ENOMEM);
597  goto fail;
598  }
599 
600  int line = filter->offsets[0];
601  for (int y = 0; y < filter->dst_size - 1; y++) {
602  int next = filter->offsets[y + 1];
603  bump[y] = next - line - 1;
604  line = next;
605  }
606  bump[filter->dst_size - 1] = 0;
607  p->exec_base.in_bump_y = bump;
608  } else if (read->rw.filter.op == SWS_OP_FILTER_H) {
609  /* Compute pixel offset map for each output line */
610  const int pixels = FFALIGN(filter->dst_size, p->comp.block_size);
611  int32_t *offset = av_malloc_array(pixels, sizeof(*offset));
612  if (!offset) {
613  ret = AVERROR(ENOMEM);
614  goto fail;
615  }
616  p->exec_base.in_offset_x = offset;
617 
618  for (int x = 0; x < filter->dst_size; x++) {
619  /* Sanity check; if the tap would land on a half-pixel, we cannot
620  * reasonably expect the implementation to know about this. Just
621  * error out in such (theoretical) cases. */
622  int64_t bits = (int64_t) filter->offsets[x] * p->pixel_bits_in;
623  if ((bits & 0x7) || (bits >> 3) > INT32_MAX) {
624  ret = AVERROR(EINVAL);
625  goto fail;
626  }
627  offset[x] = bits >> 3;
628  }
629  for (int x = filter->dst_size; x < pixels; x++)
630  offset[x] = offset[filter->dst_size - 1];
631  for (int i = 0; i < 4; i++)
632  p->exec_base.block_size_in[i] = 0; /* ptr does not advance */
633  p->filter_size_h = filter->filter_size;
634  }
635 
636  ret = ff_sws_graph_add_pass(graph, dst->format, dst->width, dst->height,
637  input, 0, comp->slice_align, op_pass_run,
639  if (ret < 0)
640  return ret;
641 
642  (*output)->backend = comp->backend->flags;
643  align_pass(input, comp->block_size, comp->over_read, p->pixel_bits_in);
644  align_pass(*output, comp->block_size, comp->over_write, p->pixel_bits_out);
645  return 0;
646 
647 fail:
648  op_pass_free(p);
649  return ret;
650 }
651 
652 int ff_sws_compile_pass(SwsGraph *graph, const SwsOpBackend *backend,
653  SwsOpList **pops, int flags, SwsPass *input,
654  SwsPass **output)
655 {
656  const int passes_orig = graph->num_passes;
657  SwsContext *ctx = graph->ctx;
658  SwsOpList *ops = *pops;
659  int ret = 0;
660 
661  /* Check if the whole operation graph is an end-to-end no-op */
662  if (ff_sws_op_list_is_noop(ops)) {
663  if (output)
664  *output = input;
665  goto out;
666  }
667 
668  const SwsOp *read = ff_sws_op_list_input(ops);
669  const SwsOp *write = ff_sws_op_list_output(ops);
670  if (!read || !write) {
671  av_log(ctx, AV_LOG_ERROR, "First and last operations must be a read "
672  "and write, respectively.\n");
673  ret = AVERROR(EINVAL);
674  goto out;
675  }
676 
677  if (flags & SWS_OP_FLAG_OPTIMIZE) {
679  if (ret < 0)
680  goto out;
681  av_log(ctx, AV_LOG_DEBUG, "Operation list after optimizing:\n");
683  }
684 
685  ret = compile(graph, backend, ops, input, output);
686  if (ret != AVERROR(ENOTSUP))
687  goto out;
688 
689  av_log(ctx, AV_LOG_DEBUG, "Retrying with separated filter passes.\n");
690  SwsPass *prev = input;
691  bool first = true;
692  while (ops) {
693  SwsOpList *rest;
694  ret = ff_sws_op_list_subpass(ops, &rest);
695  if (ret < 0)
696  goto out;
697 
698  if (first && !rest) {
699  /* No point in compiling an unsplit pass again */
700  ret = AVERROR(ENOTSUP);
701  goto out;
702  }
703 
704  ret = compile(graph, backend, ops, prev, output ? &prev : NULL);
705  if (ret < 0) {
706  ff_sws_op_list_free(&rest);
707  goto out;
708  }
709 
710  ff_sws_op_list_free(&ops);
711  first = false;
712  ops = rest;
713  }
714 
715  if (output) {
716  /* Return last subpass successfully compiled */
717  av_log(ctx, AV_LOG_VERBOSE, "Using %d separate passes.\n",
718  graph->num_passes - passes_orig);
719  *output = prev;
720  }
721 
722 out:
723  if (ret == AVERROR(ENOTSUP)) {
724  av_log(ctx, AV_LOG_WARNING, "No backend found for operations:\n");
726  }
727  if (ret < 0)
728  ff_sws_graph_rollback(graph, passes_orig);
729  ff_sws_op_list_free(&ops);
730  *pops = NULL;
731  return ret;
732 }
flags
const SwsFlags flags[]
Definition: swscale.c:85
SwsOpPass::tail_buf
uint8_t * tail_buf
Definition: ops_dispatch.c:55
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:361
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:56
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:634
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:46
SwsOpPass::tail_size_out
int tail_size_out
Definition: ops_dispatch.c:41
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:648
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:97
mem_internal.h
out
static FILE * out
Definition: movenc.c:55
SwsOpPass::exec_tail
SwsOpExec exec_tail
Definition: ops_dispatch.c:36
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:685
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
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
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:54
SwsOpBackend::name
const char * name
Definition: ops_dispatch.h:134
SwsOpPass::idx_out
int idx_out[4]
Definition: ops_dispatch.c:47
ff_sws_pixel_type_size
int ff_sws_pixel_type_size(SwsPixelType type)
Definition: ops.c:77
cpu.h
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:959
SwsOpList::plane_dst
uint8_t plane_dst[4]
Definition: ops.h:291
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:981
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
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:472
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:52
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:144
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:191
SWS_RW_PACKED
@ SWS_RW_PACKED
Definition: ops.h:98
SwsFrame
Represents a view into a single field of frame data.
Definition: format.h:224
SwsBackend
SwsBackend
Definition: swscale.h:110
first
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But first
Definition: rate_distortion.txt:12
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: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
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:694
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:34
SwsOpBackend
Definition: ops_dispatch.h:133
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:733
op_pass_free
static void op_pass_free(void *ptr)
Definition: ops_dispatch.c:130
NULL
#define NULL
Definition: coverity.c:32
ff_sws_compiled_op_unref
void ff_sws_compiled_op_unref(SwsCompiledOp *comp)
Definition: ops_dispatch.c:122
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
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:479
compile
static int compile(SwsGraph *graph, const SwsOpBackend *backend, const SwsOpList *ops, SwsPass *input, SwsPass **output)
Definition: ops_dispatch.c:514
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:50
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:48
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
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:201
SwsOpPass::offsets_y
int * offsets_y
Definition: ops_dispatch.c:49
SwsOpList::src
SwsFormat src
Definition: ops.h:288
ff_sws_op_list_update_comps
void ff_sws_op_list_update_comps(SwsOpList *ops)
Infer + propagate known information about components.
Definition: ops.c:355
compile_backend
static int compile_backend(SwsContext *ctx, const SwsOpBackend *backend, const SwsOpList *ops, SwsCompiledOp *out)
Definition: ops_dispatch.c:59
SwsFormat
Definition: format.h:77
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
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
align_pass
static void align_pass(SwsPass *pass, int block_size, const int *over_rw, int pixel_bits)
Definition: ops_dispatch.c:496
SWS_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops.h:367
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:42
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:155
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:45
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:43
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
SwsOpPass::tail_size_in
int tail_size_in
Definition: ops_dispatch.c:40
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
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
Copyright (C) 2025 Niklas Haas.
Definition: ops_dispatch.c:33
pixel_bytes
static size_t pixel_bytes(size_t pixels, int pixel_bits, enum AVRounding rounding)
Definition: ops_dispatch.c:167
SwsOp
Definition: ops.h:228
SwsOpPass::memcpy_first
bool memcpy_first
Definition: ops_dispatch.c:51
ret
ret
Definition: filter_design.txt:187
SwsOpList::dst
SwsFormat dst
Definition: ops.h:288
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:99
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:82
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:37
safe_bytes_pad
static size_t safe_bytes_pad(int linesize, int plane_pad)
Definition: ops_dispatch.c:184
SwsOpPass::exec_base
SwsOpExec exec_base
Definition: ops_dispatch.c:35
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:652
SwsOpPass::pixel_bits_in
int pixel_bits_in
Definition: ops_dispatch.c:44
SwsOpPass::tail_off_in
int tail_off_in
Definition: ops_dispatch.c:38
SwsOpPass::memcpy_out
bool memcpy_out
Definition: ops_dispatch.c:53
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:372
int32_t
int32_t
Definition: audioconvert.c:56
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:291
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:283
SwsContext
Main external API structure.
Definition: swscale.h:229
SwsOpPass::tail_off_out
int tail_off_out
Definition: ops_dispatch.c:39
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
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:100
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:883