FFmpeg
graph.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2024 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/error.h"
24 #include "libavutil/imgutils.h"
25 #include "libavutil/macros.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/pixdesc.h"
29 #include "libavutil/refstruct.h"
30 #include "libavutil/slicethread.h"
31 
32 #include "libswscale/swscale.h"
33 #include "libswscale/format.h"
34 
35 #include "cms.h"
36 #include "lut3d.h"
37 #include "swscale_internal.h"
38 #include "graph.h"
39 #include "ops.h"
40 
41 static int buffer_get_sizes(SwsPassBuffer *buffer, size_t sizes[4])
42 {
43  const int align = av_cpu_max_align();
44  const int format = buffer->img.fmt;
45  const int width = FFALIGN(buffer->width, align);
46  const int height = buffer->height;
47  int ret;
48 
49  ret = av_image_check_size2(width, height, INT64_MAX, format, 0, NULL);
50  if (ret < 0)
51  return ret;
52 
53  int *linesize = buffer->img.linesize;
55  if (ret < 0)
56  return ret;
57 
58  ptrdiff_t linesize1[4];
59  for (int i = 0; i < 4; i++)
60  linesize1[i] = linesize[i] = FFALIGN(linesize[i], align);
61 
62  return av_image_fill_plane_sizes(sizes, format, height, linesize1);
63 }
64 
65 static int pass_alloc_output(SwsPass *pass)
66 {
67  if (!pass || pass->output->buf[0])
68  return 0;
69 
70  size_t sizes[4];
71  SwsPassBuffer *output = pass->output;
73  if (ret < 0)
74  return ret;
75 
76  const int align = av_cpu_max_align();
77  for (int i = 0; i < 4; i++) {
78  if (!sizes[i])
79  break;
80  if (sizes[i] > SIZE_MAX - align)
81  return AVERROR(EINVAL);
82 
84  if (!buf)
85  return AVERROR(ENOMEM);
86  output->img.data[i] = (uint8_t *) FFALIGN((uintptr_t) buf->data, align);
87  output->buf[i] = buf;
88  }
89  return 0;
90 }
91 
92 static void free_buffer(AVRefStructOpaque opaque, void *obj)
93 {
94  SwsPassBuffer *buffer = obj;
95  for (int i = 0; i < FF_ARRAY_ELEMS(buffer->buf); i++)
97 }
98 
100  int width, int height, SwsPass *input,
101  int align, void *priv, sws_filter_run_t run)
102 {
103  int ret;
104  SwsPass *pass = av_mallocz(sizeof(*pass));
105  if (!pass)
106  return NULL;
107 
108  pass->graph = graph;
109  pass->run = run;
110  pass->priv = priv;
111  pass->format = fmt;
112  pass->width = width;
113  pass->height = height;
114  pass->input = input;
115  pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, free_buffer);
116  if (!pass->output)
117  goto fail;
118 
120  if (ret < 0)
121  goto fail;
122 
123  if (!align) {
124  pass->slice_h = pass->height;
125  pass->num_slices = 1;
126  } else {
127  pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads;
128  pass->slice_h = FFALIGN(pass->slice_h, align);
129  pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
130  }
131 
132  /* Align output buffer to include extra slice padding */
133  pass->output->img.fmt = fmt;
134  pass->output->width = pass->width;
135  pass->output->height = pass->slice_h * pass->num_slices;
136 
137  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
138  if (ret < 0)
139  goto fail;
140 
141  return pass;
142 
143 fail:
144  av_refstruct_unref(&pass->output);
145  av_free(pass);
146  return NULL;
147 }
148 
149 /* Wrapper around ff_sws_graph_add_pass() that chains a pass "in-place" */
150 static int pass_append(SwsGraph *graph, enum AVPixelFormat fmt, int w, int h,
151  SwsPass **pass, int align, void *priv, sws_filter_run_t run)
152 {
153  SwsPass *new = ff_sws_graph_add_pass(graph, fmt, w, h, *pass, align, priv, run);
154  if (!new)
155  return AVERROR(ENOMEM);
156  *pass = new;
157  return 0;
158 }
159 
160 static void run_copy(const SwsImg *out_base, const SwsImg *in_base,
161  int y, int h, const SwsPass *pass)
162 {
163  SwsImg in = ff_sws_img_shift(in_base, y);
164  SwsImg out = ff_sws_img_shift(out_base, y);
165 
166  for (int i = 0; i < FF_ARRAY_ELEMS(out.data) && out.data[i]; i++) {
167  const int lines = h >> ff_fmt_vshift(in.fmt, i);
168  av_assert1(in.data[i]);
169 
170  if (in.data[i] == out.data[i]) {
171  av_assert0(in.linesize[i] == out.linesize[i]);
172  } else if (in.linesize[i] == out.linesize[i]) {
173  memcpy(out.data[i], in.data[i], lines * out.linesize[i]);
174  } else {
175  const int linesize = FFMIN(out.linesize[i], in.linesize[i]);
176  for (int j = 0; j < lines; j++) {
177  memcpy(out.data[i], in.data[i], linesize);
178  in.data[i] += in.linesize[i];
179  out.data[i] += out.linesize[i];
180  }
181  }
182  }
183 }
184 
185 static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h,
186  const SwsPass *pass)
187 {
188  SwsInternal *c = pass->priv;
189  const int x0 = c->src0Alpha - 1;
190  const int w4 = 4 * pass->width;
191  const int src_stride = in->linesize[0];
192  const int dst_stride = out->linesize[0];
193  const uint8_t *src = in->data[0] + y * src_stride;
194  uint8_t *dst = out->data[0] + y * dst_stride;
195 
196  for (int y = 0; y < h; y++) {
197  memcpy(dst, src, w4 * sizeof(*dst));
198  for (int x = x0; x < w4; x += 4)
199  dst[x] = 0xFF;
200 
201  src += src_stride;
202  dst += dst_stride;
203  }
204 }
205 
206 static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h,
207  const SwsPass *pass)
208 {
209  const SwsInternal *c = pass->priv;
210  c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
211  in->data[0] + y * in->linesize[0], in->linesize[0],
212  pass->width, h);
213 }
214 
215 static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h,
216  const SwsPass *pass)
217 {
218  const SwsInternal *c = pass->priv;
219  c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0],
220  in->data[0] + y * in->linesize[0], in->linesize[0],
221  pass->width, h);
222 }
223 
224 /***********************************************************************
225  * Internal ff_swscale() wrapper. This reuses the legacy scaling API. *
226  * This is considered fully deprecated, and will be replaced by a full *
227  * reimplementation ASAP. *
228  ***********************************************************************/
229 
230 static void free_legacy_swscale(void *priv)
231 {
232  SwsContext *sws = priv;
234 }
235 
236 static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in,
237  const SwsPass *pass)
238 {
239  SwsContext *sws = pass->priv;
241  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
242  for (int i = 0; i < 4; i++)
243  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
244  }
245 
246  if (usePal(sws->src_format))
247  ff_update_palette(c, (const uint32_t *) in->data[1]);
248 }
249 
250 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
251 {
252  SwsContext *sws = pass->priv;
253  SwsInternal *parent = sws_internal(sws);
254  if (pass->num_slices == 1)
255  return sws;
256 
257  av_assert1(parent->nb_slice_ctx == pass->num_slices);
258  sws = parent->slice_ctx[y / pass->slice_h];
259 
260  if (usePal(sws->src_format)) {
261  SwsInternal *sub = sws_internal(sws);
262  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
263  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
264  }
265 
266  return sws;
267 }
268 
269 static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in_base,
270  int y, int h, const SwsPass *pass)
271 {
272  SwsContext *sws = slice_ctx(pass, y);
274  const SwsImg in = ff_sws_img_shift(in_base, y);
275 
276  c->convert_unscaled(c, (const uint8_t *const *) in.data, in.linesize, y, h,
277  out->data, out->linesize);
278 }
279 
280 static void run_legacy_swscale(const SwsImg *out_base, const SwsImg *in,
281  int y, int h, const SwsPass *pass)
282 {
283  SwsContext *sws = slice_ctx(pass, y);
285  const SwsImg out = ff_sws_img_shift(out_base, y);
286 
287  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
288  sws->src_h, out.data, out.linesize, y, h);
289 }
290 
291 static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
292  const SwsFormat *fmt)
293 {
294  enum AVChromaLocation chroma_loc = fmt->loc;
295  const int sub_x = fmt->desc->log2_chroma_w;
296  const int sub_y = fmt->desc->log2_chroma_h;
297  int x_pos, y_pos;
298 
299  /* Explicitly default to center siting for compatibility with swscale */
300  if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
301  chroma_loc = AVCHROMA_LOC_CENTER;
302  graph->incomplete |= sub_x || sub_y;
303  }
304 
305  /* av_chroma_location_enum_to_pos() always gives us values in the range from
306  * 0 to 256, but we need to adjust this to the true value range of the
307  * subsampling grid, which may be larger for h/v_sub > 1 */
308  av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
309  x_pos *= (1 << sub_x) - 1;
310  y_pos *= (1 << sub_y) - 1;
311 
312  /* Fix vertical chroma position for interlaced frames */
313  if (sub_y && fmt->interlaced) {
314  /* When vertically subsampling, chroma samples are effectively only
315  * placed next to even rows. To access them from the odd field, we need
316  * to account for this shift by offsetting the distance of one luma row.
317  *
318  * For 4x vertical subsampling (v_sub == 2), they are only placed
319  * next to every *other* even row, so we need to shift by three luma
320  * rows to get to the chroma sample. */
321  if (graph->field == FIELD_BOTTOM)
322  y_pos += (256 << sub_y) - 256;
323 
324  /* Luma row distance is doubled for fields, so halve offsets */
325  y_pos >>= 1;
326  }
327 
328  /* Explicitly strip chroma offsets when not subsampling, because it
329  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
330  *h_chr_pos = sub_x ? x_pos : -513;
331  *v_chr_pos = sub_y ? y_pos : -513;
332 }
333 
334 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
335 {
336  if (override == -513 || override == *chr_pos)
337  return;
338 
339  if (!*warned) {
341  "Setting chroma position directly is deprecated, make sure "
342  "the frame is tagged with the correct chroma location.\n");
343  *warned = 1;
344  }
345 
346  *chr_pos = override;
347 }
348 
349 /* Takes over ownership of `sws` */
352 {
354  const int src_w = sws->src_w, src_h = sws->src_h;
355  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
356  const int unscaled = src_w == dst_w && src_h == dst_h;
357  int align = c->dst_slice_align;
358  SwsPass *pass = NULL;
359  int ret;
360 
361  if (c->cascaded_context[0]) {
362  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
363  for (int i = 0; i < num_cascaded; i++) {
364  const int is_last = i + 1 == num_cascaded;
365 
366  /* Steal cascaded context, so we can manage its lifetime independently */
367  SwsContext *sub = c->cascaded_context[i];
368  c->cascaded_context[i] = NULL;
369 
370  ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input);
371  if (ret < 0)
372  break;
373  }
374 
376  return ret;
377  }
378 
379  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
380  align = 0; /* disable slice threading */
381 
382  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
383  ret = pass_append(graph, AV_PIX_FMT_RGBA, src_w, src_h, &input, 1, c, run_rgb0);
384  if (ret < 0) {
386  return ret;
387  }
388  }
389 
390  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
391  ret = pass_append(graph, AV_PIX_FMT_RGB48, src_w, src_h, &input, 1, c, run_xyz2rgb);
392  if (ret < 0) {
394  return ret;
395  }
396  }
397 
398  pass = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, align, sws,
399  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale);
400  if (!pass) {
402  return AVERROR(ENOMEM);
403  }
404  pass->setup = setup_legacy_swscale;
405  pass->free = free_legacy_swscale;
406 
407  /**
408  * For slice threading, we need to create sub contexts, similar to how
409  * swscale normally handles it internally. The most important difference
410  * is that we handle cascaded contexts before threaded contexts; whereas
411  * context_init_threaded() does it the other way around.
412  */
413 
414  if (pass->num_slices > 1) {
415  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
416  if (!c->slice_ctx)
417  return AVERROR(ENOMEM);
418 
419  for (int i = 0; i < pass->num_slices; i++) {
420  SwsContext *slice;
421  SwsInternal *c2;
422  slice = c->slice_ctx[i] = sws_alloc_context();
423  if (!slice)
424  return AVERROR(ENOMEM);
425  c->nb_slice_ctx++;
426 
427  c2 = sws_internal(slice);
428  c2->parent = sws;
429 
430  ret = av_opt_copy(slice, sws);
431  if (ret < 0)
432  return ret;
433 
435  if (ret < 0)
436  return ret;
437 
438  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
439  slice->src_range, c->dstColorspaceTable,
440  slice->dst_range, c->brightness, c->contrast,
441  c->saturation);
442 
443  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
444  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
445  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
446  }
447  }
448  }
449 
450  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
451  ret = pass_append(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, &pass, 1, c, run_rgb2xyz);
452  if (ret < 0)
453  return ret;
454  }
455 
456  *output = pass;
457  return 0;
458 }
459 
462 {
463  int ret, warned = 0;
464  SwsContext *const ctx = graph->ctx;
466  if (!sws)
467  return AVERROR(ENOMEM);
468 
469  sws->flags = ctx->flags;
470  sws->dither = ctx->dither;
471  sws->alpha_blend = ctx->alpha_blend;
472  sws->gamma_flag = ctx->gamma_flag;
473 
474  sws->src_w = src.width;
475  sws->src_h = src.height;
476  sws->src_format = src.format;
477  sws->src_range = src.range == AVCOL_RANGE_JPEG;
478 
479  sws->dst_w = dst.width;
480  sws->dst_h = dst.height;
481  sws->dst_format = dst.format;
482  sws->dst_range = dst.range == AVCOL_RANGE_JPEG;
485 
486  graph->incomplete |= src.range == AVCOL_RANGE_UNSPECIFIED;
487  graph->incomplete |= dst.range == AVCOL_RANGE_UNSPECIFIED;
488 
489  /* Allow overriding chroma position with the legacy API */
490  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
491  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
492  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
493  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
494 
495  sws->scaler_params[0] = ctx->scaler_params[0];
496  sws->scaler_params[1] = ctx->scaler_params[1];
497 
499  if (ret < 0) {
501  return ret;
502  }
503 
504  /* Set correct color matrices */
505  {
506  int in_full, out_full, brightness, contrast, saturation;
507  const int *inv_table, *table;
508  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
509  (int **)&table, &out_full,
510  &brightness, &contrast, &saturation);
511 
512  inv_table = sws_getCoefficients(src.csp);
514 
515  graph->incomplete |= src.csp != dst.csp &&
516  (src.csp == AVCOL_SPC_UNSPECIFIED ||
517  dst.csp == AVCOL_SPC_UNSPECIFIED);
518 
519  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
520  brightness, contrast, saturation);
521  }
522 
523  return init_legacy_subpass(graph, sws, input, output);
524 }
525 
526 /*********************
527  * Format conversion *
528  *********************/
529 
530 #if CONFIG_UNSTABLE
531 static int add_convert_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst,
533 {
535 
536  SwsContext *ctx = graph->ctx;
537  SwsOpList *ops = NULL;
538  int ret = AVERROR(ENOTSUP);
539 
540  /* Mark the entire new ops infrastructure as experimental for now */
541  if (!(ctx->flags & SWS_UNSTABLE))
542  goto fail;
543 
544  /* The new format conversion layer cannot scale for now */
545  if (src.width != dst.width || src.height != dst.height ||
546  src.desc->log2_chroma_h || src.desc->log2_chroma_w ||
547  dst.desc->log2_chroma_h || dst.desc->log2_chroma_w)
548  goto fail;
549 
550  /* The new code does not yet support alpha blending */
551  if (src.desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
552  ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
553  goto fail;
554 
555  ops = ff_sws_op_list_alloc();
556  if (!ops)
557  return AVERROR(ENOMEM);
558  ops->src = src;
559  ops->dst = dst;
560 
561  ret = ff_sws_decode_pixfmt(ops, src.format);
562  if (ret < 0)
563  goto fail;
564  ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete);
565  if (ret < 0)
566  goto fail;
567  ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete);
568  if (ret < 0)
569  goto fail;
570  ret = ff_sws_encode_pixfmt(ops, dst.format);
571  if (ret < 0)
572  goto fail;
573 
574  av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
576 
577  av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
579  av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n");
582 
583  ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output);
584  if (ret < 0)
585  goto fail;
586 
587  ret = 0;
588  /* fall through */
589 
590 fail:
591  ff_sws_op_list_free(&ops);
592  if (ret == AVERROR(ENOTSUP))
593  return add_legacy_sws_pass(graph, src, dst, input, output);
594  return ret;
595 }
596 #else
597 #define add_convert_pass add_legacy_sws_pass
598 #endif
599 
600 
601 /**************************
602  * Gamut and tone mapping *
603  **************************/
604 
605 static void free_lut3d(void *priv)
606 {
607  SwsLut3D *lut = priv;
608  ff_sws_lut3d_free(&lut);
609 }
610 
611 static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
612 {
613  SwsLut3D *lut = pass->priv;
614 
615  /* Update dynamic frame metadata from the original source frame */
616  ff_sws_lut3d_update(lut, &pass->graph->src.color);
617 }
618 
619 static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base,
620  int y, int h, const SwsPass *pass)
621 {
622  SwsLut3D *lut = pass->priv;
623  const SwsImg in = ff_sws_img_shift(in_base, y);
624  const SwsImg out = ff_sws_img_shift(out_base, y);
625 
626  ff_sws_lut3d_apply(lut, in.data[0], in.linesize[0], out.data[0],
627  out.linesize[0], pass->width, h);
628 }
629 
632 {
633  enum AVPixelFormat fmt_in, fmt_out;
634  SwsColorMap map = {0};
635  SwsLut3D *lut;
636  SwsPass *pass;
637  int ret;
638 
639  /**
640  * Grayspace does not really have primaries, so just force the use of
641  * the equivalent other primary set to avoid a conversion. Technically,
642  * this does affect the weights used for the Grayscale conversion, but
643  * in practise, that should give the expected results more often than not.
644  */
645  if (isGray(dst.format)) {
646  dst.color = src.color;
647  } else if (isGray(src.format)) {
648  src.color = dst.color;
649  }
650 
651  /* Fully infer color spaces before color mapping logic */
652  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
653 
654  map.intent = graph->ctx->intent;
655  map.src = src.color;
656  map.dst = dst.color;
657 
659  return 0;
660 
661  lut = ff_sws_lut3d_alloc();
662  if (!lut)
663  return AVERROR(ENOMEM);
664 
665  fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0);
666  fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1);
667  if (fmt_in != src.format) {
668  SwsFormat tmp = src;
669  tmp.format = fmt_in;
670  ret = add_convert_pass(graph, src, tmp, input, &input);
671  if (ret < 0)
672  return ret;
673  }
674 
675  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
676  if (ret < 0) {
677  ff_sws_lut3d_free(&lut);
678  return ret;
679  }
680 
681  pass = ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
682  input, 1, lut, run_lut3d);
683  if (!pass) {
684  ff_sws_lut3d_free(&lut);
685  return AVERROR(ENOMEM);
686  }
687  pass->setup = setup_lut3d;
688  pass->free = free_lut3d;
689 
690  *output = pass;
691  return 0;
692 }
693 
694 /***************************************
695  * Main filter graph construction code *
696  ***************************************/
697 
698 static int init_passes(SwsGraph *graph)
699 {
700  SwsFormat src = graph->src;
701  SwsFormat dst = graph->dst;
702  SwsPass *pass = NULL; /* read from main input image */
703  int ret;
704 
705  ret = adapt_colors(graph, src, dst, pass, &pass);
706  if (ret < 0)
707  return ret;
708  src.format = pass ? pass->format : src.format;
709  src.color = dst.color;
710 
711  if (!ff_fmt_equal(&src, &dst)) {
712  ret = add_convert_pass(graph, src, dst, pass, &pass);
713  if (ret < 0)
714  return ret;
715  }
716 
717  if (!pass) {
718  /* No passes were added, so no operations were necessary */
719  graph->noop = 1;
720 
721  /* Add threaded memcpy pass */
722  pass = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
723  pass, 1, NULL, run_copy);
724  if (!pass)
725  return AVERROR(ENOMEM);
726  }
727 
728  return 0;
729 }
730 
731 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
732  int nb_threads)
733 {
734  SwsGraph *graph = priv;
735  const SwsPass *pass = graph->exec.pass;
736  const int slice_y = jobnr * pass->slice_h;
737  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
738 
739  pass->run(&graph->exec.output, &graph->exec.input, slice_y, slice_h, pass);
740 }
741 
743  int field, SwsGraph **out_graph)
744 {
745  int ret;
746  SwsGraph *graph = av_mallocz(sizeof(*graph));
747  if (!graph)
748  return AVERROR(ENOMEM);
749 
750  graph->ctx = ctx;
751  graph->src = *src;
752  graph->dst = *dst;
753  graph->field = field;
754  graph->opts_copy = *ctx;
755 
756  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
757  sws_graph_worker, NULL, ctx->threads);
758  if (ret == AVERROR(ENOSYS))
759  graph->num_threads = 1;
760  else if (ret < 0)
761  goto error;
762  else
763  graph->num_threads = ret;
764 
765  ret = init_passes(graph);
766  if (ret < 0)
767  goto error;
768 
769  *out_graph = graph;
770  return 0;
771 
772 error:
773  ff_sws_graph_free(&graph);
774  return ret;
775 }
776 
778 {
779  SwsGraph *graph = *pgraph;
780  if (!graph)
781  return;
782 
784 
785  for (int i = 0; i < graph->num_passes; i++) {
786  SwsPass *pass = graph->passes[i];
787  if (pass->free)
788  pass->free(pass->priv);
789  av_refstruct_unref(&pass->output);
790  av_free(pass);
791  }
792  av_free(graph->passes);
793 
794  av_free(graph);
795  *pgraph = NULL;
796 }
797 
798 /* Tests only options relevant to SwsGraph */
799 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
800 {
801  return c1->flags == c2->flags &&
802  c1->threads == c2->threads &&
803  c1->dither == c2->dither &&
804  c1->alpha_blend == c2->alpha_blend &&
805  c1->gamma_flag == c2->gamma_flag &&
806  c1->src_h_chr_pos == c2->src_h_chr_pos &&
807  c1->src_v_chr_pos == c2->src_v_chr_pos &&
808  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
809  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
810  c1->intent == c2->intent &&
811  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
812 
813 }
814 
816  int field, SwsGraph **out_graph)
817 {
818  SwsGraph *graph = *out_graph;
819  if (graph && ff_fmt_equal(&graph->src, src) &&
820  ff_fmt_equal(&graph->dst, dst) &&
821  opts_equal(ctx, &graph->opts_copy))
822  {
823  ff_sws_graph_update_metadata(graph, &src->color);
824  return 0;
825  }
826 
827  ff_sws_graph_free(out_graph);
828  return ff_sws_graph_create(ctx, dst, src, field, out_graph);
829 }
830 
832 {
833  if (!color)
834  return;
835 
837 }
838 
839 static SwsImg pass_output(const SwsPass *pass, const SwsImg *fallback)
840 {
841  if (!pass)
842  return *fallback;
843 
844  SwsImg img = pass->output->img;
845  for (int i = 0; i < FF_ARRAY_ELEMS(img.data); i++) {
846  if (!img.data[i]) {
847  img.data[i] = fallback->data[i];
848  img.linesize[i] = fallback->linesize[i];
849  }
850  }
851 
852  return img;
853 }
854 
855 void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input)
856 {
857  av_assert0(output->fmt == graph->dst.format);
858  av_assert0(input->fmt == graph->src.format);
859 
860  for (int i = 0; i < graph->num_passes; i++) {
861  const SwsPass *pass = graph->passes[i];
862  graph->exec.pass = pass;
863  graph->exec.input = pass_output(pass->input, input);
864  graph->exec.output = pass_output(pass, output);
865  if (pass->setup)
866  pass->setup(&graph->exec.output, &graph->exec.input, pass);
868  }
869 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
sws_setColorspaceDetails
int sws_setColorspaceDetails(SwsContext *c, const int inv_table[4], int srcRange, const int table[4], int dstRange, int brightness, int contrast, int saturation)
Definition: utils.c:845
ff_sws_encode_colors
int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, const SwsFormat src, const SwsFormat dst, bool *incomplete)
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:481
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
SwsGraph::slicethread
AVSliceThread * slicethread
Definition: graph.h:121
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:120
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:79
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:469
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:147
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
opt.h
SwsGraph::passes
SwsPass ** passes
Sorted sequence of filter passes to apply.
Definition: graph.h:127
adapt_colors
static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:630
out
static FILE * out
Definition: movenc.c:55
color
Definition: vf_paletteuse.c:513
init_passes
static int init_passes(SwsGraph *graph)
Definition: graph.c:698
SwsFormat::interlaced
int interlaced
Definition: format.h:79
SwsContext::src_w
int src_w
Deprecated frame property overrides, for the legacy API only.
Definition: swscale.h:237
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
ff_sws_graph_reinit
int ff_sws_graph_reinit(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, int field, SwsGraph **out_graph)
Wrapper around ff_sws_graph_create() that reuses the existing graph if the format is compatible.
Definition: graph.c:815
AVRefStructOpaque
RefStruct is an API for creating reference-counted objects with minimal overhead.
Definition: refstruct.h:58
SwsPass::format
enum AVPixelFormat format
Definition: graph.h:88
saturation
static IPT saturation(const CmsCtx *ctx, IPT ipt)
Definition: cms.c:559
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
sws_filter_run_t
void(* sws_filter_run_t)(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Output h lines of filtered data.
Definition: graph.h:62
SwsGraph::src
SwsFormat src
Currently active format and processing parameters.
Definition: graph.h:139
avpriv_slicethread_execute
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
Definition: slicethread.c:271
pixdesc.h
ops.h
AVFrame::width
int width
Definition: frame.h:499
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:777
isGray
static av_always_inline int isGray(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:803
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:158
table
static const uint16_t table[]
Definition: prosumer.c:203
SwsContext::flags
unsigned flags
Bitmask of SWS_*.
Definition: swscale.h:204
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
ff_sws_lut3d_pick_pixfmt
enum AVPixelFormat ff_sws_lut3d_pick_pixfmt(SwsFormat fmt, int output)
Pick the best compatible pixfmt for a given SwsFormat.
Definition: lut3d.c:52
SwsPass::free
void(* free)(void *priv)
Optional private state and associated free() function.
Definition: graph.h:112
c1
static const uint64_t c1
Definition: murmur3.c:52
SwsImg
Represents a view into a single field of frame data.
Definition: graph.h:35
format.h
AVFrame::buf
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:604
SWS_ALPHA_BLEND_NONE
@ SWS_ALPHA_BLEND_NONE
Definition: swscale.h:89
ff_sws_init_single_context
int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, SwsFilter *dstFilter)
Definition: utils.c:1117
SwsColorMap
Definition: cms.h:60
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:30
SwsPass::width
int width
Definition: graph.h:89
ff_color_update_dynamic
static void ff_color_update_dynamic(SwsColor *dst, const SwsColor *src)
Definition: format.h:70
init_legacy_subpass
static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws, SwsPass *input, SwsPass **output)
Definition: graph.c:350
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:35
avpriv_slicethread_create
int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, void(*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), void(*main_func)(void *priv), int nb_threads)
Create slice threading context.
Definition: slicethread.c:262
macros.h
pass_append
static int pass_append(SwsGraph *graph, enum AVPixelFormat fmt, int w, int h, SwsPass **pass, int align, void *priv, sws_filter_run_t run)
Definition: graph.c:150
fail
#define fail()
Definition: checkasm.h:218
SwsContext::src_v_chr_pos
int src_v_chr_pos
Source vertical chroma position in luma grid / 256.
Definition: swscale.h:243
slice_ctx
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition: graph.c:250
sws_init_context
av_warn_unused_result int sws_init_context(SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter)
Initialize the swscaler context sws_context.
Definition: utils.c:1890
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:134
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
refstruct.h
av_image_check_size2
int av_image_check_size2(unsigned int w, unsigned int h, int64_t max_pixels, enum AVPixelFormat pix_fmt, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of a plane of an image with...
Definition: imgutils.c:289
ff_sws_graph_create
int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, int field, SwsGraph **out_graph)
Allocate and initialize the filter graph.
Definition: graph.c:742
avassert.h
SwsInternal::pal_rgb
uint32_t pal_rgb[256]
Definition: swscale_internal.h:396
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
legacy_chr_pos
static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
Definition: graph.c:334
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:219
SwsPass::priv
void * priv
Definition: graph.h:113
SwsInternal::nb_slice_ctx
int nb_slice_ctx
Definition: swscale_internal.h:340
av_image_fill_linesizes
int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width)
Fill plane linesizes for an image with pixel format pix_fmt and width width.
Definition: imgutils.c:89
SwsInternal::slice_ctx
SwsContext ** slice_ctx
Definition: swscale_internal.h:338
av_chroma_location_enum_to_pos
int av_chroma_location_enum_to_pos(int *xpos, int *ypos, enum AVChromaLocation pos)
Converts AVChromaLocation to swscale x/y chroma position.
Definition: pixdesc.c:3898
ff_update_palette
void ff_update_palette(SwsInternal *c, const uint32_t *pal)
Definition: swscale.c:870
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1415
ff_sws_lut3d_alloc
SwsLut3D * ff_sws_lut3d_alloc(void)
Definition: lut3d.c:32
SwsPass::setup
void(* setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Called once from the main thread before running the filter.
Definition: graph.h:107
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
SwsContext::intent
int intent
Desired ICC intent for color space conversions.
Definition: swscale.h:251
av_refstruct_alloc_ext
static void * av_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque, void(*free_cb)(AVRefStructOpaque opaque, void *obj))
A wrapper around av_refstruct_alloc_ext_c() for the common case of a non-const qualified opaque.
Definition: refstruct.h:94
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:128
AV_PIX_FMT_FLAG_ALPHA
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition: pixdesc.h:147
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
ff_sws_lut3d_update
void ff_sws_lut3d_update(SwsLut3D *lut3d, const SwsColor *new_src)
Update the tone mapping state.
Definition: lut3d.c:239
field
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 field
Definition: writing_filters.txt:78
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
free_buffer
static void free_buffer(AVRefStructOpaque opaque, void *obj)
Definition: graph.c:92
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
SwsGraph::field
int field
Definition: graph.h:140
ff_sws_graph_add_pass
SwsPass * ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int align, void *priv, sws_filter_run_t run)
Allocate and add a new pass to the filter graph.
Definition: graph.c:99
ff_sws_lut3d_free
void ff_sws_lut3d_free(SwsLut3D **plut3d)
Definition: lut3d.c:42
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: format.h:57
NULL
#define NULL
Definition: coverity.c:32
sizes
static const int sizes[][2]
Definition: img2dec.c:61
format
New swscale design to change SwsGraph is what coordinates multiple passes These can include cascaded scaling error diffusion and so on Or we could have separate passes for the vertical and horizontal scaling In between each SwsPass lies a fully allocated image buffer Graph passes may have different levels of e g we can have a single threaded error diffusion pass following a multi threaded scaling pass SwsGraph is internally recreated whenever the image format
Definition: swscale-v2.txt:14
ff_sws_graph_run
void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input)
Dispatch the filter graph on a single field.
Definition: graph.c:855
run
uint8_t run
Definition: svq3.c:207
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
SwsContext::gamma_flag
int gamma_flag
Use gamma correct scaling.
Definition: swscale.h:229
av_image_fill_plane_sizes
int av_image_fill_plane_sizes(size_t sizes[4], enum AVPixelFormat pix_fmt, int height, const ptrdiff_t linesizes[4])
Fill plane sizes for an image with pixel format pix_fmt and height height.
Definition: imgutils.c:111
run_xyz2rgb
static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:206
ff_infer_colors
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition: format.c:508
SwsGraph::input
SwsImg input
Definition: graph.h:148
ff_sws_lut3d_generate
int ff_sws_lut3d_generate(SwsLut3D *lut3d, enum AVPixelFormat fmt_in, enum AVPixelFormat fmt_out, const SwsColorMap *map)
Recalculate the (static) 3DLUT state with new settings.
Definition: lut3d.c:211
SwsContext::src_range
int src_range
Source is full range.
Definition: swscale.h:241
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:283
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:80
AVCOL_RANGE_UNSPECIFIED
@ AVCOL_RANGE_UNSPECIFIED
Definition: pixfmt.h:743
SwsContext::dst_h_chr_pos
int dst_h_chr_pos
Destination horizontal chroma position.
Definition: swscale.h:246
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
run_legacy_swscale
static void run_legacy_swscale(const SwsImg *out_base, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:280
error.h
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:2155
ff_sws_graph_free
void ff_sws_graph_free(SwsGraph **pgraph)
Uninitialize any state associate with this filter graph and free it.
Definition: graph.c:777
SwsPass::height
int height
Definition: graph.h:89
SwsImg::linesize
int linesize[4]
Definition: graph.h:38
add_legacy_sws_pass
static int add_legacy_sws_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:460
lut3d.h
free_lut3d
static void free_lut3d(void *priv)
Definition: graph.c:605
height
#define height
Definition: dsp.h:89
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1028
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:87
usePal
static av_always_inline int usePal(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:934
cpu.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
SwsPassBuffer::img
SwsImg img
Definition: graph.h:69
setup_lut3d
static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Definition: graph.c:611
ff_sws_lut3d_apply
void ff_sws_lut3d_apply(const SwsLut3D *lut3d, const uint8_t *in, int in_stride, uint8_t *out, int out_stride, int w, int h)
Applies a color transformation to a plane.
Definition: lut3d.c:250
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:525
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:224
SwsPassBuffer::height
int height
Definition: graph.h:70
SwsOpList::src
SwsFormat src
Definition: ops.h:241
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:237
SwsGraph::exec
struct SwsGraph::@537 exec
Temporary execution state inside ff_sws_graph_run(); used to pass data to worker threads.
SwsGraph::output
SwsImg output
Definition: graph.h:149
AVCHROMA_LOC_UNSPECIFIED
@ AVCHROMA_LOC_UNSPECIFIED
Definition: pixfmt.h:797
SwsFormat
Definition: format.h:77
sws_getColorspaceDetails
int sws_getColorspaceDetails(SwsContext *c, int **inv_table, int *srcRange, int **table, int *dstRange, int *brightness, int *contrast, int *saturation)
Definition: utils.c:1003
align
static const uint8_t *BS_FUNC() align(BSCTX *bc)
Skip bits to a byte boundary.
Definition: bitstream_template.h:419
SwsFormat::loc
enum AVChromaLocation loc
Definition: format.h:83
img
#define img
Definition: vf_colormatrix.c:114
SwsColor
Definition: format.h:60
SwsPass::output
SwsPassBuffer * output
Filter output buffer.
Definition: graph.h:102
av_buffer_alloc
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:77
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:240
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
slicethread.h
AVChromaLocation
AVChromaLocation
Location of chroma samples.
Definition: pixfmt.h:796
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
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:283
sws
static SwsContext * sws[3]
Definition: swscale.c:73
free_legacy_swscale
static void free_legacy_swscale(void *priv)
Definition: graph.c:230
pass_output
static SwsImg pass_output(const SwsPass *pass, const SwsImg *fallback)
Definition: graph.c:839
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:139
ff_fmt_vshift
static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane)
Definition: graph.h:41
SwsFormat::format
enum AVPixelFormat format
Definition: format.h:80
SwsPass::slice_h
int slice_h
Definition: graph.h:90
SwsGraph::num_threads
int num_threads
Definition: graph.h:122
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:799
run_rgb0
static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:185
SwsFormat::desc
const AVPixFmtDescriptor * desc
Definition: format.h:84
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:58
run_rgb2xyz
static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:215
swscale_internal.h
graph.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:238
run_copy
static void run_copy(const SwsImg *out_base, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:160
AVCOL_SPC_UNSPECIFIED
@ AVCOL_SPC_UNSPECIFIED
Definition: pixfmt.h:703
ff_sws_img_shift
static av_const SwsImg ff_sws_img_shift(const SwsImg *base, const int y)
Definition: graph.h:47
ff_sws_decode_pixfmt
int ff_sws_decode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
Append a set of operations for decoding/encoding raw pixels.
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
get_chroma_pos
static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos, const SwsFormat *fmt)
Definition: graph.c:291
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
SwsInternal
Definition: swscale_internal.h:330
ret
ret
Definition: filter_design.txt:187
SwsOpList::dst
SwsFormat dst
Definition: ops.h:241
ff_fmt_equal
static int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
Definition: format.h:129
ff_sws_decode_colors
int ff_sws_decode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, const SwsFormat fmt, bool *incomplete)
Append a set of operations for transforming decoded pixel values to/from normalized RGB in the specif...
SwsGraph::noop
bool noop
Definition: graph.h:124
av_dynarray_add_nofree
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition: mem.c:315
AVFrame::height
int height
Definition: frame.h:499
c2
static const uint64_t c2
Definition: murmur3.c:53
SwsPassBuffer::width
int width
Definition: graph.h:70
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, SwsFormat dst, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
SwsContext::scaler_params
double scaler_params[2]
Extra parameters for fine-tuning certain scalers.
Definition: swscale.h:209
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
AVCHROMA_LOC_CENTER
@ AVCHROMA_LOC_CENTER
MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0.
Definition: pixfmt.h:799
SwsFormat::color
SwsColor color
Definition: format.h:85
ff_sws_color_map_noop
bool ff_sws_color_map_noop(const SwsColorMap *map)
Returns true if the given color map is a semantic no-op - that is, the overall RGB end to end transfo...
Definition: cms.c:34
setup_legacy_swscale
static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Definition: graph.c:236
ff_swscale
int ff_swscale(SwsInternal *c, const uint8_t *const src[], const int srcStride[], int srcSliceY, int srcSliceH, uint8_t *const dst[], const int dstStride[], int dstSliceY, int dstSliceH)
Definition: swscale.c:259
cms.h
add_convert_pass
#define add_convert_pass
Definition: graph.c:597
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:395
SwsGraph::incomplete
bool incomplete
Definition: graph.h:123
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
sws_getCoefficients
const int * sws_getCoefficients(int colorspace)
Return a pointer to yuv<->rgb coefficients for the given colorspace suitable for sws_setColorspaceDet...
Definition: yuv2rgb.c:61
SwsContext::dst_w
int dst_w
Definition: swscale.h:238
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:119
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:239
w
uint8_t w
Definition: llvidencdsp.c:39
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
SwsImg::fmt
enum AVPixelFormat fmt
Definition: graph.h:36
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
SwsContext::dst_range
int dst_range
Destination is full range.
Definition: swscale.h:242
pass_alloc_output
static int pass_alloc_output(SwsPass *pass)
Definition: graph.c:65
run_legacy_unscaled
static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:269
SwsPass::run
sws_filter_run_t run
Filter main execution function.
Definition: graph.h:87
sws_free_context
void sws_free_context(SwsContext **ctx)
Free the context and everything associated with it, and write NULL to the provided pointer.
Definition: utils.c:2337
imgutils.h
ff_sws_op_list_print
void ff_sws_op_list_print(void *log, int lev, const SwsOpList *ops)
Print out the contents of an operation list.
Definition: ops.c:692
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:472
avpriv_slicethread_free
void avpriv_slicethread_free(AVSliceThread **pctx)
Destroy slice threading context.
Definition: slicethread.c:276
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
SwsContext::src_h_chr_pos
int src_h_chr_pos
Source horizontal chroma position.
Definition: swscale.h:244
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:74
SwsPass::input
const SwsPass * input
Filter input.
Definition: graph.h:97
SwsPassBuffer
Represents an allocated output buffer for a filter pass.
Definition: graph.h:68
h
h
Definition: vp9dsp_template.c:2070
SwsPass::num_slices
int num_slices
Definition: graph.h:91
width
#define width
Definition: dsp.h:89
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:222
run_lut3d
static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:619
SwsPassBuffer::buf
AVBufferRef * buf[4]
Definition: graph.h:71
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:245
SwsContext
Main external API structure.
Definition: swscale.h:191
sws_graph_worker
static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
Definition: graph.c:731
ff_sws_graph_update_metadata
void ff_sws_graph_update_metadata(SwsGraph *graph, const SwsColor *color)
Update dynamic per-frame HDR metadata without requiring a full reinit.
Definition: graph.c:831
SWS_UNSTABLE
@ SWS_UNSTABLE
Allow using experimental new code paths.
Definition: swscale.h:165
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
buffer_get_sizes
static int buffer_get_sizes(SwsPassBuffer *buffer, size_t sizes[4])
Definition: graph.c:41
swscale.h
SwsImg::data
uint8_t * data[4]
Definition: graph.h:37
ff_sws_encode_pixfmt
int ff_sws_encode_pixfmt(SwsOpList *ops, enum AVPixelFormat fmt)
av_get_pix_fmt_name
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:3376
isALPHA
static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:894