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