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 
108  int width, int height, SwsPass *input,
109  int align, void *priv, sws_filter_run_t run,
110  SwsPass **out_pass)
111 {
112  int ret;
113  SwsPass *pass = av_mallocz(sizeof(*pass));
114  if (!pass)
115  return AVERROR(ENOMEM);
116 
117  pass->graph = graph;
118  pass->run = run;
119  pass->priv = priv;
120  pass->format = fmt;
121  pass->width = width;
122  pass->height = height;
123  pass->input = input;
124  pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, free_buffer);
125  if (!pass->output) {
126  ret = AVERROR(ENOMEM);
127  goto fail;
128  }
129 
131  if (ret < 0)
132  goto fail;
133 
134  if (!align) {
135  pass->slice_h = pass->height;
136  pass->num_slices = 1;
137  } else {
138  pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads;
139  pass->slice_h = FFALIGN(pass->slice_h, align);
140  pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
141  }
142 
143  /* Align output buffer to include extra slice padding */
144  pass->output->width = pass->width;
145  pass->output->height = pass->slice_h * pass->num_slices;
146 
147  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
148  if (ret < 0)
149  goto fail;
150 
151  *out_pass = pass;
152  return 0;
153 
154 fail:
155  av_refstruct_unref(&pass->output);
156  av_free(pass);
157  return ret;
158 }
159 
160 static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
161 {
162  for (int i = 0; i < 4; i++) {
163  if (f->data[i])
164  data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * f->linesize[i];
165  else
166  data[i] = NULL;
167  }
168 }
169 
170 static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h,
171  const SwsPass *pass)
172 {
173  uint8_t *in_data[4], *out_data[4];
174  frame_shift(in, y, in_data);
175  frame_shift(out, y, out_data);
176 
177  for (int i = 0; i < 4 && out_data[i]; i++) {
178  const int lines = h >> ff_fmt_vshift(in->format, i);
179  av_assert1(in_data[i]);
180 
181  if (in_data[i] == out_data[i]) {
182  av_assert0(in->linesize[i] == out->linesize[i]);
183  } else if (in->linesize[i] == out->linesize[i]) {
184  memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
185  } else {
186  const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
187  for (int j = 0; j < lines; j++) {
188  memcpy(out_data[i], in_data[i], linesize);
189  in_data[i] += in->linesize[i];
190  out_data[i] += out->linesize[i];
191  }
192  }
193  }
194 }
195 
196 static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h,
197  const SwsPass *pass)
198 {
199  SwsInternal *c = pass->priv;
200  const int x0 = c->src0Alpha - 1;
201  const int w4 = 4 * pass->width;
202  const int src_stride = in->linesize[0];
203  const int dst_stride = out->linesize[0];
204  const uint8_t *src = in->data[0] + y * src_stride;
205  uint8_t *dst = out->data[0] + y * dst_stride;
206 
207  for (int y = 0; y < h; y++) {
208  memcpy(dst, src, w4 * sizeof(*dst));
209  for (int x = x0; x < w4; x += 4)
210  dst[x] = 0xFF;
211 
212  src += src_stride;
213  dst += dst_stride;
214  }
215 }
216 
217 static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h,
218  const SwsPass *pass)
219 {
220  const SwsInternal *c = pass->priv;
221  c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
222  in->data[0] + y * in->linesize[0], in->linesize[0],
223  pass->width, h);
224 }
225 
226 static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h,
227  const SwsPass *pass)
228 {
229  const SwsInternal *c = pass->priv;
230  c->rgb48Toxyz12(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 /***********************************************************************
236  * Internal ff_swscale() wrapper. This reuses the legacy scaling API. *
237  * This is considered fully deprecated, and will be replaced by a full *
238  * reimplementation ASAP. *
239  ***********************************************************************/
240 
241 static void free_legacy_swscale(void *priv)
242 {
243  SwsContext *sws = priv;
245 }
246 
247 static void setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
248  const SwsPass *pass)
249 {
250  SwsContext *sws = pass->priv;
252  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
253  for (int i = 0; i < 4; i++)
254  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
255  }
256 
257  if (usePal(sws->src_format))
258  ff_update_palette(c, (const uint32_t *) in->data[1]);
259 }
260 
261 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
262 {
263  SwsContext *sws = pass->priv;
264  SwsInternal *parent = sws_internal(sws);
265  if (pass->num_slices == 1)
266  return sws;
267 
268  av_assert1(parent->nb_slice_ctx == pass->num_slices);
269  sws = parent->slice_ctx[y / pass->slice_h];
270 
271  if (usePal(sws->src_format)) {
272  SwsInternal *sub = sws_internal(sws);
273  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
274  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
275  }
276 
277  return sws;
278 }
279 
280 static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in,
281  int y, int h, const SwsPass *pass)
282 {
283  SwsContext *sws = slice_ctx(pass, y);
285  uint8_t *in_data[4];
286  frame_shift(in, y, in_data);
287 
288  c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h,
289  out->data, out->linesize);
290 }
291 
292 static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
293  int y, int h, const SwsPass *pass)
294 {
295  SwsContext *sws = slice_ctx(pass, y);
297  uint8_t *out_data[4];
298  frame_shift(out, y, out_data);
299 
300  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
301  sws->src_h, out_data, out->linesize, y, h);
302 }
303 
304 static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
305  const SwsFormat *fmt)
306 {
307  enum AVChromaLocation chroma_loc = fmt->loc;
308  const int sub_x = fmt->desc->log2_chroma_w;
309  const int sub_y = fmt->desc->log2_chroma_h;
310  int x_pos, y_pos;
311 
312  /* Explicitly default to center siting for compatibility with swscale */
313  if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
314  chroma_loc = AVCHROMA_LOC_CENTER;
315  graph->incomplete |= sub_x || sub_y;
316  }
317 
318  /* av_chroma_location_enum_to_pos() always gives us values in the range from
319  * 0 to 256, but we need to adjust this to the true value range of the
320  * subsampling grid, which may be larger for h/v_sub > 1 */
321  av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
322  x_pos *= (1 << sub_x) - 1;
323  y_pos *= (1 << sub_y) - 1;
324 
325  /* Fix vertical chroma position for interlaced frames */
326  if (sub_y && fmt->interlaced) {
327  /* When vertically subsampling, chroma samples are effectively only
328  * placed next to even rows. To access them from the odd field, we need
329  * to account for this shift by offsetting the distance of one luma row.
330  *
331  * For 4x vertical subsampling (v_sub == 2), they are only placed
332  * next to every *other* even row, so we need to shift by three luma
333  * rows to get to the chroma sample. */
334  if (graph->field == FIELD_BOTTOM)
335  y_pos += (256 << sub_y) - 256;
336 
337  /* Luma row distance is doubled for fields, so halve offsets */
338  y_pos >>= 1;
339  }
340 
341  /* Explicitly strip chroma offsets when not subsampling, because it
342  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
343  *h_chr_pos = sub_x ? x_pos : -513;
344  *v_chr_pos = sub_y ? y_pos : -513;
345 }
346 
347 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
348 {
349  if (override == -513 || override == *chr_pos)
350  return;
351 
352  if (!*warned) {
354  "Setting chroma position directly is deprecated, make sure "
355  "the frame is tagged with the correct chroma location.\n");
356  *warned = 1;
357  }
358 
359  *chr_pos = override;
360 }
361 
362 /* Takes over ownership of `sws` */
365 {
367  const int src_w = sws->src_w, src_h = sws->src_h;
368  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
369  const int unscaled = src_w == dst_w && src_h == dst_h;
370  int align = c->dst_slice_align;
371  SwsPass *pass = NULL;
372  int ret;
373 
374  if (c->cascaded_context[0]) {
375  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
376  for (int i = 0; i < num_cascaded; i++) {
377  const int is_last = i + 1 == num_cascaded;
378 
379  /* Steal cascaded context, so we can manage its lifetime independently */
380  SwsContext *sub = c->cascaded_context[i];
381  c->cascaded_context[i] = NULL;
382 
383  ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input);
384  if (ret < 0)
385  break;
386  }
387 
389  return ret;
390  }
391 
392  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
393  align = 0; /* disable slice threading */
394 
395  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
396  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGBA, src_w, src_h, input,
397  1, c, run_rgb0, &input);
398  if (ret < 0) {
400  return ret;
401  }
402  }
403 
404  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
405  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, src_w, src_h, input,
406  1, c, run_xyz2rgb, &input);
407  if (ret < 0) {
409  return ret;
410  }
411  }
412 
413  ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, align, sws,
414  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale,
415  &pass);
416  if (ret < 0) {
418  return ret;
419  }
420  pass->setup = setup_legacy_swscale;
421  pass->free = free_legacy_swscale;
422 
423  /**
424  * For slice threading, we need to create sub contexts, similar to how
425  * swscale normally handles it internally. The most important difference
426  * is that we handle cascaded contexts before threaded contexts; whereas
427  * context_init_threaded() does it the other way around.
428  */
429 
430  if (pass->num_slices > 1) {
431  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
432  if (!c->slice_ctx)
433  return AVERROR(ENOMEM);
434 
435  for (int i = 0; i < pass->num_slices; i++) {
436  SwsContext *slice;
437  SwsInternal *c2;
438  slice = c->slice_ctx[i] = sws_alloc_context();
439  if (!slice)
440  return AVERROR(ENOMEM);
441  c->nb_slice_ctx++;
442 
443  c2 = sws_internal(slice);
444  c2->parent = sws;
445 
446  ret = av_opt_copy(slice, sws);
447  if (ret < 0)
448  return ret;
449 
451  if (ret < 0)
452  return ret;
453 
454  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
455  slice->src_range, c->dstColorspaceTable,
456  slice->dst_range, c->brightness, c->contrast,
457  c->saturation);
458 
459  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
460  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
461  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
462  }
463  }
464  }
465 
466  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
467  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, pass,
468  1, c, run_rgb2xyz, &pass);
469  if (ret < 0)
470  return ret;
471  }
472 
473  *output = pass;
474  return 0;
475 }
476 
477 static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src,
478  const SwsFormat *dst, SwsPass *input,
479  SwsPass **output)
480 {
481  int ret, warned = 0;
482  SwsContext *const ctx = graph->ctx;
483  if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE)
484  return AVERROR(ENOTSUP);
485 
487  if (!sws)
488  return AVERROR(ENOMEM);
489 
490  sws->flags = ctx->flags;
491  sws->dither = ctx->dither;
492  sws->alpha_blend = ctx->alpha_blend;
493  sws->gamma_flag = ctx->gamma_flag;
494 
495  sws->src_w = src->width;
496  sws->src_h = src->height;
497  sws->src_format = src->format;
498  sws->src_range = src->range == AVCOL_RANGE_JPEG;
499 
500  sws->dst_w = dst->width;
501  sws->dst_h = dst->height;
502  sws->dst_format = dst->format;
503  sws->dst_range = dst->range == AVCOL_RANGE_JPEG;
506 
507  graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED;
508  graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED;
509 
510  /* Allow overriding chroma position with the legacy API */
511  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
512  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
513  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
514  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
515 
516  sws->scaler_params[0] = ctx->scaler_params[0];
517  sws->scaler_params[1] = ctx->scaler_params[1];
518 
520  if (ret < 0) {
522  return ret;
523  }
524 
525  /* Set correct color matrices */
526  {
527  int in_full, out_full, brightness, contrast, saturation;
528  const int *inv_table, *table;
529  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
530  (int **)&table, &out_full,
531  &brightness, &contrast, &saturation);
532 
533  inv_table = sws_getCoefficients(src->csp);
534  table = sws_getCoefficients(dst->csp);
535 
536  graph->incomplete |= src->csp != dst->csp &&
537  (src->csp == AVCOL_SPC_UNSPECIFIED ||
538  dst->csp == AVCOL_SPC_UNSPECIFIED);
539 
540  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
541  brightness, contrast, saturation);
542  }
543 
544  return init_legacy_subpass(graph, sws, input, output);
545 }
546 
547 /*********************
548  * Format conversion *
549  *********************/
550 
551 #if CONFIG_UNSTABLE
552 static int add_convert_pass(SwsGraph *graph, const SwsFormat *src,
553  const SwsFormat *dst, SwsPass *input,
554  SwsPass **output)
555 {
557 
558  SwsContext *ctx = graph->ctx;
559  SwsOpList *ops = NULL;
560  int ret = AVERROR(ENOTSUP);
561 
562  /* Mark the entire new ops infrastructure as experimental for now */
563  if (!(ctx->flags & SWS_UNSTABLE))
564  goto fail;
565 
566  /* The new format conversion layer cannot scale for now */
567  if (src->width != dst->width || src->height != dst->height ||
568  src->desc->log2_chroma_h || src->desc->log2_chroma_w ||
569  dst->desc->log2_chroma_h || dst->desc->log2_chroma_w)
570  goto fail;
571 
572  /* The new code does not yet support alpha blending */
573  if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
574  ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
575  goto fail;
576 
577  ops = ff_sws_op_list_alloc();
578  if (!ops)
579  return AVERROR(ENOMEM);
580  ops->src = *src;
581  ops->dst = *dst;
582 
583  ret = ff_sws_decode_pixfmt(ops, src->format);
584  if (ret < 0)
585  goto fail;
586  ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete);
587  if (ret < 0)
588  goto fail;
589  ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete);
590  if (ret < 0)
591  goto fail;
592  ret = ff_sws_encode_pixfmt(ops, dst->format);
593  if (ret < 0)
594  goto fail;
595 
596  av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
597  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
598 
599  av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
601  av_log(ctx, AV_LOG_DEBUG, "Optimized operation list:\n");
604 
605  ret = ff_sws_compile_pass(graph, ops, 0, dst, input, output);
606  if (ret < 0)
607  goto fail;
608 
609  ret = 0;
610  /* fall through */
611 
612 fail:
613  ff_sws_op_list_free(&ops);
614  if (ret == AVERROR(ENOTSUP))
615  return add_legacy_sws_pass(graph, src, dst, input, output);
616  return ret;
617 }
618 #else
619 #define add_convert_pass add_legacy_sws_pass
620 #endif
621 
622 
623 /**************************
624  * Gamut and tone mapping *
625  **************************/
626 
627 static void free_lut3d(void *priv)
628 {
629  SwsLut3D *lut = priv;
630  ff_sws_lut3d_free(&lut);
631 }
632 
633 static void setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
634 {
635  SwsLut3D *lut = pass->priv;
636 
637  /* Update dynamic frame metadata from the original source frame */
638  ff_sws_lut3d_update(lut, &pass->graph->src.color);
639 }
640 
641 static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h,
642  const SwsPass *pass)
643 {
644  SwsLut3D *lut = pass->priv;
645  uint8_t *in_data[4], *out_data[4];
646  frame_shift(in, y, in_data);
647  frame_shift(out, y, out_data);
648 
649  ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0],
650  out->linesize[0], pass->width, h);
651 }
652 
655 {
656  enum AVPixelFormat fmt_in, fmt_out;
657  SwsColorMap map = {0};
658  SwsLut3D *lut;
659  SwsPass *pass;
660  int ret;
661 
662  /**
663  * Grayspace does not really have primaries, so just force the use of
664  * the equivalent other primary set to avoid a conversion. Technically,
665  * this does affect the weights used for the Grayscale conversion, but
666  * in practise, that should give the expected results more often than not.
667  */
668  if (isGray(dst.format)) {
669  dst.color = src.color;
670  } else if (isGray(src.format)) {
671  src.color = dst.color;
672  }
673 
674  /* Fully infer color spaces before color mapping logic */
675  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
676 
677  map.intent = graph->ctx->intent;
678  map.src = src.color;
679  map.dst = dst.color;
680 
682  return 0;
683 
684  if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE)
685  return AVERROR(ENOTSUP);
686 
687  lut = ff_sws_lut3d_alloc();
688  if (!lut)
689  return AVERROR(ENOMEM);
690 
691  fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0);
692  fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1);
693  if (fmt_in != src.format) {
694  SwsFormat tmp = src;
695  tmp.format = fmt_in;
696  ret = add_convert_pass(graph, &src, &tmp, input, &input);
697  if (ret < 0)
698  return ret;
699  }
700 
701  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
702  if (ret < 0) {
703  ff_sws_lut3d_free(&lut);
704  return ret;
705  }
706 
707  ret = ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
708  input, 1, lut, run_lut3d, &pass);
709  if (ret < 0) {
710  ff_sws_lut3d_free(&lut);
711  return ret;
712  }
713  pass->setup = setup_lut3d;
714  pass->free = free_lut3d;
715 
716  *output = pass;
717  return 0;
718 }
719 
720 /***************************************
721  * Main filter graph construction code *
722  ***************************************/
723 
724 static int init_passes(SwsGraph *graph)
725 {
726  SwsFormat src = graph->src;
727  SwsFormat dst = graph->dst;
728  SwsPass *pass = NULL; /* read from main input image */
729  int ret;
730 
731  ret = adapt_colors(graph, src, dst, pass, &pass);
732  if (ret < 0)
733  return ret;
734  src.format = pass ? pass->format : src.format;
735  src.color = dst.color;
736 
737  if (!ff_fmt_equal(&src, &dst)) {
738  ret = add_convert_pass(graph, &src, &dst, pass, &pass);
739  if (ret < 0)
740  return ret;
741  }
742 
743  if (!pass) {
744  /* No passes were added, so no operations were necessary */
745  graph->noop = 1;
746 
747  /* Add threaded memcpy pass */
748  ret = ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
749  pass, 1, NULL, run_copy, &pass);
750  if (ret < 0)
751  return ret;
752  }
753 
754  return 0;
755 }
756 
757 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
758  int nb_threads)
759 {
760  SwsGraph *graph = priv;
761  const SwsPass *pass = graph->exec.pass;
762  const int slice_y = jobnr * pass->slice_h;
763  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
764 
765  pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
766 }
767 
769  int field, SwsGraph **out_graph)
770 {
771  int ret;
772  SwsGraph *graph = av_mallocz(sizeof(*graph));
773  if (!graph)
774  return AVERROR(ENOMEM);
775 
776  graph->ctx = ctx;
777  graph->src = *src;
778  graph->dst = *dst;
779  graph->field = field;
780  graph->opts_copy = *ctx;
781 
782  if (ctx->threads == 1) {
783  graph->num_threads = 1;
784  } else {
785  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
786  sws_graph_worker, NULL, ctx->threads);
787  if (ret == AVERROR(ENOSYS)) {
788  /* Fall back to single threaded operation */
789  graph->num_threads = 1;
790  } else if (ret < 0) {
791  goto error;
792  } else {
793  graph->num_threads = ret;
794  }
795  }
796 
797  ret = init_passes(graph);
798  if (ret < 0)
799  goto error;
800 
801  *out_graph = graph;
802  return 0;
803 
804 error:
805  ff_sws_graph_free(&graph);
806  return ret;
807 }
808 
810 {
811  SwsGraph *graph = *pgraph;
812  if (!graph)
813  return;
814 
816 
817  for (int i = 0; i < graph->num_passes; i++) {
818  SwsPass *pass = graph->passes[i];
819  if (pass->free)
820  pass->free(pass->priv);
821  av_refstruct_unref(&pass->output);
822  av_free(pass);
823  }
824  av_free(graph->passes);
825 
826  av_free(graph);
827  *pgraph = NULL;
828 }
829 
830 /* Tests only options relevant to SwsGraph */
831 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
832 {
833  return c1->flags == c2->flags &&
834  c1->threads == c2->threads &&
835  c1->dither == c2->dither &&
836  c1->alpha_blend == c2->alpha_blend &&
837  c1->gamma_flag == c2->gamma_flag &&
838  c1->src_h_chr_pos == c2->src_h_chr_pos &&
839  c1->src_v_chr_pos == c2->src_v_chr_pos &&
840  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
841  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
842  c1->intent == c2->intent &&
843  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
844 
845 }
846 
848  int field, SwsGraph **out_graph)
849 {
850  SwsGraph *graph = *out_graph;
851  if (graph && ff_fmt_equal(&graph->src, src) &&
852  ff_fmt_equal(&graph->dst, dst) &&
853  opts_equal(ctx, &graph->opts_copy))
854  {
855  ff_sws_graph_update_metadata(graph, &src->color);
856  return 0;
857  }
858 
859  ff_sws_graph_free(out_graph);
860  return ff_sws_graph_create(ctx, dst, src, field, out_graph);
861 }
862 
864 {
865  if (!color)
866  return;
867 
869 }
870 
871 static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
872 {
874 
875  if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) {
876  av_assert1(!graph->field);
877  return;
878  }
879 
880  if (graph->field == FIELD_BOTTOM) {
881  /* Odd rows, offset by one line */
883  for (int i = 0; i < 4; i++) {
884  if (frame->data[i])
885  frame->data[i] += frame->linesize[i];
886  if (desc->flags & AV_PIX_FMT_FLAG_PAL)
887  break;
888  }
889  }
890 
891  /* Take only every second line */
892  for (int i = 0; i < 4; i++)
893  frame->linesize[i] <<= 1;
894 
895  frame->height = (frame->height + (graph->field == FIELD_TOP)) >> 1;
896 }
897 
898 void ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
899 {
900  av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format);
901  av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format);
902 
903  SwsFrame src_field, dst_field;
904  get_field(graph, dst, &dst_field);
905  get_field(graph, src, &src_field);
906 
907  for (int i = 0; i < graph->num_passes; i++) {
908  const SwsPass *pass = graph->passes[i];
909  graph->exec.pass = pass;
910  graph->exec.input = pass->input ? &pass->input->output->frame : &src_field;
911  graph->exec.output = pass->output->avframe ? &pass->output->frame : &dst_field;
912  if (pass->setup)
913  pass->setup(graph->exec.output, graph->exec.input, pass);
914 
915  if (graph->num_threads == 1) {
916  pass->run(graph->exec.output, graph->exec.input, 0, pass->height, pass);
917  } else {
919  }
920  }
921 }
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:850
ff_sws_op_list_free
void ff_sws_op_list_free(SwsOpList **p_ops)
Definition: ops.c:501
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:477
SwsGraph::slicethread
AVSliceThread * slicethread
Definition: graph.h:105
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:104
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:63
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:489
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:133
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:113
adapt_colors
static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:653
out
static FILE * out
Definition: movenc.c:55
setup_legacy_swscale
static void setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: graph.c:247
color
Definition: vf_paletteuse.c:513
init_passes
static int init_passes(SwsGraph *graph)
Definition: graph.c:724
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:237
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
ff_sws_graph_reinit
int ff_sws_graph_reinit(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, int field, SwsGraph **out_graph)
Wrapper around ff_sws_graph_create() that reuses the existing graph if the format is compatible.
Definition: graph.c:847
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:72
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:196
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:125
avpriv_slicethread_execute
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
Definition: slicethread.c:271
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:160
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:800
SwsGraph::output
const SwsFrame * output
Definition: graph.h:135
run_copy
static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:170
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:158
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:204
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
ff_sws_lut3d_pick_pixfmt
enum AVPixelFormat ff_sws_lut3d_pick_pixfmt(SwsFormat fmt, int output)
Pick the best compatible pixfmt for a given SwsFormat.
Definition: lut3d.c:52
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:96
c1
static const uint64_t c1
Definition: murmur3.c:52
format.h
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:1122
SwsColorMap
Definition: cms.h:60
SwsPixelType
SwsPixelType
Copyright (C) 2025 Niklas Haas.
Definition: ops.h:30
SwsPass::width
int width
Definition: graph.h:73
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:728
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:363
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:35
ff_sws_graph_run
void 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:898
SwsFrame::data
uint8_t * data[4]
Definition: format.h:190
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
fail
#define fail()
Definition: checkasm.h:219
SwsContext::src_v_chr_pos
int src_v_chr_pos
Source vertical chroma position in luma grid / 256.
Definition: swscale.h:243
slice_ctx
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition: graph.c:261
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:1880
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:120
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:52
ff_sws_compile_pass
int ff_sws_compile_pass(SwsGraph *graph, SwsOpList *ops, int flags, const SwsFormat *dst, SwsPass *input, SwsPass **output)
Resolves an operation list to a graph pass.
Definition: ops_dispatch.c:366
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:768
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:347
SwsFrame::format
enum AVPixelFormat format
Definition: format.h:197
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:219
SwsPass::priv
void * priv
Definition: graph.h:97
run_xyz2rgb
static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:217
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
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1415
ff_sws_lut3d_alloc
SwsLut3D * ff_sws_lut3d_alloc(void)
Definition: lut3d.c:32
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:42
SwsContext::intent
int intent
Desired ICC intent for color space conversions.
Definition: swscale.h:251
av_refstruct_alloc_ext
static void * av_refstruct_alloc_ext(size_t size, unsigned flags, void *opaque, void(*free_cb)(AVRefStructOpaque opaque, void *obj))
A wrapper around av_refstruct_alloc_ext_c() for the common case of a non-const qualified opaque.
Definition: refstruct.h:94
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
SwsGraph::num_passes
int num_passes
Definition: graph.h:114
AV_PIX_FMT_FLAG_ALPHA
#define AV_PIX_FMT_FLAG_ALPHA
The pixel format has an alpha channel.
Definition: pixdesc.h:147
ctx
static AVFormatContext * ctx
Definition: movenc.c:49
ff_sws_lut3d_update
void ff_sws_lut3d_update(SwsLut3D *lut3d, const SwsColor *new_src)
Update the tone mapping state.
Definition: lut3d.c:239
field
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this field
Definition: writing_filters.txt:78
AVPixFmtDescriptor::log2_chroma_w
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:80
free_buffer
static void free_buffer(AVRefStructOpaque opaque, void *obj)
Definition: graph.c: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:126
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:292
SwsContext::gamma_flag
int gamma_flag
Use gamma correct scaling.
Definition: swscale.h:229
av_image_fill_plane_sizes
int av_image_fill_plane_sizes(size_t sizes[4], enum AVPixelFormat pix_fmt, int height, const ptrdiff_t linesizes[4])
Fill plane sizes for an image with pixel format pix_fmt and height height.
Definition: imgutils.c:111
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:241
av_cpu_max_align
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
Definition: cpu.c:286
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:64
FIELD_TOP
@ FIELD_TOP
Definition: format.h:56
AVCOL_RANGE_UNSPECIFIED
@ AVCOL_RANGE_UNSPECIFIED
Definition: pixfmt.h:743
SwsContext::dst_h_chr_pos
int dst_h_chr_pos
Destination horizontal chroma position.
Definition: swscale.h:246
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
SwsPassBuffer::avframe
AVFrame * avframe
Definition: graph.h:55
error.h
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:2155
ff_sws_graph_free
void ff_sws_graph_free(SwsGraph **pgraph)
Uninitialize any state associate with this filter graph and free it.
Definition: graph.c:809
SwsPass::height
int height
Definition: graph.h:73
f
f
Definition: af_crystalizer.c:122
lut3d.h
free_lut3d
static void free_lut3d(void *priv)
Definition: graph.c:627
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:1033
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:931
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:280
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:224
SwsPassBuffer::height
int height
Definition: graph.h:54
SwsOpList::src
SwsFormat src
Definition: ops.h:227
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:237
ff_sws_graph_add_pass
int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int align, void *priv, sws_filter_run_t run, SwsPass **out_pass)
Allocate and add a new pass to the filter graph.
Definition: graph.c:107
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:1008
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:86
av_buffer_alloc
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition: buffer.c:77
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:240
run_lut3d
static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:641
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:134
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
setup_lut3d
static void setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: graph.c:633
sws_filter_run_t
void(* sws_filter_run_t)(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Output h lines of filtered data.
Definition: graph.h:45
ff_sws_op_list_optimize
int ff_sws_op_list_optimize(SwsOpList *ops)
Fuse compatible and eliminate redundant operations, as well as replacing some operations with more ef...
Definition: ops_optimizer.c:283
sws
static SwsContext * sws[3]
Definition: swscale.c:73
free_legacy_swscale
static void free_legacy_swscale(void *priv)
Definition: graph.c:241
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:125
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:74
SwsGraph::num_threads
int num_threads
Definition: graph.h:106
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:831
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
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::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:238
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:304
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
SwsInternal
Definition: swscale_internal.h:334
ret
ret
Definition: filter_design.txt:187
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
SwsPass::setup
void(* setup)(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Called once from the main thread before running the filter.
Definition: graph.h:91
SwsOpList::dst
SwsFormat dst
Definition: ops.h:227
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:108
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:54
SwsContext::scaler_params
double scaler_params[2]
Extra parameters for fine-tuning certain scalers.
Definition: swscale.h:209
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
AVCHROMA_LOC_CENTER
@ AVCHROMA_LOC_CENTER
MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0.
Definition: pixfmt.h:799
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:81
SwsFormat::color
SwsColor color
Definition: format.h:86
get_field
static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
Definition: graph.c:871
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
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:619
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:107
mem.h
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
sws_getCoefficients
const int * sws_getCoefficients(int colorspace)
Return a pointer to yuv<->rgb coefficients for the given colorspace suitable for sws_setColorspaceDet...
Definition: yuv2rgb.c:61
SwsContext::dst_w
int dst_w
Definition: swscale.h:238
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:103
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:239
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: format.h:57
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:226
SwsContext::dst_range
int dst_range
Destination is full range.
Definition: swscale.h:242
pass_alloc_output
static int pass_alloc_output(SwsPass *pass)
Definition: graph.c:77
SwsPass::run
sws_filter_run_t run
Filter main execution function.
Definition: graph.h:71
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:2328
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:244
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:78
SwsPass::input
const SwsPass * input
Filter input.
Definition: graph.h:81
SwsPassBuffer
Represents an allocated output buffer for a filter pass.
Definition: graph.h:51
h
h
Definition: vp9dsp_template.c:2070
SwsPass::num_slices
int num_slices
Definition: graph.h:75
width
#define width
Definition: dsp.h:89
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:222
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:245
SwsContext
Main external API structure.
Definition: swscale.h:191
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:757
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:863
SWS_UNSTABLE
@ SWS_UNSTABLE
Allow using experimental new code paths.
Definition: swscale.h:165
AVPixFmtDescriptor::log2_chroma_h
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:89
src
#define src
Definition: vp8dsp.c:248
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:891
SwsGraph::exec
struct SwsGraph::@541 exec
Temporary execution state inside ff_sws_graph_run(); used to pass data to worker threads.
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