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_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_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_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_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{
179 SwsPassBuffer *buffer = obj;
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
293 if (in_data[i] == out_data[i]) {
294 av_assert0(in->linesize[i] == out->linesize[i]);
295 } else if (in->linesize[i] == out->linesize[i]) {
296 memcpy(out_data[i], in_data[i], lines * out->linesize[i]);
297 } else {
298 const int linesize = FFMIN(out->linesize[i], in->linesize[i]);
299 for (int j = 0; j < lines; j++) {
300 memcpy(out_data[i], in_data[i], linesize);
301 in_data[i] += in->linesize[i];
302 out_data[i] += out->linesize[i];
303 }
304 }
305 }
306}
307
308static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h,
309 const SwsPass *pass)
310{
311 SwsInternal *c = pass->priv;
312 const int x0 = c->src0Alpha - 1;
313 const int w4 = 4 * out->width;
314 const int src_stride = in->linesize[0];
315 const int dst_stride = out->linesize[0];
316 const uint8_t *src = in->data[0] + y * src_stride;
317 uint8_t *dst = out->data[0] + y * dst_stride;
318
319 for (int y = 0; y < h; y++) {
320 memcpy(dst, src, w4 * sizeof(*dst));
321 for (int x = x0; x < w4; x += 4)
322 dst[x] = 0xFF;
323
324 src += src_stride;
325 dst += dst_stride;
326 }
327}
328
329static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h,
330 const SwsPass *pass)
331{
332 const SwsInternal *c = pass->priv;
333 c->xyz12Torgb48(c, out->data[0] + y * out->linesize[0], out->linesize[0],
334 in->data[0] + y * in->linesize[0], in->linesize[0],
335 out->width, h);
336}
337
338static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h,
339 const SwsPass *pass)
340{
341 const SwsInternal *c = pass->priv;
342 c->rgb48Toxyz12(c, out->data[0] + y * out->linesize[0], out->linesize[0],
343 in->data[0] + y * in->linesize[0], in->linesize[0],
344 out->width, h);
345}
346
347/***********************************************************************
348 * Internal ff_swscale() wrapper. This reuses the legacy scaling API. *
349 * This is considered fully deprecated, and will be replaced by a full *
350 * reimplementation ASAP. *
351 ***********************************************************************/
352
353static void free_legacy_swscale(void *priv)
354{
355 SwsContext *sws = priv;
356 sws_free_context(&sws);
357}
358
359static int setup_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
360 const SwsPass *pass)
361{
362 SwsContext *sws = pass->priv;
363 SwsInternal *c = sws_internal(sws);
364 if (sws->flags & SWS_BITEXACT && sws->dither == SWS_DITHER_ED && c->dither_error[0]) {
365 for (int i = 0; i < 4; i++)
366 memset(c->dither_error[i], 0, sizeof(c->dither_error[0][0]) * (sws->dst_w + 2));
367 }
368
369 if (usePal(sws->src_format))
370 ff_update_palette(c, (const uint32_t *) in->data[1]);
371
372 return 0;
373}
374
375static inline SwsContext *slice_ctx(const SwsPass *pass, int y)
376{
377 SwsContext *sws = pass->priv;
378 SwsInternal *parent = sws_internal(sws);
379 if (pass->num_slices == 1)
380 return sws;
381
382 av_assert1(parent->nb_slice_ctx == pass->num_slices);
383 sws = parent->slice_ctx[y / pass->slice_h];
384
385 if (usePal(sws->src_format)) {
386 SwsInternal *sub = sws_internal(sws);
387 memcpy(sub->pal_yuv, parent->pal_yuv, sizeof(sub->pal_yuv));
388 memcpy(sub->pal_rgb, parent->pal_rgb, sizeof(sub->pal_rgb));
389 }
390
391 return sws;
392}
393
394static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in,
395 int y, int h, const SwsPass *pass)
396{
397 SwsContext *sws = slice_ctx(pass, y);
398 SwsInternal *c = sws_internal(sws);
399 uint8_t *in_data[4];
400 frame_shift(in, y, in_data);
401
402 c->convert_unscaled(c, (const uint8_t *const *) in_data, in->linesize, y, h,
403 out->data, out->linesize);
404}
405
406static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in,
407 int y, int h, const SwsPass *pass)
408{
409 SwsContext *sws = slice_ctx(pass, y);
410 SwsInternal *c = sws_internal(sws);
411 uint8_t *out_data[4];
412 frame_shift(out, y, out_data);
413
414 ff_swscale(c, (const uint8_t *const *) in->data, in->linesize, 0,
415 sws->src_h, out_data, out->linesize, y, h);
416}
417
418static void run_legacy_lut3d(const SwsFrame *out, const SwsFrame *in,
419 int y, int h, const SwsPass *pass)
420{
421 const SwsLut3D *lut = pass->graph->lut3d;
422 uint8_t *in_data[4], *out_data[4];
423 frame_shift(in, y, in_data);
424 frame_shift(out, y, out_data);
425
426 ff_sws_lut3d_apply_rgba64(lut, in_data[0], in->linesize[0], out_data[0],
427 out->linesize[0], out->width, h);
428}
429
430static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
431{
432 if (override == -513 || override == *chr_pos)
433 return;
434
435 if (!*warned) {
437 "Setting chroma position directly is deprecated, make sure "
438 "the frame is tagged with the correct chroma location.\n");
439 *warned = 1;
440 }
441
442 *chr_pos = override;
443}
444
445/* Takes over ownership of `sws` */
447 SwsPass *input, SwsPass **output)
448{
449 SwsInternal *c = sws_internal(sws);
450 const int src_w = sws->src_w, src_h = sws->src_h;
451 const int dst_w = sws->dst_w, dst_h = sws->dst_h;
452 const int unscaled = src_w == dst_w && src_h == 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 && unscaled)) {
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
530 ret = ff_sws_init_single_context(slice, NULL, NULL);
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 }
545
546 if (c->dstXYZ && !(c->srcXYZ && unscaled)) {
547 ret = ff_sws_graph_add_pass(graph, AV_PIX_FMT_RGB48, dst_w, dst_h, pass,
548 0, 1, run_rgb2xyz, NULL, c, NULL, &pass);
549 if (ret < 0)
550 return ret;
551 }
552
553 *output = pass;
554 return 0;
555}
556
557static int add_legacy_3dlut_pass(SwsGraph *graph, const SwsFormat *src,
558 SwsPass *input, SwsPass **output);
559
560static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src,
561 const SwsFormat *dst, const SwsLut3D *lut3d,
562 SwsPass *input, SwsPass **output)
563{
564 int ret, warned = 0;
565 SwsContext *const ctx = graph->ctx;
566 const SwsBackend backend = ff_sws_enabled_backends(ctx);
567 if (!(backend & SWS_BACKEND_LEGACY))
568 return AVERROR(ENOTSUP);
569 if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE)
570 return AVERROR(ENOTSUP);
571
572 /* Re-check this here because this might not be excluded if the caller was
573 * testing against multiple backends */
574 if (!sws_isSupportedInput(src->format) || !sws_isSupportedOutput(dst->format))
575 return AVERROR(ENOTSUP);
576
577 /* If we need to apply a 3D LUT, add it as an explicit input prepass */
578 if (lut3d) {
579 ret = add_legacy_3dlut_pass(graph, src, input, &input);
580 if (ret < 0)
581 return ret;
582
583 SwsFormat tmp = *src;
584 tmp.format = input->format;
585 tmp.color = lut3d->map.dst;
586 return add_legacy_sws_pass(graph, &tmp, dst, NULL, input, output);
587 }
588
590 if (!sws)
591 return AVERROR(ENOMEM);
592
593 sws->flags = ctx->flags;
594 sws->dither = ctx->dither;
595 sws->alpha_blend = ctx->alpha_blend;
596 sws->gamma_flag = ctx->gamma_flag;
597 sws->scaler = ctx->scaler;
598 sws->scaler_sub = ctx->scaler_sub;
599
600 sws->src_w = src->width;
601 sws->src_h = src->height;
602 sws->src_format = src->format;
603 sws->src_range = src->range == AVCOL_RANGE_JPEG;
604
605 sws->dst_w = dst->width;
606 sws->dst_h = dst->height;
607 sws->dst_format = dst->format;
608 sws->dst_range = dst->range == AVCOL_RANGE_JPEG;
611
612 graph->incomplete |= src->range == AVCOL_RANGE_UNSPECIFIED;
613 graph->incomplete |= dst->range == AVCOL_RANGE_UNSPECIFIED;
614
615 /* Allow overriding chroma position with the legacy API */
616 legacy_chr_pos(graph, &sws->src_h_chr_pos, ctx->src_h_chr_pos, &warned);
617 legacy_chr_pos(graph, &sws->src_v_chr_pos, ctx->src_v_chr_pos, &warned);
618 legacy_chr_pos(graph, &sws->dst_h_chr_pos, ctx->dst_h_chr_pos, &warned);
619 legacy_chr_pos(graph, &sws->dst_v_chr_pos, ctx->dst_v_chr_pos, &warned);
620
621 /* Explicitly strip chroma offsets when not subsampling, because it
622 * interferes with the operation of flags like SWS_FULL_CHR_H_INP */
623 if (!src->desc->log2_chroma_w)
624 sws->src_h_chr_pos = -513;
625 if (!src->desc->log2_chroma_h)
626 sws->src_v_chr_pos = -513;
627 if (!dst->desc->log2_chroma_w)
628 sws->dst_h_chr_pos = -513;
629 if (!dst->desc->log2_chroma_h)
630 sws->dst_v_chr_pos = -513;
631
632 for (int i = 0; i < SWS_NUM_SCALER_PARAMS; i++)
633 sws->scaler_params[i] = ctx->scaler_params[i];
634
635 ret = sws_init_context(sws, NULL, NULL);
636 if (ret < 0) {
637 sws_free_context(&sws);
638 return ret;
639 }
640
641 /* Set correct color matrices */
642 {
643 int in_full, out_full, brightness, contrast, saturation;
644 const int *inv_table, *table;
645 sws_getColorspaceDetails(sws, (int **)&inv_table, &in_full,
646 (int **)&table, &out_full,
647 &brightness, &contrast, &saturation);
648
649 inv_table = sws_getCoefficients(src->csp);
651
652 graph->incomplete |= src->csp != dst->csp &&
653 (src->csp == AVCOL_SPC_UNSPECIFIED ||
654 dst->csp == AVCOL_SPC_UNSPECIFIED);
655
656 sws_setColorspaceDetails(sws, inv_table, in_full, table, out_full,
657 brightness, contrast, saturation);
658 }
659
660 return init_legacy_subpass(graph, sws, input, output);
661}
662
663static int add_legacy_3dlut_pass(SwsGraph *graph, const SwsFormat *src,
664 SwsPass *input, SwsPass **output)
665{
666 int ret;
667
668 const SwsLut3D *lut3d = graph->lut3d;
669 if (!lut3d)
670 return 0;
671
672 const enum AVPixelFormat fmt = AV_PIX_FMT_RGBA64;
673 if (src->format != fmt) {
674 SwsFormat tmp = *src;
675 tmp.format = fmt;
676 ret = add_legacy_sws_pass(graph, src, &tmp, NULL, input, &input);
677 if (ret < 0)
678 return ret;
679 }
680
681 ret = ff_sws_graph_add_pass(graph, fmt, src->width, src->height,
682 input, 0, 1, run_legacy_lut3d, NULL, NULL, NULL,
683 output);
684 if (ret < 0)
685 return ret;
686
687 return 0;
688}
689
690/*********************************
691 * Format conversion and scaling *
692 *********************************/
693
694static int add_ops_convert_pass(SwsGraph *graph, const SwsFormat *src,
695 const SwsFormat *dst, const SwsLut3D *lut3d,
696 SwsPass *input, SwsPass **output)
697{
698#if CONFIG_UNSTABLE
699 SwsContext *ctx = graph->ctx;
700
701 /* Preemptively skip the ops list generation if the backend was
702 * constrained to the legacy implementation only. This would
703 * normally also fail in ff_sws_compile_pass() with the same
704 * error, but this way saves a bit of unnecessary overhead */
705 const SwsBackend backends = ff_sws_enabled_backends(ctx);
706 if (backends == SWS_BACKEND_LEGACY)
707 return AVERROR(ENOTSUP);
708
709 SwsOpList *ops;
710 int ret = ff_sws_op_list_generate(ctx, src, dst, lut3d, &ops, &graph->incomplete);
711 if (ret < 0)
712 return ret;
713
714 av_log(ctx, AV_LOG_VERBOSE, "Conversion pass for %s -> %s:\n",
716
717 av_log(ctx, AV_LOG_DEBUG, "Unoptimized operation list:\n");
719
721 return ff_sws_compile_pass(graph, NULL, &ops, flags, input, output);
722#else
723 return AVERROR(ENOTSUP);
724#endif
725}
726
728{
729 if (ctx->flags & SWS_UNSTABLE)
730 return true;
731 if (isFloat(src->format) || isFloat(dst->format))
732 return true; /* ops backend has better support for float formats */
733 return false; /* default to legacy for stability reasons */
734}
735
736static int add_convert_pass(SwsGraph *graph, const SwsFormat *src,
737 const SwsFormat *dst, const SwsLut3D *lut3d,
738 SwsPass *input, SwsPass **output)
739{
740 SwsContext *ctx = graph->ctx;
741 int ret;
742
743 if (prefer_ops_backend(ctx, src, dst)) {
744 ret = add_ops_convert_pass(graph, src, dst, lut3d, input, output);
745 if (ret == AVERROR(ENOTSUP))
746 ret = add_legacy_sws_pass(graph, src, dst, lut3d, input, output);
747 } else {
748 ret = add_legacy_sws_pass(graph, src, dst, lut3d, input, output);
749 if (ret == AVERROR(ENOTSUP))
750 ret = add_ops_convert_pass(graph, src, dst, lut3d, input, output);
751 }
752
753 return ret;
754}
755
756/**************************
757 * Gamut and tone mapping *
758 **************************/
759
761{
762 SwsColorMap map = {0};
763
764 /**
765 * Grayspace does not really have primaries, so just force the use of
766 * the equivalent other primary set to avoid a conversion. Technically,
767 * this does affect the weights used for the Grayscale conversion, but
768 * in practise, that should give the expected results more often than not.
769 */
770 if (isGray(dst->format)) {
771 dst->color = src->color;
772 } else if (isGray(src->format)) {
773 src->color = dst->color;
774 }
775
776 /* Fully infer color spaces before color mapping logic */
777 graph->incomplete |= ff_infer_colors(&src->color, &dst->color);
778
779 map.intent = graph->ctx->intent;
780 map.src = src->color;
781 map.dst = dst->color;
782
784 return 0;
785
786 if (src->hw_format != AV_PIX_FMT_NONE || dst->hw_format != AV_PIX_FMT_NONE)
787 return AVERROR(ENOTSUP);
788
789 graph->lut3d = ff_sws_lut3d_alloc();
790 if (!graph->lut3d)
791 return AVERROR(ENOMEM);
792
793 return ff_sws_lut3d_generate(graph->lut3d, &map);
794}
795
796/***************************************
797 * Main filter graph construction code *
798 ***************************************/
799
800static int init_passes(SwsGraph *graph)
801{
802 SwsFormat src = graph->src;
803 SwsFormat dst = graph->dst;
804 SwsPass *pass = NULL; /* read from main input image */
805 int ret;
806
807 ret = generate_3dlut(graph, &src, &dst);
808 if (ret < 0)
809 return ret;
810
811 if (!ff_fmt_equal(&src, &dst) || graph->lut3d) {
812 ret = add_convert_pass(graph, &src, &dst, graph->lut3d, pass, &pass);
813 if (ret < 0)
814 return ret;
815 }
816
817 if (!pass) {
818 /* No passes were added, so no operations were necessary */
819 graph->noop = 1;
820
821 const int nb_planes = av_pix_fmt_count_planes(dst.format);
822 for (int i = 0; i < nb_planes; i++)
823 graph->plane_copy[i] = i;
824
825 /* Add threaded memcpy pass */
826 return ff_sws_graph_add_pass(graph, dst.format, dst.width, dst.height,
827 pass, 0, 1, run_copy, NULL, NULL, NULL, &pass);
828 }
829
830 /* Compute end-to-end plane copy map */
831 for (int n = 0; n < graph->num_passes; n++) {
832 const SwsPass *pass = graph->passes[n];
833 /* This pass writes to an output buffer other than the image
834 * output, or copies from the output of a different pass */
835 if (pass->output->avframe || pass->input)
836 continue;
837 for (int i = 0; i < FF_ARRAY_ELEMS(graph->plane_copy); i++) {
838 const int idx = pass->output->plane_copy[i];
839 if (idx < 0)
840 continue;
841 if (graph->plane_copy[i] < 0) {
842 graph->plane_copy[i] = idx;
843 av_log(graph->ctx, AV_LOG_DEBUG, "Plane %d passthrough from "
844 "plane %d\n", i, idx);
845 } else {
846 av_assert0(graph->plane_copy[i] == idx);
847 }
848 }
849 }
850
851 return 0;
852}
853
854static int sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs,
855 int nb_threads)
856{
857 SwsGraph *graph = priv;
858 const SwsPass *pass = graph->exec.pass;
859 const int slice_y = jobnr * pass->slice_h;
860 const int slice_h = FFMIN(pass->slice_h, pass->lines - slice_y);
861
862 pass->run(graph->exec.output, graph->exec.input, slice_y, slice_h, pass);
863 return 0;
864}
865
867{
868 return av_mallocz(sizeof(SwsGraph));
869}
870
871static void graph_uninit(SwsGraph *graph)
872{
874
875 for (int i = 0; i < graph->num_passes; i++)
876 pass_free(graph->passes[i]);
877 av_free(graph->passes);
878
879 av_refstruct_unref(&graph->lut3d);
880
881 memset(graph, 0, sizeof(*graph));
882}
883
885 const SwsFormat *src)
886{
887 int ret;
888 if (graph->ctx) {
889 av_log(ctx, AV_LOG_ERROR, "Graph is already initialized\n");
890 return AVERROR(EINVAL);
891 }
892
893 graph->ctx = ctx;
894 graph->src = *src;
895 graph->dst = *dst;
896 graph->opts_copy = *ctx;
897 av_assert0(src->interlaced == dst->interlaced);
898 av_assert0(src->field == dst->field);
899 memset(graph->plane_copy, -1, sizeof(graph->plane_copy));
900
901 if (ctx->threads == 1) {
902 graph->num_threads = 1;
903 } else {
904 ret = avpriv_slicethread_create2(&graph->slicethread, (void *) graph,
905 sws_graph_worker, NULL, ctx->threads);
906 if (ret == AVERROR(ENOSYS)) {
907 /* Fall back to single threaded operation */
908 graph->num_threads = 1;
909 } else if (ret < 0) {
910 goto error;
911 } else {
912 graph->num_threads = ret;
913 }
914 }
915
916 ret = init_passes(graph);
917 if (ret < 0)
918 goto error;
919
920 /* Resolve output buffers for all intermediate passes */
921 for (int i = 0; i < graph->num_passes; i++) {
922 graph->backend |= graph->passes[i]->backend;
923 ret = pass_alloc_output(graph->passes[i]->input);
924 if (ret < 0)
925 goto error;
926 }
927
928 return 0;
929
930error:
931 graph_uninit(graph);
932 return ret;
933}
934
935void ff_sws_graph_rollback(SwsGraph *graph, int since_idx)
936{
937 for (int i = since_idx; i < graph->num_passes; i++)
938 pass_free(graph->passes[i]);
939 graph->num_passes = since_idx;
940}
941
943{
944 SwsGraph *graph = *pgraph;
945 if (!graph)
946 return;
947
948 graph_uninit(graph);
949 av_free(graph);
950 *pgraph = NULL;
951}
952
953/* Tests only options relevant to SwsGraph */
954static int opts_equal(const SwsContext *c1, const SwsContext *c2)
955{
956 return c1->flags == c2->flags &&
957 c1->threads == c2->threads &&
958 c1->dither == c2->dither &&
959 c1->alpha_blend == c2->alpha_blend &&
960 c1->gamma_flag == c2->gamma_flag &&
961 c1->src_h_chr_pos == c2->src_h_chr_pos &&
962 c1->src_v_chr_pos == c2->src_v_chr_pos &&
963 c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
964 c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
965 c1->intent == c2->intent &&
966 c1->scaler == c2->scaler &&
967 c1->scaler_sub == c2->scaler_sub &&
968 c1->backends == c2->backends &&
969 !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
970
971}
972
974 const SwsFormat *src)
975{
976 if (ff_fmt_equal(&graph->src, src) && ff_fmt_equal(&graph->dst, dst) &&
977 opts_equal(ctx, &graph->opts_copy))
978 {
979 ff_sws_graph_update_metadata(graph, &src->color);
980 return 0;
981 }
982
983 graph_uninit(graph);
984 return ff_sws_graph_init(graph, ctx, dst, src);
985}
986
988{
989 if (!color)
990 return;
991
993
994 if (graph->lut3d)
995 ff_sws_lut3d_update(graph->lut3d, &graph->src.color);
996}
997
998static void get_field(SwsGraph *graph, const SwsFormat *fmt,
999 const AVFrame *avframe, SwsFrame *frame)
1000{
1002
1003 if (!(avframe->flags & AV_FRAME_FLAG_INTERLACED)) {
1004 av_assert1(!fmt->field);
1005 return;
1006 }
1007
1008 if (fmt->field == FIELD_BOTTOM) {
1009 /* Odd rows, offset by one line */
1011 for (int i = 0; i < 4; i++) {
1012 if (frame->data[i])
1013 frame->data[i] += frame->linesize[i];
1014 if (desc->flags & AV_PIX_FMT_FLAG_PAL)
1015 break;
1016 }
1017 }
1018
1019 /* Take only every second line */
1020 for (int i = 0; i < 4; i++)
1021 frame->linesize[i] <<= 1;
1022
1023 frame->height = (frame->height + (fmt->field == FIELD_TOP)) >> 1;
1024}
1025
1026int ff_sws_graph_run(SwsGraph *graph, const AVFrame *dst, const AVFrame *src)
1027{
1028 av_assert0(dst->format == graph->dst.hw_format || dst->format == graph->dst.format);
1029 av_assert0(src->format == graph->src.hw_format || src->format == graph->src.format);
1030
1031 SwsFrame src_field, dst_field;
1032 get_field(graph, &graph->dst, dst, &dst_field);
1033 get_field(graph, &graph->src, src, &src_field);
1034
1035 for (int i = 0; i < graph->num_passes; i++) {
1036 const SwsPass *pass = graph->passes[i];
1037 graph->exec.pass = pass;
1038 graph->exec.input = pass->input ? &pass->input->output->frame : &src_field;
1039 graph->exec.output = pass->output->avframe ? &pass->output->frame : &dst_field;
1040 if (pass->setup) {
1041 int ret = pass->setup(graph->exec.output, graph->exec.input, pass);
1042 if (ret < 0)
1043 return ret;
1044 }
1045
1046 if (pass->num_slices == 1) {
1047 pass->run(graph->exec.output, graph->exec.input, 0, pass->lines, pass);
1048 } else {
1050 }
1051 }
1052
1053 return 0;
1054}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
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
@ 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:125
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...
static void ff_color_update_dynamic(SwsColor *dst, const SwsColor *src)
Definition format.h:70
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:987
static void run_rgb2xyz(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition graph.c:338
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:884
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:727
static void legacy_chr_pos(SwsGraph *graph, int *chr_pos, int override, int *warned)
Definition graph.c:430
static int add_ops_convert_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, const SwsLut3D *lut3d, SwsPass *input, SwsPass **output)
Definition graph.c:694
static int sws_graph_worker(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
Definition graph.c:854
static void run_rgb0(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition graph.c:308
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:935
static int add_legacy_3dlut_pass(SwsGraph *graph, const SwsFormat *src, SwsPass *input, SwsPass **output)
Definition graph.c:663
static int add_convert_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, const SwsLut3D *lut3d, SwsPass *input, SwsPass **output)
Definition graph.c:736
static void graph_uninit(SwsGraph *graph)
Definition graph.c:871
static int opts_equal(const SwsContext *c1, const SwsContext *c2)
Definition graph.c:954
static void run_legacy_unscaled(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition graph.c:394
static SwsContext * slice_ctx(const SwsPass *pass, int y)
Definition graph.c:375
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:1026
static void run_legacy_swscale(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition graph.c:406
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:418
static int add_legacy_sws_pass(SwsGraph *graph, const SwsFormat *src, const SwsFormat *dst, const SwsLut3D *lut3d, SwsPass *input, SwsPass **output)
Definition graph.c:560
SwsGraph * ff_sws_graph_alloc(void)
Allocate an empty SwsGraph.
Definition graph.c:866
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:973
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:446
void ff_sws_graph_free(SwsGraph **pgraph)
Uninitialize any state associate with this filter graph and free it.
Definition graph.c:942
static void run_xyz2rgb(const SwsFrame *out, const SwsFrame *in, int y, int h, const SwsPass *pass)
Definition graph.c:329
static void free_legacy_swscale(void *priv)
Definition graph.c:353
static int generate_3dlut(SwsGraph *graph, SwsFormat *src, SwsFormat *dst)
Definition graph.c:760
static void get_field(SwsGraph *graph, const SwsFormat *fmt, const AVFrame *avframe, SwsFrame *frame)
Definition graph.c:998
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:359
static int init_passes(SwsGraph *graph)
Definition graph.c:800
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:139
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition buffer.c:103
AVBufferRef * av_buffer_alloc(size_t size)
Allocate an AVBuffer of the given size using av_malloc().
Definition buffer.c:77
#define AVERROR(e)
Definition error.h:45
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition frame.h:695
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition frame.c:496
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
#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:313
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_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:1007
av_warn_unused_result int sws_init_context(SwsContext *sws_context, SwsFilter *srcFilter, SwsFilter *dstFilter)
Initialize the swscaler context sws_context.
Definition utils.c:1884
SwsContext * sws_alloc_context(void)
Allocate an empty SwsContext and set its fields to default values.
Definition utils.c:1032
void sws_free_context(SwsContext **ctx)
Free the context and everything associated with it, and write NULL to the provided pointer.
Definition utils.c:2321
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:849
@ 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:2217
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition hwcontext.c:337
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition hwcontext.c:263
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
const VDPAUPixFmtMap * map
static const int sizes[][2]
Definition img2dec.c:62
misc image utilities
size_t av_cpu_max_align(void)
Get the maximum data alignment that may be required by FFmpeg.
Definition cpu.c:287
const char * desc
Definition libsvtav1.c:83
bool ff_infer_colors(SwsColor *src, SwsColor *dst)
Definition format.c:537
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:554
void ff_sws_frame_from_avframe(SwsFrame *dst, const AVFrame *src)
Initialize a SwsFrame from an AVFrame.
Definition format.c:707
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:264
Memory handling functions.
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_print(void *log, int lev, int lev_extra, const SwsOpList *ops)
Print out the contents of an operation list.
Definition ops.c:987
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:3500
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:3380
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#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:749
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
#define AV_PIX_FMT_RGBA64
Definition pixfmt.h:535
#define AV_PIX_FMT_RGB48
Definition pixfmt.h:531
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
@ AVCOL_SPC_UNSPECIFIED
Definition pixfmt.h:709
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:120
void av_refstruct_replace(void *dstp, const void *src)
Ensure *dstp refers to the same object as src.
Definition refstruct.c:160
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:472
int width
Definition frame.h:544
int height
Definition frame.h:544
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition frame.h:716
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition frame.h:559
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
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:87
enum AVPixelFormat format
Definition format.h:81
int field
Definition format.h:80
enum AVPixelFormat hw_format
Definition format.h:82
Represents a view into a single field of frame data.
Definition format.h:236
uint8_t * data[4]
Definition format.h:238
int linesize[4]
Definition format.h:239
enum AVPixelFormat format
Definition format.h:245
Filter graph, which represents a 'baked' pixel format conversion.
Definition graph.h:132
bool noop
Definition graph.h:137
const SwsFrame * output
Definition graph.h:179
SwsPass ** passes
Sorted sequence of filter passes to apply.
Definition graph.h:153
bool incomplete
Definition graph.h:136
SwsFormat src
Currently active format and processing parameters.
Definition graph.h:165
int num_passes
Definition graph.h:154
const SwsPass * pass
Definition graph.h:177
SwsContext opts_copy
Cached copy of the public options that were used to construct this SwsGraph.
Definition graph.h:160
SwsLut3D * lut3d
3DLUT state used for gamut/tone mapping.
Definition graph.h:170
SwsFormat dst
Definition graph.h:165
SwsContext * ctx
Definition graph.h:133
int plane_copy[4]
Map of planes which directly copied from the input.
Definition graph.h:150
int num_threads
Definition graph.h:135
AVSliceThread * slicethread
Definition graph.h:134
SwsBackend backend
Definition graph.h:138
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:178
uint32_t pal_rgb[256]
uint32_t pal_yuv[256]
SwsContext ** slice_ctx
Append a set of operations for applying a gamut/tone mapping 3D LUT to the pixels.
Definition lut3d.h:50
SwsColorMap map
Definition lut3d.h:51
Helper struct for representing a list of operations.
Definition ops.h:293
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:98
SwsPass * input
Filter input.
Definition graph.h:104
void * priv
Definition graph.h:121
enum AVPixelFormat format
Definition graph.h:95
int lines
Definition graph.h:96
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:109
void(* free)(void *priv)
Optional private state and associated free() function.
Definition graph.h:120
SwsBackend backend
Definition graph.h:94
SwsPassSetup setup
Called once from the main thread before running the filter.
Definition graph.h:115
int slice_h
Definition graph.h:97
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:263
void ff_update_palette(SwsInternal *c, const uint32_t *pal)
Definition swscale.c:873
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:1137
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)
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:32
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
RefStruct is an API for creating reference-counted objects with minimal overhead.
Definition refstruct.h:58
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:74