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 /* Allocates one buffer per plane */
43 {
44  int ret = av_image_check_size2(dst->width, dst->height, INT64_MAX,
45  dst->format, 0, NULL);
46  if (ret < 0)
47  return ret;
48 
49  const int align = av_cpu_max_align();
50  const int aligned_w = FFALIGN(dst->width, align);
51  ret = av_image_fill_linesizes(dst->linesize, dst->format, aligned_w);
52  if (ret < 0)
53  return ret;
54 
55  ptrdiff_t linesize1[4];
56  for (int i = 0; i < 4; i++)
57  linesize1[i] = dst->linesize[i] = FFALIGN(dst->linesize[i], align);
58 
59  size_t sizes[4];
60  ret = av_image_fill_plane_sizes(sizes, dst->format, dst->height, linesize1);
61  if (ret < 0)
62  return ret;
63 
64  for (int i = 0; i < 4; i++) {
65  if (!sizes[i])
66  break;
68  if (!buf)
69  return AVERROR(ENOMEM);
70  dst->data[i] = buf->data;
71  dst->buf[i] = buf;
72  }
73 
74  return 0;
75 }
76 
77 static int pass_alloc_output(SwsPass *pass)
78 {
79  if (!pass || pass->output->avframe)
80  return 0;
81 
82  SwsPassBuffer *buffer = pass->output;
83  AVFrame *avframe = av_frame_alloc();
84  if (!avframe)
85  return AVERROR(ENOMEM);
86  avframe->format = pass->format;
87  avframe->width = buffer->width;
88  avframe->height = buffer->height;
89 
90  int ret = frame_alloc_planes(avframe);
91  if (ret < 0) {
92  av_frame_free(&avframe);
93  return ret;
94  }
95 
96  buffer->avframe = avframe;
97  ff_sws_frame_from_avframe(&buffer->frame, avframe);
98  return 0;
99 }
100 
101 static void free_buffer(AVRefStructOpaque opaque, void *obj)
102 {
103  SwsPassBuffer *buffer = obj;
104  av_frame_free(&buffer->avframe);
105 }
106 
107 static void pass_free(SwsPass *pass)
108 {
109  if (pass->free)
110  pass->free(pass->priv);
111  av_refstruct_unref(&pass->output);
112  av_free(pass);
113 }
114 
116  int width, int height, SwsPass *input,
117  int align, SwsPassFunc run, SwsPassSetup setup,
118  void *priv, void (*free_cb)(void *priv),
119  SwsPass **out_pass)
120 {
121  int ret;
122  SwsPass *pass = av_mallocz(sizeof(*pass));
123  if (!pass) {
124  if (free_cb)
125  free_cb(priv);
126  return AVERROR(ENOMEM);
127  }
128 
129  pass->graph = graph;
130  pass->run = run;
131  pass->setup = setup;
132  pass->priv = priv;
133  pass->free = free_cb;
134  pass->format = fmt;
135  pass->width = width;
136  pass->height = height;
137  pass->input = input;
138  pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, free_buffer);
139  if (!pass->output) {
140  ret = AVERROR(ENOMEM);
141  goto fail;
142  }
143 
144  if (!align) {
145  pass->slice_h = pass->height;
146  pass->num_slices = 1;
147  } else {
148  pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads;
149  pass->slice_h = FFALIGN(pass->slice_h, align);
150  pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
151  }
152 
153  /* Align output buffer to include extra slice padding */
154  pass->output->width = pass->width;
155  pass->output->height = pass->slice_h * pass->num_slices;
156 
157  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
158  if (ret < 0)
159  goto fail;
160 
161  *out_pass = pass;
162  return 0;
163 
164 fail:
165  pass_free(pass);
166  return ret;
167 }
168 
169 static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
170 {
171  for (int i = 0; i < 4; i++) {
172  if (f->data[i])
173  data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * f->linesize[i];
174  else
175  data[i] = NULL;
176  }
177 }
178 
179 static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h,
180  const SwsPass *pass)
181 {
182  uint8_t *in_data[4], *out_data[4];
183  frame_shift(in, y, in_data);
184  frame_shift(out, y, out_data);
185 
186  for (int i = 0; i < 4 && out_data[i]; i++) {
187  const int lines = h >> ff_fmt_vshift(in->format, i);
188  av_assert1(in_data[i]);
189 
190  if (in_data[i] == out_data[i]) {
191  av_assert0(in->linesize[i] == out->linesize[i]);
192  } else if (in->linesize[i] == out->linesize[i]) {
193  memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
194  } else {
195  const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
196  for (int j = 0; j < lines; j++) {
197  memcpy(out_data[i], in_data[i], linesize);
198  in_data[i] += in->linesize[i];
199  out_data[i] += out->linesize[i];
200  }
201  }
202  }
203 }
204 
205 static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h,
206  const SwsPass *pass)
207 {
208  SwsInternal *c = pass->priv;
209  const int x0 = c->src0Alpha - 1;
210  const int w4 = 4 * pass->width;
211  const int src_stride = in->linesize[0];
212  const int dst_stride = out->linesize[0];
213  const uint8_t *src = in->data[0] + y * src_stride;
214  uint8_t *dst = out->data[0] + y * dst_stride;
215 
216  for (int y = 0; y < h; y++) {
217  memcpy(dst, src, w4 * sizeof(*dst));
218  for (int x = x0; x < w4; x += 4)
219  dst[x] = 0xFF;
220 
221  src += src_stride;
222  dst += dst_stride;
223  }
224 }
225 
226 static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h,
227  const SwsPass *pass)
228 {
229  const SwsInternal *c = pass->priv;
230  c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
231  in->data[0] + y * in->linesize[0], in->linesize[0],
232  pass->width, h);
233 }
234 
235 static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h,
236  const SwsPass *pass)
237 {
238  const SwsInternal *c = pass->priv;
239  c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0],
240  in->data[0] + y * in->linesize[0], in->linesize[0],
241  pass->width, h);
242 }
243 
244 /***********************************************************************
245  * Internal ff_swscale() wrapper. This reuses the legacy scaling API. *
246  * This is considered fully deprecated, and will be replaced by a full *
247  * reimplementation ASAP. *
248  ***********************************************************************/
249 
250 static void free_legacy_swscale(void *priv)
251 {
252  SwsContext *sws = priv;
253  sws_free_context(&sws);
254 }
255 
256 static int setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
257  const SwsPass *pass)
258 {
259  SwsContext *sws = pass->priv;
260  SwsInternal *c = sws_internal(sws);
261  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
262  for (int i = 0; i < 4; i++)
263  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
264  }
265 
266  if (usePal(sws->src_format))
267  ff_update_palette(c, (const uint32_t *) in->data[1]);
268 
269  return 0;
270 }
271 
272 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
273 {
274  SwsContext *sws = pass->priv;
275  SwsInternal *parent = sws_internal(sws);
276  if (pass->num_slices == 1)
277  return sws;
278 
279  av_assert1(parent->nb_slice_ctx == pass->num_slices);
280  sws = parent->slice_ctx[y / pass->slice_h];
281 
282  if (usePal(sws->src_format)) {
283  SwsInternal *sub = sws_internal(sws);
284  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
285  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
286  }
287 
288  return sws;
289 }
290 
291 static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in,
292  int y, int h, const SwsPass *pass)
293 {
294  SwsContext *sws = slice_ctx(pass, y);
295  SwsInternal *c = sws_internal(sws);
296  uint8_t *in_data[4];
297  frame_shift(in, y, in_data);
298 
299  c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h,
300  out->data, out->linesize);
301 }
302 
303 static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
304  int y, int h, const SwsPass *pass)
305 {
306  SwsContext *sws = slice_ctx(pass, y);
307  SwsInternal *c = sws_internal(sws);
308  uint8_t *out_data[4];
309  frame_shift(out, y, out_data);
310 
311  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
312  sws->src_h, out_data, out->linesize, y, h);
313 }
314 
315 static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
316  const SwsFormat *fmt)
317 {
318  enum AVChromaLocation chroma_loc = fmt->loc;
319  const int sub_x = fmt->desc->log2_chroma_w;
320  const int sub_y = fmt->desc->log2_chroma_h;
321  int x_pos, y_pos;
322 
323  /* Explicitly default to center siting for compatibility with swscale */
324  if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
325  chroma_loc = AVCHROMA_LOC_CENTER;
326  graph->incomplete |= sub_x || sub_y;
327  }
328 
329  /* av_chroma_location_enum_to_pos() always gives us values in the range from
330  * 0 to 256, but we need to adjust this to the true value range of the
331  * subsampling grid, which may be larger for h/v_sub > 1 */
332  av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
333  x_pos *= (1 << sub_x) - 1;
334  y_pos *= (1 << sub_y) - 1;
335 
336  /* Fix vertical chroma position for interlaced frames */
337  if (sub_y && fmt->interlaced) {
338  /* When vertically subsampling, chroma samples are effectively only
339  * placed next to even rows. To access them from the odd field, we need
340  * to account for this shift by offsetting the distance of one luma row.
341  *
342  * For 4x vertical subsampling (v_sub == 2), they are only placed
343  * next to every *other* even row, so we need to shift by three luma
344  * rows to get to the chroma sample. */
345  if (graph->field == FIELD_BOTTOM)
346  y_pos += (256 << sub_y) - 256;
347 
348  /* Luma row distance is doubled for fields, so halve offsets */
349  y_pos >>= 1;
350  }
351 
352  /* Explicitly strip chroma offsets when not subsampling, because it
353  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
354  *h_chr_pos = sub_x ? x_pos : -513;
355  *v_chr_pos = sub_y ? y_pos : -513;
356 }
357 
358 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
359 {
360  if (override == -513 || override == *chr_pos)
361  return;
362 
363  if (!*warned) {
365  "Setting chroma position directly is deprecated, make sure "
366  "the frame is tagged with the correct chroma location.\n");
367  *warned = 1;
368  }
369 
370  *chr_pos = override;
371 }
372 
373 /* Takes over ownership of `sws` */
374 static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws,
376 {
377  SwsInternal *c = sws_internal(sws);
378  const int src_w = sws->src_w, src_h = sws->src_h;
379  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
380  const int unscaled = src_w == dst_w && src_h == dst_h;
381  int align = c->dst_slice_align;
382  SwsPass *pass = NULL;
383  int ret;
384 
385  if (c->cascaded_context[0]) {
386  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
387  for (int i = 0; i < num_cascaded; i++) {
388  const int is_last = i + 1 == num_cascaded;
389 
390  /* Steal cascaded context, so we can manage its lifetime independently */
391  SwsContext *sub = c->cascaded_context[i];
392  c->cascaded_context[i] = NULL;
393 
394  ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input);
395  if (ret < 0)
396  break;
397  }
398 
399  sws_free_context(&sws);
400  return ret;
401  }
402 
403  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
404  align = 0; /* disable slice threading */
405 
406  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
407  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGBA, src_w, src_h, input,
408  1, run_rgb0, NULL, c, NULL, &input);
409  if (ret < 0) {
410  sws_free_context(&sws);
411  return ret;
412  }
413  }
414 
415  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
416  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, src_w, src_h, input,
417  1, run_xyz2rgb, NULL, c, NULL, &input);
418  if (ret < 0) {
419  sws_free_context(&sws);
420  return ret;
421  }
422  }
423 
424  ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, align,
425  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale,
427  if (ret < 0)
428  return ret;
429 
430  /**
431  * For slice threading, we need to create sub contexts, similar to how
432  * swscale normally handles it internally. The most important difference
433  * is that we handle cascaded contexts before threaded contexts; whereas
434  * context_init_threaded() does it the other way around.
435  */
436 
437  if (pass->num_slices > 1) {
438  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
439  if (!c->slice_ctx)
440  return AVERROR(ENOMEM);
441 
442  for (int i = 0; i < pass->num_slices; i++) {
443  SwsContext *slice;
444  SwsInternal *c2;
445  slice = c->slice_ctx[i] = sws_alloc_context();
446  if (!slice)
447  return AVERROR(ENOMEM);
448  c->nb_slice_ctx++;
449 
450  c2 = sws_internal(slice);
451  c2->parent = sws;
452 
453  ret = av_opt_copy(slice, sws);
454  if (ret < 0)
455  return ret;
456 
458  if (ret < 0)
459  return ret;
460 
461  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
462  slice->src_range, c->dstColorspaceTable,
463  slice->dst_range, c->brightness, c->contrast,
464  c->saturation);
465 
466  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
467  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
468  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
469  }
470  }
471  }
472 
473  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
474  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, pass,
475  1, run_rgb2xyz, NULL, c, NULL, &pass);
476  if (ret < 0)
477  return ret;
478  }
479 
480  *output = pass;
481  return 0;
482 }
483 
484 static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src,
485  const SwsFormat *dst, SwsPass *input,
486  SwsPass **output)
487 {
488  int ret, warned = 0;
489  SwsContext *const ctx = graph->ctx;
490  if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE)
491  return AVERROR(ENOTSUP);
492 
493  SwsContext *sws = sws_alloc_context();
494  if (!sws)
495  return AVERROR(ENOMEM);
496 
497  sws->flags = ctx->flags;
498  sws->dither = ctx->dither;
499  sws->alpha_blend = ctx->alpha_blend;
500  sws->gamma_flag = ctx->gamma_flag;
501  sws->scaler = ctx->scaler;
502  sws->scaler_sub = ctx->scaler_sub;
503 
504  sws->src_w = src->width;
505  sws->src_h = src->height;
506  sws->src_format = src->format;
507  sws->src_range = src->range == AVCOL_RANGE_JPEG;
508 
509  sws->dst_w = dst->width;
510  sws->dst_h = dst->height;
511  sws->dst_format = dst->format;
512  sws->dst_range = dst->range == AVCOL_RANGE_JPEG;
513  get_chroma_pos(graph, &sws->src_h_chr_pos, &sws->src_v_chr_pos, src);
514  get_chroma_pos(graph, &sws->dst_h_chr_pos, &sws->dst_v_chr_pos, dst);
515 
516  graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED;
517  graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED;
518 
519  /* Allow overriding chroma position with the legacy API */
520  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
521  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
522  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
523  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
524 
525  for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
526  sws->scaler_params[i] = ctx->scaler_params[i];
527 
528  ret = sws_init_context(sws, NULL, NULL);
529  if (ret < 0) {
530  sws_free_context(&sws);
531  return ret;
532  }
533 
534  /* Set correct color matrices */
535  {
536  int in_full, out_full, brightness, contrast, saturation;
537  const int *inv_table, *table;
538  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
539  (int **)&table, &out_full,
540  &brightness, &contrast, &saturation);
541 
542  inv_table = sws_getCoefficients(src->csp);
543  table = sws_getCoefficients(dst->csp);
544 
545  graph->incomplete |= src->csp != dst->csp &&
546  (src->csp == AVCOL_SPC_UNSPECIFIED ||
547  dst->csp == AVCOL_SPC_UNSPECIFIED);
548 
549  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
550  brightness, contrast, saturation);
551  }
552 
553  return init_legacy_subpass(graph, sws, input, output);
554 }
555 
556 /*********************
557  * Format conversion *
558  *********************/
559 
560 #if CONFIG_UNSTABLE
561 static int add_convert_pass(SwsGraph *graph, const SwsFormat *src,
562  const SwsFormat *dst, SwsPass *input,
563  SwsPass **output)
564 {
566 
567  SwsContext *ctx = graph->ctx;
568  SwsOpList *ops = NULL;
569  int ret = AVERROR(ENOTSUP);
570 
571  /* Mark the entire new ops infrastructure as experimental for now */
572  if (!(ctx->flags & SWS_UNSTABLE))
573  goto fail;
574 
575  /* The new format conversion layer cannot scale for now */
576  if (src->width != dst->width || src->height != dst->height)
577  goto fail;
578 
579  /* The new code does not yet support alpha blending */
580  if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
581  ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
582  goto fail;
583 
584  ops = ff_sws_op_list_alloc();
585  if (!ops)
586  return AVERROR(ENOMEM);
587  ops->src = *src;
588  ops->dst = *dst;
589 
590  ret = ff_sws_decode_pixfmt(ops, src->format);
591  if (ret < 0)
592  goto fail;
593  ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete);
594  if (ret < 0)
595  goto fail;
596  ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete);
597  if (ret < 0)
598  goto fail;
599  ret = ff_sws_encode_pixfmt(ops, dst->format);
600  if (ret < 0)
601  goto fail;
602 
603  av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
604  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
605 
606  av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
608 
610  if (ret < 0)
611  goto fail;
612 
613  ret = 0;
614  /* fall through */
615 
616 fail:
617  ff_sws_op_list_free(&ops);
618  if (ret == AVERROR(ENOTSUP))
619  return add_legacy_sws_pass(graph, src, dst, input, output);
620  return ret;
621 }
622 #else
623 #define add_convert_pass add_legacy_sws_pass
624 #endif
625 
626 
627 /**************************
628  * Gamut and tone mapping *
629  **************************/
630 
631 static void free_lut3d(void *priv)
632 {
633  SwsLut3D *lut = priv;
634  ff_sws_lut3d_free(&lut);
635 }
636 
637 static int setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
638 {
639  SwsLut3D *lut = pass->priv;
640 
641  /* Update dynamic frame metadata from the original source frame */
642  ff_sws_lut3d_update(lut, &pass->graph->src.color);
643  return 0;
644 }
645 
646 static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h,
647  const SwsPass *pass)
648 {
649  SwsLut3D *lut = pass->priv;
650  uint8_t *in_data[4], *out_data[4];
651  frame_shift(in, y, in_data);
652  frame_shift(out, y, out_data);
653 
654  ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0],
655  out->linesize[0], pass->width, h);
656 }
657 
660 {
661  enum AVPixelFormat fmt_in, fmt_out;
662  SwsColorMap map = {0};
663  SwsLut3D *lut;
664  int ret;
665 
666  /**
667  * Grayspace does not really have primaries, so just force the use of
668  * the equivalent other primary set to avoid a conversion. Technically,
669  * this does affect the weights used for the Grayscale conversion, but
670  * in practise, that should give the expected results more often than not.
671  */
672  if (isGray(dst.format)) {
673  dst.color = src.color;
674  } else if (isGray(src.format)) {
675  src.color = dst.color;
676  }
677 
678  /* Fully infer color spaces before color mapping logic */
679  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
680 
681  map.intent = graph->ctx->intent;
682  map.src = src.color;
683  map.dst = dst.color;
684 
686  return 0;
687 
688  if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE)
689  return AVERROR(ENOTSUP);
690 
691  lut = ff_sws_lut3d_alloc();
692  if (!lut)
693  return AVERROR(ENOMEM);
694 
695  fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0);
696  fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1);
697  if (fmt_in != src.format) {
698  SwsFormat tmp = src;
699  tmp.format = fmt_in;
700  ret = add_convert_pass(graph, &src, &tmp, input, &input);
701  if (ret < 0) {
702  ff_sws_lut3d_free(&lut);
703  return ret;
704  }
705  }
706 
707  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
708  if (ret < 0) {
709  ff_sws_lut3d_free(&lut);
710  return ret;
711  }
712 
713  return ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
714  input, 1, run_lut3d, setup_lut3d, lut,
715  free_lut3d, output);
716 }
717 
718 /***************************************
719  * Main filter graph construction code *
720  ***************************************/
721 
722 static int init_passes(SwsGraph *graph)
723 {
724  SwsFormat src = graph->src;
725  SwsFormat dst = graph->dst;
726  SwsPass *pass = NULL; /* read from main input image */
727  int ret;
728 
729  ret = adapt_colors(graph, src, dst, pass, &pass);
730  if (ret < 0)
731  return ret;
732  src.format = pass ? pass->format : src.format;
733  src.color = dst.color;
734 
735  if (!ff_fmt_equal(&src, &dst)) {
736  ret = add_convert_pass(graph, &src, &dst, pass, &pass);
737  if (ret < 0)
738  return ret;
739  }
740 
741  if (pass)
742  return 0;
743 
744  /* No passes were added, so no operations were necessary */
745  graph->noop = 1;
746 
747  /* Add threaded memcpy pass */
748  return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
749  pass, 1, run_copy, NULL, NULL, NULL, &pass);
750 }
751 
752 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
753  int nb_threads)
754 {
755  SwsGraph *graph = priv;
756  const SwsPass *pass = graph->exec.pass;
757  const int slice_y = jobnr * pass->slice_h;
758  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
759 
760  pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
761 }
762 
764  int field, SwsGraph **out_graph)
765 {
766  int ret;
767  SwsGraph *graph = av_mallocz(sizeof(*graph));
768  if (!graph)
769  return AVERROR(ENOMEM);
770 
771  graph->ctx = ctx;
772  graph->src = *src;
773  graph->dst = *dst;
774  graph->field = field;
775  graph->opts_copy = *ctx;
776 
777  if (ctx->threads == 1) {
778  graph->num_threads = 1;
779  } else {
780  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
781  sws_graph_worker, NULL, ctx->threads);
782  if (ret == AVERROR(ENOSYS)) {
783  /* Fall back to single threaded operation */
784  graph->num_threads = 1;
785  } else if (ret < 0) {
786  goto error;
787  } else {
788  graph->num_threads = ret;
789  }
790  }
791 
792  ret = init_passes(graph);
793  if (ret < 0)
794  goto error;
795 
796  /* Resolve output buffers for all intermediate passes */
797  for (int i = 0; i < graph->num_passes; i++) {
798  ret = pass_alloc_output(graph->passes[i]->input);
799  if (ret < 0)
800  goto error;
801  }
802 
803  *out_graph = graph;
804  return 0;
805 
806 error:
807  ff_sws_graph_free(&graph);
808  return ret;
809 }
810 
812 {
813  SwsGraph *graph = *pgraph;
814  if (!graph)
815  return;
816 
818 
819  for (int i = 0; i < graph->num_passes; i++)
820  pass_free(graph->passes[i]);
821  av_free(graph->passes);
822 
823  av_free(graph);
824  *pgraph = NULL;
825 }
826 
827 /* Tests only options relevant to SwsGraph */
828 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
829 {
830  return c1->flags == c2->flags &&
831  c1->threads == c2->threads &&
832  c1->dither == c2->dither &&
833  c1->alpha_blend == c2->alpha_blend &&
834  c1->gamma_flag == c2->gamma_flag &&
835  c1->src_h_chr_pos == c2->src_h_chr_pos &&
836  c1->src_v_chr_pos == c2->src_v_chr_pos &&
837  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
838  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
839  c1->intent == c2->intent &&
840  c1->scaler == c2->scaler &&
841  c1->scaler_sub == c2->scaler_sub &&
842  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
843 
844 }
845 
847  int field, SwsGraph **out_graph)
848 {
849  SwsGraph *graph = *out_graph;
850  if (graph && ff_fmt_equal(&graph->src, src) &&
851  ff_fmt_equal(&graph->dst, dst) &&
852  opts_equal(ctx, &graph->opts_copy))
853  {
854  ff_sws_graph_update_metadata(graph, &src->color);
855  return 0;
856  }
857 
858  ff_sws_graph_free(out_graph);
859  return ff_sws_graph_create(ctx, dst, src, field, out_graph);
860 }
861 
863 {
864  if (!color)
865  return;
866 
868 }
869 
870 static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
871 {
873 
874  if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) {
875  av_assert1(!graph->field);
876  return;
877  }
878 
879  if (graph->field == FIELD_BOTTOM) {
880  /* Odd rows, offset by one line */
882  for (int i = 0; i < 4; i++) {
883  if (frame->data[i])
884  frame->data[i] += frame->linesize[i];
885  if (desc->flags & AV_PIX_FMT_FLAG_PAL)
886  break;
887  }
888  }
889 
890  /* Take only every second line */
891  for (int i = 0; i < 4; i++)
892  frame->linesize[i] <<= 1;
893 
894  frame->height = (frame->height + (graph->field == FIELD_TOP)) >> 1;
895 }
896 
897 int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
898 {
899  av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format);
900  av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format);
901 
902  SwsFrame src_field, dst_field;
903  get_field(graph, dst, &dst_field);
904  get_field(graph, src, &src_field);
905 
906  for (int i = 0; i < graph->num_passes; i++) {
907  const SwsPass *pass = graph->passes[i];
908  graph->exec.pass = pass;
909  graph->exec.input = pass->input ? &pass->input->output->frame : &src_field;
910  graph->exec.output = pass->output->avframe ? &pass->output->frame : &dst_field;
911  if (pass->setup) {
912  int ret = pass->setup(graph->exec.output, graph->exec.input, pass);
913  if (ret < 0)
914  return ret;
915  }
916 
917  if (pass->num_slices == 1) {
918  pass->run(graph->exec.output, graph->exec.input, 0, pass->height, pass);
919  } else {
921  }
922  }
923 
924  return 0;
925 }
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:848
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:527
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
add_legacy_sws_pass
static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, SwsPass *input, SwsPass **output)
Definition: graph.c:484
SwsGraph::slicethread
AVSliceThread * slicethread
Definition: graph.h:114
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:113
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:71
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:515
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:142
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:122
adapt_colors
static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:658
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:722
SwsFormat::interlaced
int interlaced
Definition: format.h:79
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
SwsContext::src_w
int src_w
Deprecated frame property overrides, for the legacy API only.
Definition: swscale.h:253
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:846
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:80
saturation
static IPT saturation(const CmsCtx *ctx, IPT ipt)
Definition: cms.c:559
run_rgb0
static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:205
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:226
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
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::src
SwsFormat src
Currently active format and processing parameters.
Definition: graph.h:134
avpriv_slicethread_execute
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
Definition: slicethread.c:270
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
pixdesc.h
frame_shift
static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
Definition: graph.c:169
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:802
SwsGraph::output
const SwsFrame * output
Definition: graph.h:144
run_copy
static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:179
pass_free
static void pass_free(SwsPass *pass)
Definition: graph.c:107
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:157
SwsPass::setup
SwsPassSetup setup
Called once from the main thread before running the filter.
Definition: graph.h:100
table
static const uint16_t table[]
Definition: prosumer.c:203
data
const char data[16]
Definition: mxf.c:149
SwsContext::flags
unsigned flags
Bitmask of SWS_*.
Definition: swscale.h:219
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
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:671
SwsPass::free
void(* free)(void *priv)
Optional private state and associated free() function.
Definition: graph.h:105
c1
static const uint64_t c1
Definition: murmur3.c:52
format.h
SwsPass::input
SwsPass * input
Filter input.
Definition: graph.h:89
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:1136
SwsColorMap
Definition: cms.h:60
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:30
SwsPass::width
int width
Definition: graph.h:81
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:754
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:374
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:35
SwsFrame::data
uint8_t * data[4]
Definition: format.h:190
setup_lut3d
static int setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: graph.c:637
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:261
macros.h
fail
#define fail()
Definition: checkasm.h:221
SwsContext::src_v_chr_pos
int src_v_chr_pos
Source vertical chroma position in luma grid / 256.
Definition: swscale.h:259
slice_ctx
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition: graph.c:272
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:1919
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:129
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
SwsPassBuffer::frame
SwsFrame frame
Definition: graph.h:60
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:763
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:52
SwsFrame
Represents a view into a single field of frame data.
Definition: format.h:188
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:400
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:358
SwsFrame::format
enum AVPixelFormat format
Definition: format.h:197
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:235
SwsPass::priv
void * priv
Definition: graph.h:106
run_xyz2rgb
static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:226
SwsGraph::exec
struct SwsGraph::@548 exec
Temporary execution state inside ff_sws_graph_run(); used to pass data to worker threads.
SwsInternal::nb_slice_ctx
int nb_slice_ctx
Definition: swscale_internal.h:344
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:342
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
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: format.h:57
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1414
ff_sws_lut3d_alloc
SwsLut3D * ff_sws_lut3d_alloc(void)
Definition: lut3d.c:32
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:267
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:123
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
SwsPass::run
SwsPassFunc run
Filter main execution function.
Definition: graph.h:79
free_buffer
static void free_buffer(AVRefStructOpaque opaque, void *obj)
Definition: graph.c:101
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:135
ff_sws_lut3d_free
void ff_sws_lut3d_free(SwsLut3D **plut3d)
Definition: lut3d.c:42
NULL
#define NULL
Definition: coverity.c:32
sizes
static const int sizes[][2]
Definition: img2dec.c:61
run
uint8_t run
Definition: svq3.c:207
run_legacy_swscale
static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:303
SwsContext::gamma_flag
int gamma_flag
Use gamma correct scaling.
Definition: swscale.h:245
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
ff_infer_colors
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition: format.c:526
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:257
av_cpu_max_align
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
Definition: cpu.c:287
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:72
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:262
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
SwsPassBuffer::avframe
AVFrame * avframe
Definition: graph.h:63
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:2145
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:811
SwsPass::height
int height
Definition: graph.h:81
f
f
Definition: af_crystalizer.c:122
lut3d.h
free_lut3d
static void free_lut3d(void *priv)
Definition: graph.c:631
height
#define height
Definition: dsp.h:89
frame_alloc_planes
static int frame_alloc_planes(AVFrame *dst)
Definition: graph.c:42
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1031
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:933
cpu.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
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
run_legacy_unscaled
static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:291
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:240
SwsPassBuffer::height
int height
Definition: graph.h:62
SwsOpList::src
SwsFormat src
Definition: ops.h:229
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:253
AVCHROMA_LOC_UNSPECIFIED
@ AVCHROMA_LOC_UNSPECIFIED
Definition: pixfmt.h:797
SwsFormat
Definition: format.h:77
AVFrame::format
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:514
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:1006
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
SwsColor
Definition: format.h:60
SwsPass::output
SwsPassBuffer * output
Filter output buffer.
Definition: graph.h:94
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:256
SWS_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops.h:308
run_lut3d
static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:646
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
SwsGraph::input
const SwsFrame * input
Definition: graph.h:143
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
free_legacy_swscale
static void free_legacy_swscale(void *priv)
Definition: graph.c:250
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:134
ff_fmt_vshift
static av_always_inline av_const int ff_fmt_vshift(enum AVPixelFormat fmt, int plane)
Definition: graph.h:32
SwsFormat::format
enum AVPixelFormat format
Definition: format.h:80
SwsPass::slice_h
int slice_h
Definition: graph.h:82
SwsGraph::num_threads
int num_threads
Definition: graph.h:115
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:828
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
setup_legacy_swscale
static int setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: graph.c:256
SwsContext::scaler
SwsScaler scaler
Scaling filter.
Definition: swscale.h:275
swscale_internal.h
graph.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
ff_sws_encode_colors
int ff_sws_encode_colors(SwsContext *ctx, SwsPixelType type, SwsOpList *ops, const SwsFormat *src, const SwsFormat *dst, bool *incomplete)
SwsContext::scaler_sub
SwsScaler scaler_sub
Scaler used specifically for up/downsampling subsampled (chroma) planes.
Definition: swscale.h:283
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:254
AVCOL_SPC_UNSPECIFIED
@ AVCOL_SPC_UNSPECIFIED
Definition: pixfmt.h:703
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_FRAME_FLAG_INTERLACED
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition: frame.h:650
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:315
ff_sws_graph_add_pass
int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int align, SwsPassFunc run, SwsPassSetup setup, void *priv, void(*free_cb)(void *priv), SwsPass **out_pass)
Allocate and add a new pass to the filter graph.
Definition: graph.c:115
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
SwsInternal
Definition: swscale_internal.h:334
ret
ret
Definition: filter_design.txt:187
SwsPassFunc
void(* SwsPassFunc)(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Output h lines of filtered data.
Definition: graph.h:45
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:265
SwsOpList::dst
SwsFormat dst
Definition: ops.h:229
ff_fmt_equal
static int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
Definition: format.h:130
SwsGraph::noop
bool noop
Definition: graph.h:117
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:62
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
SWS_NUM_SCALER_PARAMS
#define SWS_NUM_SCALER_PARAMS
Extra parameters for fine-tuning certain scalers.
Definition: swscale.h:224
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
get_field
static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
Definition: graph.c:870
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
SwsPassSetup
int(* SwsPassSetup)(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Function to run from the main thread before processing any lines.
Definition: graph.h:51
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:623
desc
const char * desc
Definition: libsvtav1.c:82
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:399
SwsGraph::incomplete
bool incomplete
Definition: graph.h:116
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:254
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:112
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:255
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
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
run_rgb2xyz
static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:235
SwsContext::dst_range
int dst_range
Destination is full range.
Definition: swscale.h:258
pass_alloc_output
static int pass_alloc_output(SwsPass *pass)
Definition: graph.c:77
ff_sws_graph_run
int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
Dispatch the filter graph on a single field of the given frames.
Definition: graph.c:897
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:2368
imgutils.h
avpriv_slicethread_free
void avpriv_slicethread_free(AVSliceThread **pctx)
Destroy slice threading context.
Definition: slicethread.c:275
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:260
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:78
SwsPassBuffer
Represents an output buffer for a filter pass.
Definition: graph.h:59
h
h
Definition: vp9dsp_template.c:2070
SwsPass::num_slices
int num_slices
Definition: graph.h:83
width
#define width
Definition: dsp.h:89
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:224
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:261
SwsContext
Main external API structure.
Definition: swscale.h:206
AV_PIX_FMT_FLAG_PAL
#define AV_PIX_FMT_FLAG_PAL
Pixel format has a palette in data[1], values are indexes in this palette.
Definition: pixdesc.h:120
SwsFrame::linesize
int linesize[4]
Definition: format.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:752
FIELD_TOP
@ FIELD_TOP
Definition: format.h:56
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:862
SWS_UNSTABLE
@ SWS_UNSTABLE
Allow using experimental new code paths.
Definition: swscale.h:164
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
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, SwsOpList **ops, int flags, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
Definition: ops_dispatch.c:378
SwsContext::scaler_params
double scaler_params[SWS_NUM_SCALER_PARAMS]
Definition: swscale.h:225
src
#define src
Definition: vp8dsp.c:248
swscale.h
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:893
ff_sws_frame_from_avframe
void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src)
Initialize a SwsFrame from an AVFrame.
Definition: format.c:639