FFmpeg
Loading...
Searching...
No Matches
vf_libplacebo.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <math.h>
20
21#include "libavutil/avassert.h"
22#include "libavutil/avstring.h"
23#include "libavutil/eval.h"
24#include "libavutil/fifo.h"
25#include "libavutil/file.h"
26#include "libavutil/frame.h"
27#include "libavutil/mem.h"
28#include "libavutil/opt.h"
30#include "formats.h"
31#include "filters.h"
32#include "video.h"
33#include "vulkan_filter.h"
34#include "scale_eval.h"
35
36#include <libplacebo/options.h>
37#include <libplacebo/renderer.h>
38#include <libplacebo/utils/libav.h>
39#include <libplacebo/utils/frame_queue.h>
40#include <libplacebo/vulkan.h>
41
42enum {
56};
57
58enum {
69};
70
71static const char *const var_names[] = {
72 "in_idx", "idx",///< index of input
73 "in_w", "iw", ///< width of the input video frame
74 "in_h", "ih", ///< height of the input video frame
75 "out_w", "ow", ///< width of the output video frame
76 "out_h", "oh", ///< height of the output video frame
77 "crop_w", "cw", ///< evaluated input crop width
78 "crop_h", "ch", ///< evaluated input crop height
79 "pos_w", "pw", ///< evaluated output placement width
80 "pos_h", "ph", ///< evaluated output placement height
81 "a", ///< iw/ih
82 "sar", ///< input pixel aspect ratio
83 "dar", ///< output pixel aspect ratio
84 "hsub", ///< input horizontal subsampling factor
85 "vsub", ///< input vertical subsampling factor
86 "ohsub", ///< output horizontal subsampling factor
87 "ovsub", ///< output vertical subsampling factor
88 "in_t", "t", ///< input frame pts
89 "out_t", "ot", ///< output frame pts
90 "n", ///< number of frame
91 NULL,
92};
93
116
117/* per-input dynamic filter state */
118typedef struct LibplaceboInput {
119 int idx;
120 pl_renderer renderer;
121 pl_queue queue;
122 enum pl_queue_status qstatus;
123 struct pl_frame_mix mix; ///< temporary storage
124 AVFifo *out_pts; ///< timestamps of wanted output frames
128
137
143
144typedef struct LibplaceboContext {
145 /* lavfi vulkan*/
147
148 /* libplacebo */
149 pl_log log;
150 pl_vulkan vulkan;
151 pl_gpu gpu;
152 pl_tex tex[4];
153 struct pl_custom_lut *lut;
154
155 /* dedicated renderer for linear output composition */
156 pl_renderer linear_rr;
158
159 /* input state */
163
164 /* settings */
167 uint8_t fillcolor[4];
169 char *w_expr;
170 char *h_expr;
172 AVRational fps; ///< parsed FPS, or 0/0 for "none"
177 // Parsed expressions for input/output crop
183 /* enum pl_lut_type */
201
202 pl_cache cache;
205
207
208 /* pl_render_params */
209 pl_options opts;
210 char *upscaler;
220
221 /* pl_deinterlace_params */
225
226 /* pl_deband_params */
232
233 /* pl_color_adjustment */
235 float contrast;
237 float hue;
238 float gamma;
240
241 /* pl_peak_detect_params */
247
248 /* pl_color_map_params */
256
257 /* pl_dither_params */
261
262 /* pl_cone_params */
263 int cones;
264 float cone_str;
265
266 /* custom shaders */
270 const struct pl_hook *hooks[2];
273
274static inline enum pl_log_level get_log_level(void)
275{
276 int av_lev = av_log_get_level();
277 return av_lev >= AV_LOG_TRACE ? PL_LOG_TRACE :
278 av_lev >= AV_LOG_DEBUG ? PL_LOG_DEBUG :
279 av_lev >= AV_LOG_VERBOSE ? PL_LOG_INFO :
280 av_lev >= AV_LOG_WARNING ? PL_LOG_WARN :
281 av_lev >= AV_LOG_ERROR ? PL_LOG_ERR :
282 av_lev >= AV_LOG_FATAL ? PL_LOG_FATAL :
283 PL_LOG_NONE;
284}
285
286static void pl_av_log(void *log_ctx, enum pl_log_level level, const char *msg)
287{
288 int av_lev;
289
290 switch (level) {
291 case PL_LOG_FATAL: av_lev = AV_LOG_FATAL; break;
292 case PL_LOG_ERR: av_lev = AV_LOG_ERROR; break;
293 case PL_LOG_WARN: av_lev = AV_LOG_WARNING; break;
294 case PL_LOG_INFO: av_lev = AV_LOG_VERBOSE; break;
295 case PL_LOG_DEBUG: av_lev = AV_LOG_DEBUG; break;
296 case PL_LOG_TRACE: av_lev = AV_LOG_TRACE; break;
297 default: return;
298 }
299
300 av_log(log_ctx, av_lev, "%s\n", msg);
301}
302
303static const struct pl_tone_map_function *get_tonemapping_func(int tm) {
304 switch (tm) {
305 case TONE_MAP_AUTO: return &pl_tone_map_auto;
306 case TONE_MAP_CLIP: return &pl_tone_map_clip;
307 case TONE_MAP_ST2094_40: return &pl_tone_map_st2094_40;
308 case TONE_MAP_ST2094_10: return &pl_tone_map_st2094_10;
309 case TONE_MAP_BT2390: return &pl_tone_map_bt2390;
310 case TONE_MAP_BT2446A: return &pl_tone_map_bt2446a;
311 case TONE_MAP_SPLINE: return &pl_tone_map_spline;
312 case TONE_MAP_REINHARD: return &pl_tone_map_reinhard;
313 case TONE_MAP_MOBIUS: return &pl_tone_map_mobius;
314 case TONE_MAP_HABLE: return &pl_tone_map_hable;
315 case TONE_MAP_GAMMA: return &pl_tone_map_gamma;
316 case TONE_MAP_LINEAR: return &pl_tone_map_linear;
317 default: av_assert0(0);
318 }
319}
320
321static void set_gamut_mode(struct pl_color_map_params *p, int gamut_mode)
322{
323 switch (gamut_mode) {
324 case GAMUT_MAP_CLIP: p->gamut_mapping = &pl_gamut_map_clip; return;
325 case GAMUT_MAP_PERCEPTUAL: p->gamut_mapping = &pl_gamut_map_perceptual; return;
326 case GAMUT_MAP_RELATIVE: p->gamut_mapping = &pl_gamut_map_relative; return;
327 case GAMUT_MAP_SATURATION: p->gamut_mapping = &pl_gamut_map_saturation; return;
328 case GAMUT_MAP_ABSOLUTE: p->gamut_mapping = &pl_gamut_map_absolute; return;
329 case GAMUT_MAP_DESATURATE: p->gamut_mapping = &pl_gamut_map_desaturate; return;
330 case GAMUT_MAP_DARKEN: p->gamut_mapping = &pl_gamut_map_darken; return;
331 case GAMUT_MAP_HIGHLIGHT: p->gamut_mapping = &pl_gamut_map_highlight; return;
332 case GAMUT_MAP_LINEAR: p->gamut_mapping = &pl_gamut_map_linear; return;
333 }
334
335 av_assert0(0);
336};
337
338static int find_scaler(AVFilterContext *avctx,
339 const struct pl_filter_config **opt,
340 const char *name, int frame_mixing)
341{
342 const struct pl_filter_preset *preset, *presets_avail;
343 presets_avail = frame_mixing ? pl_frame_mixers : pl_scale_filters;
344
345 if (!strcmp(name, "help")) {
346 av_log(avctx, AV_LOG_INFO, "Available scaler presets:\n");
347 for (preset = presets_avail; preset->name; preset++)
348 av_log(avctx, AV_LOG_INFO, " %s\n", preset->name);
349 return AVERROR_EXIT;
350 }
351
352 for (preset = presets_avail; preset->name; preset++) {
353 if (!strcmp(name, preset->name)) {
354 *opt = preset->filter;
355 return 0;
356 }
357 }
358
359 av_log(avctx, AV_LOG_ERROR, "No such scaler preset '%s'.\n", name);
360 return AVERROR(EINVAL);
361}
362
364{
365 LibplaceboContext *s = avctx->priv;
366 int ret;
367 uint8_t *lutbuf;
368 size_t lutbuf_size;
369
370 if ((ret = av_file_map(s->lut_filename, &lutbuf, &lutbuf_size, 0, s)) < 0) {
371 av_log(avctx, AV_LOG_ERROR,
372 "The LUT file '%s' could not be read: %s\n",
373 s->lut_filename, av_err2str(ret));
374 return ret;
375 }
376
377 s->lut = pl_lut_parse_cube(s->log, lutbuf, lutbuf_size);
378 av_file_unmap(lutbuf, lutbuf_size);
379 if (!s->lut)
380 return AVERROR(EINVAL);
381 return 0;
382}
383
385{
386 int err = 0;
387 LibplaceboContext *s = ctx->priv;
389 pl_options opts = s->opts;
390 int gamut_mode = s->gamut_mode;
391
392 opts->deinterlace_params = *pl_deinterlace_params(
393 .algo = s->deinterlace,
394 .skip_spatial_check = s->skip_spatial_check,
395 );
396
397 opts->deband_params = *pl_deband_params(
398 .iterations = s->deband_iterations,
399 .threshold = s->deband_threshold,
400 .radius = s->deband_radius,
401 .grain = s->deband_grain,
402 );
403
404 opts->sigmoid_params = pl_sigmoid_default_params;
405
406 opts->color_adjustment = (struct pl_color_adjustment) {
407 .brightness = s->brightness,
408 .contrast = s->contrast,
409 .saturation = s->saturation,
410 .hue = s->hue,
411 .gamma = s->gamma,
412 // libplacebo uses a normalized/relative scale for CCT
413 .temperature = (s->temperature - 6500.0) / 3500.0,
414 };
415
416 opts->peak_detect_params = (struct pl_peak_detect_params) {
417 PL_PEAK_DETECT_DEFAULTS
418 .smoothing_period = s->smoothing,
419 .scene_threshold_low = s->scene_low,
420 .scene_threshold_high = s->scene_high,
421 .percentile = s->percentile,
422 };
423
424 opts->color_map_params = (struct pl_color_map_params) {
425 PL_COLOR_MAP_DEFAULTS
426 .tone_mapping_function = get_tonemapping_func(s->tonemapping),
427 .tone_mapping_param = s->tonemapping_param,
428 .inverse_tone_mapping = s->inverse_tonemapping,
429 .lut_size = s->tonemapping_lut_size,
430 .contrast_recovery = s->contrast_recovery,
431 .contrast_smoothness = s->contrast_smoothness,
432 };
433
434 set_gamut_mode(&opts->color_map_params, gamut_mode);
435
436 opts->dither_params = *pl_dither_params(
437 .method = s->dithering,
438 .lut_size = s->dither_lut_size,
439 .temporal = s->dither_temporal,
440 );
441
442 opts->cone_params = *pl_cone_params(
443 .cones = s->cones,
444 .strength = s->cone_str,
445 );
446
447 opts->params = (struct pl_render_params) {
448 PL_RENDER_DEFAULTS
449 .antiringing_strength = s->antiringing,
450 .background_transparency = 1.0f - (float) s->fillcolor[3] / UINT8_MAX,
451 .background_color = {
452 (float) s->fillcolor[0] / UINT8_MAX,
453 (float) s->fillcolor[1] / UINT8_MAX,
454 (float) s->fillcolor[2] / UINT8_MAX,
455 },
456 .corner_rounding = s->corner_rounding,
457
458 .deinterlace_params = &opts->deinterlace_params,
459 .deband_params = s->deband ? &opts->deband_params : NULL,
460 .sigmoid_params = s->sigmoid ? &opts->sigmoid_params : NULL,
461 .color_adjustment = &opts->color_adjustment,
462 .peak_detect_params = s->peakdetect ? &opts->peak_detect_params : NULL,
463 .color_map_params = &opts->color_map_params,
464 .dither_params = s->dithering >= 0 ? &opts->dither_params : NULL,
465 .cone_params = s->cones ? &opts->cone_params : NULL,
466
467 .hooks = s->hooks,
468 .num_hooks = s->num_hooks,
469
470 .skip_anti_aliasing = s->skip_aa,
471 .disable_linear_scaling = s->disable_linear,
472 .disable_builtin_scalers = s->disable_builtin,
473 .force_dither = s->force_dither,
474 .disable_fbos = s->disable_fbos,
475 };
476
477 RET(find_scaler(ctx, &opts->params.upscaler, s->upscaler, 0));
478 RET(find_scaler(ctx, &opts->params.downscaler, s->downscaler, 0));
479 RET(find_scaler(ctx, &opts->params.frame_mixer, s->frame_mixer, 1));
480
481 while ((e = av_dict_get(s->extra_opts, "", e, AV_DICT_IGNORE_SUFFIX))) {
482 if (!pl_options_set_str(s->opts, e->key, e->value)) {
483 err = AVERROR(EINVAL);
484 goto fail;
485 }
486 }
487
488 return 0;
489
490fail:
491 return err;
492}
493
494static int parse_shader(AVFilterContext *avctx, const void *shader, size_t len)
495{
496 LibplaceboContext *s = avctx->priv;
497 const struct pl_hook *hook;
498
499 hook = pl_mpv_user_shader_parse(s->gpu, shader, len);
500 if (!hook) {
501 av_log(avctx, AV_LOG_ERROR, "Failed parsing custom shader!\n");
502 return AVERROR(EINVAL);
503 }
504
505 s->hooks[s->num_hooks++] = hook;
506 return update_settings(avctx);
507}
508
509static void libplacebo_uninit(AVFilterContext *avctx);
510static int libplacebo_config_input(AVFilterLink *inlink);
511static int init_vulkan(AVFilterContext *avctx, const AVVulkanDeviceContext *hwctx);
512
514{
515 int err = 0;
516 LibplaceboContext *s = avctx->priv;
517
518 if (s->normalize_sar && s->fit_mode != FIT_FILL) {
519 av_log(avctx, AV_LOG_WARNING, "normalize_sar has no effect when using "
520 "a fit mode other than 'fill'\n");
521 }
522
523 /* Create libplacebo log context */
524 s->log = pl_log_create(PL_API_VER, pl_log_params(
525 .log_level = get_log_level(),
526 .log_cb = pl_av_log,
527 .log_priv = s,
528 ));
529
530 if (!s->log)
531 return AVERROR(ENOMEM);
532
533 s->opts = pl_options_alloc(s->log);
534 if (!s->opts) {
535 libplacebo_uninit(avctx);
536 return AVERROR(ENOMEM);
537 }
538
539 if (s->shader_cache && s->shader_cache[0]) {
540 s->cache = pl_cache_create(pl_cache_params(
541 .log = s->log,
542 .get = pl_cache_get_file,
543 .set = pl_cache_set_file,
544 .priv = s->shader_cache,
545 ));
546 if (!s->cache) {
547 libplacebo_uninit(avctx);
548 return AVERROR(ENOMEM);
549 }
550 }
551
552 if (s->out_format_string) {
553 s->out_format = av_get_pix_fmt(s->out_format_string);
554 if (s->out_format == AV_PIX_FMT_NONE) {
555 av_log(avctx, AV_LOG_ERROR, "Invalid output format: %s\n",
556 s->out_format_string);
557 libplacebo_uninit(avctx);
558 return AVERROR(EINVAL);
559 }
560 } else {
561 s->out_format = AV_PIX_FMT_NONE;
562 }
563
564 for (int i = 0; i < s->nb_inputs; i++) {
565 AVFilterPad pad = {
566 .name = av_asprintf("input%d", i),
567 .type = AVMEDIA_TYPE_VIDEO,
568 .config_props = &libplacebo_config_input,
569 };
570 if (!pad.name)
571 return AVERROR(ENOMEM);
572 RET(ff_append_inpad_free_name(avctx, &pad));
573 }
574
575 RET(update_settings(avctx));
576 RET(av_expr_parse(&s->crop_x_pexpr, s->crop_x_expr, var_names,
577 NULL, NULL, NULL, NULL, 0, s));
578 RET(av_expr_parse(&s->crop_y_pexpr, s->crop_y_expr, var_names,
579 NULL, NULL, NULL, NULL, 0, s));
580 RET(av_expr_parse(&s->crop_w_pexpr, s->crop_w_expr, var_names,
581 NULL, NULL, NULL, NULL, 0, s));
582 RET(av_expr_parse(&s->crop_h_pexpr, s->crop_h_expr, var_names,
583 NULL, NULL, NULL, NULL, 0, s));
584 RET(av_expr_parse(&s->pos_x_pexpr, s->pos_x_expr, var_names,
585 NULL, NULL, NULL, NULL, 0, s));
586 RET(av_expr_parse(&s->pos_y_pexpr, s->pos_y_expr, var_names,
587 NULL, NULL, NULL, NULL, 0, s));
588 RET(av_expr_parse(&s->pos_w_pexpr, s->pos_w_expr, var_names,
589 NULL, NULL, NULL, NULL, 0, s));
590 RET(av_expr_parse(&s->pos_h_pexpr, s->pos_h_expr, var_names,
591 NULL, NULL, NULL, NULL, 0, s));
592
593 if (strcmp(s->fps_string, "none") != 0)
594 RET(av_parse_video_rate(&s->fps, s->fps_string));
595
596 /* if we are told to inherit the input link's device, ignore the global
597 * hw_device_ctx even if it would be compatible. This ensure consistent
598 * behaviour when the flag is set. */
599 if (!s->inherit_device) {
600 const AVVulkanDeviceContext *vkhwctx = NULL;
601 if (avctx->hw_device_ctx) {
602 const AVHWDeviceContext *avhwctx = (void *) avctx->hw_device_ctx->data;
603 if (avhwctx->type == AV_HWDEVICE_TYPE_VULKAN)
604 vkhwctx = avhwctx->hwctx;
605 }
606 RET(init_vulkan(avctx, vkhwctx));
607 }
608
609 return 0;
610
611fail:
612 return err;
613}
614
615static void lock_queue(void *priv, uint32_t qf, uint32_t qidx)
616{
617 AVHWDeviceContext *avhwctx = priv;
618 const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
619#if FF_API_VULKAN_SYNC_QUEUES
621 hwctx->lock_queue(avhwctx, qf, qidx);
623#endif
624}
625
626static void unlock_queue(void *priv, uint32_t qf, uint32_t qidx)
627{
628 AVHWDeviceContext *avhwctx = priv;
629 const AVVulkanDeviceContext *hwctx = avhwctx->hwctx;
630#if FF_API_VULKAN_SYNC_QUEUES
632 hwctx->unlock_queue(avhwctx, qf, qidx);
634#endif
635}
636
637static int input_init(AVFilterContext *avctx, LibplaceboInput *input, int idx)
638{
639 LibplaceboContext *s = avctx->priv;
640
642 if (!input->out_pts)
643 return AVERROR(ENOMEM);
644 input->queue = pl_queue_create(s->gpu);
645 input->renderer = pl_renderer_create(s->log, s->gpu);
646 input->idx = idx;
647
648 return 0;
649}
650
651static void input_uninit(LibplaceboInput *input)
652{
653 pl_renderer_destroy(&input->renderer);
654 pl_queue_destroy(&input->queue);
655 av_fifo_freep2(&input->out_pts);
656}
657
658static int copy_pl_queue(const AVVulkanDeviceContext *hwctx,
660 struct pl_vulkan_queue *pl_qf)
661{
662 pl_qf->index = qf->idx;
663 pl_qf->count = qf->num;
664#if PL_API_VER >= 365
665 pl_qf->flags = hwctx->queue_flags;
666#else
667 if (hwctx->queue_flags != 0)
668 return AVERROR(EINVAL); // prevent undefined behavior
669#endif
670 return 0;
671}
672
673static int init_vulkan(AVFilterContext *avctx, const AVVulkanDeviceContext *hwctx)
674{
675 int err = 0;
676 LibplaceboContext *s = avctx->priv;
677 uint8_t *buf = NULL;
678 size_t buf_len;
679
680 if (hwctx) {
681 struct pl_vulkan_import_params import_params = {
682 .instance = hwctx->inst,
683 .get_proc_addr = hwctx->get_proc_addr,
684 .phys_device = hwctx->phys_dev,
685 .device = hwctx->act_dev,
686 .extensions = hwctx->enabled_dev_extensions,
687 .num_extensions = hwctx->nb_enabled_dev_extensions,
688 .features = &hwctx->device_features,
689 .lock_queue = lock_queue,
690 .unlock_queue = unlock_queue,
691 .queue_ctx = avctx->hw_device_ctx->data,
692 .queue_graphics = { VK_QUEUE_FAMILY_IGNORED },
693 .queue_compute = { VK_QUEUE_FAMILY_IGNORED },
694 .queue_transfer = { VK_QUEUE_FAMILY_IGNORED },
695 /* This is the highest version created by hwcontext_vulkan.c */
696 .max_api_version = VK_API_VERSION_1_3,
697 };
698 for (int i = 0; i < hwctx->nb_qf; i++) {
699 const AVVulkanDeviceQueueFamily *qf = &hwctx->qf[i];
700 if (qf->flags & VK_QUEUE_GRAPHICS_BIT)
701 RET(copy_pl_queue(hwctx, qf, &import_params.queue_graphics));
702 if (qf->flags & VK_QUEUE_COMPUTE_BIT)
703 RET(copy_pl_queue(hwctx, qf, &import_params.queue_compute));
704 if (qf->flags & VK_QUEUE_TRANSFER_BIT)
705 RET(copy_pl_queue(hwctx, qf, &import_params.queue_transfer));
706 }
707
708 /* Import libavfilter vulkan context into libplacebo */
709 s->vulkan = pl_vulkan_import(s->log, &import_params);
710 s->have_hwdevice = 1;
711 } else {
712 s->vulkan = pl_vulkan_create(s->log, pl_vulkan_params(
713 .queue_count = 0, /* enable all queues for parallelization */
714 ));
715 }
716
717 if (!s->vulkan) {
718 av_log(avctx, AV_LOG_ERROR, "Failed %s Vulkan device!\n",
719 hwctx ? "importing" : "creating");
720 err = AVERROR_EXTERNAL;
721 goto fail;
722 }
723
724 s->gpu = s->vulkan->gpu;
725 pl_gpu_set_cache(s->gpu, s->cache);
726
727 /* Parse the user shaders, if requested */
728 if (s->shader_bin_len)
729 RET(parse_shader(avctx, s->shader_bin, s->shader_bin_len));
730
731 if (s->shader_path && s->shader_path[0]) {
732 RET(av_file_map(s->shader_path, &buf, &buf_len, 0, s));
733 RET(parse_shader(avctx, buf, buf_len));
734 }
735
736 if (s->lut_filename)
737 RET(parse_custom_lut(avctx));
738
739 /* Initialize inputs */
740 s->inputs = av_calloc(s->nb_inputs, sizeof(*s->inputs));
741 if (!s->inputs)
742 return AVERROR(ENOMEM);
743 for (int i = 0; i < s->nb_inputs; i++)
744 RET(input_init(avctx, &s->inputs[i], i));
745 s->nb_active = s->nb_inputs;
746 s->linear_rr = pl_renderer_create(s->log, s->gpu);
747
748 /* fall through */
749fail:
750 if (buf)
751 av_file_unmap(buf, buf_len);
752 return err;
753}
754
756{
757 LibplaceboContext *s = avctx->priv;
758
759 for (int i = 0; i < FF_ARRAY_ELEMS(s->tex); i++)
760 pl_tex_destroy(s->gpu, &s->tex[i]);
761 for (int i = 0; i < s->num_hooks; i++)
762 pl_mpv_user_shader_destroy(&s->hooks[i]);
763 if (s->inputs) {
764 for (int i = 0; i < s->nb_inputs; i++)
765 input_uninit(&s->inputs[i]);
766 av_freep(&s->inputs);
767 }
768
769 pl_lut_free(&s->lut);
770 pl_cache_destroy(&s->cache);
771 pl_renderer_destroy(&s->linear_rr);
772 pl_tex_destroy(s->gpu, &s->linear_tex);
773 pl_options_free(&s->opts);
774 pl_vulkan_destroy(&s->vulkan);
775 pl_log_destroy(&s->log);
776 ff_vk_uninit(&s->vkctx);
777 s->gpu = NULL;
778
779 av_expr_free(s->crop_x_pexpr);
780 av_expr_free(s->crop_y_pexpr);
781 av_expr_free(s->crop_w_pexpr);
782 av_expr_free(s->crop_h_pexpr);
783 av_expr_free(s->pos_x_pexpr);
784 av_expr_free(s->pos_y_pexpr);
785 av_expr_free(s->pos_w_pexpr);
786 av_expr_free(s->pos_h_pexpr);
787}
788
789static int libplacebo_process_command(AVFilterContext *ctx, const char *cmd,
790 const char *arg, char *res, int res_len,
791 int flags)
792{
793 int err = 0;
794 RET(ff_filter_process_command(ctx, cmd, arg, res, res_len, flags));
796 return 0;
797
798fail:
799 return err;
800}
801
802static const AVFrame *ref_frame(const struct pl_frame_mix *mix)
803{
804 for (int i = 0; i < mix->num_frames; i++) {
805 if (i+1 == mix->num_frames || mix->timestamps[i+1] > 0)
806 return pl_get_mapped_avframe(mix->frames[i]);
807 }
808 return NULL;
809}
810
811static inline double q2d_fallback(AVRational q, const double def)
812{
813 return (q.num && q.den) ? av_q2d(q) : def;
814}
815
817 struct pl_frame *target, double target_pts)
818{
819 FilterLink *outl = ff_filter_link(ctx->outputs[0]);
820 LibplaceboContext *s = ctx->priv;
821 const AVFilterLink *outlink = ctx->outputs[0];
822 const AVFilterLink *inlink = ctx->inputs[in->idx];
823 const AVFrame *ref = ref_frame(&in->mix);
824
825 for (int i = 0; i < in->mix.num_frames; i++) {
826 // Mutate the `pl_frame.crop` fields in-place. This is fine because we
827 // own the entire pl_queue, and hence, the pointed-at frames.
828 struct pl_frame *image = (struct pl_frame *) in->mix.frames[i];
829 const AVFrame *src = pl_get_mapped_avframe(image);
830 double image_pts = TS2T(src->pts, inlink->time_base);
831
832 /* Update dynamic variables */
833 s->var_values[VAR_IN_IDX] = s->var_values[VAR_IDX] = in->idx;
834 s->var_values[VAR_IN_W] = s->var_values[VAR_IW] = inlink->w;
835 s->var_values[VAR_IN_H] = s->var_values[VAR_IH] = inlink->h;
836 s->var_values[VAR_A] = (double) inlink->w / inlink->h;
837 s->var_values[VAR_SAR] = q2d_fallback(inlink->sample_aspect_ratio, 1.0);
838 s->var_values[VAR_IN_T] = s->var_values[VAR_T] = image_pts;
839 s->var_values[VAR_OUT_T] = s->var_values[VAR_OT] = target_pts;
840 s->var_values[VAR_N] = outl->frame_count_out;
841
842 /* Clear these explicitly to avoid leaking previous frames' state */
843 s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] = NAN;
844 s->var_values[VAR_CROP_H] = s->var_values[VAR_CH] = NAN;
845 s->var_values[VAR_POS_W] = s->var_values[VAR_PW] = NAN;
846 s->var_values[VAR_POS_H] = s->var_values[VAR_PH] = NAN;
847
848 /* Compute dimensions first and placement second */
849 s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] =
850 av_expr_eval(s->crop_w_pexpr, s->var_values, NULL);
851 s->var_values[VAR_CROP_H] = s->var_values[VAR_CH] =
852 av_expr_eval(s->crop_h_pexpr, s->var_values, NULL);
853 s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] =
854 av_expr_eval(s->crop_w_pexpr, s->var_values, NULL);
855 s->var_values[VAR_POS_W] = s->var_values[VAR_PW] =
856 av_expr_eval(s->pos_w_pexpr, s->var_values, NULL);
857 s->var_values[VAR_POS_H] = s->var_values[VAR_PH] =
858 av_expr_eval(s->pos_h_pexpr, s->var_values, NULL);
859 s->var_values[VAR_POS_W] = s->var_values[VAR_PW] =
860 av_expr_eval(s->pos_w_pexpr, s->var_values, NULL);
861
862 image->crop.x0 = av_expr_eval(s->crop_x_pexpr, s->var_values, NULL);
863 image->crop.y0 = av_expr_eval(s->crop_y_pexpr, s->var_values, NULL);
864 image->crop.x1 = image->crop.x0 + s->var_values[VAR_CROP_W];
865 image->crop.y1 = image->crop.y0 + s->var_values[VAR_CROP_H];
866
867 const pl_rect2df crop_orig = image->crop;
868 pl_rotation rot_total = PL_ROTATION_360 + image->rotation - target->rotation;
869 if (rot_total % PL_ROTATION_180 == PL_ROTATION_90) {
870 /* Libplacebo expects the input crop relative to the actual frame
871 * dimensions, so un-transpose them here */
872 FFSWAP(float, image->crop.x0, image->crop.y0);
873 FFSWAP(float, image->crop.x1, image->crop.y1);
874 }
875
876 if (src == ref) {
877 /* Only update the target crop once, for the 'reference' frame */
878 target->crop.x0 = av_expr_eval(s->pos_x_pexpr, s->var_values, NULL);
879 target->crop.y0 = av_expr_eval(s->pos_y_pexpr, s->var_values, NULL);
880 target->crop.x1 = target->crop.x0 + s->var_values[VAR_POS_W];
881 target->crop.y1 = target->crop.y0 + s->var_values[VAR_POS_H];
882
883 /* Effective visual crop */
884 double sar_in = q2d_fallback(inlink->sample_aspect_ratio, 1.0);
885 double sar_out = q2d_fallback(outlink->sample_aspect_ratio, 1.0);
886 if (rot_total % PL_ROTATION_180 == PL_ROTATION_90)
887 sar_in = 1.0 / sar_in;
888
889 pl_rect2df fixed = crop_orig;
890 pl_rect2df_stretch(&fixed, sar_in / sar_out, 1.0);
891
892 switch (s->fit_mode) {
893 case FIT_FILL:
894 if (s->normalize_sar)
895 pl_rect2df_aspect_copy(&target->crop, &fixed, s->pad_crop_ratio);
896 break;
897 case FIT_CONTAIN:
898 pl_rect2df_aspect_copy(&target->crop, &fixed, 0.0);
899 break;
900 case FIT_COVER:
901 pl_rect2df_aspect_copy(&target->crop, &fixed, 1.0);
902 break;
903 case FIT_NONE: {
904 const float sx = fabsf(pl_rect_w(fixed)) / pl_rect_w(target->crop);
905 const float sy = fabsf(pl_rect_h(fixed)) / pl_rect_h(target->crop);
906 pl_rect2df_stretch(&target->crop, sx, sy);
907 break;
908 }
909 case FIT_SCALE_DOWN:
910 pl_rect2df_aspect_fit(&target->crop, &fixed, 0.0);
911 }
912 }
913 }
914}
915
916/* Construct and emit an output frame for a given timestamp */
918{
919 int err = 0, ok, changed = 0;
920 LibplaceboContext *s = ctx->priv;
921 pl_options opts = s->opts;
922 AVFilterLink *outlink = ctx->outputs[0];
923 const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(outlink->format);
924 const double target_pts = TS2T(pts, outlink->time_base);
925 struct pl_frame target;
926 const AVFrame *ref = NULL;
927 AVFrame *out;
928
929 /* Count the number of visible inputs, by excluding frames which are fully
930 * obscured or which have no frames in the mix */
931 int idx_start = 0, nb_visible = 0;
932 for (int i = 0; i < s->nb_inputs; i++) {
933 LibplaceboInput *in = &s->inputs[i];
934 struct pl_frame dummy;
935 if (in->qstatus != PL_QUEUE_OK || !in->mix.num_frames)
936 continue;
937 const struct pl_frame *cur = pl_frame_mix_nearest(&in->mix);
938 av_assert1(cur);
939 update_crops(ctx, in, &dummy, target_pts);
940 const int x0 = roundf(FFMIN(dummy.crop.x0, dummy.crop.x1)),
941 y0 = roundf(FFMIN(dummy.crop.y0, dummy.crop.y1)),
942 x1 = roundf(FFMAX(dummy.crop.x0, dummy.crop.x1)),
943 y1 = roundf(FFMAX(dummy.crop.y0, dummy.crop.y1));
944
945 /* If an opaque frame covers entire the output, disregard all lower layers */
946 const bool cropped = x0 > 0 || y0 > 0 || x1 < outlink->w || y1 < outlink->h;
947 if (!cropped && cur->repr.alpha == PL_ALPHA_NONE) {
948 idx_start = i;
949 nb_visible = 0;
950 ref = NULL;
951 }
952 /* Use first visible input as overall reference */
953 if (!ref)
954 ref = ref_frame(&in->mix);
955 nb_visible++;
956 }
957
958 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
959 if (!out)
960 return AVERROR(ENOMEM);
961
962 if (!ref)
963 goto props_done;
964
966 out->width = outlink->w;
967 out->height = outlink->h;
968 out->colorspace = outlink->colorspace;
969 out->color_range = outlink->color_range;
970 out->alpha_mode = outlink->alpha_mode;
971 if (s->deinterlace)
973
975 /* Output of dovi reshaping is always BT.2020+PQ, so infer the correct
976 * output colorspace defaults */
977 out->color_primaries = AVCOL_PRI_BT2020;
978 out->color_trc = AVCOL_TRC_SMPTE2084;
980 }
981
982 if (s->color_trc >= 0)
983 out->color_trc = s->color_trc;
984 if (s->color_primaries >= 0)
985 out->color_primaries = s->color_primaries;
986 if (s->chroma_location >= 0)
987 out->chroma_location = s->chroma_location;
988
989 /* Strip side data if no longer relevant */
990 if (out->width != ref->width || out->height != ref->height)
992 if (ref->color_trc != out->color_trc || ref->color_primaries != out->color_primaries)
994 av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data, changed);
995
996 if (s->apply_filmgrain)
998
999 if (s->reset_sar) {
1000 out->sample_aspect_ratio = ref->sample_aspect_ratio;
1001 } else {
1002 const AVRational ar_ref = { ref->width, ref->height };
1003 const AVRational ar_out = { out->width, out->height };
1004 const AVRational stretch = av_div_q(ar_ref, ar_out);
1005 out->sample_aspect_ratio = av_mul_q(ref->sample_aspect_ratio, stretch);
1006 }
1007
1008props_done:
1009 out->pts = pts;
1010 if (s->fps.num)
1011 out->duration = 1;
1012
1013 /* Map, render and unmap output frame */
1014 if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
1015 ok = pl_map_avframe_ex(s->gpu, &target, pl_avframe_params(
1016 .frame = out,
1017 .map_dovi = false,
1018 ));
1019 } else {
1020 ok = pl_frame_recreate_from_avframe(s->gpu, &target, s->tex, out);
1021 }
1022 if (!ok) {
1023 err = AVERROR_EXTERNAL;
1024 goto fail;
1025 }
1026
1027 struct pl_frame orig_target = target;
1028 bool use_linear_compositor = false;
1029 if (s->linear_tex && target.color.transfer != PL_COLOR_TRC_LINEAR &&
1030 !s->disable_linear && nb_visible > 1) {
1031 target = (struct pl_frame) {
1032 .num_planes = 1,
1033 .planes[0] = {
1034 .components = 4,
1035 .component_mapping = {0, 1, 2, 3},
1036 .texture = s->linear_tex,
1037 },
1038 .repr = pl_color_repr_rgb,
1039 .color = orig_target.color,
1040 .rotation = orig_target.rotation,
1041 };
1042 target.repr.alpha = PL_ALPHA_PREMULTIPLIED;
1043 target.color.transfer = PL_COLOR_TRC_LINEAR;
1044 use_linear_compositor = true;
1045 }
1046
1047 /* Draw first frame opaque, others with blending */
1048 struct pl_render_params tmp_params = opts->params;
1049 for (int i = 0; i < s->nb_inputs; i++) {
1050 LibplaceboInput *in = &s->inputs[i];
1051 if (!in->renderer)
1052 continue; /* input was already freed */
1053 FilterLink *il = ff_filter_link(ctx->inputs[i]);
1054 FilterLink *ol = ff_filter_link(outlink);
1055 int high_fps = av_cmp_q(il->frame_rate, ol->frame_rate) >= 0;
1056 if (in->qstatus != PL_QUEUE_OK || !in->mix.num_frames || i < idx_start) {
1057 pl_renderer_flush_cache(in->renderer);
1058 continue;
1059 }
1060 tmp_params.skip_caching_single_frame = high_fps;
1061 update_crops(ctx, in, &target, target_pts);
1062 pl_render_image_mix(in->renderer, &in->mix, &target, &tmp_params);
1063
1064 /* Force straight output and set correct blend operator. This is
1065 * required to get correct blending onto YUV target buffers. */
1066 target.repr.alpha = PL_ALPHA_INDEPENDENT;
1067 tmp_params.blend_params = &pl_alpha_overlay;
1068 tmp_params.background = tmp_params.border = PL_CLEAR_SKIP;
1069 }
1070
1071 if (use_linear_compositor) {
1072 /* Blit the linear intermediate image to the output frame */
1073 target.crop = orig_target.crop = (struct pl_rect2df) {0};
1074 target.repr.alpha = PL_ALPHA_PREMULTIPLIED;
1075 pl_render_image(s->linear_rr, &target, &orig_target, &opts->params);
1076 target = orig_target;
1077 } else if (!ref) {
1078 /* Render an empty image to clear the frame to the desired fill color */
1079 pl_render_image(s->linear_rr, NULL, &target, &opts->params);
1080 }
1081
1082 if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
1083 pl_unmap_avframe(s->gpu, &target);
1084 } else if (!pl_download_avframe(s->gpu, &target, out)) {
1085 err = AVERROR_EXTERNAL;
1086 goto fail;
1087 }
1088 return ff_filter_frame(outlink, out);
1089
1090fail:
1092 return err;
1093}
1094
1095static bool map_frame(pl_gpu gpu, pl_tex *tex,
1096 const struct pl_source_frame *src,
1097 struct pl_frame *out)
1098{
1099 AVFrame *avframe = src->frame_data;
1100 LibplaceboContext *s = avframe->opaque;
1101 bool ok = pl_map_avframe_ex(gpu, out, pl_avframe_params(
1102 .frame = avframe,
1103 .tex = tex,
1104 .map_dovi = s->apply_dovi,
1105 ));
1106 out->lut = s->lut;
1107 out->lut_type = s->lut_type;
1108 out->rotation += s->rotation;
1109
1110 if (!s->apply_filmgrain)
1111 out->film_grain.type = PL_FILM_GRAIN_NONE;
1112
1113 av_frame_free(&avframe);
1114 return ok;
1115}
1116
1117static void unmap_frame(pl_gpu gpu, struct pl_frame *frame,
1118 const struct pl_source_frame *src)
1119{
1120 pl_unmap_avframe(gpu, frame);
1121}
1122
1123static void discard_frame(const struct pl_source_frame *src)
1124{
1125 AVFrame *avframe = src->frame_data;
1126 av_frame_free(&avframe);
1127}
1128
1130{
1131 int ret, status;
1132 LibplaceboContext *s = ctx->priv;
1133 AVFilterLink *outlink = ctx->outputs[0];
1134 AVFilterLink *inlink = ctx->inputs[input->idx];
1135 AVFrame *in;
1136 int64_t pts;
1137
1138 while ((ret = ff_inlink_consume_frame(inlink, &in)) > 0) {
1139 struct pl_source_frame src = {
1140 .pts = TS2T(in->pts, inlink->time_base),
1141 .duration = TS2T(in->duration, inlink->time_base),
1142 .first_field = s->deinterlace ? pl_field_from_avframe(in) : PL_FIELD_NONE,
1143 .frame_data = in,
1144 .map = map_frame,
1145 .unmap = unmap_frame,
1146 .discard = discard_frame,
1147 };
1148
1149 in->opaque = s;
1150 pl_queue_push(input->queue, &src);
1151
1152 if (!s->fps.num) {
1153 /* Internally queue an output frame for the same PTS */
1154 pts = av_rescale_q(in->pts, inlink->time_base, outlink->time_base);
1155 av_fifo_write(input->out_pts, &pts, 1);
1156
1157 if (s->send_fields && src.first_field != PL_FIELD_NONE) {
1158 /* Queue the second field for interlaced content */
1159 pts += av_rescale_q(in->duration, inlink->time_base, outlink->time_base) / 2;
1160 av_fifo_write(input->out_pts, &pts, 1);
1161 }
1162 }
1163 }
1164
1165 if (ret < 0)
1166 return ret;
1167
1168 if (!input->status && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
1169 pts = av_rescale_q_rnd(pts, inlink->time_base, outlink->time_base,
1170 AV_ROUND_UP);
1171 pl_queue_push(input->queue, NULL); /* Signal EOF to pl_queue */
1172 input->status = status;
1173 input->status_pts = pts;
1174 s->nb_active--;
1175 }
1176
1177 return 0;
1178}
1179
1181{
1182 int64_t pts;
1183 while (av_fifo_peek(in->out_pts, &pts, 1, 0) >= 0 && pts <= until)
1184 av_fifo_drain2(in->out_pts, 1);
1185}
1186
1188{
1189 int ret, ok = 0, retry = 0;
1190 LibplaceboContext *s = ctx->priv;
1191 AVFilterLink *outlink = ctx->outputs[0];
1192 FilterLink *outl = ff_filter_link(outlink);
1193 int64_t pts, out_pts;
1194
1196 pl_log_level_update(s->log, get_log_level());
1197
1198 for (int i = 0; i < s->nb_inputs; i++) {
1199 if ((ret = handle_input(ctx, &s->inputs[i])) < 0)
1200 return ret;
1201 }
1202
1203 if (ff_outlink_frame_wanted(outlink)) {
1204 if (s->fps.num) {
1205 out_pts = outl->frame_count_out;
1206 } else {
1207 /* Determine the PTS of the next frame from any active input */
1208 out_pts = INT64_MAX;
1209 for (int i = 0; i < s->nb_inputs; i++) {
1210 LibplaceboInput *in = &s->inputs[i];
1211 if (av_fifo_peek(in->out_pts, &pts, 1, 0) >= 0) {
1212 out_pts = FFMIN(out_pts, pts);
1213 } else if (!in->status) {
1214 ff_inlink_request_frame(ctx->inputs[i]);
1215 retry = true;
1216 }
1217 }
1218
1219 if (retry) /* some inputs are incomplete */
1220 return 0;
1221 }
1222
1223 /* Update all input queues to the chosen out_pts */
1224 for (int i = 0; i < s->nb_inputs; i++) {
1225 LibplaceboInput *in = &s->inputs[i];
1226 FilterLink *l = ff_filter_link(outlink);
1227 if (in->status && out_pts >= in->status_pts) {
1228 /* Free up resources which will never be needed again */
1229 pl_renderer_destroy(&in->renderer);
1230 pl_queue_destroy(&in->queue);
1231 in->qstatus = PL_QUEUE_EOF;
1232 continue;
1233 }
1234
1235 in->qstatus = pl_queue_update(in->queue, &in->mix, pl_queue_params(
1236 .pts = TS2T(out_pts, outlink->time_base),
1237 .radius = pl_frame_mix_radius(&s->opts->params),
1238 .vsync_duration = q2d_fallback(av_inv_q(l->frame_rate), 0.0),
1239 ));
1240
1241 switch (in->qstatus) {
1242 case PL_QUEUE_MORE:
1243 ff_inlink_request_frame(ctx->inputs[i]);
1244 retry = true;
1245 break;
1246 case PL_QUEUE_OK:
1247 ok |= in->mix.num_frames > 0;
1248 break;
1249 case PL_QUEUE_ERR:
1250 return AVERROR_EXTERNAL;
1251 }
1252 }
1253
1254 /* In constant FPS mode, we can also output an empty frame if there is
1255 * a gap in the input timeline and we still have active streams */
1256 ok |= s->fps.num && s->nb_active > 0;
1257
1258 if (retry) {
1259 return 0;
1260 } else if (ok) {
1261 /* Got any valid frame mixes, drain PTS queue and render output */
1262 for (int i = 0; i < s->nb_inputs; i++)
1263 drain_input_pts(&s->inputs[i], out_pts);
1264 return output_frame(ctx, out_pts);
1265 } else if (s->nb_active == 0) {
1266 /* Forward most recent status */
1267 int status = s->inputs[0].status;
1268 int64_t status_pts = s->inputs[0].status_pts;
1269 for (int i = 1; i < s->nb_inputs; i++) {
1270 const LibplaceboInput *in = &s->inputs[i];
1271 if (in->status_pts > status_pts) {
1272 status = s->inputs[i].status;
1273 status_pts = s->inputs[i].status_pts;
1274 }
1275 }
1276 ff_outlink_set_status(outlink, status, status_pts);
1277 return 0;
1278 }
1279
1280 return AVERROR_BUG;
1281 }
1282
1283 return FFERROR_NOT_READY;
1284}
1285
1287 AVFilterFormatsConfig **cfg_in,
1288 AVFilterFormatsConfig **cfg_out)
1289{
1290 int err;
1291 const LibplaceboContext *s = ctx->priv;
1292 const AVPixFmtDescriptor *desc = NULL;
1293 AVFilterFormats *infmts = NULL, *outfmts = NULL;
1294
1295 if (!s->gpu) {
1296 /* Device deferred to config_input (inherit_device): we have no GPU yet
1297 * to enumerate software formats against, and this mode requires Vulkan
1298 * input, so advertise Vulkan only. */
1300 if (s->out_format == AV_PIX_FMT_NONE || av_vkfmt_from_pixfmt(s->out_format))
1302 goto done;
1303 }
1304
1305 /* List AV_PIX_FMT_VULKAN first to prefer it when possible */
1306 if (s->have_hwdevice) {
1308 if (s->out_format == AV_PIX_FMT_NONE || av_vkfmt_from_pixfmt(s->out_format))
1310 }
1311
1312 while ((desc = av_pix_fmt_desc_next(desc))) {
1315 continue; /* Handled above */
1316
1317 if (!pl_test_pixfmt(s->gpu, pixfmt))
1318 continue;
1319
1320 RET(ff_add_format(&infmts, pixfmt));
1321
1322 /* Filter for supported output pixel formats */
1323 if (desc->flags & AV_PIX_FMT_FLAG_BE)
1324 continue; /* BE formats are not supported by pl_download_avframe */
1325
1326 /* Mask based on user specified format */
1327 if (pixfmt != s->out_format && s->out_format != AV_PIX_FMT_NONE)
1328 continue;
1329
1330 if (!pl_test_pixfmt_caps(s->gpu, pixfmt, PL_FMT_CAP_RENDERABLE))
1331 continue;
1332
1333 RET(ff_add_format(&outfmts, pixfmt));
1334 }
1335
1336done:
1337
1338 if (!infmts || !outfmts) {
1339 err = AVERROR(EINVAL);
1340 goto fail;
1341 }
1342
1343 for (int i = 0; i < s->nb_inputs; i++) {
1344 if (i > 0) {
1345 /* Duplicate the format list for each subsequent input */
1346 infmts = NULL;
1347 for (int n = 0; n < cfg_in[0]->formats->nb_formats; n++)
1348 RET(ff_add_format(&infmts, cfg_in[0]->formats->formats[n]));
1349 }
1350 RET(ff_formats_ref(infmts, &cfg_in[i]->formats));
1351 RET(ff_formats_ref(ff_all_color_spaces(), &cfg_in[i]->color_spaces));
1352 RET(ff_formats_ref(ff_all_color_ranges(), &cfg_in[i]->color_ranges));
1353 RET(ff_formats_ref(ff_all_alpha_modes(), &cfg_in[i]->alpha_modes));
1354 }
1355
1356 RET(ff_formats_ref(outfmts, &cfg_out[0]->formats));
1357
1358 outfmts = s->colorspace > 0 ? ff_make_formats_list_singleton(s->colorspace)
1360 RET(ff_formats_ref(outfmts, &cfg_out[0]->color_spaces));
1361
1362 outfmts = s->color_range > 0 ? ff_make_formats_list_singleton(s->color_range)
1364 RET(ff_formats_ref(outfmts, &cfg_out[0]->color_ranges));
1365
1366 outfmts = s->alpha_mode > 0 ? ff_make_formats_list_singleton(s->alpha_mode)
1368 RET(ff_formats_ref(outfmts, &cfg_out[0]->alpha_modes));
1369 return 0;
1370
1371fail:
1372 if (infmts && !infmts->refcount)
1373 ff_formats_unref(&infmts);
1374 if (outfmts && !outfmts->refcount)
1375 ff_formats_unref(&outfmts);
1376 return err;
1377}
1378
1380{
1381 AVFilterContext *avctx = inlink->dst;
1382 LibplaceboContext *s = avctx->priv;
1383 FilterLink *l = ff_filter_link(inlink);
1384
1385 if (s->rotation % PL_ROTATION_180 == PL_ROTATION_90) {
1386 /* Swap width and height for 90 degree rotations to make the size and
1387 * scaling calculations work out correctly */
1388 FFSWAP(int, inlink->w, inlink->h);
1389 if (inlink->sample_aspect_ratio.num)
1391 }
1392
1393 /* Deferred Vulkan setup (inherit_device): the device was not created at
1394 * init; adopt the one the input frames live on. query_formats advertised
1395 * Vulkan only, so a non-Vulkan input here is a configuration error. */
1396 if (!s->gpu) {
1397 AVHWFramesContext *hwfc;
1398 int err;
1399 av_assert0(s->inherit_device);
1400 if (inlink->format != AV_PIX_FMT_VULKAN || !l->hw_frames_ctx) {
1401 av_log(avctx, AV_LOG_ERROR, "inherit_device requires a Vulkan "
1402 "hardware frames context on the input.\n");
1403 return AVERROR(EINVAL);
1404 }
1405 hwfc = (AVHWFramesContext *) l->hw_frames_ctx->data;
1407 avctx->hw_device_ctx = av_buffer_ref(hwfc->device_ref);
1408 if (!avctx->hw_device_ctx)
1409 return AVERROR(ENOMEM);
1410 if ((err = init_vulkan(avctx, hwfc->device_ctx->hwctx)) < 0)
1411 return err;
1412 }
1413
1414 if (inlink->format == AV_PIX_FMT_VULKAN)
1415 return ff_vk_filter_config_input(inlink);
1416
1417 /* Forward this to the vkctx for format selection */
1418 s->vkctx.input_format = inlink->format;
1419
1420 return 0;
1421}
1422
1424{
1425 return av_cmp_q(a, b) < 0 ? b : a;
1426}
1427
1429{
1430 int err;
1431 FilterLink *l = ff_filter_link(outlink);
1432 AVFilterContext *avctx = outlink->src;
1433 LibplaceboContext *s = avctx->priv;
1434 AVFilterLink *inlink = outlink->src->inputs[0];
1435 FilterLink *ol = ff_filter_link(outlink);
1437 const AVPixFmtDescriptor *out_desc = av_pix_fmt_desc_get(outlink->format);
1438 AVHWFramesContext *hwfc;
1440
1441 /* Frame dimensions */
1442 RET(ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, inlink, outlink,
1443 &outlink->w, &outlink->h));
1444
1445 s->reset_sar |= s->normalize_sar || s->nb_inputs > 1;
1446 double sar_in = q2d_fallback(inlink->sample_aspect_ratio, 1.0);
1447
1448 int force_oar = s->force_original_aspect_ratio;
1449 if (!force_oar && s->fit_sense == FIT_CONSTRAINT) {
1450 if (s->fit_mode == FIT_CONTAIN || s->fit_mode == FIT_SCALE_DOWN) {
1451 force_oar = SCALE_FORCE_OAR_DECREASE;
1452 } else if (s->fit_mode == FIT_COVER) {
1453 force_oar = SCALE_FORCE_OAR_INCREASE;
1454 }
1455 }
1456
1457 RET(ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
1458 force_oar, s->force_divisible_by,
1459 s->reset_sar ? sar_in : 1.0));
1460
1461 if (s->fit_mode == FIT_SCALE_DOWN && s->fit_sense == FIT_CONSTRAINT) {
1462 int w_adj = s->reset_sar ? sar_in * inlink->w : inlink->w;
1463 outlink->w = FFMIN(outlink->w, w_adj);
1464 outlink->h = FFMIN(outlink->h, inlink->h);
1465 }
1466
1467 if (s->nb_inputs > 1 && !s->disable_fbos) {
1468 /* Create a separate renderer and composition texture */
1469 const enum pl_fmt_caps caps = PL_FMT_CAP_BLENDABLE | PL_FMT_CAP_BLITTABLE;
1470 pl_fmt fmt = pl_find_fmt(s->gpu, PL_FMT_FLOAT, 4, 16, 0, caps);
1471 bool ok = !!fmt;
1472 if (ok) {
1473 ok = pl_tex_recreate(s->gpu, &s->linear_tex, pl_tex_params(
1474 .format = fmt,
1475 .w = outlink->w,
1476 .h = outlink->h,
1477 .blit_dst = true,
1478 .renderable = true,
1479 .sampleable = true,
1480 .storable = fmt->caps & PL_FMT_CAP_STORABLE,
1481 ));
1482 }
1483
1484 if (!ok) {
1485 av_log(avctx, AV_LOG_WARNING, "Failed to create a linear texture "
1486 "for compositing multiple inputs, falling back to non-linear "
1487 "blending.\n");
1488 }
1489 }
1490
1491 if (s->reset_sar) {
1492 /* SAR is normalized, or we have multiple inputs, set out to 1:1 */
1493 outlink->sample_aspect_ratio = (AVRational){ 1, 1 };
1494 } else if (inlink->sample_aspect_ratio.num && s->fit_mode == FIT_FILL) {
1495 /* This is consistent with other scale_* filters, which only
1496 * set the outlink SAR to be equal to the scale SAR iff the input SAR
1497 * was set to something nonzero */
1498 const AVRational ar_in = { inlink->w, inlink->h };
1499 const AVRational ar_out = { outlink->w, outlink->h };
1500 const AVRational stretch = av_div_q(ar_in, ar_out);
1501 outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, stretch);
1502 } else {
1503 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
1504 }
1505
1506 /* Frame rate */
1507 if (s->fps.num) {
1508 ol->frame_rate = s->fps;
1509 outlink->time_base = av_inv_q(s->fps);
1510 } else {
1511 FilterLink *il = ff_filter_link(avctx->inputs[0]);
1512 ol->frame_rate = il->frame_rate;
1513 outlink->time_base = avctx->inputs[0]->time_base;
1514 for (int i = 1; i < s->nb_inputs; i++) {
1515 il = ff_filter_link(avctx->inputs[i]);
1516 ol->frame_rate = max_q(ol->frame_rate, il->frame_rate);
1517 outlink->time_base = av_gcd_q(outlink->time_base,
1518 avctx->inputs[i]->time_base,
1520 }
1521
1522 if (s->deinterlace && s->send_fields) {
1523 const AVRational q2 = { 2, 1 };
1524 ol->frame_rate = av_mul_q(ol->frame_rate, q2);
1525 /* Ensure output frame timestamps are divisible by two */
1526 outlink->time_base = av_div_q(outlink->time_base, q2);
1527 }
1528 }
1529
1530 /* Static variables */
1531 s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = outlink->w;
1532 s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = outlink->h;
1533 s->var_values[VAR_DAR] = q2d_fallback(outlink->sample_aspect_ratio, 1.0);
1534 s->var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
1535 s->var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
1536 s->var_values[VAR_OHSUB] = 1 << out_desc->log2_chroma_w;
1537 s->var_values[VAR_OVSUB] = 1 << out_desc->log2_chroma_h;
1538
1539 if (outlink->format != AV_PIX_FMT_VULKAN)
1540 return 0;
1541
1542 s->vkctx.output_width = outlink->w;
1543 s->vkctx.output_height = outlink->h;
1544 /* Default to reusing the input format */
1545 if (s->out_format == AV_PIX_FMT_NONE || s->out_format == AV_PIX_FMT_VULKAN) {
1546 s->vkctx.output_format = s->vkctx.input_format;
1547 } else {
1548 s->vkctx.output_format = s->out_format;
1549 }
1551 hwfc = (AVHWFramesContext *)l->hw_frames_ctx->data;
1552 vkfc = hwfc->hwctx;
1553 vkfc->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1554
1555 return 0;
1556
1557fail:
1558 return err;
1559}
1560
1561#define OFFSET(x) offsetof(LibplaceboContext, x)
1562#define STATIC (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
1563#define DYNAMIC (STATIC | AV_OPT_FLAG_RUNTIME_PARAM)
1564
1566 { "inputs", "Number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, .flags = STATIC },
1567 { "inherit_device", "Inherit the Vulkan device from the input's hardware frames context",
1568 OFFSET(inherit_device), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = STATIC },
1569 { "w", "Output video frame width", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = STATIC },
1570 { "h", "Output video frame height", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = STATIC },
1571 { "fps", "Output video frame rate", OFFSET(fps_string), AV_OPT_TYPE_STRING, {.str = "none"}, .flags = STATIC },
1572 { "crop_x", "Input video crop x", OFFSET(crop_x_expr), AV_OPT_TYPE_STRING, {.str = "(iw-cw)/2"}, .flags = DYNAMIC },
1573 { "crop_y", "Input video crop y", OFFSET(crop_y_expr), AV_OPT_TYPE_STRING, {.str = "(ih-ch)/2"}, .flags = DYNAMIC },
1574 { "crop_w", "Input video crop w", OFFSET(crop_w_expr), AV_OPT_TYPE_STRING, {.str = "iw"}, .flags = DYNAMIC },
1575 { "crop_h", "Input video crop h", OFFSET(crop_h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = DYNAMIC },
1576 { "pos_x", "Output video placement x", OFFSET(pos_x_expr), AV_OPT_TYPE_STRING, {.str = "(ow-pw)/2"}, .flags = DYNAMIC },
1577 { "pos_y", "Output video placement y", OFFSET(pos_y_expr), AV_OPT_TYPE_STRING, {.str = "(oh-ph)/2"}, .flags = DYNAMIC },
1578 { "pos_w", "Output video placement w", OFFSET(pos_w_expr), AV_OPT_TYPE_STRING, {.str = "ow"}, .flags = DYNAMIC },
1579 { "pos_h", "Output video placement h", OFFSET(pos_h_expr), AV_OPT_TYPE_STRING, {.str = "oh"}, .flags = DYNAMIC },
1580 { "format", "Output video format", OFFSET(out_format_string), AV_OPT_TYPE_STRING, .flags = STATIC },
1581 { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, SCALE_FORCE_OAR_NB-1, STATIC, .unit = "force_oar" },
1582 { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DISABLE }, 0, 0, STATIC, .unit = "force_oar" },
1583 { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_DECREASE }, 0, 0, STATIC, .unit = "force_oar" },
1584 { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_FORCE_OAR_INCREASE }, 0, 0, STATIC, .unit = "force_oar" },
1585 { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, STATIC },
1586 { "reset_sar", "force SAR normalization to 1:1 by adjusting pos_x/y/w/h", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, STATIC },
1587 { "normalize_sar", "like reset_sar, but pad/crop instead of stretching the video", OFFSET(normalize_sar), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, STATIC },
1588 { "pad_crop_ratio", "ratio between padding and cropping when normalizing SAR (0=pad, 1=crop)", OFFSET(pad_crop_ratio), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, 1.0, DYNAMIC },
1589 { "fit_mode", "Content fit strategy for placing input layers in the output", OFFSET(fit_mode), AV_OPT_TYPE_INT, {.i64 = FIT_FILL }, 0, FIT_MODE_NB - 1, STATIC, .unit = "fit_mode" },
1590 { "fill", "Stretch content, ignoring aspect ratio", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_FILL }, 0, 0, STATIC, .unit = "fit_mode" },
1591 { "contain", "Stretch content, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_CONTAIN }, 0, 0, STATIC, .unit = "fit_mode" },
1592 { "cover", "Stretch content, cropping to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_COVER }, 0, 0, STATIC, .unit = "fit_mode" },
1593 { "none", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
1594 { "place", "Keep input unscaled, padding and cropping as needed", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_NONE }, 0, 0, STATIC, .unit = "fit_mode" },
1595 { "scale_down", "Downscale only if larger, padding to preserve aspect", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_SCALE_DOWN }, 0, 0, STATIC, .unit = "fit_mode" },
1596 { "fit_sense", "Output size strategy (for the base layer only)", OFFSET(fit_sense), AV_OPT_TYPE_INT, {.i64 = FIT_TARGET }, 0, FIT_SENSE_NB - 1, STATIC, .unit = "fit_sense" },
1597 { "target", "Computed resolution is the exact output size", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_TARGET }, 0, 0, STATIC, .unit = "fit_sense" },
1598 { "constraint", "Computed resolution constrains the output size", 0, AV_OPT_TYPE_CONST, {.i64 = FIT_CONSTRAINT }, 0, 0, STATIC, .unit = "fit_sense" },
1599 { "fillcolor", "Background fill color", OFFSET(fillcolor), AV_OPT_TYPE_COLOR, {.str = "black@0"}, .flags = DYNAMIC },
1600 { "corner_rounding", "Corner rounding radius", OFFSET(corner_rounding), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, .flags = DYNAMIC },
1601 { "lut", "Path to custom LUT file to apply", OFFSET(lut_filename), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = STATIC },
1602 { "lut_type", "Application mode of the custom LUT", OFFSET(lut_type), AV_OPT_TYPE_INT, { .i64 = PL_LUT_UNKNOWN }, 0, PL_LUT_CONVERSION, STATIC, .unit = "lut_type" },
1603 { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = PL_LUT_UNKNOWN }, 0, 0, STATIC, .unit = "lut_type" },
1604 { "native", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = PL_LUT_NATIVE }, 0, 0, STATIC, .unit = "lut_type" },
1605 { "normalized", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = PL_LUT_NORMALIZED }, 0, 0, STATIC, .unit = "lut_type" },
1606 { "conversion", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = PL_LUT_CONVERSION }, 0, 0, STATIC, .unit = "lut_type" },
1607
1608 { "extra_opts", "Pass extra libplacebo-specific options using a :-separated list of key=value pairs", OFFSET(extra_opts), AV_OPT_TYPE_DICT, .flags = DYNAMIC },
1609 { "shader_cache", "Set shader cache path", OFFSET(shader_cache), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = STATIC },
1610
1611 {"colorspace", "select colorspace", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_SPC_NB-1, DYNAMIC, .unit = "colorspace"},
1612 {"auto", "keep the same colorspace", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1613 {"gbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_RGB}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1614 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1615 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1616 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1617 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1618 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1619 {"ycgco", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1620 {"bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1621 {"bt2020c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_CL}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1622 {"ictcp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_ICTCP}, INT_MIN, INT_MAX, STATIC, .unit = "colorspace"},
1623
1624 {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_RANGE_NB-1, DYNAMIC, .unit = "range"},
1625 {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, STATIC, .unit = "range"},
1626 {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, STATIC, .unit = "range"},
1627 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, STATIC, .unit = "range"},
1628 {"limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, STATIC, .unit = "range"},
1629 {"tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, STATIC, .unit = "range"},
1630 {"mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, STATIC, .unit = "range"},
1631 {"full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, .unit = "range"},
1632 {"pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, .unit = "range"},
1633 {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, .unit = "range"},
1634
1635 {"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_EXT_NB-1, DYNAMIC, .unit = "color_primaries"},
1636 {"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1637 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1638 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1639 {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1640 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1641 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1642 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1643 {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1644 {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1645 {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1646 {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1647 {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1648 {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1649 {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1650 {"vgamut", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_V_GAMUT}, INT_MIN, INT_MAX, STATIC, .unit = "color_primaries"},
1651
1652 {"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_EXT_NB-1, DYNAMIC, .unit = "color_trc"},
1653 {"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1654 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1655 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1656 {"gamma22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1657 {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1658 {"gamma28", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1659 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1660 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1661 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1662 {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1663 {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1664 {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1665 {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1666 {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1667 {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1668 {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1669 {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1670 {"vlog", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_V_LOG}, INT_MIN, INT_MAX, STATIC, .unit = "color_trc"},
1671
1672 {"chroma_location", "select chroma location", OFFSET(chroma_location), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCHROMA_LOC_NB-1, DYNAMIC, .unit = "chroma_location"},
1673 {"auto", "keep the same chroma location", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, STATIC, .unit = "chroma_location"},
1674 {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, STATIC, .unit = "chroma_location"},
1675 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_UNSPECIFIED}, 0, 0, STATIC, .unit = "chroma_location"},
1676 {"left", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_LEFT}, 0, 0, STATIC, .unit = "chroma_location"},
1677 {"center", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_CENTER}, 0, 0, STATIC, .unit = "chroma_location"},
1678 {"topleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOPLEFT}, 0, 0, STATIC, .unit = "chroma_location"},
1679 {"top", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_TOP}, 0, 0, STATIC, .unit = "chroma_location"},
1680 {"bottomleft", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOMLEFT}, 0, 0, STATIC, .unit = "chroma_location"},
1681 {"bottom", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCHROMA_LOC_BOTTOM}, 0, 0, STATIC, .unit = "chroma_location"},
1682
1683 {"rotate", "rotate the input clockwise", OFFSET(rotation), AV_OPT_TYPE_INT, {.i64=PL_ROTATION_0}, PL_ROTATION_0, PL_ROTATION_360, DYNAMIC, .unit = "rotation"},
1684 {"0", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_0}, .flags = STATIC, .unit = "rotation"},
1685 {"90", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_90}, .flags = STATIC, .unit = "rotation"},
1686 {"180", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_180}, .flags = STATIC, .unit = "rotation"},
1687 {"270", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_270}, .flags = STATIC, .unit = "rotation"},
1688 {"360", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PL_ROTATION_360}, .flags = STATIC, .unit = "rotation"},
1689
1690 {"alpha_mode", "select alpha moda", OFFSET(alpha_mode), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVALPHA_MODE_NB-1, DYNAMIC, .unit = "alpha_mode"},
1691 {"auto", "keep the same alpha mode", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, DYNAMIC, .unit = "alpha_mode"},
1692 {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_UNSPECIFIED}, 0, 0, DYNAMIC, .unit = "alpha_mode"},
1693 {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_UNSPECIFIED}, 0, 0, DYNAMIC, .unit = "alpha_mode"},
1694 {"premultiplied", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_PREMULTIPLIED}, 0, 0, DYNAMIC, .unit = "alpha_mode"},
1695 {"straight", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVALPHA_MODE_STRAIGHT}, 0, 0, DYNAMIC, .unit = "alpha_mode"},
1696
1697 { "upscaler", "Upscaler function", OFFSET(upscaler), AV_OPT_TYPE_STRING, {.str = "spline36"}, .flags = DYNAMIC },
1698 { "downscaler", "Downscaler function", OFFSET(downscaler), AV_OPT_TYPE_STRING, {.str = "mitchell"}, .flags = DYNAMIC },
1699 { "frame_mixer", "Frame mixing function", OFFSET(frame_mixer), AV_OPT_TYPE_STRING, {.str = "none"}, .flags = DYNAMIC },
1700 { "antiringing", "Antiringing strength (for non-EWA filters)", OFFSET(antiringing), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, DYNAMIC },
1701 { "sigmoid", "Enable sigmoid upscaling", OFFSET(sigmoid), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC },
1702 { "apply_filmgrain", "Apply film grain metadata", OFFSET(apply_filmgrain), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC },
1703 { "apply_dolbyvision", "Apply Dolby Vision metadata", OFFSET(apply_dovi), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC },
1704
1705 { "deinterlace", "Deinterlacing mode", OFFSET(deinterlace), AV_OPT_TYPE_INT, {.i64 = PL_DEINTERLACE_WEAVE}, 0, PL_DEINTERLACE_ALGORITHM_COUNT - 1, DYNAMIC, .unit = "deinterlace" },
1706 { "weave", "Weave fields together (no-op)", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DEINTERLACE_WEAVE}, 0, 0, STATIC, .unit = "deinterlace" },
1707 { "bob", "Naive bob deinterlacing", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DEINTERLACE_BOB}, 0, 0, STATIC, .unit = "deinterlace" },
1708 { "yadif", "Yet another deinterlacing filter", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DEINTERLACE_YADIF}, 0, 0, STATIC, .unit = "deinterlace" },
1709#if PL_API_VER >= 353
1710 { "bwdif", "Bob weaver deinterlacing filter", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DEINTERLACE_BWDIF}, 0, 0, STATIC, .unit = "deinterlace" },
1711#endif
1712 { "skip_spatial_check", "Skip yadif spatial check", OFFSET(skip_spatial_check), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1713 { "send_fields", "Output a frame for each field", OFFSET(send_fields), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1714
1715 { "deband", "Enable debanding", OFFSET(deband), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1716 { "deband_iterations", "Deband iterations", OFFSET(deband_iterations), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 16, DYNAMIC },
1717 { "deband_threshold", "Deband threshold", OFFSET(deband_threshold), AV_OPT_TYPE_FLOAT, {.dbl = 4.0}, 0.0, 1024.0, DYNAMIC },
1718 { "deband_radius", "Deband radius", OFFSET(deband_radius), AV_OPT_TYPE_FLOAT, {.dbl = 16.0}, 0.0, 1024.0, DYNAMIC },
1719 { "deband_grain", "Deband grain", OFFSET(deband_grain), AV_OPT_TYPE_FLOAT, {.dbl = 6.0}, 0.0, 1024.0, DYNAMIC },
1720
1721 { "brightness", "Brightness boost", OFFSET(brightness), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, -1.0, 1.0, DYNAMIC },
1722 { "contrast", "Contrast gain", OFFSET(contrast), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 16.0, DYNAMIC },
1723 { "saturation", "Saturation gain", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 16.0, DYNAMIC },
1724 { "hue", "Hue shift", OFFSET(hue), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, -M_PI, M_PI, DYNAMIC },
1725 { "gamma", "Gamma adjustment", OFFSET(gamma), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 16.0, DYNAMIC },
1726 { "temperature", "Color temperature adjustment (kelvin)", OFFSET(temperature), AV_OPT_TYPE_FLOAT, {.dbl = 6500.0}, 1667.0, 25000.0, DYNAMIC },
1727
1728 { "peak_detect", "Enable dynamic peak detection for HDR tone-mapping", OFFSET(peakdetect), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC },
1729 { "smoothing_period", "Peak detection smoothing period", OFFSET(smoothing), AV_OPT_TYPE_FLOAT, {.dbl = 20.0}, 0.0, 1000.0, DYNAMIC },
1730 { "scene_threshold_low", "Scene change low threshold", OFFSET(scene_low), AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, -1.0, 100.0, DYNAMIC },
1731 { "scene_threshold_high", "Scene change high threshold", OFFSET(scene_high), AV_OPT_TYPE_FLOAT, {.dbl = 3.0}, -1.0, 100.0, DYNAMIC },
1732 { "percentile", "Peak detection percentile", OFFSET(percentile), AV_OPT_TYPE_FLOAT, {.dbl = 99.995}, 0.0, 100.0, DYNAMIC },
1733
1734 { "gamut_mode", "Gamut-mapping mode", OFFSET(gamut_mode), AV_OPT_TYPE_INT, {.i64 = GAMUT_MAP_PERCEPTUAL}, 0, GAMUT_MAP_COUNT - 1, DYNAMIC, .unit = "gamut_mode" },
1735 { "clip", "Hard-clip (RGB per-channel)", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_CLIP}, 0, 0, STATIC, .unit = "gamut_mode" },
1736 { "perceptual", "Colorimetric soft clipping", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_PERCEPTUAL}, 0, 0, STATIC, .unit = "gamut_mode" },
1737 { "relative", "Relative colorimetric clipping", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_RELATIVE}, 0, 0, STATIC, .unit = "gamut_mode" },
1738 { "saturation", "Saturation mapping (RGB -> RGB)", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_SATURATION}, 0, 0, STATIC, .unit = "gamut_mode" },
1739 { "absolute", "Absolute colorimetric clipping", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_ABSOLUTE}, 0, 0, STATIC, .unit = "gamut_mode" },
1740 { "desaturate", "Colorimetrically desaturate colors towards white", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_DESATURATE}, 0, 0, STATIC, .unit = "gamut_mode" },
1741 { "darken", "Colorimetric clip with bias towards darkening image to fit gamut", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_DARKEN}, 0, 0, STATIC, .unit = "gamut_mode" },
1742 { "warn", "Highlight out-of-gamut colors", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_HIGHLIGHT}, 0, 0, STATIC, .unit = "gamut_mode" },
1743 { "linear", "Linearly reduce chromaticity to fit gamut", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_LINEAR}, 0, 0, STATIC, .unit = "gamut_mode" },
1744 { "tonemapping", "Tone-mapping algorithm", OFFSET(tonemapping), AV_OPT_TYPE_INT, {.i64 = TONE_MAP_AUTO}, 0, TONE_MAP_COUNT - 1, DYNAMIC, .unit = "tonemap" },
1745 { "auto", "Automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_AUTO}, 0, 0, STATIC, .unit = "tonemap" },
1746 { "clip", "No tone mapping (clip", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_CLIP}, 0, 0, STATIC, .unit = "tonemap" },
1747 { "st2094-40", "SMPTE ST 2094-40", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_ST2094_40}, 0, 0, STATIC, .unit = "tonemap" },
1748 { "st2094-10", "SMPTE ST 2094-10", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_ST2094_10}, 0, 0, STATIC, .unit = "tonemap" },
1749 { "bt.2390", "ITU-R BT.2390 EETF", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_BT2390}, 0, 0, STATIC, .unit = "tonemap" },
1750 { "bt.2446a", "ITU-R BT.2446 Method A", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_BT2446A}, 0, 0, STATIC, .unit = "tonemap" },
1751 { "spline", "Single-pivot polynomial spline", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_SPLINE}, 0, 0, STATIC, .unit = "tonemap" },
1752 { "reinhard", "Reinhard", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_REINHARD}, 0, 0, STATIC, .unit = "tonemap" },
1753 { "mobius", "Mobius", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_MOBIUS}, 0, 0, STATIC, .unit = "tonemap" },
1754 { "hable", "Filmic tone-mapping (Hable)", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_HABLE}, 0, 0, STATIC, .unit = "tonemap" },
1755 { "gamma", "Gamma function with knee", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_GAMMA}, 0, 0, STATIC, .unit = "tonemap" },
1756 { "linear", "Perceptually linear stretch", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_LINEAR}, 0, 0, STATIC, .unit = "tonemap" },
1757 { "tonemapping_param", "Tunable parameter for some tone-mapping functions", OFFSET(tonemapping_param), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 100.0, .flags = DYNAMIC },
1758 { "inverse_tonemapping", "Inverse tone mapping (range expansion)", OFFSET(inverse_tonemapping), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1759 { "tonemapping_lut_size", "Tone-mapping LUT size", OFFSET(tonemapping_lut_size), AV_OPT_TYPE_INT, {.i64 = 256}, 2, 1024, DYNAMIC },
1760 { "contrast_recovery", "HDR contrast recovery strength", OFFSET(contrast_recovery), AV_OPT_TYPE_FLOAT, {.dbl = 0.30}, 0.0, 3.0, DYNAMIC },
1761 { "contrast_smoothness", "HDR contrast recovery smoothness", OFFSET(contrast_smoothness), AV_OPT_TYPE_FLOAT, {.dbl = 3.50}, 1.0, 32.0, DYNAMIC },
1762
1763 { "dithering", "Dither method to use", OFFSET(dithering), AV_OPT_TYPE_INT, {.i64 = PL_DITHER_BLUE_NOISE}, -1, PL_DITHER_METHOD_COUNT - 1, DYNAMIC, .unit = "dither" },
1764 { "none", "Disable dithering", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, STATIC, .unit = "dither" },
1765 { "blue", "Blue noise", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DITHER_BLUE_NOISE}, 0, 0, STATIC, .unit = "dither" },
1766 { "ordered", "Ordered LUT", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DITHER_ORDERED_LUT}, 0, 0, STATIC, .unit = "dither" },
1767 { "ordered_fixed", "Fixed function ordered", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DITHER_ORDERED_FIXED}, 0, 0, STATIC, .unit = "dither" },
1768 { "white", "White noise", 0, AV_OPT_TYPE_CONST, {.i64 = PL_DITHER_WHITE_NOISE}, 0, 0, STATIC, .unit = "dither" },
1769 { "dither_lut_size", "Dithering LUT size", OFFSET(dither_lut_size), AV_OPT_TYPE_INT, {.i64 = 6}, 1, 8, STATIC },
1770 { "dither_temporal", "Enable temporal dithering", OFFSET(dither_temporal), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1771
1772 { "cones", "Colorblindness adaptation model", OFFSET(cones), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, PL_CONE_LMS, DYNAMIC, .unit = "cone" },
1773 { "l", "L cone", 0, AV_OPT_TYPE_CONST, {.i64 = PL_CONE_L}, 0, 0, STATIC, .unit = "cone" },
1774 { "m", "M cone", 0, AV_OPT_TYPE_CONST, {.i64 = PL_CONE_M}, 0, 0, STATIC, .unit = "cone" },
1775 { "s", "S cone", 0, AV_OPT_TYPE_CONST, {.i64 = PL_CONE_S}, 0, 0, STATIC, .unit = "cone" },
1776 { "cone-strength", "Colorblindness adaptation strength", OFFSET(cone_str), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 10.0, DYNAMIC },
1777
1778 { "custom_shader_path", "Path to custom user shader (mpv .hook format)", OFFSET(shader_path), AV_OPT_TYPE_STRING, .flags = STATIC },
1779 { "custom_shader_bin", "Custom user shader as binary (mpv .hook format)", OFFSET(shader_bin), AV_OPT_TYPE_BINARY, .flags = STATIC },
1780
1781 /* Performance/quality tradeoff options */
1782 { "skip_aa", "Skip anti-aliasing", OFFSET(skip_aa), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1783 { "disable_linear", "Disable linear scaling", OFFSET(disable_linear), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1784 { "disable_builtin", "Disable built-in scalers", OFFSET(disable_builtin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1785 { "force_dither", "Force dithering", OFFSET(force_dither), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1786 { "disable_fbos", "Force-disable FBOs", OFFSET(disable_fbos), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
1787 { NULL },
1788};
1789
1791
1793 {
1794 .name = "default",
1795 .type = AVMEDIA_TYPE_VIDEO,
1796 .config_props = &libplacebo_config_output,
1797 },
1798};
1799
1801 .p.name = "libplacebo",
1802 .p.description = NULL_IF_CONFIG_SMALL("Apply various GPU filters from libplacebo"),
1803 .p.priv_class = &libplacebo_class,
1805 .priv_size = sizeof(LibplaceboContext),
1812 .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
1813};
@ VAR_CH
Definition aeval.c:49
@ VAR_T
Definition aeval.c:53
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
static const char *const format[]
Definition af_aiir.c:444
const FFFilter ff_vf_libplacebo
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
int ff_append_inpad_free_name(AVFilterContext *f, AVFilterPad *p)
Definition avfilter.c:132
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition avfilter.c:1467
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_outlink_frame_wanted(AVFilterLink *link)
Test if a frame is wanted on an output link.
Definition avfilter.c:1690
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition avfilter.c:906
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Definition avfilter.c:1520
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition avfilter.c:1623
char * av_asprintf(const char *fmt,...)
Definition avstring.c:115
@ VAR_VSUB
Definition boxblur.c:42
@ VAR_CW
Definition boxblur.c:39
@ VAR_HSUB
Definition boxblur.c:41
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
static IPT saturation(const CmsCtx *ctx, IPT ipt)
Definition cms.c:559
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static const AVColorPrimariesDesc color_primaries[AVCOL_PRI_NB]
Definition csp.c:76
static __device__ float fabsf(float a)
static AVFrame * frame
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition eval.c:368
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition eval.c:824
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition eval.c:735
simple arithmetic expression evaluator
@ VAR_IW
Definition f_select.c:147
@ VAR_IH
Definition f_select.c:146
static int dummy
Definition ffplay.c:3754
A generic FIFO API.
Misc file utilities.
int ff_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
Add ref as a new reference to formats.
Definition formats.c:756
AVFilterFormats * ff_all_color_spaces(void)
Construct an AVFilterFormats representing all possible color spaces.
Definition formats.c:697
AVFilterFormats * ff_make_formats_list_singleton(int fmt)
Equivalent to ff_make_format_list({const int[]}{ fmt, -1 })
Definition formats.c:596
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
Add fmt to the list of media formats contained in *avff.
Definition formats.c:571
void ff_formats_unref(AVFilterFormats **ref)
If *ref is non-NULL, remove *ref as a reference to the format list it currently points to,...
Definition formats.c:795
AVFilterFormats * ff_all_color_ranges(void)
Construct an AVFilterFormats representing all possible color ranges.
Definition formats.c:713
AVFilterFormats * ff_all_alpha_modes(void)
Construct an AVFilterFormats representing all possible alpha modes.
Definition formats.c:724
reference-counted frame API
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_BINARY
Underlying C type is a uint8_t* that is either NULL or points to an array allocated with the av_mallo...
Definition opt.h:285
@ AV_OPT_TYPE_FLAGS
Underlying C type is unsigned int.
Definition opt.h:254
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
@ AV_OPT_TYPE_DICT
Underlying C type is AVDictionary*.
Definition opt.h:289
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
@ AV_OPT_TYPE_COLOR
Underlying C type is uint8_t[4].
Definition opt.h:322
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition avfilter.h:187
#define AVFILTER_FLAG_DYNAMIC_INPUTS
The number of the filter inputs is not determined just by AVFilter.inputs.
Definition avfilter.h:155
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
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition dict.c:60
#define AV_DICT_IGNORE_SUFFIX
Return first entry in a dictionary whose first part corresponds to the search key,...
Definition dict.h:75
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition error.h:58
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition error.h:52
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition error.h:122
#define AVERROR(e)
Definition error.h:45
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
Definition fifo.c:47
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition fifo.c:286
#define AV_FIFO_FLAG_AUTO_GROW
Automatically resize the FIFO on writes, so that the data fits.
Definition fifo.h:63
int av_fifo_peek(const AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
Definition fifo.c:255
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
Definition fifo.c:188
void av_fifo_drain2(AVFifo *f, size_t size)
Discard the specified amount of data from an AVFifo.
Definition fifo.c:266
#define AV_FRAME_FLAG_INTERLACED
A flag to mark frames whose content is interlaced.
Definition frame.h:695
#define AV_FRAME_FLAG_TOP_FIELD_FIRST
A flag to mark frames where the top field is displayed first if the content is interlaced.
Definition frame.h:700
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition frame.c:659
void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type)
Remove and free all side data instances of the given type.
Definition frame.c:725
void av_frame_side_data_remove_by_props(AVFrameSideData ***sd, int *nb_sd, int props)
Remove and free all side data instances that match any of the given side data properties.
Definition side_data.c:123
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
@ AV_SIDE_DATA_PROP_SIZE_DEPENDENT
Side data depends on the video dimensions.
Definition frame.h:354
@ AV_SIDE_DATA_PROP_COLOR_DEPENDENT
Side data depends on the video color space.
Definition frame.h:361
@ AV_FRAME_DATA_DOVI_METADATA
Parsed Dolby Vision metadata, suitable for passing to a software implementation.
Definition frame.h:208
@ AV_FRAME_DATA_FILM_GRAIN_PARAMS
Film grain parameters for a frame, described by AVFilmGrainParams.
Definition frame.h:188
#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_FATAL
Something went wrong and recovery is not possible.
Definition log.h:204
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
int av_log_get_level(void)
Get the current log level.
Definition log.c:471
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition rational.c:80
AVRational av_gcd_q(AVRational a, AVRational b, int max_den, AVRational def)
Return the best rational so that a and b are multiple of it.
Definition rational.c:188
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition rational.h:104
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition rational.h:89
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition rational.h:159
AVRational av_div_q(AVRational b, AVRational c)
Divide one rational by another.
Definition rational.c:88
int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, enum AVRounding rnd)
Rescale a 64-bit integer by 2 rational numbers with specified rounding.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AV_ROUND_UP
Round toward +infinity.
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define AV_TIME_BASE
Internal time base represented as integer.
Definition avutil.h:253
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
int a
@ AV_HWDEVICE_TYPE_VULKAN
Definition hwcontext.h:39
const VkFormat * av_vkfmt_from_pixfmt(enum AVPixelFormat p)
Returns the optimal per-plane Vulkan format for a given sw_format, one for each plane.
#define b
Definition input.c:43
enum AVPixelFormat pixfmt
Definition kmsgrab.c:367
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
static int get_log_level(int level)
Definition lcevcdec.c:348
static int mix(int c0, int c1)
Definition 4xm.c:717
#define fixed(width, name, value)
Definition cbs_apv.c:75
static void log_cb(cmsContext ctx, cmsUInt32Number error, const char *str)
Definition fflcms2.c:24
const char * arg
Definition jacosubdec.c:65
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition filters.h:208
#define TS2T(ts, tb)
Definition filters.h:483
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition filters.h:629
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
Definition filters.h:34
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
Definition filters.h:652
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define FILTER_QUERY_FUNC2(func)
Definition filters.h:241
void av_file_unmap(uint8_t *bufptr, size_t size)
Unmap or free the buffer bufptr created by av_file_map().
Definition file.c:142
int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, int log_offset, void *log_ctx)
Read the file with name filename, and put its content in a newly allocated buffer or map it with mmap...
Definition file.c:55
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition internal.h:66
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition internal.h:67
void ff_vk_uninit(FFVulkanContext *s)
Frees main context.
Definition vulkan.c:2808
static av_always_inline av_const float roundf(float x)
Definition libm.h:453
const char * desc
Definition libsvtav1.c:83
uint8_t w
Definition llvidencdsp.c:39
#define FFSWAP(type, a, b)
Definition macros.h:52
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define NAN
#define M_PI
Definition mathematics.h:67
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:264
Memory handling functions.
var_name
Definition noise.c:46
@ VAR_N
Definition noise.c:47
@ VAR_VARS_NB
Definition noise.c:59
static const char *const var_names[]
Definition noise.c:30
AVOptions.
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
Definition parseutils.c:181
misc parsing utilities
enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc)
Definition pixdesc.c:3479
const AVPixFmtDescriptor * av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev)
Iterate over all pixel format descriptors known to libavutil.
Definition pixdesc.c:3467
enum AVPixelFormat av_get_pix_fmt(const char *name)
Return the pixel format corresponding to name.
Definition pixdesc.c:3392
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_FLAG_HWACCEL
Pixel format is an HW accelerated format.
Definition pixdesc.h:128
#define AV_PIX_FMT_FLAG_BE
Pixel format is big-endian.
Definition pixdesc.h:116
@ AVCHROMA_LOC_TOP
Definition pixfmt.h:807
@ AVCHROMA_LOC_BOTTOM
Definition pixfmt.h:809
@ AVCHROMA_LOC_TOPLEFT
ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2.
Definition pixfmt.h:806
@ AVCHROMA_LOC_NB
Not part of ABI.
Definition pixfmt.h:810
@ AVCHROMA_LOC_LEFT
MPEG-2/4 4:2:0, H.264 default for 4:2:0.
Definition pixfmt.h:804
@ AVCHROMA_LOC_BOTTOMLEFT
Definition pixfmt.h:808
@ AVCHROMA_LOC_CENTER
MPEG-1 4:2:0, JPEG 4:2:0, H.263 4:2:0.
Definition pixfmt.h:805
@ AVCHROMA_LOC_UNSPECIFIED
Definition pixfmt.h:803
@ AVCOL_RANGE_MPEG
Narrow or limited range content.
Definition pixfmt.h:766
@ AVCOL_RANGE_UNSPECIFIED
Definition pixfmt.h:749
@ AVCOL_RANGE_NB
Not part of ABI.
Definition pixfmt.h:784
@ AVCOL_RANGE_JPEG
Full range content.
Definition pixfmt.h:783
@ AVALPHA_MODE_NB
Not part of ABI.
Definition pixfmt.h:820
@ AVALPHA_MODE_STRAIGHT
Alpha channel is independent of color values.
Definition pixfmt.h:819
@ AVALPHA_MODE_UNSPECIFIED
Unknown alpha handling, or no alpha channel.
Definition pixfmt.h:817
@ AVALPHA_MODE_PREMULTIPLIED
Alpha channel is multiplied into color values.
Definition pixfmt.h:818
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
@ AVCOL_PRI_BT470BG
also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM
Definition pixfmt.h:649
@ AVCOL_PRI_FILM
colour filters using Illuminant C
Definition pixfmt.h:652
@ AVCOL_PRI_SMPTE432
SMPTE ST 432-1 (2010) / P3 D65 / Display P3.
Definition pixfmt.h:657
@ AVCOL_PRI_V_GAMUT
Definition pixfmt.h:664
@ AVCOL_PRI_BT709
also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP 177 Annex B
Definition pixfmt.h:644
@ AVCOL_PRI_EXT_NB
Not part of ABI.
Definition pixfmt.h:665
@ AVCOL_PRI_JEDEC_P22
Definition pixfmt.h:659
@ AVCOL_PRI_SMPTE240M
identical to above, also called "SMPTE C" even though it uses D65
Definition pixfmt.h:651
@ AVCOL_PRI_UNSPECIFIED
Definition pixfmt.h:645
@ AVCOL_PRI_EBU3213
EBU Tech. 3213-E (nothing there) / one of JEDEC P22 group phosphors.
Definition pixfmt.h:658
@ AVCOL_PRI_SMPTE431
SMPTE ST 431-2 (2011) / DCI P3.
Definition pixfmt.h:656
@ AVCOL_PRI_SMPTE428
SMPTE ST 428-1 (CIE 1931 XYZ)
Definition pixfmt.h:654
@ AVCOL_PRI_SMPTE170M
also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC
Definition pixfmt.h:650
@ AVCOL_PRI_BT2020
ITU-R BT2020.
Definition pixfmt.h:653
@ AVCOL_PRI_BT470M
also FCC Title 47 Code of Federal Regulations 73.682 (a)(20)
Definition pixfmt.h:647
@ AVCOL_TRC_SMPTE170M
also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC
Definition pixfmt.h:679
@ AVCOL_TRC_SMPTE2084
SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems.
Definition pixfmt.h:689
@ AVCOL_TRC_GAMMA22
also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
Definition pixfmt.h:677
@ AVCOL_TRC_V_LOG
Definition pixfmt.h:698
@ AVCOL_TRC_BT1361_ECG
ITU-R BT1361 Extended Colour Gamut.
Definition pixfmt.h:685
@ AVCOL_TRC_SMPTE240M
Definition pixfmt.h:680
@ AVCOL_TRC_IEC61966_2_4
IEC 61966-2-4.
Definition pixfmt.h:684
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition pixfmt.h:681
@ AVCOL_TRC_GAMMA28
also ITU-R BT470BG
Definition pixfmt.h:678
@ AVCOL_TRC_ARIB_STD_B67
ARIB STD-B67, known as "Hybrid log-gamma".
Definition pixfmt.h:693
@ AVCOL_TRC_BT2020_12
ITU-R BT2020 for 12-bit system.
Definition pixfmt.h:688
@ AVCOL_TRC_IEC61966_2_1
IEC 61966-2-1 (sRGB or sYCC)
Definition pixfmt.h:686
@ AVCOL_TRC_EXT_NB
Not part of ABI.
Definition pixfmt.h:699
@ AVCOL_TRC_BT2020_10
ITU-R BT2020 for 10-bit system.
Definition pixfmt.h:687
@ AVCOL_TRC_UNSPECIFIED
Definition pixfmt.h:675
@ AVCOL_TRC_BT709
also ITU-R BT1361
Definition pixfmt.h:674
@ AVCOL_SPC_BT709
also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / derived in SMPTE RP 177 Annex B
Definition pixfmt.h:708
@ AVCOL_SPC_BT470BG
also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601
Definition pixfmt.h:712
@ AVCOL_SPC_BT2020_CL
ITU-R BT2020 constant luminance system.
Definition pixfmt.h:718
@ AVCOL_SPC_NB
Not part of ABI.
Definition pixfmt.h:726
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition pixfmt.h:707
@ AVCOL_SPC_BT2020_NCL
ITU-R BT2020 non-constant luminance system.
Definition pixfmt.h:717
@ AVCOL_SPC_UNSPECIFIED
Definition pixfmt.h:709
@ AVCOL_SPC_SMPTE170M
also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above
Definition pixfmt.h:713
@ AVCOL_SPC_SMPTE240M
derived from 170M primaries and D65 white point, 170M is derived from BT470 System M's primaries
Definition pixfmt.h:714
@ AVCOL_SPC_YCGCO
used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16
Definition pixfmt.h:715
@ AVCOL_SPC_ICTCP
ITU-R BT.2100-0, ICtCp.
Definition pixfmt.h:722
const char * name
Definition qsvenc.c:142
@ VAR_OUT_H
Definition scale_eval.c:47
@ VAR_SAR
Definition scale_eval.c:49
@ VAR_OH
Definition scale_eval.c:47
@ VAR_IN_W
Definition scale_eval.c:44
@ VAR_OW
Definition scale_eval.c:46
@ VAR_OHSUB
Definition scale_eval.c:53
@ VAR_A
Definition scale_eval.c:48
@ VAR_OUT_W
Definition scale_eval.c:46
@ VAR_OVSUB
Definition scale_eval.c:54
@ VAR_IN_H
Definition scale_eval.c:45
@ VAR_DAR
Definition scale_eval.c:50
int ff_scale_adjust_dimensions(AVFilterLink *inlink, int *ret_w, int *ret_h, int force_original_aspect_ratio, int force_divisible_by, double w_adj)
Transform evaluated width and height obtained from ff_scale_eval_dimensions into actual target width ...
Definition scale_eval.c:123
int ff_scale_eval_dimensions(void *log_ctx, const char *w_expr, const char *h_expr, AVFilterLink *inlink, AVFilterLink *outlink, int *ret_w, int *ret_h)
Parse and evaluate string expressions for width and height.
Definition scale_eval.c:58
@ SCALE_FORCE_OAR_DISABLE
Definition scale_eval.h:25
@ SCALE_FORCE_OAR_NB
Definition scale_eval.h:28
@ SCALE_FORCE_OAR_INCREASE
Definition scale_eval.h:27
@ SCALE_FORCE_OAR_DECREASE
Definition scale_eval.h:26
formats
Definition signature.h:47
#define FF_ARRAY_ELEMS(a)
uint8_t * data
The data buffer.
Definition buffer.h:90
char * key
Definition dict.h:91
char * value
Definition dict.h:92
Definition eval.c:171
Definition fifo.c:35
An instance of a filter.
Definition avfilter.h:273
AVFilterLink ** inputs
array of pointers to input links
Definition avfilter.h:281
void * priv
private data for use by the filter
Definition avfilter.h:288
AVBufferRef * hw_device_ctx
For filters which will create hardware frames, sets the device the filter should create them in.
Definition avfilter.h:336
Lists of formats / etc.
Definition avfilter.h:120
AVFilterFormats * formats
List of supported formats (pixel or sample).
Definition avfilter.h:125
A list of supported formats for one end of a filter link.
Definition formats.h:64
unsigned refcount
number of references to this list
Definition formats.h:68
unsigned nb_formats
number of formats
Definition formats.h:65
A filter pad used for either input or output.
Definition filters.h:40
const char * name
Pad name.
Definition filters.h:46
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition frame.h:574
void * opaque
Frame owner's private data.
Definition frame.h:610
int64_t duration
Duration of the frame, in the same units as pts.
Definition frame.h:820
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition hwcontext.h:63
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition hwcontext.h:88
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition hwcontext.h:75
This struct describes a set or pool of "hardware" frames (i.e.
Definition hwcontext.h:118
AVBufferRef * device_ref
A reference to the parent AVHWDeviceContext.
Definition hwcontext.h:129
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition hwcontext.h:153
AVHWDeviceContext * device_ctx
The parent AVHWDeviceContext.
Definition hwcontext.h:137
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition pixdesc.h:80
uint64_t flags
Combination of AV_PIX_FMT_FLAG_... flags.
Definition pixdesc.h:94
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition pixdesc.h:89
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
Main Vulkan context, allocated as AVHWDeviceContext.hwctx.
VkPhysicalDevice phys_dev
Physical device.
AVVulkanDeviceQueueFamily qf[64]
Queue families used.
const char *const * enabled_dev_extensions
Enabled device extensions.
VkDevice act_dev
Active device.
VkInstance inst
Vulkan instance.
VkPhysicalDeviceFeatures2 device_features
This structure should be set to the set of features that present and enabled during device creation.
VkDeviceQueueCreateFlags queue_flags
PFN_vkGetInstanceProcAddr get_proc_addr
Pointer to a vkGetInstanceProcAddr loading function.
Allocated as AVHWFramesContext.hwctx, used to set pool-specific options.
VkImageUsageFlagBits usage
Defines extra usage of output frames.
struct pl_custom_lut * lut
double var_values[VAR_VARS_NB]
AVDictionary * extra_opts
enum AVPixelFormat out_format
AVRational fps
parsed FPS, or 0/0 for "none"
pl_renderer linear_rr
LibplaceboInput * inputs
const struct pl_hook * hooks[2]
FFVulkanContext vkctx
struct pl_frame_mix mix
temporary storage
enum pl_queue_status qstatus
pl_renderer renderer
AVFifo * out_pts
timestamps of wanted output frames
Definition dct.c:58
uint8_t level
Definition svq3.c:208
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static int ref[MAX_W *MAX_W]
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
static AVDictionary * opts
Definition movenc.c:51
static int64_t pts
preset
Definition vf_curves.c:47
static float sigmoid(float x)
static int libplacebo_config_output(AVFilterLink *outlink)
@ VAR_CROP_H
@ VAR_POS_W
@ VAR_CROP_W
@ VAR_IN_IDX
@ VAR_POS_H
@ VAR_PH
@ VAR_IDX
@ VAR_OT
@ VAR_IN_T
@ VAR_VARS_NB
@ VAR_PW
@ VAR_OUT_T
static int update_settings(AVFilterContext *ctx)
static int find_scaler(AVFilterContext *avctx, const struct pl_filter_config **opt, const char *name, int frame_mixing)
#define STATIC
static const AVOption libplacebo_options[]
#define DYNAMIC
static void pl_av_log(void *log_ctx, enum pl_log_level level, const char *msg)
static int parse_shader(AVFilterContext *avctx, const void *shader, size_t len)
static int init_vulkan(AVFilterContext *avctx, const AVVulkanDeviceContext *hwctx)
static const AVFilterPad libplacebo_outputs[]
static void lock_queue(void *priv, uint32_t qf, uint32_t qidx)
static void libplacebo_uninit(AVFilterContext *avctx)
static int handle_input(AVFilterContext *ctx, LibplaceboInput *input)
static int output_frame(AVFilterContext *ctx, int64_t pts)
static void unlock_queue(void *priv, uint32_t qf, uint32_t qidx)
static void unmap_frame(pl_gpu gpu, struct pl_frame *frame, const struct pl_source_frame *src)
static void set_gamut_mode(struct pl_color_map_params *p, int gamut_mode)
static int libplacebo_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
static void drain_input_pts(LibplaceboInput *in, int64_t until)
static int libplacebo_init(AVFilterContext *avctx)
@ GAMUT_MAP_LINEAR
@ GAMUT_MAP_ABSOLUTE
@ GAMUT_MAP_DESATURATE
@ GAMUT_MAP_COUNT
@ GAMUT_MAP_DARKEN
@ GAMUT_MAP_CLIP
@ GAMUT_MAP_PERCEPTUAL
@ GAMUT_MAP_RELATIVE
@ GAMUT_MAP_SATURATION
@ GAMUT_MAP_HIGHLIGHT
static int parse_custom_lut(AVFilterContext *avctx)
static const AVFrame * ref_frame(const struct pl_frame_mix *mix)
static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src, struct pl_frame *out)
fit_sense
@ FIT_TARGET
@ FIT_CONSTRAINT
@ FIT_SENSE_NB
static void discard_frame(const struct pl_source_frame *src)
static int libplacebo_config_input(AVFilterLink *inlink)
static AVRational max_q(AVRational a, AVRational b)
static int copy_pl_queue(const AVVulkanDeviceContext *hwctx, const AVVulkanDeviceQueueFamily *qf, struct pl_vulkan_queue *pl_qf)
static int input_init(AVFilterContext *avctx, LibplaceboInput *input, int idx)
static const struct pl_tone_map_function * get_tonemapping_func(int tm)
#define OFFSET(x)
fit_mode
@ FIT_SCALE_DOWN
@ FIT_COVER
@ FIT_FILL
@ FIT_CONTAIN
@ FIT_NONE
@ FIT_MODE_NB
static int libplacebo_query_format(const AVFilterContext *ctx, AVFilterFormatsConfig **cfg_in, AVFilterFormatsConfig **cfg_out)
static double q2d_fallback(AVRational q, const double def)
static void update_crops(AVFilterContext *ctx, LibplaceboInput *in, struct pl_frame *target, double target_pts)
static int libplacebo_activate(AVFilterContext *ctx)
static enum pl_log_level get_log_level(void)
static void input_uninit(LibplaceboInput *input)
@ TONE_MAP_BT2390
@ TONE_MAP_BT2446A
@ TONE_MAP_SPLINE
@ TONE_MAP_ST2094_40
@ TONE_MAP_LINEAR
@ TONE_MAP_HABLE
@ TONE_MAP_AUTO
@ TONE_MAP_CLIP
@ TONE_MAP_GAMMA
@ TONE_MAP_ST2094_10
@ TONE_MAP_COUNT
@ TONE_MAP_REINHARD
@ TONE_MAP_MOBIUS
color_range
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition video.c:89
int len
#define RET(x)
Definition vulkan.h:37
int ff_vk_filter_config_input(AVFilterLink *inlink)
int ff_vk_filter_config_output(AVFilterLink *outlink)