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/hwcontext.h"
25 #include "libavutil/imgutils.h"
26 #include "libavutil/macros.h"
27 #include "libavutil/mem.h"
28 #include "libavutil/opt.h"
29 #include "libavutil/pixdesc.h"
30 #include "libavutil/refstruct.h"
31 #include "libavutil/slicethread.h"
32 
33 #include "libswscale/swscale.h"
34 #include "libswscale/format.h"
35 
36 #include "cms.h"
37 #include "lut3d.h"
38 #include "swscale_internal.h"
39 #include "graph.h"
40 #include "ops.h"
41 #include "ops_dispatch.h"
42 #if CONFIG_VULKAN
43 #include "vulkan/ops.h"
44 #endif
45 
47 {
48  if (!pass)
49  return width;
50 
51  size_t aligned_w = width;
52  aligned_w = FFALIGN(aligned_w, pass->output->width_align);
53  aligned_w += pass->output->width_pad;
54  return aligned_w <= INT_MAX ? aligned_w : width;
55 }
56 
57 /* Allocates one buffer per plane */
59 {
60  int ret = av_image_check_size2(dst->width, dst->height, INT64_MAX,
61  dst->format, 0, NULL);
62  if (ret < 0)
63  return ret;
64 
65  const int align = av_cpu_max_align();
66  const int aligned_w = FFALIGN(dst->width, align);
67  ret = av_image_fill_linesizes(dst->linesize, dst->format, aligned_w);
68  if (ret < 0)
69  return ret;
70 
71  ptrdiff_t linesize1[4];
72  for (int i = 0; i < 4; i++)
73  linesize1[i] = dst->linesize[i] = FFALIGN(dst->linesize[i], align);
74 
75  size_t sizes[4];
76  ret = av_image_fill_plane_sizes(sizes, dst->format, dst->height, linesize1);
77  if (ret < 0)
78  return ret;
79 
80  for (int i = 0; i < 4; i++) {
81  if (!sizes[i])
82  break;
84  if (!buf)
85  return AVERROR(ENOMEM);
86  dst->data[i] = buf->data;
87  dst->buf[i] = buf;
88  }
89 
90  return 0;
91 }
92 
93 #if CONFIG_VULKAN
94 static int pass_alloc_output_hw(SwsPass *pass, AVFrame *avframe,
95  AVBufferRef *dev_ref)
96 {
97  SwsPassBuffer *buffer = pass->output;
98  AVBufferRef *frames_ref = av_hwframe_ctx_alloc(dev_ref);
99  if (!frames_ref)
100  return AVERROR(ENOMEM);
101 
102  AVHWFramesContext *hwfc = (AVHWFramesContext *)frames_ref->data;
103  hwfc->format = AV_PIX_FMT_VULKAN;
104  hwfc->sw_format = pass->format;
105  hwfc->width = buffer->width;
106  hwfc->height = buffer->height;
107 
108  int ret = av_hwframe_ctx_init(frames_ref);
109  if (ret >= 0) {
110  avframe->format = AV_PIX_FMT_VULKAN;
111  ret = av_hwframe_get_buffer(frames_ref, avframe, 0);
112  }
113  av_buffer_unref(&frames_ref);
114  return ret;
115 }
116 #endif
117 
118 static int pass_alloc_output(SwsPass *pass)
119 {
120  if (!pass || pass->output->avframe)
121  return 0;
122 
123  SwsPassBuffer *buffer = pass->output;
124  AVFrame *avframe = av_frame_alloc();
125  if (!avframe)
126  return AVERROR(ENOMEM);
127  avframe->width = buffer->width;
128  avframe->height = buffer->height;
129 
130  int ret;
131 
132 #if CONFIG_VULKAN
133  const SwsGraph *graph = pass->graph;
134  if (graph->src.hw_format == AV_PIX_FMT_VULKAN &&
135  graph->dst.hw_format == AV_PIX_FMT_VULKAN) {
136  AVBufferRef *dev_ref = ff_sws_vk_device_ref(graph->ctx);
137  if (dev_ref) {
138  ret = pass_alloc_output_hw(pass, avframe, dev_ref);
139  if (ret >= 0)
140  goto done;
141  av_frame_unref(avframe);
142  }
143  }
144 #endif
145 
146  avframe->format = pass->format;
147  ret = frame_alloc_planes(avframe);
148  if (ret < 0) {
149  av_frame_free(&avframe);
150  return ret;
151  }
152 
153 #if CONFIG_VULKAN
154 done:
155 #endif
156  buffer->avframe = avframe;
157  ff_sws_frame_from_avframe(&buffer->frame, avframe);
158  return 0;
159 }
160 
161 static void free_buffer(AVRefStructOpaque opaque, void *obj)
162 {
163  SwsPassBuffer *buffer = obj;
164  av_frame_free(&buffer->avframe);
165 }
166 
167 static void pass_free(SwsPass *pass)
168 {
169  if (pass->free)
170  pass->free(pass->priv);
171  av_refstruct_unref(&pass->output);
172  av_free(pass);
173 }
174 
176  int width, int height, SwsPass *input,
177  int lines, int align,
179  void *priv, void (*free_cb)(void *priv),
180  SwsPass **out_pass)
181 {
182  int ret;
183  SwsPass *pass = av_mallocz(sizeof(*pass));
184  if (!pass) {
185  if (free_cb)
186  free_cb(priv);
187  return AVERROR(ENOMEM);
188  }
189 
190  if (!lines)
191  lines = height;
192 
193  pass->graph = graph;
194  pass->run = run;
195  pass->setup = setup;
196  pass->priv = priv;
197  pass->free = free_cb;
198  pass->format = fmt;
199  pass->lines = lines;
200  pass->input = input;
201  pass->output = av_refstruct_alloc_ext(sizeof(*pass->output), 0, NULL, free_buffer);
202  if (!pass->output) {
203  ret = AVERROR(ENOMEM);
204  goto fail;
205  }
206 
207  pass->output->height = height;
208  pass->output->width = width;
209  pass->output->width_align = 1;
210 
211  if (!align) {
212  pass->slice_h = pass->lines;
213  pass->num_slices = 1;
214  } else {
215  pass->slice_h = (pass->lines + graph->num_threads - 1) / graph->num_threads;
216  pass->slice_h = FFALIGN(pass->slice_h, align);
217  pass->num_slices = (pass->lines + pass->slice_h - 1) / pass->slice_h;
218  }
219 
220  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
221  if (ret < 0)
222  goto fail;
223 
224  *out_pass = pass;
225  return 0;
226 
227 fail:
228  pass_free(pass);
229  return ret;
230 }
231 
233 {
234  if (!dst || !src || dst == src)
235  return;
236 
237  av_assert0(dst->format == src->format);
238  SwsPassBuffer *keep = src->output, *drop = dst->output;
239 
240  av_assert1(keep->width == drop->width);
241  av_assert1(keep->height == drop->height);
242  keep->width_align = FFMAX(keep->width_align, drop->width_align);
243  keep->width_pad = FFMAX(keep->width_pad, drop->width_pad);
244 
245  av_refstruct_replace(&dst->output, src->output);
246 }
247 
248 static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
249 {
250  for (int i = 0; i < 4; i++) {
251  if (f->data[i])
252  data[i] = f->data[i] + (y >> ff_fmt_vshift(f->format, i)) * f->linesize[i];
253  else
254  data[i] = NULL;
255  }
256 }
257 
258 static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h,
259  const SwsPass *pass)
260 {
261  uint8_t *in_data[4], *out_data[4];
262  frame_shift(in, y, in_data);
263  frame_shift(out, y, out_data);
264 
265  for (int i = 0; i < 4 && out_data[i]; i++) {
266  const int lines = h >> ff_fmt_vshift(in->format, i);
267  av_assert1(in_data[i]);
268 
269  if (in_data[i] == out_data[i]) {
270  av_assert0(in->linesize[i] == out->linesize[i]);
271  } else if (in->linesize[i] == out->linesize[i]) {
272  memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
273  } else {
274  const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
275  for (int j = 0; j < lines; j++) {
276  memcpy(out_data[i], in_data[i], linesize);
277  in_data[i] += in->linesize[i];
278  out_data[i] += out->linesize[i];
279  }
280  }
281  }
282 }
283 
284 static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h,
285  const SwsPass *pass)
286 {
287  SwsInternal *c = pass->priv;
288  const int x0 = c->src0Alpha - 1;
289  const int w4 = 4 * out->width;
290  const int src_stride = in->linesize[0];
291  const int dst_stride = out->linesize[0];
292  const uint8_t *src = in->data[0] + y * src_stride;
293  uint8_t *dst = out->data[0] + y * dst_stride;
294 
295  for (int y = 0; y < h; y++) {
296  memcpy(dst, src, w4 * sizeof(*dst));
297  for (int x = x0; x < w4; x += 4)
298  dst[x] = 0xFF;
299 
300  src += src_stride;
301  dst += dst_stride;
302  }
303 }
304 
305 static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h,
306  const SwsPass *pass)
307 {
308  const SwsInternal *c = pass->priv;
309  c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
310  in->data[0] + y * in->linesize[0], in->linesize[0],
311  out->width, h);
312 }
313 
314 static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h,
315  const SwsPass *pass)
316 {
317  const SwsInternal *c = pass->priv;
318  c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0],
319  in->data[0] + y * in->linesize[0], in->linesize[0],
320  out->width, h);
321 }
322 
323 /***********************************************************************
324  * Internal ff_swscale() wrapper. This reuses the legacy scaling API. *
325  * This is considered fully deprecated, and will be replaced by a full *
326  * reimplementation ASAP. *
327  ***********************************************************************/
328 
329 static void free_legacy_swscale(void *priv)
330 {
331  SwsContext *sws = priv;
332  sws_free_context(&sws);
333 }
334 
335 static int setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
336  const SwsPass *pass)
337 {
338  SwsContext *sws = pass->priv;
339  SwsInternal *c = sws_internal(sws);
340  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
341  for (int i = 0; i < 4; i++)
342  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
343  }
344 
345  if (usePal(sws->src_format))
346  ff_update_palette(c, (const uint32_t *) in->data[1]);
347 
348  return 0;
349 }
350 
351 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
352 {
353  SwsContext *sws = pass->priv;
354  SwsInternal *parent = sws_internal(sws);
355  if (pass->num_slices == 1)
356  return sws;
357 
358  av_assert1(parent->nb_slice_ctx == pass->num_slices);
359  sws = parent->slice_ctx[y / pass->slice_h];
360 
361  if (usePal(sws->src_format)) {
362  SwsInternal *sub = sws_internal(sws);
363  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
364  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
365  }
366 
367  return sws;
368 }
369 
370 static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in,
371  int y, int h, const SwsPass *pass)
372 {
373  SwsContext *sws = slice_ctx(pass, y);
374  SwsInternal *c = sws_internal(sws);
375  uint8_t *in_data[4];
376  frame_shift(in, y, in_data);
377 
378  c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h,
379  out->data, out->linesize);
380 }
381 
382 static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
383  int y, int h, const SwsPass *pass)
384 {
385  SwsContext *sws = slice_ctx(pass, y);
386  SwsInternal *c = sws_internal(sws);
387  uint8_t *out_data[4];
388  frame_shift(out, y, out_data);
389 
390  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
391  sws->src_h, out_data, out->linesize, y, h);
392 }
393 
394 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
395 {
396  if (override == -513 || override == *chr_pos)
397  return;
398 
399  if (!*warned) {
401  "Setting chroma position directly is deprecated, make sure "
402  "the frame is tagged with the correct chroma location.\n");
403  *warned = 1;
404  }
405 
406  *chr_pos = override;
407 }
408 
409 /* Takes over ownership of `sws` */
410 static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws,
412 {
413  SwsInternal *c = sws_internal(sws);
414  const int src_w = sws->src_w, src_h = sws->src_h;
415  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
416  const int unscaled = src_w == dst_w && src_h == dst_h;
417  int align = c->dst_slice_align;
418  SwsPass *pass = NULL;
419  int ret;
420 
421  if (c->cascaded_context[0]) {
422  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
423  for (int i = 0; i < num_cascaded; i++) {
424  const int is_last = i + 1 == num_cascaded;
425 
426  /* Steal cascaded context, so we can manage its lifetime independently */
427  SwsContext *sub = c->cascaded_context[i];
428  c->cascaded_context[i] = NULL;
429 
430  ret = init_legacy_subpass(graph, sub, input, is_last ? output : &input);
431  if (ret < 0)
432  break;
433  }
434 
435  sws_free_context(&sws);
436  return ret;
437  }
438 
439  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
440  align = 0; /* disable slice threading */
441 
442  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
443  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGBA, src_w, src_h, input,
444  0, 1, run_rgb0, NULL, c, NULL, &input);
445  if (ret < 0) {
446  sws_free_context(&sws);
447  return ret;
448  }
449  }
450 
451  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
452  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, src_w, src_h, input,
453  0, 1, run_xyz2rgb, NULL, c, NULL, &input);
454  if (ret < 0) {
455  sws_free_context(&sws);
456  return ret;
457  }
458  }
459 
460  ret = ff_sws_graph_add_pass(graph, sws->dst_format, dst_w, dst_h, input, 0, align,
461  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale,
463  if (ret < 0)
464  return ret;
465  pass->backend = SWS_BACKEND_LEGACY;
466 
467  /**
468  * For slice threading, we need to create sub contexts, similar to how
469  * swscale normally handles it internally. The most important difference
470  * is that we handle cascaded contexts before threaded contexts; whereas
471  * context_init_threaded() does it the other way around.
472  */
473 
474  if (pass->num_slices > 1) {
475  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
476  if (!c->slice_ctx)
477  return AVERROR(ENOMEM);
478 
479  for (int i = 0; i < pass->num_slices; i++) {
480  SwsContext *slice;
481  SwsInternal *c2;
482  slice = c->slice_ctx[i] = sws_alloc_context();
483  if (!slice)
484  return AVERROR(ENOMEM);
485  c->nb_slice_ctx++;
486 
487  c2 = sws_internal(slice);
488  c2->parent = sws;
489 
490  ret = av_opt_copy(slice, sws);
491  if (ret < 0)
492  return ret;
493 
495  if (ret < 0)
496  return ret;
497 
498  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
499  slice->src_range, c->dstColorspaceTable,
500  slice->dst_range, c->brightness, c->contrast,
501  c->saturation);
502 
503  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
504  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
505  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
506  }
507  }
508  }
509 
510  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
511  ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, pass,
512  0, 1, run_rgb2xyz, NULL, c, NULL, &pass);
513  if (ret < 0)
514  return ret;
515  }
516 
517  *output = pass;
518  return 0;
519 }
520 
521 static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src,
522  const SwsFormat *dst, SwsPass *input,
523  SwsPass **output)
524 {
525  int ret, warned = 0;
526  SwsContext *const ctx = graph->ctx;
527  const SwsBackend backend = ff_sws_enabled_backends(ctx);
528  if (!(backend & SWS_BACKEND_LEGACY))
529  return AVERROR(ENOTSUP);
530  if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE)
531  return AVERROR(ENOTSUP);
532 
533  /* Re-check this here because this might not be excluded if the caller was
534  * testing against multiple backends */
535  if (!sws_isSupportedInput(src->format) || !sws_isSupportedOutput(dst->format))
536  return AVERROR(ENOTSUP);
537 
538  SwsContext *sws = sws_alloc_context();
539  if (!sws)
540  return AVERROR(ENOMEM);
541 
542  sws->flags = ctx->flags;
543  sws->dither = ctx->dither;
544  sws->alpha_blend = ctx->alpha_blend;
545  sws->gamma_flag = ctx->gamma_flag;
546  sws->scaler = ctx->scaler;
547  sws->scaler_sub = ctx->scaler_sub;
548 
549  sws->src_w = src->width;
550  sws->src_h = src->height;
551  sws->src_format = src->format;
552  sws->src_range = src->range == AVCOL_RANGE_JPEG;
553 
554  sws->dst_w = dst->width;
555  sws->dst_h = dst->height;
556  sws->dst_format = dst->format;
557  sws->dst_range = dst->range == AVCOL_RANGE_JPEG;
560 
561  graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED;
562  graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED;
563 
564  /* Allow overriding chroma position with the legacy API */
565  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
566  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
567  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
568  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
569 
570  /* Explicitly strip chroma offsets when not subsampling, because it
571  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
572  if (!src->desc->log2_chroma_w)
573  sws->src_h_chr_pos = -513;
574  if (!src->desc->log2_chroma_h)
575  sws->src_v_chr_pos = -513;
576  if (!dst->desc->log2_chroma_w)
577  sws->dst_h_chr_pos = -513;
578  if (!dst->desc->log2_chroma_h)
579  sws->dst_v_chr_pos = -513;
580 
581  for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
582  sws->scaler_params[i] = ctx->scaler_params[i];
583 
584  ret = sws_init_context(sws, NULL, NULL);
585  if (ret < 0) {
586  sws_free_context(&sws);
587  return ret;
588  }
589 
590  /* Set correct color matrices */
591  {
592  int in_full, out_full, brightness, contrast, saturation;
593  const int *inv_table, *table;
594  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
595  (int **)&table, &out_full,
596  &brightness, &contrast, &saturation);
597 
598  inv_table = sws_getCoefficients(src->csp);
599  table = sws_getCoefficients(dst->csp);
600 
601  graph->incomplete |= src->csp != dst->csp &&
602  (src->csp == AVCOL_SPC_UNSPECIFIED ||
603  dst->csp == AVCOL_SPC_UNSPECIFIED);
604 
605  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
606  brightness, contrast, saturation);
607  }
608 
609  return init_legacy_subpass(graph, sws, input, output);
610 }
611 
612 /*********************************
613  * Format conversion and scaling *
614  *********************************/
615 
616 static int add_ops_convert_pass(SwsGraph *graph, const SwsFormat *src,
617  const SwsFormat *dst, SwsPass *input,
618  SwsPass **output)
619 {
620 #if CONFIG_UNSTABLE
621  SwsContext *ctx = graph->ctx;
622 
623  /* Preemptively skip the ops list generation if the backend was
624  * constrained to the legacy implementation only. This would
625  * normally also fail in ff_sws_compile_pass() with the same
626  * error, but this way saves a bit of unnecessary overhead */
627  const SwsBackend backends = ff_sws_enabled_backends(ctx);
628  if (backends == SWS_BACKEND_LEGACY)
629  return AVERROR(ENOTSUP);
630 
631  SwsOpList *ops;
632  int ret = ff_sws_op_list_generate(ctx, src, dst, &ops, &graph->incomplete);
633  if (ret < 0)
634  return ret;
635 
636  av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
637  av_get_pix_fmt_name(src->format), av_get_pix_fmt_name(dst->format));
638 
639  av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
641 
643  return ff_sws_compile_pass(graph, NULL, &ops, flags, input, output);
644 #else
645  return AVERROR(ENOTSUP);
646 #endif
647 }
648 
650 {
651  if (ctx->flags & SWS_UNSTABLE)
652  return true;
653  if (isFloat(src->format) || isFloat(dst->format))
654  return true; /* ops backend has better support for float formats */
655  return false; /* default to legacy for stability reasons */
656 }
657 
658 static int add_convert_pass(SwsGraph *graph, const SwsFormat *src,
659  const SwsFormat *dst, SwsPass *input,
660  SwsPass **output)
661 {
662  SwsContext *ctx = graph->ctx;
663  int ret;
664 
665  if (prefer_ops_backend(ctx, src, dst)) {
667  if (ret == AVERROR(ENOTSUP))
668  ret = add_legacy_sws_pass(graph, src, dst, input, output);
669  } else {
670  ret = add_legacy_sws_pass(graph, src, dst, input, output);
671  if (ret == AVERROR(ENOTSUP))
673  }
674 
675  return ret;
676 }
677 
678 /**************************
679  * Gamut and tone mapping *
680  **************************/
681 
682 static void free_lut3d(void *priv)
683 {
684  SwsLut3D *lut = priv;
685  ff_sws_lut3d_free(&lut);
686 }
687 
688 static int setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
689 {
690  SwsLut3D *lut = pass->priv;
691 
692  /* Update dynamic frame metadata from the original source frame */
693  ff_sws_lut3d_update(lut, &pass->graph->src.color);
694  return 0;
695 }
696 
697 static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h,
698  const SwsPass *pass)
699 {
700  SwsLut3D *lut = pass->priv;
701  uint8_t *in_data[4], *out_data[4];
702  frame_shift(in, y, in_data);
703  frame_shift(out, y, out_data);
704 
705  ff_sws_lut3d_apply(lut, in_data[0], in->linesize[0], out_data[0],
706  out->linesize[0], out->width, h);
707 }
708 
709 static int adapt_colors(SwsGraph *graph, const SwsFormat *src_fmt,
710  const SwsFormat *dst_fmt, SwsPass *input,
711  SwsPass **output)
712 {
713  SwsFormat src = *src_fmt;
714  SwsFormat dst = *dst_fmt;
715  enum AVPixelFormat fmt_in, fmt_out;
716  SwsColorMap map = {0};
717  SwsLut3D *lut;
718  int ret;
719 
720  /**
721  * Grayspace does not really have primaries, so just force the use of
722  * the equivalent other primary set to avoid a conversion. Technically,
723  * this does affect the weights used for the Grayscale conversion, but
724  * in practise, that should give the expected results more often than not.
725  */
726  if (isGray(dst.format)) {
727  dst.color = src.color;
728  } else if (isGray(src.format)) {
729  src.color = dst.color;
730  }
731 
732  /* Fully infer color spaces before color mapping logic */
733  graph->incomplete |= ff_infer_colors(&src.color, &dst.color);
734 
735  map.intent = graph->ctx->intent;
736  map.src = src.color;
737  map.dst = dst.color;
738 
740  return 0;
741 
742  if (src.hw_format != AV_PIX_FMT_NONE || dst.hw_format != AV_PIX_FMT_NONE)
743  return AVERROR(ENOTSUP);
744 
745  lut = ff_sws_lut3d_alloc();
746  if (!lut)
747  return AVERROR(ENOMEM);
748 
749  fmt_in = ff_sws_lut3d_pick_pixfmt(&src, 0);
750  fmt_out = ff_sws_lut3d_pick_pixfmt(&dst, 1);
751  if (fmt_in != src.format) {
752  SwsFormat tmp = src;
753  tmp.format = fmt_in;
754  ret = add_convert_pass(graph, &src, &tmp, input, &input);
755  if (ret < 0) {
756  ff_sws_lut3d_free(&lut);
757  return ret;
758  }
759  }
760 
761  ret = ff_sws_lut3d_generate(lut, fmt_in, fmt_out, &map);
762  if (ret < 0) {
763  ff_sws_lut3d_free(&lut);
764  return ret;
765  }
766 
767  return ff_sws_graph_add_pass(graph, fmt_out, src.width, src.height,
768  input, 0, 1, run_lut3d, setup_lut3d, lut,
769  free_lut3d, output);
770 }
771 
772 /***************************************
773  * Main filter graph construction code *
774  ***************************************/
775 
776 static int init_passes(SwsGraph *graph)
777 {
778  SwsFormat src = graph->src;
779  SwsFormat dst = graph->dst;
780  SwsPass *pass = NULL; /* read from main input image */
781  int ret;
782 
783  ret = adapt_colors(graph, &src, &dst, pass, &pass);
784  if (ret < 0)
785  return ret;
786  src.format = pass ? pass->format : src.format;
787  src.color = dst.color;
788 
789  if (!ff_fmt_equal(&src, &dst)) {
790  ret = add_convert_pass(graph, &src, &dst, pass, &pass);
791  if (ret < 0)
792  return ret;
793  }
794 
795  if (pass)
796  return 0;
797 
798  /* No passes were added, so no operations were necessary */
799  graph->noop = 1;
800 
801  /* Add threaded memcpy pass */
802  return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
803  pass, 0, 1, run_copy, NULL, NULL, NULL, &pass);
804 }
805 
806 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
807  int nb_threads)
808 {
809  SwsGraph *graph = priv;
810  const SwsPass *pass = graph->exec.pass;
811  const int slice_y = jobnr * pass->slice_h;
812  const int slice_h = FFMIN(pass->slice_h, pass->lines - slice_y);
813 
814  pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
815 }
816 
818 {
819  return av_mallocz(sizeof(SwsGraph));
820 }
821 
822 static void graph_uninit(SwsGraph *graph)
823 {
825 
826  for (int i = 0; i < graph->num_passes; i++)
827  pass_free(graph->passes[i]);
828  av_free(graph->passes);
829 
830  memset(graph, 0, sizeof(*graph));
831 }
832 
834  const SwsFormat *src)
835 {
836  int ret;
837  if (graph->ctx) {
838  av_log(ctx, AV_LOG_ERROR, "Graph is already initialized\n");
839  return AVERROR(EINVAL);
840  }
841 
842  graph->ctx = ctx;
843  graph->src = *src;
844  graph->dst = *dst;
845  graph->opts_copy = *ctx;
846  av_assert0(src->interlaced == dst->interlaced);
847  av_assert0(src->field == dst->field);
848 
849  if (ctx->threads == 1) {
850  graph->num_threads = 1;
851  } else {
852  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
853  sws_graph_worker, NULL, ctx->threads);
854  if (ret == AVERROR(ENOSYS)) {
855  /* Fall back to single threaded operation */
856  graph->num_threads = 1;
857  } else if (ret < 0) {
858  goto error;
859  } else {
860  graph->num_threads = ret;
861  }
862  }
863 
864  ret = init_passes(graph);
865  if (ret < 0)
866  goto error;
867 
868  /* Resolve output buffers for all intermediate passes */
869  for (int i = 0; i < graph->num_passes; i++) {
870  graph->backend |= graph->passes[i]->backend;
871  ret = pass_alloc_output(graph->passes[i]->input);
872  if (ret < 0)
873  goto error;
874  }
875 
876  return 0;
877 
878 error:
879  graph_uninit(graph);
880  return ret;
881 }
882 
884  SwsGraph **out_graph)
885 {
886  SwsGraph *graph = ff_sws_graph_alloc();
887  if (!graph)
888  return AVERROR(ENOMEM);
889 
890  int ret = ff_sws_graph_init(graph, ctx, dst, src);
891  if (ret < 0) {
892  ff_sws_graph_free(&graph);
893  return ret;
894  }
895 
896  *out_graph = graph;
897  return 0;
898 }
899 
900 void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
901 {
902  for (int i = since_idx; i < graph->num_passes; i++)
903  pass_free(graph->passes[i]);
904  graph->num_passes = since_idx;
905 }
906 
908 {
909  SwsGraph *graph = *pgraph;
910  if (!graph)
911  return;
912 
913  graph_uninit(graph);
914  av_free(graph);
915  *pgraph = NULL;
916 }
917 
918 /* Tests only options relevant to SwsGraph */
919 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
920 {
921  return c1->flags == c2->flags &&
922  c1->threads == c2->threads &&
923  c1->dither == c2->dither &&
924  c1->alpha_blend == c2->alpha_blend &&
925  c1->gamma_flag == c2->gamma_flag &&
926  c1->src_h_chr_pos == c2->src_h_chr_pos &&
927  c1->src_v_chr_pos == c2->src_v_chr_pos &&
928  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
929  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
930  c1->intent == c2->intent &&
931  c1->scaler == c2->scaler &&
932  c1->scaler_sub == c2->scaler_sub &&
933  c1->backends == c2->backends &&
934  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
935 
936 }
937 
939  const SwsFormat *src)
940 {
941  if (ff_fmt_equal(&graph->src, src) && ff_fmt_equal(&graph->dst, dst) &&
942  opts_equal(ctx, &graph->opts_copy))
943  {
944  ff_sws_graph_update_metadata(graph, &src->color);
945  return 0;
946  }
947 
948  graph_uninit(graph);
949  return ff_sws_graph_init(graph, ctx, dst, src);
950 }
951 
953 {
954  if (!color)
955  return;
956 
958 }
959 
960 static void get_field(SwsGraph *graph, const SwsFormat *fmt,
961  const AVFrame *avframe, SwsFrame *frame)
962 {
964 
965  if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) {
966  av_assert1(!fmt->field);
967  return;
968  }
969 
970  if (fmt->field == FIELD_BOTTOM) {
971  /* Odd rows, offset by one line */
973  for (int i = 0; i < 4; i++) {
974  if (frame->data[i])
975  frame->data[i] += frame->linesize[i];
976  if (desc->flags & AV_PIX_FMT_FLAG_PAL)
977  break;
978  }
979  }
980 
981  /* Take only every second line */
982  for (int i = 0; i < 4; i++)
983  frame->linesize[i] <<= 1;
984 
985  frame->height = (frame->height + (fmt->field == FIELD_TOP)) >> 1;
986 }
987 
988 int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
989 {
990  av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format);
991  av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format);
992 
993  SwsFrame src_field, dst_field;
994  get_field(graph, &graph->dst, dst, &dst_field);
995  get_field(graph, &graph->src, src, &src_field);
996 
997  for (int i = 0; i < graph->num_passes; i++) {
998  const SwsPass *pass = graph->passes[i];
999  graph->exec.pass = pass;
1000  graph->exec.input = pass->input ? &pass->input->output->frame : &src_field;
1001  graph->exec.output = pass->output->avframe ? &pass->output->frame : &dst_field;
1002  if (pass->setup) {
1003  int ret = pass->setup(graph->exec.output, graph->exec.input, pass);
1004  if (ret < 0)
1005  return ret;
1006  }
1007 
1008  if (pass->num_slices == 1) {
1009  pass->run(graph->exec.output, graph->exec.input, 0, pass->lines, pass);
1010  } else {
1012  }
1013  }
1014 
1015  return 0;
1016 }
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:32
flags
const SwsFlags flags[]
Definition: swscale.c:85
ff_sws_graph_add_pass
int ff_sws_graph_add_pass(SwsGraph *graph, enum AVPixelFormat fmt, int width, int height, SwsPass *input, int lines, 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:175
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:860
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:521
SwsGraph::slicethread
AVSliceThread * slicethread
Definition: graph.h:124
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:123
ff_sws_graph_create
int ff_sws_graph_create(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, SwsGraph **out_graph)
Allocate and initialize the filter graph.
Definition: graph.c:883
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:75
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:152
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
ff_sws_pass_link_output
void ff_sws_pass_link_output(SwsPass *dst, const SwsPass *src)
Link the output buffers to a different pass, rather than allocating new image buffers.
Definition: graph.c:232
SwsGraph::passes
SwsPass ** passes
Sorted sequence of filter passes to apply.
Definition: graph.h:133
out
static FILE * out
Definition: movenc.c:55
sws_isSupportedOutput
#define sws_isSupportedOutput(x)
color
Definition: vf_paletteuse.c:513
init_passes
static int init_passes(SwsGraph *graph)
Definition: graph.c:776
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: format.h:57
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:276
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
SwsPass::lines
int lines
Definition: graph.h:86
AVRefStructOpaque
RefStruct is an API for creating reference-counted objects with minimal overhead.
Definition: refstruct.h:58
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:200
SwsPass::format
enum AVPixelFormat format
Definition: graph.h:85
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:284
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:145
avpriv_slicethread_execute
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
Definition: slicethread.c:270
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:337
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:466
pixdesc.h
frame_shift
static void frame_shift(const SwsFrame *f, const int y, uint8_t *data[4])
Definition: graph.c:248
ops.h
AVFrame::width
int width
Definition: frame.h:538
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:807
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:263
SwsGraph::output
const SwsFrame * output
Definition: graph.h:154
SwsPass::backend
SwsBackend backend
Definition: graph.h:84
run_copy
static void run_copy(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:258
pass_free
static void pass_free(SwsPass *pass)
Definition: graph.c:167
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:180
SwsPass::setup
SwsPassSetup setup
Called once from the main thread before running the filter.
Definition: graph.h:105
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:242
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
ops_dispatch.h
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:710
SwsPass::free
void(* free)(void *priv)
Optional private state and associated free() function.
Definition: graph.h:110
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
c1
static const uint64_t c1
Definition: murmur3.c:52
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:220
format.h
add_ops_convert_pass
static int add_ops_convert_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, SwsPass *input, SwsPass **output)
Definition: graph.c:616
SwsPass::input
SwsPass * input
Filter input.
Definition: graph.h:94
cpu.h
AV_PIX_FMT_VULKAN
@ AV_PIX_FMT_VULKAN
Vulkan hardware images.
Definition: pixfmt.h:379
ff_sws_graph_alloc
SwsGraph * ff_sws_graph_alloc(void)
Allocate an empty SwsGraph.
Definition: graph.c:817
ff_sws_init_single_context
int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, SwsFilter *dstFilter)
Definition: utils.c:1148
SwsColorMap
Definition: cms.h:60
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:997
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:410
SwsFrame::data
uint8_t * data[4]
Definition: format.h:226
setup_lut3d
static int setup_lut3d(const SwsFrame *out, const SwsFrame *in, const SwsPass *pass)
Definition: graph.c:688
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
SwsContext::src_v_chr_pos
int src_v_chr_pos
Source vertical chroma position in luma grid / 256.
Definition: swscale.h:282
slice_ctx
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition: graph.c:351
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:1931
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:140
SwsPassBuffer::frame
SwsFrame frame
Definition: graph.h:60
SWS_BACKEND_LEGACY
@ SWS_BACKEND_LEGACY
Legacy bespoke format-specific code.
Definition: swscale.h:112
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
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:224
SwsBackend
SwsBackend
Definition: swscale.h:110
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:403
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:394
SwsFrame::format
enum AVPixelFormat format
Definition: format.h:233
AVHWFramesContext::height
int height
Definition: hwcontext.h:220
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:258
SwsPass::priv
void * priv
Definition: graph.h:111
run_xyz2rgb
static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:305
SwsInternal::nb_slice_ctx
int nb_slice_ctx
Definition: swscale_internal.h:347
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:345
ff_update_palette
void ff_update_palette(SwsInternal *c, const uint32_t *pal)
Definition: swscale.c:873
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1465
ops.h
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:290
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:134
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
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:161
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
fail
#define fail
Definition: test.h:478
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
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:213
run
uint8_t run
Definition: svq3.c:207
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
run_legacy_swscale
static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:382
SwsContext::gamma_flag
int gamma_flag
Use gamma correct scaling.
Definition: swscale.h:268
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:541
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:280
FIELD_TOP
@ FIELD_TOP
Definition: format.h:56
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:76
adapt_colors
static int adapt_colors(SwsGraph *graph, const SwsFormat *src_fmt, const SwsFormat *dst_fmt, SwsPass *input, SwsPass **output)
Definition: graph.c:709
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:285
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:46
graph_uninit
static void graph_uninit(SwsGraph *graph)
Definition: graph.c:822
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:907
f
f
Definition: af_crystalizer.c:122
lut3d.h
free_lut3d
static void free_lut3d(void *priv)
Definition: graph.c:682
SwsGraph::exec
struct SwsGraph::@567 exec
Temporary execution state inside ff_sws_graph_run(); used to pass data to worker threads.
SWS_OP_FLAG_SPLIT_MEMCPY
@ SWS_OP_FLAG_SPLIT_MEMCPY
Definition: ops_dispatch.h:173
height
#define height
Definition: dsp.h:89
frame_alloc_planes
static int frame_alloc_planes(AVFrame *dst)
Definition: graph.c:58
ff_sws_enabled_backends
SwsBackend ff_sws_enabled_backends(const SwsContext *ctx)
Definition: utils.c:71
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1043
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:938
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
SwsGraph::backend
SwsBackend backend
Definition: graph.h:128
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:370
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:263
SwsPassBuffer::height
int height
Definition: graph.h:62
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:276
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:553
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:1018
align
static const uint8_t *BS_FUNC() align(BSCTX *bc)
Skip bits to a byte boundary.
Definition: bitstream_template.h:419
SwsColor
Definition: format.h:60
SwsPass::output
SwsPassBuffer * output
Filter output buffer.
Definition: graph.h:99
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:279
sws_isSupportedInput
#define sws_isSupportedInput(x)
run_lut3d
static void run_lut3d(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition: graph.c:697
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:153
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:329
SwsLut3D
Definition: lut3d.h:50
SwsGraph::dst
SwsFormat dst
Definition: graph.h:145
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:81
SwsPass::slice_h
int slice_h
Definition: graph.h:87
SwsGraph::num_threads
int num_threads
Definition: graph.h:125
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:919
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
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:335
SwsContext::scaler
SwsScaler scaler
Scaling filter.
Definition: swscale.h:298
swscale_internal.h
graph.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_frame_unref
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:496
get_field
static void get_field(SwsGraph *graph, const SwsFormat *fmt, const AVFrame *avframe, SwsFrame *frame)
Definition: graph.c:960
SwsContext::scaler_sub
SwsScaler scaler_sub
Scaler used specifically for up/downsampling subsampled (chroma) planes.
Definition: swscale.h:306
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:277
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:689
av_calloc
void * av_calloc(size_t nmemb, size_t size)
Definition: mem.c:264
isFloat
static av_always_inline int isFloat(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:884
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:118
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
prefer_ops_backend
static bool prefer_ops_backend(SwsContext *ctx, const SwsFormat *src, const SwsFormat *dst)
Definition: graph.c:649
SwsInternal
Definition: swscale_internal.h:337
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:125
SwsPassBuffer::width_pad
int width_pad
Definition: graph.h:67
SwsFormat::field
int field
Definition: format.h:80
SwsGraph::noop
bool noop
Definition: graph.h:127
ff_sws_graph_reinit
int ff_sws_graph_reinit(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src)
Wrapper around ff_sws_graph_init() that reuses the existing graph if the format is compatible.
Definition: graph.c:938
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:538
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
av_refstruct_replace
void av_refstruct_replace(void *dstp, const void *src)
Ensure *dstp refers to the same object as src.
Definition: refstruct.c:160
SWS_NUM_SCALER_PARAMS
#define SWS_NUM_SCALER_PARAMS
Extra parameters for fine-tuning certain scalers.
Definition: swscale.h:247
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
SwsFormat::hw_format
enum AVPixelFormat hw_format
Definition: format.h:82
SwsFormat::color
SwsColor color
Definition: format.h:87
ff_sws_lut3d_pick_pixfmt
enum AVPixelFormat ff_sws_lut3d_pick_pixfmt(const SwsFormat *fmt, int output)
Pick the best compatible pixfmt for a given SwsFormat.
Definition: lut3d.c:52
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:751
cms.h
desc
const char * desc
Definition: libsvtav1.c:83
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:402
SwsGraph::incomplete
bool incomplete
Definition: graph.h:126
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:277
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:122
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:278
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:314
SwsContext::dst_range
int dst_range
Destination is full range.
Definition: swscale.h:281
pass_alloc_output
static int pass_alloc_output(SwsPass *pass)
Definition: graph.c:118
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:988
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:2381
SWS_OP_FLAG_OPTIMIZE
@ SWS_OP_FLAG_OPTIMIZE
Definition: ops_dispatch.h:167
imgutils.h
hwcontext.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:283
add_convert_pass
static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, SwsPass *input, SwsPass **output)
Definition: graph.c:658
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:88
width
#define width
Definition: dsp.h:89
ff_sws_vk_device_ref
AVBufferRef * ff_sws_vk_device_ref(SwsContext *sws)
Returns the Vulkan device reference associated with sws, or NULL if Vulkan has not been initialized f...
Definition: ops.c:86
SwsOpList
Helper struct for representing a list of operations.
Definition: ops.h:285
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:284
SwsContext
Main external API structure.
Definition: swscale.h:229
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
av_hwframe_get_buffer
int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
Allocate a new frame attached to the given AVHWFramesContext.
Definition: hwcontext.c:506
SwsFrame::linesize
int linesize[4]
Definition: format.h:227
sws_graph_worker
static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
Definition: graph.c:806
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:952
SWS_UNSTABLE
@ SWS_UNSTABLE
Allow/prefer using experimental new code paths.
Definition: swscale.h:187
SwsContext::scaler_params
double scaler_params[SWS_NUM_SCALER_PARAMS]
Definition: swscale.h:248
src
#define src
Definition: vp8dsp.c:248
swscale.h
ff_sws_chroma_pos
void ff_sws_chroma_pos(const SwsFormat *fmt, bool *incomplete, int *out_xpos, int *out_ypos)
Wrapper around av_chroma_location_enum_to_pos() that accounts for the per-field offset introduced by ...
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:898
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:900
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:670
ff_sws_graph_init
int ff_sws_graph_init(SwsGraph *graph, SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src)
Initialize the filter graph for a given pair of formats.
Definition: graph.c:833