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