FFmpeg
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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/error.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/macros.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/opt.h"
27 #include "libavutil/pixdesc.h"
28 #include "libavutil/slicethread.h"
29 
30 #include "libswscale/swscale.h"
31 #include "libswscale/format.h"
32 
33 #include "cms.h"
34 #include "lut3d.h"
35 #include "swscale_internal.h"
36 #include "graph.h"
37 
38 static int pass_alloc_output(SwsPass *pass)
39 {
40  if (!pass || pass->output.fmt != AV_PIX_FMT_NONE)
41  return 0;
42  pass->output.fmt = pass->format;
43  return av_image_alloc(pass->output.data, pass->output.linesize, pass->width,
44  pass->num_slices * pass->slice_h, pass->format, 64);
45 }
46 
48  int width, int height, SwsPass *input,
49  int align, void *priv, sws_filter_run_t run)
50 {
51  int ret;
52  SwsPass *pass = av_mallocz(sizeof(*pass));
53  if (!pass)
54  return NULL;
55 
56  pass->graph = graph;
57  pass->run = run;
58  pass->priv = priv;
59  pass->format = fmt;
60  pass->width = width;
61  pass->height = height;
62  pass->input = input;
63  pass->output.fmt = AV_PIX_FMT_NONE;
64 
66  if (ret < 0) {
67  av_free(pass);
68  return NULL;
69  }
70 
71  if (!align) {
72  pass->slice_h = pass->height;
73  pass->num_slices = 1;
74  } else {
75  pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads;
76  pass->slice_h = FFALIGN(pass->slice_h, align);
77  pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
78  }
79 
80  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
81  if (ret < 0)
82  av_freep(&pass);
83  return pass;
84 }
85 
86 /* Wrapper around ff_sws_graph_add_pass() that chains a pass "in-place" */
87 static int pass_append(SwsGraph *graph, enum AVPixelFormat fmt, int w, int h,
88  SwsPass **pass, int align, void *priv, sws_filter_run_t run)
89 {
90  SwsPass *new = ff_sws_graph_add_pass(graph, fmt, w, h, *pass, align, priv, run);
91  if (!new)
92  return AVERROR(ENOMEM);
93  *pass = new;
94  return 0;
95 }
96 
97 static void run_copy(const SwsImg *out_base, const SwsImg *in_base,
98  int y, int h, const SwsPass *pass)
99 {
100  SwsImg in = ff_sws_img_shift(in_base, y);
101  SwsImg out = ff_sws_img_shift(out_base, y);
102 
103  for (int i = 0; i < FF_ARRAY_ELEMS(out.data) && out.data[i]; i++) {
104  const int lines = h >> ff_fmt_vshift(in.fmt, i);
105  av_assert1(in.data[i]);
106 
107  if (in.linesize[i] == out.linesize[i]) {
108  memcpy(out.data[i], in.data[i], lines * out.linesize[i]);
109  } else {
110  const int linesize = FFMIN(out.linesize[i], in.linesize[i]);
111  for (int j = 0; j < lines; j++) {
112  memcpy(out.data[i], in.data[i], linesize);
113  in.data[i] += in.linesize[i];
114  out.data[i] += out.linesize[i];
115  }
116  }
117  }
118 }
119 
120 static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h,
121  const SwsPass *pass)
122 {
123  SwsInternal *c = pass->priv;
124  const int x0 = c->src0Alpha - 1;
125  const int w4 = 4 * pass->width;
126  const int src_stride = in->linesize[0];
127  const int dst_stride = out->linesize[0];
128  const uint8_t *src = in->data[0] + y * src_stride;
129  uint8_t *dst = out->data[0] + y * dst_stride;
130 
131  for (int y = 0; y < h; y++) {
132  memcpy(dst, src, w4 * sizeof(*dst));
133  for (int x = x0; x < w4; x += 4)
134  dst[x] = 0xFF;
135 
136  src += src_stride;
137  dst += dst_stride;
138  }
139 }
140 
141 static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h,
142  const SwsPass *pass)
143 {
144  ff_xyz12Torgb48(pass->priv, out->data[0] + y * out->linesize[0], out->linesize[0],
145  in->data[0] + y * in->linesize[0], in->linesize[0],
146  pass->width, h);
147 }
148 
149 static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h,
150  const SwsPass *pass)
151 {
152  ff_rgb48Toxyz12(pass->priv, out->data[0] + y * out->linesize[0], out->linesize[0],
153  in->data[0] + y * in->linesize[0], in->linesize[0],
154  pass->width, h);
155 }
156 
157 /***********************************************************************
158  * Internal ff_swscale() wrapper. This re-uses the legacy scaling API. *
159  * This is considered fully deprecated, and will be replaced by a full *
160  * reimplementation ASAP. *
161  ***********************************************************************/
162 
163 static void free_legacy_swscale(void *priv)
164 {
165  SwsContext *sws = priv;
167 }
168 
169 static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in,
170  const SwsPass *pass)
171 {
172  SwsContext *sws = pass->priv;
174  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
175  for (int i = 0; i < 4; i++)
176  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
177  }
178 
179  if (usePal(sws->src_format))
180  ff_update_palette(c, (const uint32_t *) in->data[1]);
181 }
182 
183 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
184 {
185  SwsContext *sws = pass->priv;
186  SwsInternal *parent = sws_internal(sws);
187  if (pass->num_slices == 1)
188  return sws;
189 
190  av_assert1(parent->nb_slice_ctx == pass->num_slices);
191  sws = parent->slice_ctx[y / pass->slice_h];
192 
193  if (usePal(sws->src_format)) {
194  SwsInternal *sub = sws_internal(sws);
195  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
196  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
197  }
198 
199  return sws;
200 }
201 
202 static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in_base,
203  int y, int h, const SwsPass *pass)
204 {
205  SwsContext *sws = slice_ctx(pass, y);
207  const SwsImg in = ff_sws_img_shift(in_base, y);
208 
209  c->convert_unscaled(c, (const uint8_t *const *) in.data, in.linesize, y, h,
210  out->data, out->linesize);
211 }
212 
213 static void run_legacy_swscale(const SwsImg *out_base, const SwsImg *in,
214  int y, int h, const SwsPass *pass)
215 {
216  SwsContext *sws = slice_ctx(pass, y);
218  const SwsImg out = ff_sws_img_shift(out_base, y);
219 
220  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
221  sws->src_h, out.data, out.linesize, y, h);
222 }
223 
224 static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
225  const SwsFormat *fmt)
226 {
227  enum AVChromaLocation chroma_loc = fmt->loc;
228  const int sub_x = fmt->desc->log2_chroma_w;
229  const int sub_y = fmt->desc->log2_chroma_h;
230  int x_pos, y_pos;
231 
232  /* Explicitly default to center siting for compatibility with swscale */
233  if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
234  chroma_loc = AVCHROMA_LOC_CENTER;
235  graph->incomplete |= sub_x || sub_y;
236  }
237 
238  /* av_chroma_location_enum_to_pos() always gives us values in the range from
239  * 0 to 256, but we need to adjust this to the true value range of the
240  * subsampling grid, which may be larger for h/v_sub > 1 */
241  av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
242  x_pos *= (1 << sub_x) - 1;
243  y_pos *= (1 << sub_y) - 1;
244 
245  /* Fix vertical chroma position for interlaced frames */
246  if (sub_y && fmt->interlaced) {
247  /* When vertically subsampling, chroma samples are effectively only
248  * placed next to even rows. To access them from the odd field, we need
249  * to account for this shift by offsetting the distance of one luma row.
250  *
251  * For 4x vertical subsampling (v_sub == 2), they are only placed
252  * next to every *other* even row, so we need to shift by three luma
253  * rows to get to the chroma sample. */
254  if (graph->field == FIELD_BOTTOM)
255  y_pos += (256 << sub_y) - 256;
256 
257  /* Luma row distance is doubled for fields, so halve offsets */
258  y_pos >>= 1;
259  }
260 
261  /* Explicitly strip chroma offsets when not subsampling, because it
262  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
263  *h_chr_pos = sub_x ? x_pos : -513;
264  *v_chr_pos = sub_y ? y_pos : -513;
265 }
266 
267 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
268 {
269  if (override == -513 || override == *chr_pos)
270  return;
271 
272  if (!*warned) {
274  "Setting chroma position directly is deprecated, make sure "
275  "the frame is tagged with the correct chroma location.\n");
276  *warned = 1;
277  }
278 
279  *chr_pos = override;
280 }
281 
284 {
286  const int src_w = sws->src_w, src_h = sws->src_h;
287  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
288  const int unscaled = src_w == dst_w && src_h == dst_h;
289  int align = c->dst_slice_align;
290  SwsPass *pass = NULL;
291  int ret;
292 
293  if (c->cascaded_context[0]) {
294  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
295  for (int i = 0; i < num_cascaded; i++) {
296  SwsContext *sub = c->cascaded_context[i];
297  const int is_last = i + 1 == num_cascaded;
298  ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input);
299  if (ret < 0)
300  return ret;
301  /* Steal cascaded context, so we can free the parent */
302  c->cascaded_context[i] = NULL;
303  }
304 
306  return 0;
307  }
308 
309  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
310  align = 0; /* disable slice threading */
311 
312  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
313  ret = pass_append(graph, AV_PIX_FMT_RGBA, src_w, src_h, &input, 1, c, run_rgb0);
314  if (ret < 0)
315  return ret;
316  }
317 
318  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
319  ret = pass_append(graph, AV_PIX_FMT_RGB48, src_w, src_h, &input, 1, c, run_xyz2rgb);
320  if (ret < 0)
321  return ret;
322  }
323 
324  pass = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, align, sws,
325  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale);
326  if (!pass)
327  return AVERROR(ENOMEM);
328  pass->setup = setup_legacy_swscale;
329  pass->free = free_legacy_swscale;
330 
331  /**
332  * For slice threading, we need to create sub contexts, similar to how
333  * swscale normally handles it internally. The most important difference
334  * is that we handle cascaded contexts before threaded contexts; whereas
335  * context_init_threaded() does it the other way around.
336  */
337 
338  if (pass->num_slices > 1) {
339  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
340  if (!c->slice_ctx)
341  return AVERROR(ENOMEM);
342 
343  for (int i = 0; i < pass->num_slices; i++) {
344  SwsContext *slice;
345  SwsInternal *c2;
346  slice = c->slice_ctx[i] = sws_alloc_context();
347  if (!slice)
348  return AVERROR(ENOMEM);
349  c->nb_slice_ctx++;
350 
351  c2 = sws_internal(slice);
352  c2->parent = sws;
353 
354  ret = av_opt_copy(slice, sws);
355  if (ret < 0)
356  return ret;
357 
359  if (ret < 0)
360  return ret;
361 
362  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
363  slice->src_range, c->dstColorspaceTable,
364  slice->dst_range, c->brightness, c->contrast,
365  c->saturation);
366 
367  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
368  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
369  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
370  }
371  }
372  }
373 
374  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
375  ret = pass_append(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, &pass, 1, c, run_rgb2xyz);
376  if (ret < 0)
377  return ret;
378  }
379 
380  *output = pass;
381  return 0;
382 }
383 
386 {
387  int ret, warned = 0;
388  SwsContext *const ctx = graph->ctx;
390  if (!sws)
391  return AVERROR(ENOMEM);
392 
393  sws->flags = ctx->flags;
394  sws->dither = ctx->dither;
395  sws->alpha_blend = ctx->alpha_blend;
396  sws->gamma_flag = ctx->gamma_flag;
397 
398  sws->src_w = src.width;
399  sws->src_h = src.height;
400  sws->src_format = src.format;
401  sws->src_range = src.range == AVCOL_RANGE_JPEG;
402 
403  sws->dst_w = dst.width;
404  sws->dst_h = dst.height;
405  sws->dst_format = dst.format;
406  sws->dst_range = dst.range == AVCOL_RANGE_JPEG;
409 
410  graph->incomplete |= src.range == AVCOL_RANGE_UNSPECIFIED;
411  graph->incomplete |= dst.range == AVCOL_RANGE_UNSPECIFIED;
412 
413  /* Allow overriding chroma position with the legacy API */
414  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
415  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
416  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
417  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
418 
419  sws->scaler_params[0] = ctx->scaler_params[0];
420  sws->scaler_params[1] = ctx->scaler_params[1];
421 
423  if (ret < 0) {
425  return ret;
426  }
427 
428  /* Set correct color matrices */
429  {
430  int in_full, out_full, brightness, contrast, saturation;
431  const int *inv_table, *table;
432  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
433  (int **)&table, &out_full,
434  &brightness, &contrast, &saturation);
435 
436  inv_table = sws_getCoefficients(src.csp);
438 
439  graph->incomplete |= src.csp != dst.csp &&
440  (src.csp == AVCOL_SPC_UNSPECIFIED ||
441  dst.csp == AVCOL_SPC_UNSPECIFIED);
442 
443  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
444  brightness, contrast, saturation);
445  }
446 
447  ret = init_legacy_subpass(graph, sws, input, output);
448  if (ret < 0) {
450  return ret;
451  }
452 
453  return 0;
454 }
455 
456 /**************************
457  * Gamut and tone mapping *
458  **************************/
459 
460 static void free_lut3d(void *priv)
461 {
462  SwsLut3D *lut = priv;
463  ff_sws_lut3d_free(&lut);
464 }
465 
466 static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
467 {
468  SwsLut3D *lut = pass->priv;
469 
470  /* Update dynamic frame metadata from the original source frame */
471  ff_sws_lut3d_update(lut, &pass->graph->src.color);
472 }
473 
474 static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base,
475  int y, int h, const SwsPass *pass)
476 {
477  SwsLut3D *lut = pass->priv;
478  const SwsImg in = ff_sws_img_shift(in_base, y);
479  const SwsImg out = ff_sws_img_shift(out_base, y);
480 
481  ff_sws_lut3d_apply(lut, in.data[0], in.linesize[0], out.data[0],
482  out.linesize[0], pass->width, h);
483 }
484 
487 {
488  enum AVPixelFormat fmt_in, fmt_out;
489  SwsColorMap map = {0};
490  SwsLut3D *lut;
491  SwsPass *pass;
492  int ret;
493 
494  /**
495  * Grayspace does not really have primaries, so just force the use of
496  * the equivalent other primary set to avoid a conversion. Technically,
497  * this does affect the weights used for the Grayscale conversion, but
498  * in practise, that should give the expected results more often than not.
499  */
500  if (isGray(dst.format)) {
501  dst.color = src.color;
502  } else if (isGray(src.format)) {
503  src.color = dst.color;
504  }
505 
506  /* Fully infer color spaces before color mapping logic */
507  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
508 
509  map.intent = graph->ctx->intent;
510  map.src = src.color;
511  map.dst = dst.color;
512 
514  return 0;
515 
516  lut = ff_sws_lut3d_alloc();
517  if (!lut)
518  return AVERROR(ENOMEM);
519 
520  fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0);
521  fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1);
522  if (fmt_in != src.format) {
523  SwsFormat tmp = src;
524  tmp.format = fmt_in;
525  ret = add_legacy_sws_pass(graph, src, tmp, input, &input);
526  if (ret < 0)
527  return ret;
528  }
529 
530  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
531  if (ret < 0) {
532  ff_sws_lut3d_free(&lut);
533  return ret;
534  }
535 
536  pass = ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
537  input, 1, lut, run_lut3d);
538  if (!pass) {
539  ff_sws_lut3d_free(&lut);
540  return AVERROR(ENOMEM);
541  }
542  pass->setup = setup_lut3d;
543  pass->free = free_lut3d;
544 
545  *output = pass;
546  return 0;
547 }
548 
549 /***************************************
550  * Main filter graph construction code *
551  ***************************************/
552 
553 static int init_passes(SwsGraph *graph)
554 {
555  SwsFormat src = graph->src;
556  SwsFormat dst = graph->dst;
557  SwsPass *pass = NULL; /* read from main input image */
558  int ret;
559 
560  ret = adapt_colors(graph, src, dst, pass, &pass);
561  if (ret < 0)
562  return ret;
563  src.format = pass ? pass->format : src.format;
564  src.color = dst.color;
565 
566  if (!ff_fmt_equal(&src, &dst)) {
567  ret = add_legacy_sws_pass(graph, src, dst, pass, &pass);
568  if (ret < 0)
569  return ret;
570  }
571 
572  if (!pass) {
573  /* No passes were added, so no operations were necessary */
574  graph->noop = 1;
575 
576  /* Add threaded memcpy pass */
577  pass = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
578  pass, 1, NULL, run_copy);
579  if (!pass)
580  return AVERROR(ENOMEM);
581  }
582 
583  return 0;
584 }
585 
586 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
587  int nb_threads)
588 {
589  SwsGraph *graph = priv;
590  const SwsPass *pass = graph->exec.pass;
591  const SwsImg *input = pass->input ? &pass->input->output : &graph->exec.input;
592  const SwsImg *output = pass->output.fmt != AV_PIX_FMT_NONE ? &pass->output : &graph->exec.output;
593  const int slice_y = jobnr * pass->slice_h;
594  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
595 
596  pass->run(output, input, slice_y, slice_h, pass);
597 }
598 
600  int field, SwsGraph **out_graph)
601 {
602  int ret;
603  SwsGraph *graph = av_mallocz(sizeof(*graph));
604  if (!graph)
605  return AVERROR(ENOMEM);
606 
607  graph->ctx = ctx;
608  graph->src = *src;
609  graph->dst = *dst;
610  graph->field = field;
611  graph->opts_copy = *ctx;
612 
613  graph->exec.input.fmt = src->format;
614  graph->exec.output.fmt = dst->format;
615 
616  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
617  sws_graph_worker, NULL, ctx->threads);
618  if (ret == AVERROR(ENOSYS))
619  graph->num_threads = 1;
620  else if (ret < 0)
621  goto error;
622  else
623  graph->num_threads = ret;
624 
625  ret = init_passes(graph);
626  if (ret < 0)
627  goto error;
628 
629  *out_graph = graph;
630  return 0;
631 
632 error:
633  ff_sws_graph_free(&graph);
634  return ret;
635 }
636 
638 {
639  SwsGraph *graph = *pgraph;
640  if (!graph)
641  return;
642 
644 
645  for (int i = 0; i < graph->num_passes; i++) {
646  SwsPass *pass = graph->passes[i];
647  if (pass->free)
648  pass->free(pass->priv);
649  if (pass->output.fmt != AV_PIX_FMT_NONE)
650  av_free(pass->output.data[0]);
651  av_free(pass);
652  }
653  av_free(graph->passes);
654 
655  av_free(graph);
656  *pgraph = NULL;
657 }
658 
659 /* Tests only options relevant to SwsGraph */
660 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
661 {
662  return c1->flags == c2->flags &&
663  c1->threads == c2->threads &&
664  c1->dither == c2->dither &&
665  c1->alpha_blend == c2->alpha_blend &&
666  c1->gamma_flag == c2->gamma_flag &&
667  c1->src_h_chr_pos == c2->src_h_chr_pos &&
668  c1->src_v_chr_pos == c2->src_v_chr_pos &&
669  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
670  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
671  c1->intent == c2->intent &&
672  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
673 
674 }
675 
677  int field, SwsGraph **out_graph)
678 {
679  SwsGraph *graph = *out_graph;
680  if (graph && ff_fmt_equal(&graph->src, src) &&
681  ff_fmt_equal(&graph->dst, dst) &&
682  opts_equal(ctx, &graph->opts_copy))
683  {
684  ff_sws_graph_update_metadata(graph, &src->color);
685  return 0;
686  }
687 
688  ff_sws_graph_free(out_graph);
689  return ff_sws_graph_create(ctx, dst, src, field, out_graph);
690 }
691 
693 {
694  if (!color)
695  return;
696 
698 }
699 
700 void ff_sws_graph_run(SwsGraph *graph, uint8_t *const out_data[4],
701  const int out_linesize[4],
702  const uint8_t *const in_data[4],
703  const int in_linesize[4])
704 {
705  SwsImg *out = &graph->exec.output;
706  SwsImg *in = &graph->exec.input;
707  memcpy(out->data, out_data, sizeof(out->data));
708  memcpy(out->linesize, out_linesize, sizeof(out->linesize));
709  memcpy(in->data, in_data, sizeof(in->data));
710  memcpy(in->linesize, in_linesize, sizeof(in->linesize));
711 
712  for (int i = 0; i < graph->num_passes; i++) {
713  const SwsPass *pass = graph->passes[i];
714  graph->exec.pass = pass;
715  if (pass->setup)
716  pass->setup(out, in, pass);
718  }
719 }
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:826
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:112
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:111
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:68
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:135
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:118
adapt_colors
static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:485
out
FILE * out
Definition: movenc.c:55
color
Definition: vf_paletteuse.c:513
init_passes
static int init_passes(SwsGraph *graph)
Definition: graph.c:553
ff_rgb48Toxyz12
void ff_rgb48Toxyz12(const SwsInternal *c, uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, int w, int h)
Definition: swscale.c:798
SwsPass::output
SwsImg output
Filter output buffer.
Definition: graph.h:91
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:228
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:676
SwsPass::format
enum AVPixelFormat format
Definition: graph.h:77
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:225
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:60
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: format.h:57
SwsGraph::src
SwsFormat src
Currently active format and processing parameters.
Definition: graph.h:130
avpriv_slicethread_execute
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
Definition: slicethread.c:271
pixdesc.h
w
uint8_t w
Definition: llviddspenc.c:38
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:750
isGray
static av_always_inline int isGray(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:787
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:156
table
static const uint16_t table[]
Definition: prosumer.c:203
SwsContext::flags
unsigned flags
Bitmask of SWS_*.
Definition: swscale.h:195
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:103
c1
static const uint64_t c1
Definition: murmur3.c:52
SwsImg
Represents a view into a single field of frame data.
Definition: graph.h:33
format.h
ff_sws_init_single_context
int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, SwsFilter *dstFilter)
Definition: utils.c:1098
SwsColorMap
Definition: cms.h:60
SwsPass::width
int width
Definition: graph.h:78
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:282
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:87
SwsContext::src_v_chr_pos
int src_v_chr_pos
Source vertical chroma position in luma grid / 256.
Definition: swscale.h:234
slice_ctx
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition: graph.c:183
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:1868
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:125
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:599
avassert.h
ff_sws_graph_run
void ff_sws_graph_run(SwsGraph *graph, uint8_t *const out_data[4], const int out_linesize[4], const uint8_t *const in_data[4], const int in_linesize[4])
Dispatch the filter graph on a single field.
Definition: graph.c:700
SwsInternal::pal_rgb
uint32_t pal_rgb[256]
Definition: swscale_internal.h:383
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:267
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:210
SwsPass::priv
void * priv
Definition: graph.h:104
SwsInternal::nb_slice_ctx
int nb_slice_ctx
Definition: swscale_internal.h:327
SwsInternal::slice_ctx
SwsContext ** slice_ctx
Definition: swscale_internal.h:325
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:3759
ff_update_palette
void ff_update_palette(SwsInternal *c, const uint32_t *pal)
Definition: swscale.c:857
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1416
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:98
SwsContext::intent
int intent
Desired ICC intent for color space conversions.
Definition: swscale.h:242
SwsGraph::num_passes
int num_passes
Definition: graph.h:119
ctx
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:252
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
ff_xyz12Torgb48
void ff_xyz12Torgb48(const SwsInternal *c, uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, int w, int h)
Definition: swscale.c:739
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:131
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:47
ff_sws_lut3d_free
void ff_sws_lut3d_free(SwsLut3D **plut3d)
Definition: lut3d.c:42
NULL
#define NULL
Definition: coverity.c:32
run
uint8_t run
Definition: svq3.c:207
tmp
static uint8_t tmp[20]
Definition: aes_ctr.c:47
SwsContext::gamma_flag
int gamma_flag
Use gamma correct scaling.
Definition: swscale.h:220
run_xyz2rgb
static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:141
ff_infer_colors
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition: format.c:486
SwsGraph::input
SwsImg input
Definition: graph.h:136
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:224
SwsContext::src_range
int src_range
Source is full range.
Definition: swscale.h:232
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:69
AVCOL_RANGE_UNSPECIFIED
@ AVCOL_RANGE_UNSPECIFIED
Definition: pixfmt.h:716
SwsContext::dst_h_chr_pos
int dst_h_chr_pos
Destination horizontal chroma position.
Definition: swscale.h:237
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:213
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:2151
av_image_alloc
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align)
Allocate an image with size w and h and pixel format pix_fmt, and fill pointers and linesizes accordi...
Definition: imgutils.c:218
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:637
SwsPass::height
int height
Definition: graph.h:78
SwsImg::linesize
int linesize[4]
Definition: graph.h:36
add_legacy_sws_pass
static int add_legacy_sws_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:384
lut3d.h
free_lut3d
static void free_lut3d(void *priv)
Definition: graph.c:460
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:1009
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:918
setup_lut3d
static void setup_lut3d(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Definition: graph.c:466
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:263
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:514
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:215
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:228
SwsGraph::output
SwsImg output
Definition: graph.h:137
AVCHROMA_LOC_UNSPECIFIED
@ AVCHROMA_LOC_UNSPECIFIED
Definition: pixfmt.h:770
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:984
align
static const uint8_t *BS_FUNC() align(BSCTX *bc)
Skip bits to a byte boundary.
Definition: bitstream_template.h:411
SwsFormat::loc
enum AVChromaLocation loc
Definition: format.h:83
SwsColor
Definition: format.h:60
SwsGraph::exec
struct SwsGraph::@493 exec
Temporary execution state inside ff_sws_graph_run.
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:231
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:769
sws
static SwsContext * sws[3]
Definition: swscale.c:73
free_legacy_swscale
static void free_legacy_swscale(void *priv)
Definition: graph.c:163
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:130
ff_fmt_vshift
static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane)
Definition: graph.h:39
SwsPass::slice_h
int slice_h
Definition: graph.h:79
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
SwsGraph::num_threads
int num_threads
Definition: graph.h:113
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:660
run_rgb0
static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:120
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:57
run_rgb2xyz
static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:149
swscale_internal.h
graph.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:229
run_copy
static void run_copy(const SwsImg *out_base, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:97
AVCOL_SPC_UNSPECIFIED
@ AVCOL_SPC_UNSPECIFIED
Definition: pixfmt.h:676
ff_sws_img_shift
static av_const SwsImg ff_sws_img_shift(const SwsImg *base, const int y)
Definition: graph.h:45
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:224
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
SwsInternal
Definition: swscale_internal.h:317
ret
ret
Definition: filter_design.txt:187
ff_fmt_equal
static int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
Definition: format.h:115
SwsGraph::noop
bool noop
Definition: graph.h:115
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
c2
static const uint64_t c2
Definition: murmur3.c:53
SwsContext::scaler_params
double scaler_params[2]
Extra parameters for fine-tuning certain scalers.
Definition: swscale.h:200
AVCHROMA_LOC_CENTER
@ AVCHROMA_LOC_CENTER
MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0.
Definition: pixfmt.h:772
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
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:169
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
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:382
SwsGraph::incomplete
bool incomplete
Definition: graph.h:114
mem.h
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:229
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:110
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:230
map
const VDPAUPixFmtMap * map
Definition: hwcontext_vdpau.c:71
SwsImg::fmt
enum AVPixelFormat fmt
Definition: graph.h:34
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:233
pass_alloc_output
static int pass_alloc_output(SwsPass *pass)
Definition: graph.c:38
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:202
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
SwsPass::run
sws_filter_run_t run
Filter main execution function.
Definition: graph.h:76
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:2315
imgutils.h
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:235
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:74
SwsPass::input
const SwsPass * input
Filter input.
Definition: graph.h:86
h
h
Definition: vp9dsp_template.c:2070
SwsPass::num_slices
int num_slices
Definition: graph.h:80
width
#define width
Definition: dsp.h:89
run_lut3d
static void run_lut3d(const SwsImg *out_base, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:474
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:236
SwsContext
Main external API structure.
Definition: swscale.h:182
sws_graph_worker
static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
Definition: graph.c:586
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:692
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
swscale.h
SwsImg::data
uint8_t * data[4]
Definition: graph.h:35
isALPHA
static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:878