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/error.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/macros.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/opt.h"
27 #include "libavutil/pixdesc.h"
28 #include "libavutil/slicethread.h"
29 
30 #include "libswscale/swscale.h"
31 #include "libswscale/utils.h"
32 
33 #include "swscale_internal.h"
34 #include "graph.h"
35 
36 static int pass_alloc_output(SwsPass *pass)
37 {
38  if (!pass || pass->output.fmt != AV_PIX_FMT_NONE)
39  return 0;
40  pass->output.fmt = pass->format;
41  return av_image_alloc(pass->output.data, pass->output.linesize, pass->width,
42  pass->num_slices * pass->slice_h, pass->format, 64);
43 }
44 
45 /* slice_align should be a power of two, or 0 to disable slice threading */
46 static SwsPass *pass_add(SwsGraph *graph, void *priv, enum AVPixelFormat fmt,
47  int w, int h, SwsPass *input, int slice_align,
49 {
50  int ret;
51  SwsPass *pass = av_mallocz(sizeof(*pass));
52  if (!pass)
53  return NULL;
54 
55  pass->graph = graph;
56  pass->run = run;
57  pass->priv = priv;
58  pass->format = fmt;
59  pass->width = w;
60  pass->height = h;
61  pass->input = input;
62  pass->output.fmt = AV_PIX_FMT_NONE;
63 
65  if (ret < 0) {
66  av_free(pass);
67  return NULL;
68  }
69 
70  if (!slice_align) {
71  pass->slice_h = pass->height;
72  pass->num_slices = 1;
73  } else {
74  pass->slice_h = (pass->height + graph->num_threads - 1) / graph->num_threads;
75  pass->slice_h = FFALIGN(pass->slice_h, slice_align);
76  pass->num_slices = (pass->height + pass->slice_h - 1) / pass->slice_h;
77  }
78 
79  ret = av_dynarray_add_nofree(&graph->passes, &graph->num_passes, pass);
80  if (ret < 0)
81  av_freep(&pass);
82  return pass;
83 }
84 
85 /* Wrapper around pass_add that chains a pass "in-place" */
86 static int pass_append(SwsGraph *graph, void *priv, enum AVPixelFormat fmt,
87  int w, int h, SwsPass **pass, int slice_align,
89 {
90  SwsPass *new = pass_add(graph, priv, fmt, w, h, *pass, slice_align, run);
91  if (!new)
92  return AVERROR(ENOMEM);
93  *pass = new;
94  return 0;
95 }
96 
97 static int vshift(enum AVPixelFormat fmt, int plane)
98 {
100  return (plane == 1 || plane == 2) ? desc->log2_chroma_h : 0;
101 }
102 
103 /* Shift an image vertically by y lines */
104 static SwsImg shift_img(const SwsImg *img_base, int y)
105 {
106  SwsImg img = *img_base;
107  for (int i = 0; i < 4 && img.data[i]; i++)
108  img.data[i] += (y >> vshift(img.fmt, i)) * img.linesize[i];
109  return img;
110 }
111 
112 static void run_copy(const SwsImg *out_base, const SwsImg *in_base,
113  int y, int h, const SwsPass *pass)
114 {
115  SwsImg in = shift_img(in_base, y);
116  SwsImg out = shift_img(out_base, y);
117 
118  for (int i = 0; i < FF_ARRAY_ELEMS(in.data) && in.data[i]; i++) {
119  const int lines = h >> vshift(in.fmt, i);
120  if (in.linesize[i] == out.linesize[i]) {
121  memcpy(out.data[i], in.data[i], lines * out.linesize[i]);
122  } else {
123  const int linesize = FFMIN(out.linesize[i], in.linesize[i]);
124  for (int j = 0; j < lines; j++) {
125  memcpy(out.data[i], in.data[i], linesize);
126  in.data[i] += in.linesize[i];
127  out.data[i] += out.linesize[i];
128  }
129  }
130  }
131 }
132 
133 static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h,
134  const SwsPass *pass)
135 {
136  SwsInternal *c = pass->priv;
137  const int x0 = c->src0Alpha - 1;
138  const int w4 = 4 * pass->width;
139  const int src_stride = in->linesize[0];
140  const int dst_stride = out->linesize[0];
141  const uint8_t *src = in->data[0] + y * src_stride;
142  uint8_t *dst = out->data[0] + y * dst_stride;
143 
144  for (int y = 0; y < h; y++) {
145  memcpy(dst, src, w4 * sizeof(*dst));
146  for (int x = x0; x < w4; x += 4)
147  dst[x] = 0xFF;
148 
149  src += src_stride;
150  dst += dst_stride;
151  }
152 }
153 
154 static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h,
155  const SwsPass *pass)
156 {
157  ff_xyz12Torgb48(pass->priv, out->data[0] + y * out->linesize[0], out->linesize[0],
158  in->data[0] + y * in->linesize[0], in->linesize[0],
159  pass->width, h);
160 }
161 
162 static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h,
163  const SwsPass *pass)
164 {
165  ff_rgb48Toxyz12(pass->priv, out->data[0] + y * out->linesize[0], out->linesize[0],
166  in->data[0] + y * in->linesize[0], in->linesize[0],
167  pass->width, h);
168 }
169 
170 /***********************************************************************
171  * Internal ff_swscale() wrapper. This re-uses the legacy scaling API. *
172  * This is considered fully deprecated, and will be replaced by a full *
173  * reimplementation ASAP. *
174  ***********************************************************************/
175 
176 static void free_legacy_swscale(void *priv)
177 {
178  SwsContext *sws = priv;
180 }
181 
182 static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in,
183  const SwsPass *pass)
184 {
185  SwsContext *sws = pass->priv;
187  if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
188  for (int i = 0; i < 4; i++)
189  memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
190  }
191 
192  if (usePal(sws->src_format))
193  ff_update_palette(c, (const uint32_t *) in->data[1]);
194 }
195 
196 static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
197 {
198  SwsContext *sws = pass->priv;
199  SwsInternal *parent = sws_internal(sws);
200  if (pass->num_slices == 1)
201  return sws;
202 
203  av_assert1(parent->nb_slice_ctx == pass->num_slices);
204  sws = parent->slice_ctx[y / pass->slice_h];
205 
206  if (usePal(sws->src_format)) {
207  SwsInternal *sub = sws_internal(sws);
208  memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
209  memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
210  }
211 
212  return sws;
213 }
214 
215 static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in_base,
216  int y, int h, const SwsPass *pass)
217 {
218  SwsContext *sws = slice_ctx(pass, y);
220  const SwsImg in = shift_img(in_base, y);
221 
222  c->convert_unscaled(c, (const uint8_t *const *) in.data, in.linesize, y, h,
223  out->data, out->linesize);
224 }
225 
226 static void run_legacy_swscale(const SwsImg *out_base, const SwsImg *in,
227  int y, int h, const SwsPass *pass)
228 {
229  SwsContext *sws = slice_ctx(pass, y);
231  const SwsImg out = shift_img(out_base, y);
232 
233  ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
234  sws->src_h, out.data, out.linesize, y, h);
235 }
236 
237 static void get_chroma_pos(SwsGraph *graph, int *h_chr_pos, int *v_chr_pos,
238  const SwsFormat *fmt)
239 {
240  enum AVChromaLocation chroma_loc = fmt->loc;
241  const int sub_x = fmt->desc->log2_chroma_w;
242  const int sub_y = fmt->desc->log2_chroma_h;
243  int x_pos, y_pos;
244 
245  /* Explicitly default to center siting for compatibility with swscale */
246  if (chroma_loc == AVCHROMA_LOC_UNSPECIFIED) {
247  chroma_loc = AVCHROMA_LOC_CENTER;
248  graph->incomplete |= sub_x || sub_y;
249  }
250 
251  /* av_chroma_location_enum_to_pos() always gives us values in the range from
252  * 0 to 256, but we need to adjust this to the true value range of the
253  * subsampling grid, which may be larger for h/v_sub > 1 */
254  av_chroma_location_enum_to_pos(&x_pos, &y_pos, chroma_loc);
255  x_pos *= (1 << sub_x) - 1;
256  y_pos *= (1 << sub_y) - 1;
257 
258  /* Fix vertical chroma position for interlaced frames */
259  if (sub_y && fmt->interlaced) {
260  /* When vertically subsampling, chroma samples are effectively only
261  * placed next to even rows. To access them from the odd field, we need
262  * to account for this shift by offsetting the distance of one luma row.
263  *
264  * For 4x vertical subsampling (v_sub == 2), they are only placed
265  * next to every *other* even row, so we need to shift by three luma
266  * rows to get to the chroma sample. */
267  if (graph->field == FIELD_BOTTOM)
268  y_pos += (256 << sub_y) - 256;
269 
270  /* Luma row distance is doubled for fields, so halve offsets */
271  y_pos >>= 1;
272  }
273 
274  /* Explicitly strip chroma offsets when not subsampling, because it
275  * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
276  *h_chr_pos = sub_x ? x_pos : -513;
277  *v_chr_pos = sub_y ? y_pos : -513;
278 }
279 
280 static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
281 {
282  if (override == -513 || override == *chr_pos)
283  return;
284 
285  if (!*warned) {
287  "Setting chroma position directly is deprecated, make sure "
288  "the frame is tagged with the correct chroma location.\n");
289  *warned = 1;
290  }
291 
292  *chr_pos = override;
293 }
294 
295 static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws, int cascaded,
297 {
299  const int src_w = sws->src_w, src_h = sws->src_h;
300  const int dst_w = sws->dst_w, dst_h = sws->dst_h;
301  const int unscaled = src_w == dst_w && src_h == dst_h;
302  int align = c->dst_slice_align;
303  SwsPass *pass = NULL;
304  int ret;
305 
306  if (c->cascaded_context[0]) {
307  const int num_cascaded = c->cascaded_context[2] ? 3 : 2;
308  for (int i = 0; i < num_cascaded; i++) {
309  SwsContext *sub = c->cascaded_context[i];
310  const int is_last = i + 1 == num_cascaded;
311  ret = init_legacy_subpass(graph, sub, 1, input, is_last ? output : &input);
312  if (ret < 0)
313  return ret;
314  }
315 
316  return 0;
317  }
318 
319  if (sws->dither == SWS_DITHER_ED && !c->convert_unscaled)
320  align = 0; /* disable slice threading */
321 
322  if (c->src0Alpha && !c->dst0Alpha && isALPHA(sws->dst_format)) {
323  ret = pass_append(graph, c, AV_PIX_FMT_RGBA, src_w, src_h, &input, 1, run_rgb0);
324  if (ret < 0)
325  return ret;
326  }
327 
328  if (c->srcXYZ && !(c->dstXYZ && unscaled)) {
329  ret = pass_append(graph, c, AV_PIX_FMT_RGB48, src_w, src_h, &input, 1, run_xyz2rgb);
330  if (ret < 0)
331  return ret;
332  }
333 
334  pass = pass_add(graph, sws, sws->dst_format, dst_w, dst_h, input, align,
335  c->convert_unscaled ? run_legacy_unscaled : run_legacy_swscale);
336  if (!pass)
337  return AVERROR(ENOMEM);
338  pass->setup = setup_legacy_swscale;
339  if (!cascaded) /* parent context frees this automatically */
340  pass->free = free_legacy_swscale;
341 
342  /**
343  * For slice threading, we need to create sub contexts, similar to how
344  * swscale normally handles it internally. The most important difference
345  * is that we handle cascaded contexts before threaded contexts; whereas
346  * context_init_threaded() does it the other way around.
347  */
348 
349  if (pass->num_slices > 1) {
350  c->slice_ctx = av_calloc(pass->num_slices, sizeof(*c->slice_ctx));
351  if (!c->slice_ctx)
352  return AVERROR(ENOMEM);
353 
354  for (int i = 0; i < pass->num_slices; i++) {
355  SwsContext *slice;
356  SwsInternal *c2;
357  slice = c->slice_ctx[i] = sws_alloc_context();
358  if (!slice)
359  return AVERROR(ENOMEM);
360  c->nb_slice_ctx++;
361 
362  c2 = sws_internal(slice);
363  c2->parent = sws;
364 
365  ret = av_opt_copy(slice, sws);
366  if (ret < 0)
367  return ret;
368 
370  if (ret < 0)
371  return ret;
372 
373  sws_setColorspaceDetails(slice, c->srcColorspaceTable,
374  slice->src_range, c->dstColorspaceTable,
375  slice->dst_range, c->brightness, c->contrast,
376  c->saturation);
377 
378  for (int i = 0; i < FF_ARRAY_ELEMS(c->srcColorspaceTable); i++) {
379  c2->srcColorspaceTable[i] = c->srcColorspaceTable[i];
380  c2->dstColorspaceTable[i] = c->dstColorspaceTable[i];
381  }
382  }
383  }
384 
385  if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
386  ret = pass_append(graph, c, AV_PIX_FMT_RGB48, dst_w, dst_h, &pass, 1, run_rgb2xyz);
387  if (ret < 0)
388  return ret;
389  }
390 
391  *output = pass;
392  return 0;
393 }
394 
397 {
398  int ret, warned = 0;
399  SwsContext *const ctx = graph->ctx;
401  if (!sws)
402  return AVERROR(ENOMEM);
403 
404  sws->flags = ctx->flags;
405  sws->dither = ctx->dither;
406  sws->alpha_blend = ctx->alpha_blend;
407  sws->gamma_flag = ctx->gamma_flag;
408 
409  sws->src_w = src.width;
410  sws->src_h = src.height;
411  sws->src_format = src.format;
412  sws->src_range = src.range == AVCOL_RANGE_JPEG;
413 
414  sws->dst_w = dst.width;
415  sws->dst_h = dst.height;
416  sws->dst_format = dst.format;
417  sws->dst_range = dst.range == AVCOL_RANGE_JPEG;
420 
421  graph->incomplete |= src.range == AVCOL_RANGE_UNSPECIFIED;
422  graph->incomplete |= dst.range == AVCOL_RANGE_UNSPECIFIED;
423 
424  /* Allow overriding chroma position with the legacy API */
425  legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
426  legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
427  legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
428  legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
429 
431  if (ret < 0) {
433  return ret;
434  }
435 
436  /* Set correct color matrices */
437  {
438  int in_full, out_full, brightness, contrast, saturation;
439  const int *inv_table, *table;
440  sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
441  (int **)&table, &out_full,
442  &brightness, &contrast, &saturation);
443 
444  inv_table = sws_getCoefficients(src.csp);
446 
447  graph->incomplete |= src.csp != dst.csp &&
448  (src.csp == AVCOL_SPC_UNSPECIFIED ||
449  dst.csp == AVCOL_SPC_UNSPECIFIED);
450 
451  sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
452  brightness, contrast, saturation);
453  }
454 
455  ret = init_legacy_subpass(graph, sws, 0, input, output);
456  if (ret < 0) {
458  return ret;
459  }
460 
461  return 0;
462 }
463 
464 
465 /***************************************
466  * Main filter graph construction code *
467  ***************************************/
468 
469 static int init_passes(SwsGraph *graph)
470 {
471  const SwsFormat src = graph->src;
472  const SwsFormat dst = graph->dst;
473  SwsPass *pass = NULL; /* read from main input image */
474  int ret;
475 
476  if (!ff_fmt_equal(&src, &dst)) {
477  ret = add_legacy_sws_pass(graph, src, dst, pass, &pass);
478  if (ret < 0)
479  return ret;
480  }
481 
482  if (!pass) {
483  /* No passes were added, so no operations were necessary */
484  graph->noop = 1;
485 
486  /* Add threaded memcpy pass */
487  pass = pass_add(graph, NULL, dst.format, dst.width, dst.height, pass, 1, run_copy);
488  if (!pass)
489  return AVERROR(ENOMEM);
490  }
491 
492  return 0;
493 }
494 
495 static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
496  int nb_threads)
497 {
498  SwsGraph *graph = priv;
499  const SwsPass *pass = graph->exec.pass;
500  const SwsImg *input = pass->input ? &pass->input->output : &graph->exec.input;
501  const SwsImg *output = pass->output.fmt != AV_PIX_FMT_NONE ? &pass->output : &graph->exec.output;
502  const int slice_y = jobnr * pass->slice_h;
503  const int slice_h = FFMIN(pass->slice_h, pass->height - slice_y);
504 
505  pass->run(output, input, slice_y, slice_h, pass);
506 }
507 
509  int field, SwsGraph **out_graph)
510 {
511  int ret;
512  SwsGraph *graph = av_mallocz(sizeof(*graph));
513  if (!graph)
514  return AVERROR(ENOMEM);
515 
516  graph->ctx = ctx;
517  graph->src = *src;
518  graph->dst = *dst;
519  graph->field = field;
520  graph->opts_copy = *ctx;
521 
522  graph->exec.input.fmt = src->format;
523  graph->exec.output.fmt = dst->format;
524 
525  ret = avpriv_slicethread_create(&graph->slicethread, (void *) graph,
526  sws_graph_worker, NULL, ctx->threads);
527  if (ret == AVERROR(ENOSYS))
528  graph->num_threads = 1;
529  else if (ret < 0)
530  goto error;
531  else
532  graph->num_threads = ret;
533 
534  ret = init_passes(graph);
535  if (ret < 0)
536  goto error;
537 
538  *out_graph = graph;
539  return 0;
540 
541 error:
542  sws_graph_free(&graph);
543  return ret;
544 }
545 
546 void sws_graph_free(SwsGraph **pgraph)
547 {
548  SwsGraph *graph = *pgraph;
549  if (!graph)
550  return;
551 
553 
554  for (int i = 0; i < graph->num_passes; i++) {
555  SwsPass *pass = graph->passes[i];
556  if (pass->free)
557  pass->free(pass->priv);
558  if (pass->output.fmt != AV_PIX_FMT_NONE)
559  av_free(pass->output.data[0]);
560  av_free(pass);
561  }
562  av_free(graph->passes);
563 
564  av_free(graph);
565  *pgraph = NULL;
566 }
567 
568 /* Tests only options relevant to SwsGraph */
569 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
570 {
571  return c1->flags == c2->flags &&
572  c1->threads == c2->threads &&
573  c1->dither == c2->dither &&
574  c1->alpha_blend == c2->alpha_blend &&
575  c1->gamma_flag == c2->gamma_flag &&
576  c1->src_h_chr_pos == c2->src_h_chr_pos &&
577  c1->src_v_chr_pos == c2->src_v_chr_pos &&
578  c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
579  c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
580  !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
581 
582 }
583 
585  int field, SwsGraph **out_graph)
586 {
587  const SwsGraph *graph = *out_graph;
588  if (graph && ff_fmt_equal(&graph->src, src) &&
589  ff_fmt_equal(&graph->dst, dst) &&
590  opts_equal(ctx, &graph->opts_copy))
591  return 0;
592 
593  sws_graph_free(out_graph);
594  return sws_graph_create(ctx, dst, src, field, out_graph);
595 }
596 
597 
598 void sws_graph_run(SwsGraph *graph, uint8_t *const out_data[4],
599  const int out_linesize[4],
600  const uint8_t *const in_data[4],
601  const int in_linesize[4])
602 {
603  SwsImg *out = &graph->exec.output;
604  SwsImg *in = &graph->exec.input;
605  memcpy(out->data, out_data, sizeof(out->data));
606  memcpy(out->linesize, out_linesize, sizeof(out->linesize));
607  memcpy(in->data, in_data, sizeof(in->data));
608  memcpy(in->linesize, in_linesize, sizeof(in->linesize));
609 
610  for (int i = 0; i < graph->num_passes; i++) {
611  const SwsPass *pass = graph->passes[i];
612  graph->exec.pass = pass;
613  if (pass->setup)
614  pass->setup(out, in, pass);
616  }
617 }
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:1046
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
SwsGraph::incomplete
int incomplete
Definition: graph.h:98
SwsGraph::slicethread
AVSliceThread * slicethread
Definition: graph.h:96
SwsGraph::ctx
SwsContext * ctx
Definition: graph.h:95
SwsPass
Represents a single filter pass in the scaling graph.
Definition: graph.h:52
SwsGraph::pass
const SwsPass * pass
Definition: graph.h:119
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:102
out
FILE * out
Definition: movenc.c:55
init_passes
static int init_passes(SwsGraph *graph)
Definition: graph.c:469
ff_rgb48Toxyz12
void ff_rgb48Toxyz12(const SwsInternal *c, uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, int w, int h)
Definition: swscale.c:718
SwsPass::output
SwsImg output
Filter output buffer.
Definition: graph.h:75
SwsFormat::interlaced
int interlaced
Definition: utils.h:36
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3170
SwsContext::src_w
int src_w
Deprecated frame property overrides, for the legacy API only.
Definition: swscale.h:220
SwsPass::format
enum AVPixelFormat format
Definition: graph.h:61
sws_graph_free
void sws_graph_free(SwsGraph **pgraph)
Uninitialize any state associate with this filter graph and free it.
Definition: graph.c:546
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:225
sws_filter_run_t
void(* sws_filter_run_t)(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Output h lines of filtered data.
Definition: graph.h:44
SwsGraph::src
SwsFormat src
Currently active format and processing parameters.
Definition: graph.h:114
avpriv_slicethread_execute
void avpriv_slicethread_execute(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
Definition: slicethread.c:271
pixdesc.h
w
uint8_t w
Definition: llviddspenc.c:38
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:717
SWS_BITEXACT
@ SWS_BITEXACT
Definition: swscale.h:156
table
static const uint16_t table[]
Definition: prosumer.c:203
pass_add
static SwsPass * pass_add(SwsGraph *graph, void *priv, enum AVPixelFormat fmt, int w, int h, SwsPass *input, int slice_align, sws_filter_run_t run)
Definition: graph.c:46
SwsContext::flags
unsigned flags
Bitmask of SWS_*.
Definition: swscale.h:187
SwsPass::free
void(* free)(void *priv)
Optional private state and associated free() function.
Definition: graph.h:87
c1
static const uint64_t c1
Definition: murmur3.c:52
SwsImg
Represents a view into a single field of frame data.
Definition: graph.h:31
shift_img
static SwsImg shift_img(const SwsImg *img_base, int y)
Definition: graph.c:104
ff_sws_init_single_context
int ff_sws_init_single_context(SwsContext *sws, SwsFilter *srcFilter, SwsFilter *dstFilter)
Definition: utils.c:1316
SwsPass::width
int width
Definition: graph.h:62
avpriv_slicethread_create
int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, void(*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), void(*main_func)(void *priv), int nb_threads)
Create slice threading context.
Definition: slicethread.c:262
macros.h
SwsContext::src_v_chr_pos
int src_v_chr_pos
Source vertical chroma position in luma grid / 256.
Definition: swscale.h:226
slice_ctx
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition: graph.c:196
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:2082
SwsGraph::opts_copy
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition: graph.h:109
utils.h
avassert.h
SwsInternal::pal_rgb
uint32_t pal_rgb[256]
Definition: swscale_internal.h:383
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:280
SwsContext::dither
SwsDither dither
Dither mode.
Definition: swscale.h:202
SwsPass::priv
void * priv
Definition: graph.h:88
SwsInternal::nb_slice_ctx
int nb_slice_ctx
Definition: swscale_internal.h:327
SwsInternal::slice_ctx
SwsContext ** slice_ctx
Definition: swscale_internal.h:325
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:3588
ff_update_palette
void ff_update_palette(SwsInternal *c, const uint32_t *pal)
Definition: swscale.c:777
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1451
SwsPass::setup
void(* setup)(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Called once from the main thread before running the filter.
Definition: graph.h:82
ff_fmt_equal
static int ff_fmt_equal(const SwsFormat *fmt1, const SwsFormat *fmt2)
Definition: utils.h:52
SwsGraph::num_passes
int num_passes
Definition: graph.h:103
ctx
AVFormatContext * ctx
Definition: movenc.c:49
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
ff_xyz12Torgb48
void ff_xyz12Torgb48(const SwsInternal *c, uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, int w, int h)
Definition: swscale.c:659
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
SwsGraph::noop
int noop
Definition: graph.h:99
SwsGraph::field
int field
Definition: graph.h:115
pass_append
static int pass_append(SwsGraph *graph, void *priv, enum AVPixelFormat fmt, int w, int h, SwsPass **pass, int slice_align, sws_filter_run_t run)
Definition: graph.c:86
NULL
#define NULL
Definition: coverity.c:32
run
uint8_t run
Definition: svq3.c:204
SwsContext::gamma_flag
int gamma_flag
Use gamma correct scaling.
Definition: swscale.h:212
run_xyz2rgb
static void run_xyz2rgb(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:154
sws_graph_reinit
int sws_graph_reinit(SwsContext *ctx, const SwsFormat *dst, const SwsFormat *src, int field, SwsGraph **out_graph)
Wrapper around sws_graph_create that does nothing if the format is unchanged.
Definition: graph.c:584
SwsGraph::input
SwsImg input
Definition: graph.h:120
SwsContext::src_range
int src_range
Source is full range.
Definition: swscale.h:224
sws_graph_run
void sws_graph_run(SwsGraph *graph, uint8_t *const out_data[4], const int out_linesize[4], const uint8_t *const in_data[4], const int in_linesize[4])
Dispatch the filter graph on a single field.
Definition: graph.c:598
SwsPass::graph
const SwsGraph * graph
Definition: graph.h:53
AVCOL_RANGE_UNSPECIFIED
@ AVCOL_RANGE_UNSPECIFIED
Definition: pixfmt.h:683
SwsContext::dst_h_chr_pos
int dst_h_chr_pos
Destination horizontal chroma position.
Definition: swscale.h:229
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
run_legacy_swscale
static void run_legacy_swscale(const SwsImg *out_base, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:226
error.h
av_opt_copy
int av_opt_copy(void *dst, const void *src)
Copy options from src object into dest object.
Definition: opt.c:2151
av_image_alloc
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align)
Allocate an image with size w and h and pixel format pix_fmt, and fill pointers and linesizes accordi...
Definition: imgutils.c:218
SwsPass::height
int height
Definition: graph.h:62
SwsImg::linesize
int linesize[4]
Definition: graph.h:34
add_legacy_sws_pass
static int add_legacy_sws_pass(SwsGraph *graph, SwsFormat src, SwsFormat dst, SwsPass *input, SwsPass **output)
Definition: graph.c:395
sws_alloc_context
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition: utils.c:1227
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
usePal
static av_always_inline int usePal(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:900
AV_PIX_FMT_RGB48
#define AV_PIX_FMT_RGB48
Definition: pixfmt.h:488
SwsContext::alpha_blend
SwsAlphaBlend alpha_blend
Alpha blending mode.
Definition: swscale.h:207
SwsContext::src_h
int src_h
Width and height of the source frame.
Definition: swscale.h:220
SwsGraph::output
SwsImg output
Definition: graph.h:121
AVCHROMA_LOC_UNSPECIFIED
@ AVCHROMA_LOC_UNSPECIFIED
Definition: pixfmt.h:737
SwsFormat
Definition: utils.h:34
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:1202
align
static const uint8_t *BS_FUNC() align(BSCTX *bc)
Skip bits to a byte boundary.
Definition: bitstream_template.h:411
SwsFormat::loc
enum AVChromaLocation loc
Definition: utils.h:42
img
#define img
Definition: vf_colormatrix.c:114
SwsContext::dst_format
int dst_format
Destination pixel format.
Definition: swscale.h:223
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
AVChromaLocation
AVChromaLocation
Location of chroma samples.
Definition: pixfmt.h:736
sws
static SwsContext * sws[3]
Definition: swscale.c:69
free_legacy_swscale
static void free_legacy_swscale(void *priv)
Definition: graph.c:176
SwsGraph::dst
SwsFormat dst
Definition: graph.h:114
SwsPass::slice_h
int slice_h
Definition: graph.h:63
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
SwsGraph::num_threads
int num_threads
Definition: graph.h:97
opts_equal
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition: graph.c:569
run_rgb0
static void run_rgb0(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:133
SwsFormat::desc
const AVPixFmtDescriptor * desc
Definition: utils.h:43
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:56
run_rgb2xyz
static void run_rgb2xyz(const SwsImg *out, const SwsImg *in, int y, int h, const SwsPass *pass)
Definition: graph.c:162
swscale_internal.h
graph.h
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
SwsContext::dst_h
int dst_h
Width and height of the destination frame.
Definition: swscale.h:221
run_copy
static void run_copy(const SwsImg *out_base, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:112
AVCOL_SPC_UNSPECIFIED
@ AVCOL_SPC_UNSPECIFIED
Definition: pixfmt.h:643
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:237
SWS_DITHER_ED
@ SWS_DITHER_ED
Definition: swscale.h:83
vshift
static int vshift(enum AVPixelFormat fmt, int plane)
Definition: graph.c:97
SwsInternal
Definition: swscale_internal.h:317
ret
ret
Definition: filter_design.txt:187
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
c2
static const uint64_t c2
Definition: murmur3.c:53
AVCHROMA_LOC_CENTER
@ AVCHROMA_LOC_CENTER
MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0.
Definition: pixfmt.h:739
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:72
setup_legacy_swscale
static void setup_legacy_swscale(const SwsImg *out, const SwsImg *in, const SwsPass *pass)
Definition: graph.c:182
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:236
desc
const char * desc
Definition: libsvtav1.c:79
SwsInternal::pal_yuv
uint32_t pal_yuv[256]
Definition: swscale_internal.h:382
mem.h
sws_graph_create
int 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:508
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:221
SwsGraph
Filter graph, which represents a 'baked' pixel format conversion.
Definition: graph.h:94
SwsContext::src_format
int src_format
Source pixel format.
Definition: swscale.h:222
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
SwsImg::fmt
enum AVPixelFormat fmt
Definition: graph.h:32
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
SwsContext::dst_range
int dst_range
Destination is full range.
Definition: swscale.h:225
pass_alloc_output
static int pass_alloc_output(SwsPass *pass)
Definition: graph.c:36
run_legacy_unscaled
static void run_legacy_unscaled(const SwsImg *out, const SwsImg *in_base, int y, int h, const SwsPass *pass)
Definition: graph.c:215
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
SwsPass::run
sws_filter_run_t run
Filter main execution function.
Definition: graph.h:60
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:2526
init_legacy_subpass
static int init_legacy_subpass(SwsGraph *graph, SwsContext *sws, int cascaded, SwsPass *input, SwsPass **output)
Definition: graph.c:295
imgutils.h
avpriv_slicethread_free
void avpriv_slicethread_free(AVSliceThread **pctx)
Destroy slice threading context.
Definition: slicethread.c:276
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
SwsContext::src_h_chr_pos
int src_h_chr_pos
Source horizontal chroma position.
Definition: swscale.h:227
sws_internal
static SwsInternal * sws_internal(const SwsContext *sws)
Definition: swscale_internal.h:74
SwsPass::input
const SwsPass * input
Filter input.
Definition: graph.h:70
h
h
Definition: vp9dsp_template.c:2070
SwsPass::num_slices
int num_slices
Definition: graph.h:64
SwsContext::dst_v_chr_pos
int dst_v_chr_pos
Destination vertical chroma position.
Definition: swscale.h:228
SwsContext
Main external API structure.
Definition: swscale.h:174
sws_graph_worker
static void sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
Definition: graph.c:495
SwsGraph::exec
struct SwsGraph::@459 exec
Temporary execution state inside sws_graph_run.
AVPixFmtDescriptor::log2_chroma_h
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:89
src
#define src
Definition: vp8dsp.c:248
swscale.h
SwsImg::data
uint8_t * data[4]
Definition: graph.h:33
isALPHA
static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt)
Definition: swscale_internal.h:860
FIELD_BOTTOM
@ FIELD_BOTTOM
Definition: utils.h:30