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