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 
42 {
43  if (!pass)
44  return width;
45 
46  size_t aligned_w = width;
47  aligned_w = FFALIGN(aligned_w, pass->output->width_align);
48  aligned_w += pass->output->width_pad;
49  return aligned_w <= INT_MAX ? aligned_w : width;
50 }
51 
52 /* Allocates one buffer per plane */
54 {
55  int ret = av_image_check_size2(dst->width, dst->height, INT64_MAX,
56  dst->format, 0, NULL);
57  if (ret < 0)
58  return ret;
59 
60  const int align = av_cpu_max_align();
61  const int aligned_w = FFALIGN(dst->width, align);
62  ret = av_image_fill_linesizes(dst->linesize, dst->format, aligned_w);
63  if (ret < 0)
64  return ret;
65 
66  ptrdiff_t linesize1[4];
67  for (int i = 0; i < 4; i++)
68  linesize1[i] = dst->linesize[i] = FFALIGN(dst->linesize[i], align);
69 
70  size_t sizes[4];
71  ret = av_image_fill_plane_sizes(sizes, dst->format, dst->height, linesize1);
72  if (ret < 0)
73  return ret;
74 
75  for (int i = 0; i < 4; i++) {
76  if (!sizes[i])
77  break;
79  if (!buf)
80  return AVERROR(ENOMEM);
81  dst->data[i] = buf->data;
82  dst->buf[i] = buf;
83  }
84 
85  return 0;
86 }
87 
88 static int pass_alloc_output(SwsPass *pass)
89 {
90  if (!pass || pass->output->avframe)
91  return 0;
92 
93  SwsPassBuffer *buffer = pass->output;
94  AVFrame *avframe = av_frame_alloc();
95  if (!avframe)
96  return AVERROR(ENOMEM);
97  avframe->format = pass->format;
98  avframe->width = buffer->width;
99  avframe->height = buffer->height;
100 
101  int ret = frame_alloc_planes(avframe);
102  if (ret < 0) {
103  av_frame_free(&avframe);
104  return ret;
105  }
106 
107  buffer->avframe = avframe;
108  ff_sws_frame_from_avframe(&buffer->frame, avframe);
109  return 0;
110 }
111 
112 static void free_buffer(AVRefStructOpaque opaque, void *obj)
113 {
114  SwsPassBuffer *buffer = obj;
115  av_frame_free(&buffer->avframe);
116 }
117 
118 static void pass_free(SwsPass *pass)
119 {
120  if (pass->free)
121  pass->free(pass->priv);
122  av_refstruct_unref(&pass->output);
123  av_free(pass);
124 }
125 
127  int width, int height, SwsPass *input,
128  int align, SwsPassFunc run, SwsPassSetup setup,
129  void *priv, void (*free_cb)(void *priv),
130  SwsPass **out_pass)
131 {
132  int ret;
133  SwsPass *pass = av_mallocz(sizeof(*pass));
134  if (!pass) {
135  if (free_cb)
136  free_cb(priv);
137  return AVERROR(ENOMEM);
138  }
139 
140  pass->graph = graph;
141  pass->run = run;
142  pass->setup = setup;
143  pass->priv = priv;
144  pass->free = free_cb;
145  pass->format = fmt;
146  pass->width = width;
147  pass->height = height;
148  pass->input = input;
149  pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, free_buffer);
150  if (!pass->output) {
151  ret = AVERROR(ENOMEM);
152  goto fail;
153  }
154 
155  if (!align) {
156  pass->slice_h = pass->height;
157  pass->num_slices = 1;
158  } else {
159  pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads;
160  pass->slice_h = FFALIGN(pass->slice_h, align);
161  pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
162  }
163 
164  /* Align output buffer to include extra slice padding */
165  pass->output->height = pass->slice_h * pass->num_slices;
166  pass->output->width = pass->width;
167  pass->output->width_align = 1;
168 
169  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
170  if (ret < 0)
171  goto fail;
172 
173  *out_pass = pass;
174  return 0;
175 
176 fail:
177  pass_free(pass);
178  return ret;
179 }
180 
181 static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
182 {
183  for (int i = 0; i < 4; i++) {
184  if (f->data[i])
185  data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * f->linesize[i];
186  else
187  data[i] = NULL;
188  }
189 }
190 
191 static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h,
192  const SwsPass *pass)
193 {
194  uint8_t *in_data[4], *out_data[4];
195  frame_shift(in, y, in_data);
196  frame_shift(out, y, out_data);
197 
198  for (int i = 0; i < 4 && out_data[i]; i++) {
199  const int lines = h >> ff_fmt_vshift(in->format, i);
200  av_assert1(in_data[i]);
201 
202  if (in_data[i] == out_data[i]) {
203  av_assert0(in->linesize[i] == out->linesize[i]);
204  } else if (in->linesize[i] == out->linesize[i]) {
205  memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
206  } else {
207  const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
208  for (int j = 0; j < lines; j++) {
209  memcpy(out_data[i], in_data[i], linesize);
210  in_data[i] += in->linesize[i];
211  out_data[i] += out->linesize[i];
212  }
213  }
214  }
215 }
216 
217 static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h,
218  const SwsPass *pass)
219 {
220  SwsInternal *c = pass->priv;
221  const int x0 = c->src0Alpha - 1;
222  const int w4 = 4 * pass->width;
223  const int src_stride = in->linesize[0];
224  const int dst_stride = out->linesize[0];
225  const uint8_t *src = in->data[0] + y * src_stride;
226  uint8_t *dst = out->data[0] + y * dst_stride;
227 
228  for (int y = 0; y < h; y++) {
229  memcpy(dst, src, w4 * sizeof(*dst));
230  for (int x = x0; x < w4; x += 4)
231  dst[x] = 0xFF;
232 
233  src += src_stride;
234  dst += dst_stride;
235  }
236 }
237 
238 static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h,
239  const SwsPass *pass)
240 {
241  const SwsInternal *c = pass->priv;
242  c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
243  in->data[0] + y * in->linesize[0], in->linesize[0],
244  pass->width, h);
245 }
246 
247 static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h,
248  const SwsPass *pass)
249 {
250  const SwsInternal *c = pass->priv;
251  c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0],
252  in->data[0] + y * in->linesize[0], in->linesize[0],
253  pass->width, h);
254 }
255 
256 /***********************************************************************
257  * Internal ff_swscale() wrapper. This reuses the legacy scaling API. *
258  * This is considered fully deprecated, and will be replaced by a full *
259  * reimplementation ASAP. *
260  ***********************************************************************/
261 
262 static void free_legacy_swscale(void *priv)
263 {
264  SwsContext *sws = priv;
265  sws_free_context(&sws);
266 }
267 
268 static int setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
269  const SwsPass *pass)
270 {
271  SwsContext *sws = pass->priv;
272  SwsInternal *c = sws_internal(sws);
273  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
274  for (int i = 0; i < 4; i++)
275  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
276  }
277 
278  if (usePal(sws->src_format))
279  ff_update_palette(c, (const uint32_t *) in->data[1]);
280 
281  return 0;
282 }
283 
284 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
285 {
286  SwsContext *sws = pass->priv;
287  SwsInternal *parent = sws_internal(sws);
288  if (pass->num_slices == 1)
289  return sws;
290 
291  av_assert1(parent->nb_slice_ctx == pass->num_slices);
292  sws = parent->slice_ctx[y / pass->slice_h];
293 
294  if (usePal(sws->src_format)) {
295  SwsInternal *sub = sws_internal(sws);
296  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
297  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
298  }
299 
300  return sws;
301 }
302 
303 static void run_legacy_unscaled(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 *in_data[4];
309  frame_shift(in, y, in_data);
310 
311  c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h,
312  out->data, out->linesize);
313 }
314 
315 static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
316  int y, int h, const SwsPass *pass)
317 {
318  SwsContext *sws = slice_ctx(pass, y);
319  SwsInternal *c = sws_internal(sws);
320  uint8_t *out_data[4];
321  frame_shift(out, y, out_data);
322 
323  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
324  sws->src_h, out_data, out->linesize, y, h);
325 }
326 
327 static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
328  const SwsFormat *fmt)
329 {
330  enum AVChromaLocation chroma_loc = fmt->loc;
331  const int sub_x = fmt->desc->log2_chroma_w;
332  const int sub_y = fmt->desc->log2_chroma_h;
333  int x_pos, y_pos;
334 
335  /* Explicitly default to center siting for compatibility with swscale */
336  if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
337  chroma_loc = AVCHROMA_LOC_CENTER;
338  graph->incomplete |= sub_x || sub_y;
339  }
340 
341  /* av_chroma_location_enum_to_pos() always gives us values in the range from
342  * 0 to 256, but we need to adjust this to the true value range of the
343  * subsampling grid, which may be larger for h/v_sub > 1 */
344  av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
345  x_pos *= (1 << sub_x) - 1;
346  y_pos *= (1 << sub_y) - 1;
347 
348  /* Fix vertical chroma position for interlaced frames */
349  if (sub_y && fmt->interlaced) {
350  /* When vertically subsampling, chroma samples are effectively only
351  * placed next to even rows. To access them from the odd field, we need
352  * to account for this shift by offsetting the distance of one luma row.
353  *
354  * For 4x vertical subsampling (v_sub == 2), they are only placed
355  * next to every *other* even row, so we need to shift by three luma
356  * rows to get to the chroma sample. */
357  if (graph->field == FIELD_BOTTOM)
358  y_pos += (256 << sub_y) - 256;
359 
360  /* Luma row distance is doubled for fields, so halve offsets */
361  y_pos >>= 1;
362  }
363 
364  /* Explicitly strip chroma offsets when not subsampling, because it
365  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
366  *h_chr_pos = sub_x ? x_pos : -513;
367  *v_chr_pos = sub_y ? y_pos : -513;
368 }
369 
370 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
371 {
372  if (override == -513 || override == *chr_pos)
373  return;
374 
375  if (!*warned) {
377  "Setting chroma position directly is deprecated, make sure "
378  "the frame is tagged with the correct chroma location.\n");
379  *warned = 1;
380  }
381 
382  *chr_pos = override;
383 }
384 
385 /* Takes over ownership of `sws` */
386 static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws,
388 {
389  SwsInternal *c = sws_internal(sws);
390  const int src_w = sws->src_w, src_h = sws->src_h;
391  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
392  const int unscaled = src_w == dst_w && src_h == dst_h;
393  int align = c->dst_slice_align;
394  SwsPass *pass = NULL;
395  int ret;
396 
397  if (c->cascaded_context[0]) {
398  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
399  for (int i = 0; i < num_cascaded; i++) {
400  const int is_last = i + 1 == num_cascaded;
401 
402  /* Steal cascaded context, so we can manage its lifetime independently */
403  SwsContext *sub = c->cascaded_context[i];
404  c->cascaded_context[i] = NULL;
405 
406  ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input);
407  if (ret < 0)
408  break;
409  }
410 
411  sws_free_context(&sws);
412  return ret;
413  }
414 
415  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
416  align = 0; /* disable slice threading */
417 
418  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
419  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGBA, src_w, src_h, input,
420  1, run_rgb0, NULL, c, NULL, &input);
421  if (ret < 0) {
422  sws_free_context(&sws);
423  return ret;
424  }
425  }
426 
427  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
428  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, src_w, src_h, input,
429  1, run_xyz2rgb, NULL, c, NULL, &input);
430  if (ret < 0) {
431  sws_free_context(&sws);
432  return ret;
433  }
434  }
435 
436  ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, align,
437  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale,
439  if (ret < 0)
440  return ret;
441 
442  /**
443  * For slice threading, we need to create sub contexts, similar to how
444  * swscale normally handles it internally. The most important difference
445  * is that we handle cascaded contexts before threaded contexts; whereas
446  * context_init_threaded() does it the other way around.
447  */
448 
449  if (pass->num_slices > 1) {
450  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
451  if (!c->slice_ctx)
452  return AVERROR(ENOMEM);
453 
454  for (int i = 0; i < pass->num_slices; i++) {
455  SwsContext *slice;
456  SwsInternal *c2;
457  slice = c->slice_ctx[i] = sws_alloc_context();
458  if (!slice)
459  return AVERROR(ENOMEM);
460  c->nb_slice_ctx++;
461 
462  c2 = sws_internal(slice);
463  c2->parent = sws;
464 
465  ret = av_opt_copy(slice, sws);
466  if (ret < 0)
467  return ret;
468 
470  if (ret < 0)
471  return ret;
472 
473  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
474  slice->src_range, c->dstColorspaceTable,
475  slice->dst_range, c->brightness, c->contrast,
476  c->saturation);
477 
478  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
479  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
480  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
481  }
482  }
483  }
484 
485  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
486  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, pass,
487  1, run_rgb2xyz, NULL, c, NULL, &pass);
488  if (ret < 0)
489  return ret;
490  }
491 
492  *output = pass;
493  return 0;
494 }
495 
496 static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src,
497  const SwsFormat *dst, SwsPass *input,
498  SwsPass **output)
499 {
500  int ret, warned = 0;
501  SwsContext *const ctx = graph->ctx;
502  if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE)
503  return AVERROR(ENOTSUP);
504 
505  SwsContext *sws = sws_alloc_context();
506  if (!sws)
507  return AVERROR(ENOMEM);
508 
509  sws->flags = ctx->flags;
510  sws->dither = ctx->dither;
511  sws->alpha_blend = ctx->alpha_blend;
512  sws->gamma_flag = ctx->gamma_flag;
513  sws->scaler = ctx->scaler;
514  sws->scaler_sub = ctx->scaler_sub;
515 
516  sws->src_w = src->width;
517  sws->src_h = src->height;
518  sws->src_format = src->format;
519  sws->src_range = src->range == AVCOL_RANGE_JPEG;
520 
521  sws->dst_w = dst->width;
522  sws->dst_h = dst->height;
523  sws->dst_format = dst->format;
524  sws->dst_range = dst->range == AVCOL_RANGE_JPEG;
525  get_chroma_pos(graph, &sws->src_h_chr_pos, &sws->src_v_chr_pos, src);
526  get_chroma_pos(graph, &sws->dst_h_chr_pos, &sws->dst_v_chr_pos, dst);
527 
528  graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED;
529  graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED;
530 
531  /* Allow overriding chroma position with the legacy API */
532  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
533  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
534  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
535  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
536 
537  for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
538  sws->scaler_params[i] = ctx->scaler_params[i];
539 
540  ret = sws_init_context(sws, NULL, NULL);
541  if (ret < 0) {
542  sws_free_context(&sws);
543  return ret;
544  }
545 
546  /* Set correct color matrices */
547  {
548  int in_full, out_full, brightness, contrast, saturation;
549  const int *inv_table, *table;
550  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
551  (int **)&table, &out_full,
552  &brightness, &contrast, &saturation);
553 
554  inv_table = sws_getCoefficients(src->csp);
555  table = sws_getCoefficients(dst->csp);
556 
557  graph->incomplete |= src->csp != dst->csp &&
558  (src->csp == AVCOL_SPC_UNSPECIFIED ||
559  dst->csp == AVCOL_SPC_UNSPECIFIED);
560 
561  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
562  brightness, contrast, saturation);
563  }
564 
565  return init_legacy_subpass(graph, sws, input, output);
566 }
567 
568 /*********************************
569  * Format conversion and scaling *
570  *********************************/
571 
572 #if CONFIG_UNSTABLE
573 static SwsScaler get_scaler_fallback(SwsContext *ctx)
574 {
575  if (ctx->scaler != SWS_SCALE_AUTO)
576  return ctx->scaler;
577 
578  /* Backwards compatibility with legacy flags API */
579  if (ctx->flags & SWS_BILINEAR) {
580  return SWS_SCALE_BILINEAR;
581  } else if (ctx->flags & (SWS_BICUBIC | SWS_BICUBLIN)) {
582  return SWS_SCALE_BICUBIC;
583  } else if (ctx->flags & SWS_POINT) {
584  return SWS_SCALE_POINT;
585  } else if (ctx->flags & SWS_AREA) {
586  return SWS_SCALE_AREA;
587  } else if (ctx->flags & SWS_GAUSS) {
588  return SWS_SCALE_GAUSSIAN;
589  } else if (ctx->flags & SWS_SINC) {
590  return SWS_SCALE_SINC;
591  } else if (ctx->flags & SWS_LANCZOS) {
592  return SWS_SCALE_LANCZOS;
593  } else if (ctx->flags & SWS_SPLINE) {
594  return SWS_SCALE_SPLINE;
595  } else {
596  return SWS_SCALE_AUTO;
597  }
598 }
599 
601  SwsOpType filter, int src_size, int dst_size)
602 {
603  if (src_size == dst_size)
604  return 0; /* no-op */
605 
606  SwsFilterParams params = {
607  .scaler = get_scaler_fallback(ctx),
608  .src_size = src_size,
609  .dst_size = dst_size,
610  };
611 
612  for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
613  params.scaler_params[i] = ctx->scaler_params[i];
614 
615  SwsFilterWeights *kernel;
616  int ret = ff_sws_filter_generate(ctx, &params, &kernel);
617  if (ret == AVERROR(ENOTSUP)) {
618  /* Filter size exceeds limit; cascade with geometric mean size */
619  int mean = sqrt((int64_t) src_size * dst_size);
620  if (mean == src_size || mean == dst_size)
621  return AVERROR_BUG; /* sanity, prevent infinite loop */
622  ret = add_filter(ctx, type, ops, filter, src_size, mean);
623  if (ret < 0)
624  return ret;
625  return add_filter(ctx, type, ops, filter, mean, dst_size);
626  } else if (ret < 0) {
627  return ret;
628  }
629 
630  return ff_sws_op_list_append(ops, &(SwsOp) {
631  .type = type,
632  .op = filter,
633  .filter.kernel = kernel,
634  });
635 }
636 
637 static int add_convert_pass(SwsGraph *graph, const SwsFormat *src,
638  const SwsFormat *dst, SwsPass *input,
639  SwsPass **output)
640 {
642 
643  SwsContext *ctx = graph->ctx;
644  SwsOpList *ops = NULL;
645  int ret = AVERROR(ENOTSUP);
646 
647  /* Mark the entire new ops infrastructure as experimental for now */
648  if (!(ctx->flags & SWS_UNSTABLE))
649  goto fail;
650 
651  /* The new code does not yet support alpha blending */
652  if (src->desc->flags & AV_PIX_FMT_FLAG_ALPHA &&
653  ctx->alpha_blend != SWS_ALPHA_BLEND_NONE)
654  goto fail;
655 
656  ops = ff_sws_op_list_alloc();
657  if (!ops)
658  return AVERROR(ENOMEM);
659  ops->src = *src;
660  ops->dst = *dst;
661 
662  ret = ff_sws_decode_pixfmt(ops, src->format);
663  if (ret < 0)
664  goto fail;
665  ret = ff_sws_decode_colors(ctx, type, ops, src, &graph->incomplete);
666  if (ret < 0)
667  goto fail;
668 
669  /**
670  * Always perform horizontal scaling first, since it's much more likely to
671  * benefit from small integer optimizations; we should maybe flip the order
672  * here if we're downscaling the vertical resolution by a lot, though.
673  */
674  ret = add_filter(ctx, type, ops, SWS_OP_FILTER_H, src->width, dst->width);
675  if (ret < 0)
676  goto fail;
677  ret = add_filter(ctx, type, ops, SWS_OP_FILTER_V, src->height, dst->height);
678  if (ret < 0)
679  goto fail;
680 
681  ret = ff_sws_encode_colors(ctx, type, ops, src, dst, &graph->incomplete);
682  if (ret < 0)
683  goto fail;
684  ret = ff_sws_encode_pixfmt(ops, dst->format);
685  if (ret < 0)
686  goto fail;
687 
688  av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
689  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
690 
691  av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
693 
695  if (ret < 0)
696  goto fail;
697 
698  ret = 0;
699  /* fall through */
700 
701 fail:
702  ff_sws_op_list_free(&ops);
703  if (ret == AVERROR(ENOTSUP))
704  return add_legacy_sws_pass(graph, src, dst, input, output);
705  return ret;
706 }
707 #else
708 #define add_convert_pass add_legacy_sws_pass
709 #endif
710 
711 
712 /**************************
713  * Gamut and tone mapping *
714  **************************/
715 
716 static void free_lut3d(void *priv)
717 {
718  SwsLut3D *lut = priv;
719  ff_sws_lut3d_free(&lut);
720 }
721 
722 static int setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
723 {
724  SwsLut3D *lut = pass->priv;
725 
726  /* Update dynamic frame metadata from the original source frame */
727  ff_sws_lut3d_update(lut, &pass->graph->src.color);
728  return 0;
729 }
730 
731 static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h,
732  const SwsPass *pass)
733 {
734  SwsLut3D *lut = pass->priv;
735  uint8_t *in_data[4], *out_data[4];
736  frame_shift(in, y, in_data);
737  frame_shift(out, y, out_data);
738 
739  ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0],
740  out->linesize[0], pass->width, h);
741 }
742 
745 {
746  enum AVPixelFormat fmt_in, fmt_out;
747  SwsColorMap map = {0};
748  SwsLut3D *lut;
749  int ret;
750 
751  /**
752  * Grayspace does not really have primaries, so just force the use of
753  * the equivalent other primary set to avoid a conversion. Technically,
754  * this does affect the weights used for the Grayscale conversion, but
755  * in practise, that should give the expected results more often than not.
756  */
757  if (isGray(dst.format)) {
758  dst.color = src.color;
759  } else if (isGray(src.format)) {
760  src.color = dst.color;
761  }
762 
763  /* Fully infer color spaces before color mapping logic */
764  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
765 
766  map.intent = graph->ctx->intent;
767  map.src = src.color;
768  map.dst = dst.color;
769 
771  return 0;
772 
773  if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE)
774  return AVERROR(ENOTSUP);
775 
776  lut = ff_sws_lut3d_alloc();
777  if (!lut)
778  return AVERROR(ENOMEM);
779 
780  fmt_in = ff_sws_lut3d_pick_pixfmt(src, 0);
781  fmt_out = ff_sws_lut3d_pick_pixfmt(dst, 1);
782  if (fmt_in != src.format) {
783  SwsFormat tmp = src;
784  tmp.format = fmt_in;
785  ret = add_convert_pass(graph, &src, &tmp, input, &input);
786  if (ret < 0) {
787  ff_sws_lut3d_free(&lut);
788  return ret;
789  }
790  }
791 
792  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
793  if (ret < 0) {
794  ff_sws_lut3d_free(&lut);
795  return ret;
796  }
797 
798  return ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
799  input, 1, run_lut3d, setup_lut3d, lut,
800  free_lut3d, output);
801 }
802 
803 /***************************************
804  * Main filter graph construction code *
805  ***************************************/
806 
807 static int init_passes(SwsGraph *graph)
808 {
809  SwsFormat src = graph->src;
810  SwsFormat dst = graph->dst;
811  SwsPass *pass = NULL; /* read from main input image */
812  int ret;
813 
814  ret = adapt_colors(graph, src, dst, pass, &pass);
815  if (ret < 0)
816  return ret;
817  src.format = pass ? pass->format : src.format;
818  src.color = dst.color;
819 
820  if (!ff_fmt_equal(&src, &dst)) {
821  ret = add_convert_pass(graph, &src, &dst, pass, &pass);
822  if (ret < 0)
823  return ret;
824  }
825 
826  if (pass)
827  return 0;
828 
829  /* No passes were added, so no operations were necessary */
830  graph->noop = 1;
831 
832  /* Add threaded memcpy pass */
833  return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
834  pass, 1, run_copy, NULL, NULL, NULL, &pass);
835 }
836 
837 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
838  int nb_threads)
839 {
840  SwsGraph *graph = priv;
841  const SwsPass *pass = graph->exec.pass;
842  const int slice_y = jobnr * pass->slice_h;
843  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
844 
845  pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
846 }
847 
849  int field, SwsGraph **out_graph)
850 {
851  int ret;
852  SwsGraph *graph = av_mallocz(sizeof(*graph));
853  if (!graph)
854  return AVERROR(ENOMEM);
855 
856  graph->ctx = ctx;
857  graph->src = *src;
858  graph->dst = *dst;
859  graph->field = field;
860  graph->opts_copy = *ctx;
861 
862  if (ctx->threads == 1) {
863  graph->num_threads = 1;
864  } else {
865  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
866  sws_graph_worker, NULL, ctx->threads);
867  if (ret == AVERROR(ENOSYS)) {
868  /* Fall back to single threaded operation */
869  graph->num_threads = 1;
870  } else if (ret < 0) {
871  goto error;
872  } else {
873  graph->num_threads = ret;
874  }
875  }
876 
877  ret = init_passes(graph);
878  if (ret < 0)
879  goto error;
880 
881  /* Resolve output buffers for all intermediate passes */
882  for (int i = 0; i < graph->num_passes; i++) {
883  ret = pass_alloc_output(graph->passes[i]->input);
884  if (ret < 0)
885  goto error;
886  }
887 
888  *out_graph = graph;
889  return 0;
890 
891 error:
892  ff_sws_graph_free(&graph);
893  return ret;
894 }
895 
896 void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
897 {
898  for (int i = since_idx; i < graph->num_passes; i++)
899  pass_free(graph->passes[i]);
900  graph->num_passes = since_idx;
901 }
902 
904 {
905  SwsGraph *graph = *pgraph;
906  if (!graph)
907  return;
908 
910 
911  for (int i = 0; i < graph->num_passes; i++)
912  pass_free(graph->passes[i]);
913  av_free(graph->passes);
914 
915  av_free(graph);
916  *pgraph = NULL;
917 }
918 
919 /* Tests only options relevant to SwsGraph */
920 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
921 {
922  return c1->flags == c2->flags &&
923  c1->threads == c2->threads &&
924  c1->dither == c2->dither &&
925  c1->alpha_blend == c2->alpha_blend &&
926  c1->gamma_flag == c2->gamma_flag &&
927  c1->src_h_chr_pos == c2->src_h_chr_pos &&
928  c1->src_v_chr_pos == c2->src_v_chr_pos &&
929  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
930  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
931  c1->intent == c2->intent &&
932  c1->scaler == c2->scaler &&
933  c1->scaler_sub == c2->scaler_sub &&
934  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
935 
936 }
937 
939  int field, SwsGraph **out_graph)
940 {
941  SwsGraph *graph = *out_graph;
942  if (graph && ff_fmt_equal(&graph->src, src) &&
943  ff_fmt_equal(&graph->dst, dst) &&
944  opts_equal(ctx, &graph->opts_copy))
945  {
946  ff_sws_graph_update_metadata(graph, &src->color);
947  return 0;
948  }
949 
950  ff_sws_graph_free(out_graph);
951  return ff_sws_graph_create(ctx, dst, src, field, out_graph);
952 }
953 
955 {
956  if (!color)
957  return;
958 
960 }
961 
962 static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
963 {
965 
966  if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) {
967  av_assert1(!graph->field);
968  return;
969  }
970 
971  if (graph->field == FIELD_BOTTOM) {
972  /* Odd rows, offset by one line */
974  for (int i = 0; i < 4; i++) {
975  if (frame->data[i])
976  frame->data[i] += frame->linesize[i];
977  if (desc->flags & AV_PIX_FMT_FLAG_PAL)
978  break;
979  }
980  }
981 
982  /* Take only every second line */
983  for (int i = 0; i < 4; i++)
984  frame->linesize[i] <<= 1;
985 
986  frame->height = (frame->height + (graph->field == FIELD_TOP)) >> 1;
987 }
988 
989 int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
990 {
991  av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format);
992  av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format);
993 
994  SwsFrame src_field, dst_field;
995  get_field(graph, dst, &dst_field);
996  get_field(graph, src, &src_field);
997 
998  for (int i = 0; i < graph->num_passes; i++) {
999  const SwsPass *pass = graph->passes[i];
1000  graph->exec.pass = pass;
1001  graph->exec.input = pass->input ? &pass->input->output->frame : &src_field;
1002  graph->exec.output = pass->output->avframe ? &pass->output->frame : &dst_field;
1003  if (pass->setup) {
1004  int ret = pass->setup(graph->exec.output, graph->exec.input, pass);
1005  if (ret < 0)
1006  return ret;
1007  }
1008 
1009  if (pass->num_slices == 1) {
1010  pass->run(graph->exec.output, graph->exec.input, 0, pass->height, pass);
1011  } else {
1013  }
1014  }
1015 
1016  return 0;
1017 }
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:592
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:496
SwsGraph::slicethread
AVSliceThread * slicethread
Definition: graph.h:123
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:122
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:75
ff_sws_op_list_alloc
SwsOpList * ff_sws_op_list_alloc(void)
Definition: ops.c:579
SWS_SCALE_AUTO
@ SWS_SCALE_AUTO
Definition: swscale.h:97
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:151
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:131
adapt_colors
static int adapt_colors(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:743
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:807
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
SWS_SCALE_BILINEAR
@ SWS_SCALE_BILINEAR
bilinear filtering
Definition: swscale.h:98
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:938
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:84
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:217
int64_t
long long int64_t
Definition: coverity.c:34
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
ff_sws_op_list_append
int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op)
These will take over ownership of op and set it to {0}, even on failure.
Definition: ops.c:686
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:143
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:434
pixdesc.h
frame_shift
static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
Definition: graph.c:181
ops.h
AVFrame::width
int width
Definition: frame.h:506
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:805
SwsFilterWeights
Represents a computed filter kernel.
Definition: filters.h:64
SwsGraph::output
const SwsFrame * output
Definition: graph.h:153
SWS_BILINEAR
@ SWS_BILINEAR
bilinear filtering
Definition: swscale.h:177
run_copy
static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:191
pass_free
static void pass_free(SwsPass *pass)
Definition: graph.c:118
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:104
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
filter
void(* filter)(uint8_t *src, int stride, int qscale)
Definition: h263dsp.c:29
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
FIELD_TOP
@ FIELD_TOP
Definition: format.h:56
SwsFilterParams
Definition: filters.h:45
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:678
SwsPass::free
void(* free)(void *priv)
Optional private state and associated free() function.
Definition: graph.h:109
c1
static const uint64_t c1
Definition: murmur3.c:52
format.h
SWS_BICUBLIN
@ SWS_BICUBLIN
bicubic luma, bilinear chroma
Definition: swscale.h:182
SwsPass::input
SwsPass * input
Filter input.
Definition: graph.h:93
SWS_ALPHA_BLEND_NONE
@ SWS_ALPHA_BLEND_NONE
Definition: swscale.h:89
ff_sws_filter_generate
int ff_sws_filter_generate(void *log, const SwsFilterParams *params, SwsFilterWeights **out)
Generate a filter kernel for the given parameters.
Definition: filters.c:183
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:33
SwsPass::width
int width
Definition: graph.h:85
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:935
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:386
SWS_PIXEL_F32
@ SWS_PIXEL_F32
Definition: ops.h:38
SwsFrame::data
uint8_t * data[4]
Definition: format.h:195
setup_lut3d
static int setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: graph.c:722
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:224
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:284
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:138
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:848
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:193
SWS_SCALE_BICUBIC
@ SWS_SCALE_BICUBIC
2-tap cubic BC-spline
Definition: swscale.h:99
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
SWS_AREA
@ SWS_AREA
area averaging
Definition: swscale.h:181
SwsInternal::pal_rgb
uint32_t pal_rgb[256]
Definition: swscale_internal.h:401
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:370
SwsFrame::format
enum AVPixelFormat format
Definition: format.h:202
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:235
SwsPass::priv
void * priv
Definition: graph.h:110
run_xyz2rgb
static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:238
SwsInternal::nb_slice_ctx
int nb_slice_ctx
Definition: swscale_internal.h:345
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:343
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:873
SWS_SCALE_LANCZOS
@ SWS_SCALE_LANCZOS
3-tap sinc/sinc
Definition: swscale.h:104
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:132
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
SWS_OP_FILTER_H
@ SWS_OP_FILTER_H
Definition: ops.h:73
SwsPass::run
SwsPassFunc run
Filter main execution function.
Definition: graph.h:83
free_buffer
static void free_buffer(AVRefStructOpaque opaque, void *obj)
Definition: graph.c:112
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
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: format.h:57
SwsGraph::field
int field
Definition: graph.h:144
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:315
SWS_BICUBIC
@ SWS_BICUBIC
2-tap cubic B-spline
Definition: swscale.h:178
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:539
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
SWS_OP_FILTER_V
@ SWS_OP_FILTER_V
Definition: ops.h:74
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
SwsScaler
SwsScaler
Definition: swscale.h:96
SwsOpType
SwsOpType
Definition: ops.h:46
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:76
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
ff_sws_pass_aligned_width
int ff_sws_pass_aligned_width(const SwsPass *pass, int width)
Align width to the optimal size for pass.
Definition: graph.c:41
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:2145
SWS_SCALE_SINC
@ SWS_SCALE_SINC
unwindowed sinc
Definition: swscale.h:103
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:903
SwsPass::height
int height
Definition: graph.h:85
f
f
Definition: af_crystalizer.c:122
lut3d.h
free_lut3d
static void free_lut3d(void *priv)
Definition: graph.c:716
height
#define height
Definition: dsp.h:89
frame_alloc_planes
static int frame_alloc_planes(AVFrame *dst)
Definition: graph.c:53
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:936
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:303
SWS_POINT
@ SWS_POINT
nearest neighbor
Definition: swscale.h:180
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:240
SwsPassBuffer::height
int height
Definition: graph.h:62
SWS_SPLINE
@ SWS_SPLINE
unwindowed natural cubic spline
Definition: swscale.h:186
SwsOpList::src
SwsFormat src
Definition: ops.h:268
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:521
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:98
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:347
SwsGraph::exec
struct SwsGraph::@563 exec
Temporary execution state inside ff_sws_graph_run(); used to pass data to worker threads.
run_lut3d
static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:731
add_filter
static int add_filter(AudioNEqualizerContext *s, AVFilterLink *inlink)
Definition: af_anequalizer.c:539
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:152
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
SwsPassBuffer::width_align
int width_align
Definition: graph.h:66
SWS_SCALE_POINT
@ SWS_SCALE_POINT
nearest neighbor (point sampling)
Definition: swscale.h:100
free_legacy_swscale
static void free_legacy_swscale(void *priv)
Definition: graph.c:262
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:143
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:86
SwsGraph::num_threads
int num_threads
Definition: graph.h:124
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:920
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:268
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)
SwsFilterParams::scaler_params
double scaler_params[SWS_NUM_SCALER_PARAMS]
Definition: filters.h:50
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
SwsOp
Definition: ops.h:218
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:657
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:327
SWS_SCALE_GAUSSIAN
@ SWS_SCALE_GAUSSIAN
2-tap gaussian approximation
Definition: swscale.h:102
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:126
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
SwsInternal
Definition: swscale_internal.h:335
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:268
ff_fmt_equal
static int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
Definition: format.h:135
SwsPassBuffer::width_pad
int width_pad
Definition: graph.h:67
SwsGraph::noop
bool noop
Definition: graph.h:126
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:506
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
SWS_SCALE_SPLINE
@ SWS_SCALE_SPLINE
unwindowned natural cubic spline
Definition: swscale.h:105
get_field
static void get_field(SwsGraph *graph, const AVFrame *avframe, SwsFrame *frame)
Definition: graph.c:962
SWS_GAUSS
@ SWS_GAUSS
gaussian approximation
Definition: swscale.h:183
mean
static float mean(const float *input, int size)
Definition: vf_nnedi.c:861
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:708
desc
const char * desc
Definition: libsvtav1.c:82
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:400
SwsGraph::incomplete
bool incomplete
Definition: graph.h:125
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:121
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:247
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:88
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:989
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:2369
imgutils.h
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
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_SCALE_AREA
@ SWS_SCALE_AREA
area averaging
Definition: swscale.h:101
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:79
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:87
SWS_LANCZOS
@ SWS_LANCZOS
3-tap sinc/sinc
Definition: swscale.h:185
width
#define width
Definition: dsp.h:89
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:263
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:261
SWS_SINC
@ SWS_SINC
unwindowed sinc
Definition: swscale.h:184
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:196
SwsFilterParams::scaler
SwsScaler scaler
The filter kernel and parameters to use.
Definition: filters.h:49
sws_graph_worker
static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
Definition: graph.c:837
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:954
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:491
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:896
ff_sws_graph_rollback
void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
Remove all passes added since the given index.
Definition: graph.c:896
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:652