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;
465  if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE)
466  return AVERROR(ENOTSUP);
467 
469  if (!sws)
470  return AVERROR(ENOMEM);
471 
472  sws->flags = ctx->flags;
473  sws->dither = ctx->dither;
474  sws->alpha_blend = ctx->alpha_blend;
475  sws->gamma_flag = ctx->gamma_flag;
476 
477  sws->src_w = src.width;
478  sws->src_h = src.height;
479  sws->src_format = src.format;
480  sws->src_range = src.range == AVCOL_RANGE_JPEG;
481 
482  sws->dst_w = dst.width;
483  sws->dst_h = dst.height;
484  sws->dst_format = dst.format;
485  sws->dst_range = dst.range == AVCOL_RANGE_JPEG;
488 
489  graph->incomplete |= src.range == AVCOL_RANGE_UNSPECIFIED;
490  graph->incomplete |= dst.range == AVCOL_RANGE_UNSPECIFIED;
491 
492  /* Allow overriding chroma position with the legacy API */
493  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
494  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
495  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
496  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
497 
498  sws->scaler_params[0] = ctx->scaler_params[0];
499  sws->scaler_params[1] = ctx->scaler_params[1];
500 
502  if (ret < 0) {
504  return ret;
505  }
506 
507  /* Set correct color matrices */
508  {
509  int in_full, out_full, brightness, contrast, saturation;
510  const int *inv_table, *table;
511  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
512  (int **)&table, &out_full,
513  &brightness, &contrast, &saturation);
514 
515  inv_table = sws_getCoefficients(src.csp);
517 
518  graph->incomplete |= src.csp != dst.csp &&
519  (src.csp == AVCOL_SPC_UNSPECIFIED ||
520  dst.csp == AVCOL_SPC_UNSPECIFIED);
521 
522  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
523  brightness, contrast, saturation);
524  }
525 
526  return init_legacy_subpass(graph, sws, input, output);
527 }
528 
529 /*********************
530  * Format conversion *
531  *********************/
532 
533 #if CONFIG_UNSTABLE
534 static int add_convert_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst,
536 {
538 
539  SwsContext *ctx = graph->ctx;
540  SwsOpList *ops = NULL;
541  int ret = AVERROR(ENOTSUP);
542 
543  /* Mark the entire new ops infrastructure as experimental for now */
544  if (!(ctx->flags & SWS_UNSTABLE))
545  goto fail;
546 
547  /* The new format conversion layer cannot scale for now */
548  if (src.width != dst.width || src.height != dst.height ||
549  src.desc->log2_chroma_h || src.desc->log2_chroma_w ||
550  dst.desc->log2_chroma_h || dst.desc->log2_chroma_w)
551  goto fail;
552 
553  /* The new code does not yet support alpha blending */
554  if (src.desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
555  ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
556  goto fail;
557 
558  ops = ff_sws_op_list_alloc();
559  if (!ops)
560  return AVERROR(ENOMEM);
561  ops->src = src;
562  ops->dst = dst;
563 
564  ret = ff_sws_decode_pixfmt(ops, src.format);
565  if (ret < 0)
566  goto fail;
567  ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete);
568  if (ret < 0)
569  goto fail;
570  ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete);
571  if (ret < 0)
572  goto fail;
573  ret = ff_sws_encode_pixfmt(ops, dst.format);
574  if (ret < 0)
575  goto fail;
576 
577  av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
579 
580  av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
582  av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n");
585 
586  ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output);
587  if (ret < 0)
588  goto fail;
589 
590  ret = 0;
591  /* fall through */
592 
593 fail:
594  ff_sws_op_list_free(&ops);
595  if (ret == AVERROR(ENOTSUP))
596  return add_legacy_sws_pass(graph, src, dst, input, output);
597  return ret;
598 }
599 #else
600 #define add_convert_pass add_legacy_sws_pass
601 #endif
602 
603 
604 /**************************
605  * Gamut and tone mapping *
606  **************************/
607 
608 static void free_lut3d(void *priv)
609 {
610  SwsLut3D *lut = priv;
611  ff_sws_lut3d_free(&lut);
612 }
613 
614 static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
615 {
616  SwsLut3D *lut = pass->priv;
617 
618  /* Update dynamic frame metadata from the original source frame */
619  ff_sws_lut3d_update(lut, &pass->graph->src.color);
620 }
621 
622 static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base,
623  int y, int h, const SwsPass *pass)
624 {
625  SwsLut3D *lut = pass->priv;
626  const SwsImg in = ff_sws_img_shift(in_base, y);
627  const SwsImg out = ff_sws_img_shift(out_base, y);
628 
629  ff_sws_lut3d_apply(lut, in.data[0], in.linesize[0], out.data[0],
630  out.linesize[0], pass->width, h);
631 }
632 
635 {
636  enum AVPixelFormat fmt_in, fmt_out;
637  SwsColorMap map = {0};
638  SwsLut3D *lut;
639  SwsPass *pass;
640  int ret;
641 
642  /**
643  * Grayspace does not really have primaries, so just force the use of
644  * the equivalent other primary set to avoid a conversion. Technically,
645  * this does affect the weights used for the Grayscale conversion, but
646  * in practise, that should give the expected results more often than not.
647  */
648  if (isGray(dst.format)) {
649  dst.color = src.color;
650  } else if (isGray(src.format)) {
651  src.color = dst.color;
652  }
653 
654  /* Fully infer color spaces before color mapping logic */
655  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
656 
657  map.intent = graph->ctx->intent;
658  map.src = src.color;
659  map.dst = dst.color;
660 
662  return 0;
663 
664  if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE)
665  return AVERROR(ENOTSUP);
666 
667  lut = ff_sws_lut3d_alloc();
668  if (!lut)
669  return AVERROR(ENOMEM);
670 
671  fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0);
672  fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1);
673  if (fmt_in != src.format) {
674  SwsFormat tmp = src;
675  tmp.format = fmt_in;
676  ret = add_convert_pass(graph, src, tmp, input, &input);
677  if (ret < 0)
678  return ret;
679  }
680 
681  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
682  if (ret < 0) {
683  ff_sws_lut3d_free(&lut);
684  return ret;
685  }
686 
687  pass = ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
688  input, 1, lut, run_lut3d);
689  if (!pass) {
690  ff_sws_lut3d_free(&lut);
691  return AVERROR(ENOMEM);
692  }
693  pass->setup = setup_lut3d;
694  pass->free = free_lut3d;
695 
696  *output = pass;
697  return 0;
698 }
699 
700 /***************************************
701  * Main filter graph construction code *
702  ***************************************/
703 
704 static int init_passes(SwsGraph *graph)
705 {
706  SwsFormat src = graph->src;
707  SwsFormat dst = graph->dst;
708  SwsPass *pass = NULL; /* read from main input image */
709  int ret;
710 
711  ret = adapt_colors(graph, src, dst, pass, &pass);
712  if (ret < 0)
713  return ret;
714  src.format = pass ? pass->format : src.format;
715  src.color = dst.color;
716 
717  if (!ff_fmt_equal(&src, &dst)) {
718  ret = add_convert_pass(graph, src, dst, pass, &pass);
719  if (ret < 0)
720  return ret;
721  }
722 
723  if (!pass) {
724  /* No passes were added, so no operations were necessary */
725  graph->noop = 1;
726 
727  /* Add threaded memcpy pass */
728  pass = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
729  pass, 1, NULL, run_copy);
730  if (!pass)
731  return AVERROR(ENOMEM);
732  }
733 
734  return 0;
735 }
736 
737 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
738  int nb_threads)
739 {
740  SwsGraph *graph = priv;
741  const SwsPass *pass = graph->exec.pass;
742  const int slice_y = jobnr * pass->slice_h;
743  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
744 
745  pass->run(&graph->exec.output, &graph->exec.input, slice_y, slice_h, pass);
746 }
747 
749  int field, SwsGraph **out_graph)
750 {
751  int ret;
752  SwsGraph *graph = av_mallocz(sizeof(*graph));
753  if (!graph)
754  return AVERROR(ENOMEM);
755 
756  graph->ctx = ctx;
757  graph->src = *src;
758  graph->dst = *dst;
759  graph->field = field;
760  graph->opts_copy = *ctx;
761 
762  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
763  sws_graph_worker, NULL, ctx->threads);
764  if (ret == AVERROR(ENOSYS))
765  graph->num_threads = 1;
766  else if (ret < 0)
767  goto error;
768  else
769  graph->num_threads = ret;
770 
771  ret = init_passes(graph);
772  if (ret < 0)
773  goto error;
774 
775  *out_graph = graph;
776  return 0;
777 
778 error:
779  ff_sws_graph_free(&graph);
780  return ret;
781 }
782 
784 {
785  SwsGraph *graph = *pgraph;
786  if (!graph)
787  return;
788 
790 
791  for (int i = 0; i < graph->num_passes; i++) {
792  SwsPass *pass = graph->passes[i];
793  if (pass->free)
794  pass->free(pass->priv);
795  av_refstruct_unref(&pass->output);
796  av_free(pass);
797  }
798  av_free(graph->passes);
799 
800  av_free(graph);
801  *pgraph = NULL;
802 }
803 
804 /* Tests only options relevant to SwsGraph */
805 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
806 {
807  return c1->flags == c2->flags &&
808  c1->threads == c2->threads &&
809  c1->dither == c2->dither &&
810  c1->alpha_blend == c2->alpha_blend &&
811  c1->gamma_flag == c2->gamma_flag &&
812  c1->src_h_chr_pos == c2->src_h_chr_pos &&
813  c1->src_v_chr_pos == c2->src_v_chr_pos &&
814  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
815  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
816  c1->intent == c2->intent &&
817  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
818 
819 }
820 
822  int field, SwsGraph **out_graph)
823 {
824  SwsGraph *graph = *out_graph;
825  if (graph && ff_fmt_equal(&graph->src, src) &&
826  ff_fmt_equal(&graph->dst, dst) &&
827  opts_equal(ctx, &graph->opts_copy))
828  {
829  ff_sws_graph_update_metadata(graph, &src->color);
830  return 0;
831  }
832 
833  ff_sws_graph_free(out_graph);
834  return ff_sws_graph_create(ctx, dst, src, field, out_graph);
835 }
836 
838 {
839  if (!color)
840  return;
841 
843 }
844 
845 static SwsImg pass_output(const SwsPass *pass, const SwsImg *fallback)
846 {
847  if (!pass)
848  return *fallback;
849 
850  SwsImg img = pass->output->img;
851  img.frame_ptr = fallback->frame_ptr;
852  for (int i = 0; i < FF_ARRAY_ELEMS(img.data); i++) {
853  if (!img.data[i]) {
854  img.data[i] = fallback->data[i];
855  img.linesize[i] = fallback->linesize[i];
856  }
857  }
858 
859  return img;
860 }
861 
862 void ff_sws_graph_run(SwsGraph *graph, const SwsImg *output, const SwsImg *input)
863 {
864  av_assert0(output->fmt == graph->dst.hw_format ||
865  output->fmt == graph->dst.format);
866  av_assert0(input->fmt == graph->src.hw_format ||
867  input->fmt == graph->src.format);
868 
869  for (int i = 0; i < graph->num_passes; i++) {
870  const SwsPass *pass = graph->passes[i];
871  graph->exec.pass = pass;
872  graph->exec.input = pass_output(pass->input, input);
873  graph->exec.output = pass_output(pass, output);
874  if (pass->setup)
875  pass->setup(&graph->exec.output, &graph->exec.input, pass);
877  }
878 }
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:849
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:507
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:122
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:121
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:80
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:495
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:150
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:130
adapt_colors
static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:633
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:704
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:821
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:89
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:63
SwsGraph::src
SwsFormat src
Currently active format and processing parameters.
Definition: graph.h:142
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:806
SwsImg::frame_ptr
const AVFrame * frame_ptr
Definition: graph.h:39
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:113
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:1121
SwsColorMap
Definition: cms.h:60
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:30
SwsPass::width
int width
Definition: graph.h:90
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:718
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:1894
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:137
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:748
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
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:114
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:874
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:108
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:131
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:143
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:862
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:526
SwsGraph::input
SwsImg input
Definition: graph.h:151
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:81
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:783
SwsPass::height
int height
Definition: graph.h:90
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:608
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:1032
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:937
cpu.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
SwsPassBuffer::img
SwsImg img
Definition: graph.h:70
setup_lut3d
static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Definition: graph.c:614
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:71
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:152
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:1007
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:84
img
#define img
Definition: vf_colormatrix.c:114
SwsColor
Definition: format.h:60
SwsPass::output
SwsPassBuffer * output
Filter output buffer.
Definition: graph.h:103
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:845
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:142
ff_fmt_vshift
static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane)
Definition: graph.h:42
SwsFormat::format
enum AVPixelFormat format
Definition: format.h:80
SwsPass::slice_h
int slice_h
Definition: graph.h:91
SwsGraph::num_threads
int num_threads
Definition: graph.h:123
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:805
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:85
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:48
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:130
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:125
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:71
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
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:81
SwsFormat::color
SwsColor color
Definition: format.h:86
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:263
cms.h
add_convert_pass
#define add_convert_pass
Definition: graph.c:600
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:395
SwsGraph::incomplete
bool incomplete
Definition: graph.h:124
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:120
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:88
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:2345
imgutils.h
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:98
SwsPassBuffer
Represents an allocated output buffer for a filter pass.
Definition: graph.h:69
h
h
Definition: vp9dsp_template.c:2070
SwsPass::num_slices
int num_slices
Definition: graph.h:92
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:622
SwsPassBuffer::buf
AVBufferRef * buf[4]
Definition: graph.h:72
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:737
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:837
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:897