On Fri, 12 Nov 2021 at 13:59, Niklas Haas <ffm...@haasn.xyz> wrote: > From: Niklas Haas <g...@haasn.dev> > > This filter conceptually maps the libplacebo `pl_renderer` API into > libavfilter, which is a high-level image rendering API designed to work > with an RGB pipeline internally. As such, there's no way to avoid e.g. > chroma interpolation with this filter, although new versions of > libplacebo support outputting back to subsampled YCbCr after processing > is done. > > That being said, `pl_renderer` supports automatic integration of the > majority of libplacebo's shaders, ranging from debanding to tone > mapping, and also supports loading custom mpv-style user shaders, making > this API a natural candidate for getting a lot of functionality out of > relatively little code. > > In the future, I may approach this problem either by rewriting this > filter to also support a non-renderer codepath, or by upgrading > libplacebo's renderer to support a full YCbCr pipeline. > > This unfortunately requires a very new version of libplacebo (unreleased > at time of writing) for timeline semaphore support. But the amount of > boilerplate needed to hack in backwards compatibility would have been > very unreasonable. > --- > configure | 3 + > libavfilter/Makefile | 1 + > libavfilter/allfilters.c | 1 + > libavfilter/vf_libplacebo.c | 717 ++++++++++++++++++++++++++++++++++++ > 4 files changed, 722 insertions(+) > create mode 100644 libavfilter/vf_libplacebo.c > > diff --git a/configure b/configure > index eb451d2782..891824757b 100755 > --- a/configure > +++ b/configure > @@ -1827,6 +1827,7 @@ EXTERNAL_LIBRARY_LIST=" > libopenmpt > libopenvino > libopus > + libplacebo > libpulse > librabbitmq > librav1e > @@ -3618,6 +3619,7 @@ interlace_filter_deps="gpl" > kerndeint_filter_deps="gpl" > ladspa_filter_deps="ladspa libdl" > lensfun_filter_deps="liblensfun version3" > +libplacebo_filter_deps="libplacebo vulkan libglslang" > lv2_filter_deps="lv2" > mcdeint_filter_deps="avcodec gpl" > metadata_filter_deps="avformat" > @@ -6493,6 +6495,7 @@ enabled libopus && { > require_pkg_config libopus opus opus_multistream.h > opus_multistream_surround_encoder_create > } > } > +enabled libplacebo && require_pkg_config libplacebo "libplacebo >= > 4.173.0" libplacebo/vulkan.h pl_vulkan_create > enabled libpulse && require_pkg_config libpulse libpulse > pulse/pulseaudio.h pa_context_new > enabled librabbitmq && require_pkg_config librabbitmq "librabbitmq > >= 0.7.1" amqp.h amqp_new_connection > enabled librav1e && require_pkg_config librav1e "rav1e >= 0.4.0" > rav1e.h rav1e_context_new > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > index 552bd4e286..e2059766b0 100644 > --- a/libavfilter/Makefile > +++ b/libavfilter/Makefile > @@ -323,6 +323,7 @@ OBJS-$(CONFIG_LAGFUN_FILTER) += > vf_lagfun.o > OBJS-$(CONFIG_LATENCY_FILTER) += f_latency.o > OBJS-$(CONFIG_LENSCORRECTION_FILTER) += vf_lenscorrection.o > OBJS-$(CONFIG_LENSFUN_FILTER) += vf_lensfun.o > +OBJS-$(CONFIG_LIBPLACEBO_FILTER) += vf_libplacebo.o vulkan.o > OBJS-$(CONFIG_LIBVMAF_FILTER) += vf_libvmaf.o framesync.o > OBJS-$(CONFIG_LIMITDIFF_FILTER) += vf_limitdiff.o framesync.o > OBJS-$(CONFIG_LIMITER_FILTER) += vf_limiter.o > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > index 667b6fc246..be94249024 100644 > --- a/libavfilter/allfilters.c > +++ b/libavfilter/allfilters.c > @@ -308,6 +308,7 @@ extern const AVFilter ff_vf_lagfun; > extern const AVFilter ff_vf_latency; > extern const AVFilter ff_vf_lenscorrection; > extern const AVFilter ff_vf_lensfun; > +extern const AVFilter ff_vf_libplacebo; > extern const AVFilter ff_vf_libvmaf; > extern const AVFilter ff_vf_limitdiff; > extern const AVFilter ff_vf_limiter; > diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c > new file mode 100644 > index 0000000000..3b48674d1a > --- /dev/null > +++ b/libavfilter/vf_libplacebo.c > @@ -0,0 +1,717 @@ > +/* > + * This file is part of FFmpeg. > + * > + * FFmpeg is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * FFmpeg is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA > 02110-1301 USA > + */ > + > +#include "libavutil/file.h" > +#include "libavutil/opt.h" > +#include "internal.h" > +#include "vulkan.h" > +#include "scale_eval.h" > + > +#include <libplacebo/renderer.h> > +#include <libplacebo/utils/libav.h> > +#include <libplacebo/vulkan.h> > + > +typedef struct LibplaceboContext { > + /* lavfi vulkan*/ > + FFVulkanContext vkctx; > + int initialized; > + > + /* libplacebo */ > + pl_log log; > + pl_vulkan vulkan; > + pl_gpu gpu; > + pl_renderer renderer; > + > + /* settings */ > + char *out_format_string; > + char *w_expr; > + char *h_expr; > + AVRational target_sar; > + float pad_crop_ratio; > + int force_original_aspect_ratio; > + int force_divisible_by; > + int normalize_sar; > + int apply_filmgrain; > + int colorspace; > + int color_range; > + int color_primaries; > + int color_trc; > + > + /* pl_render_params */ > + char *upscaler; > + char *downscaler; > + int lut_entries; > + float antiringing; > + int sigmoid; > + int skip_aa; > + float polar_cutoff; > + int disable_linear; > + int disable_builtin; > + int force_3dlut; > + int force_dither; > + int disable_fbos; > + > + /* pl_deband_params */ > + int deband; > + int deband_iterations; > + float deband_threshold; > + float deband_radius; > + float deband_grain; > + > + /* pl_color_adjustment */ > + float brightness; > + float contrast; > + float saturation; > + float hue; > + float gamma; > + > + /* pl_peak_detect_params */ > + int peakdetect; > + float smoothing; > + float min_peak; > + float scene_low; > + float scene_high; > + float overshoot; > + > + /* pl_color_map_params */ > + int intent; > + int tonemapping; > + float tonemapping_param; > + float desat_str; > + float desat_exp; > + float desat_base; > + float max_boost; > + int gamut_warning; > + int gamut_clipping; > + > + /* pl_dither_params */ > + int dithering; > + int dither_lut_size; > + int dither_temporal; > + > + /* pl_cone_params */ > + int cones; > + float cone_str; > + > + /* custom shaders */ > + char *shader_path; > + void *shader_bin; > + int shader_bin_len; > + const struct pl_hook *hooks[2]; > + int num_hooks; > +} LibplaceboContext; > + > +static void pl_av_log(void *log_ctx, enum pl_log_level level, const char > *msg) > +{ > + int av_lev; > + > + switch (level) { > + case PL_LOG_FATAL: av_lev = AV_LOG_FATAL; break; > + case PL_LOG_ERR: av_lev = AV_LOG_ERROR; break; > + case PL_LOG_WARN: av_lev = AV_LOG_WARNING; break; > + case PL_LOG_INFO: av_lev = AV_LOG_VERBOSE; break; > + case PL_LOG_DEBUG: av_lev = AV_LOG_DEBUG; break; > + case PL_LOG_TRACE: av_lev = AV_LOG_TRACE; break; > + default: return; > + } > + > + av_log(log_ctx, av_lev, "%s\n", msg); > +} > + > +static int parse_shader(AVFilterContext *avctx, const void *shader, > size_t len) > +{ > + LibplaceboContext *s = avctx->priv; > + const struct pl_hook *hook; > + > + hook = pl_mpv_user_shader_parse(s->gpu, shader, len); > + if (!hook) { > + av_log(s, AV_LOG_ERROR, "Failed parsing custom shader!\n"); > + return AVERROR(EINVAL); > + } > + > + s->hooks[s->num_hooks++] = hook; > + return 0; > +} > + > +static int find_scaler(AVFilterContext *avctx, > + const struct pl_filter_config **opt, > + const char *name) > +{ > + const struct pl_filter_preset *preset; > + if (!strcmp(name, "help")) { > + av_log(avctx, AV_LOG_INFO, "Available scaler presets:\n"); > + for (preset = pl_scale_filters; preset->name; preset++) > + av_log(avctx, AV_LOG_INFO, " %s\n", preset->name); > + return AVERROR_EXIT; > + } > + > + for (preset = pl_scale_filters; preset->name; preset++) { > + if (!strcmp(name, preset->name)) { > + *opt = preset->filter; > + return 0; > + } > + } > + > + av_log(avctx, AV_LOG_ERROR, "No such scaler preset '%s'.\n", name); > + return AVERROR(EINVAL); > +} > + > +static int libplacebo_init(AVFilterContext *avctx) > +{ > + LibplaceboContext *s = avctx->priv; > + > + /* Create libplacebo log context */ > + s->log = pl_log_create(PL_API_VER, pl_log_params( > + .log_level = PL_LOG_DEBUG, > + .log_cb = pl_av_log, > + .log_priv = s, > + )); > + > + if (!s->log) > + return AVERROR(ENOMEM); > + > + /* Note: s->vulkan etc. are initialized later, when hwctx is > available */ > + return 0; > +} > + > +static int init_vulkan(AVFilterContext *avctx) > +{ > + int err = 0; > + LibplaceboContext *s = avctx->priv; > + const AVVulkanDeviceContext *hwctx = s->vkctx.hwctx; > + uint8_t *buf = NULL; > + size_t buf_len; > + > + /* Import libavfilter vulkan context into libplacebo */ > + s->vulkan = pl_vulkan_import(s->log, pl_vulkan_import_params( > + .instance = hwctx->inst, > + .get_proc_addr = hwctx->get_proc_addr, > + .phys_device = hwctx->phys_dev, > + .device = hwctx->act_dev, > + .extensions = hwctx->enabled_dev_extensions, > + .num_extensions = hwctx->nb_enabled_dev_extensions, > + .features = &hwctx->device_features, > + .queue_graphics = { > + .index = hwctx->queue_family_index, > + .count = hwctx->nb_graphics_queues, > + }, > + .queue_compute = { > + .index = hwctx->queue_family_comp_index, > + .count = hwctx->nb_comp_queues, > + }, > + .queue_transfer = { > + .index = hwctx->queue_family_tx_index, > + .count = hwctx->nb_tx_queues, > + }, > + /* This is the highest version created by hwcontext_vulkan.c */ > + .max_api_version = VK_API_VERSION_1_2, > + )); > + > + if (!s->vulkan) { > + av_log(s, AV_LOG_ERROR, "Failed importing vulkan device to > libplacebo!\n"); > + err = AVERROR_EXTERNAL; > + goto fail; > + } > + > + /* Create the renderer */ > + s->gpu = s->vulkan->gpu; > + s->renderer = pl_renderer_create(s->log, s->gpu); > + > + /* Parse the user shaders, if requested */ > + if (s->shader_bin_len) > + RET(parse_shader(avctx, s->shader_bin, s->shader_bin_len)); > + > + if (s->shader_path && s->shader_path[0]) { > + RET(av_file_map(s->shader_path, &buf, &buf_len, 0, s)); > + RET(parse_shader(avctx, buf, buf_len)); > + } > + > + /* fall through */ > +fail: > + if (buf) > + av_file_unmap(buf, buf_len); > + s->initialized = 1; > + return err; > +} > + > +static void libplacebo_uninit(AVFilterContext *avctx) > +{ > + LibplaceboContext *s = avctx->priv; > + > + for (int i = 0; i < s->num_hooks; i++) > + pl_mpv_user_shader_destroy(&s->hooks[i]); > + pl_renderer_destroy(&s->renderer); > + pl_vulkan_destroy(&s->vulkan); > + pl_log_destroy(&s->log); > + ff_vk_filter_uninit(avctx); > + s->initialized = 0; > + s->gpu = NULL; > +} > + > +static int wrap_vkframe(pl_gpu gpu, const AVFrame *frame, int plane, > pl_tex *tex) > +{ > + AVVkFrame *vkf = (AVVkFrame *) frame->data[0]; > + const AVHWFramesContext *hwfc = (AVHWFramesContext *) > frame->hw_frames_ctx->data; > + const AVVulkanFramesContext *vkfc = hwfc->hwctx; > + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(hwfc->sw_format); > + const VkFormat *vk_fmt = av_vkfmt_from_pixfmt(hwfc->sw_format); > + const int chroma = plane == 1 || plane == 2; > + > + *tex = pl_vulkan_wrap(gpu, pl_vulkan_wrap_params( > + .image = vkf->img[plane], > + .format = vk_fmt[plane], > + .width = AV_CEIL_RSHIFT(frame->width, chroma ? > desc->log2_chroma_w : 0), > + .height = AV_CEIL_RSHIFT(frame->height, chroma ? > desc->log2_chroma_h : 0), > + .usage = vkfc->usage, > + )); > + > + if (!*tex) > + return AVERROR(ENOMEM); > + > + pl_vulkan_release(gpu, *tex, vkf->layout[plane], (pl_vulkan_sem) { > + .sem = vkf->sem[plane], > + .value = vkf->sem_value[plane] > + }); > + return 0; > +} > + > +static int unwrap_vkframe(pl_gpu gpu, AVFrame *frame, int plane, pl_tex > *tex) > +{ > + AVVkFrame *vkf = (AVVkFrame *) frame->data[0]; > + uint64_t sem_value = ++vkf->sem_value[plane]; > + int ok = pl_vulkan_hold_raw(gpu, *tex, &vkf->layout[plane], > + (pl_vulkan_sem) { vkf->sem[plane], > sem_value }); > + vkf->access[plane] = 0; > + return ok ? 0 : AVERROR_EXTERNAL; > +} > + > +static void set_sample_depth(struct pl_frame *out_frame, const AVFrame > *frame) > +{ > + const AVHWFramesContext *hwfc = (AVHWFramesContext *) > frame->hw_frames_ctx->data; > + pl_fmt fmt = out_frame->planes[0].texture->params.format; > + struct pl_bit_encoding *bits = &out_frame->repr.bits; > + bits->sample_depth = fmt->component_depth[0]; > + > + switch (hwfc->sw_format) { > + case AV_PIX_FMT_P010: bits->bit_shift = 6; break; > + default: break; > + } > +} > + > +static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame > *in) > +{ > + int err = 0; > + LibplaceboContext *s = avctx->priv; > + struct pl_render_params params; > + struct pl_frame image, target; > + pl_frame_from_avframe(&image, in); > + pl_frame_from_avframe(&target, out); > + > + if (!s->apply_filmgrain) > + image.film_grain.type = PL_FILM_GRAIN_NONE; > + > + if (s->target_sar.num) { > + float aspect = pl_rect2df_aspect(&target.crop) * > av_q2d(s->target_sar); > + pl_rect2df_aspect_set(&target.crop, aspect, s->pad_crop_ratio); > + } > + > + /* Update render params */ > + params = (struct pl_render_params) { > + PL_RENDER_DEFAULTS > + .lut_entries = s->lut_entries, > + .antiringing_strength = s->antiringing, > + > + .deband_params = !s->deband ? NULL : pl_deband_params( > + .iterations = s->deband_iterations, > + .threshold = s->deband_threshold, > + .radius = s->deband_radius, > + .grain = s->deband_grain, > + ), > + > + .sigmoid_params = s->sigmoid ? &pl_sigmoid_default_params : NULL, > + > + .color_adjustment = &(struct pl_color_adjustment) { > + .brightness = s->brightness, > + .contrast = s->contrast, > + .saturation = s->saturation, > + .hue = s->hue, > + .gamma = s->gamma, > + }, > + > + .peak_detect_params = !s->peakdetect ? NULL : > pl_peak_detect_params( > + .smoothing_period = s->smoothing, > + .minimum_peak = s->min_peak, > + .scene_threshold_low = s->scene_low, > + .scene_threshold_high = s->scene_high, > + .overshoot_margin = s->overshoot, > + ), > + > + .color_map_params = pl_color_map_params( > + .intent = s->intent, > + .tone_mapping_algo = s->tonemapping, > + .tone_mapping_param = s->tonemapping_param, > + .desaturation_strength = s->desat_str, > + .desaturation_exponent = s->desat_exp, > + .desaturation_base = s->desat_base, > + .max_boost = s->max_boost, > + .gamut_warning = s->gamut_warning, > + .gamut_clipping = s->gamut_clipping, > + ), > + > + .dither_params = s->dithering < 0 ? NULL : pl_dither_params( > + .method = s->dithering, > + .lut_size = s->dither_lut_size, > + .temporal = s->dither_temporal, > + ), > + > + .cone_params = !s->cones ? NULL : pl_cone_params( > + .cones = s->cones, > + .strength = s->cone_str, > + ), > + > + .hooks = s->hooks, > + .num_hooks = s->num_hooks, > + > + .skip_anti_aliasing = s->skip_aa, > + .polar_cutoff = s->polar_cutoff, > + .disable_linear_scaling = s->disable_linear, > + .disable_builtin_scalers = s->disable_builtin, > + .force_3dlut = s->force_3dlut, > + .force_dither = s->force_dither, > + .disable_fbos = s->disable_fbos, > + }; > + > + RET(find_scaler(avctx, ¶ms.upscaler, s->upscaler)); > + RET(find_scaler(avctx, ¶ms.downscaler, s->downscaler)); > + > + /* Ideally, we would persistently wrap all of these AVVkFrames into > pl_tex > + * objects, but for now we'll just create and destroy a wrapper per > frame. > + * Note that doing it this way is suboptimal, since it results in the > + * creation and destruction of a VkSampler and VkFramebuffer per > frame. > + * > + * FIXME: Can we do better? */ > + for (int i = 0; i < image.num_planes; i++) > + RET(wrap_vkframe(s->gpu, in, i, &image.planes[i].texture)); > + for (int i = 0; i < target.num_planes; i++) > + RET(wrap_vkframe(s->gpu, out, i, &target.planes[i].texture)); > + > + /* Since we-re mapping vkframes manually, the pl_frame helpers don't > know > + * about the mismatch between the sample format and the color depth. > */ > + set_sample_depth(&image, in); > + set_sample_depth(&target, out); > + > + pl_render_image(s->renderer, &image, &target, ¶ms); > + > + for (int i = 0; i < image.num_planes; i++) > + RET(unwrap_vkframe(s->gpu, in, i, &image.planes[i].texture)); > + for (int i = 0; i < target.num_planes; i++) > + RET(unwrap_vkframe(s->gpu, out, i, &target.planes[i].texture)); > + > + /* Flush the command queues for performance */ > + pl_gpu_flush(s->gpu); > + > + /* fall through */ > +fail: > + for (int i = 0; i < image.num_planes; i++) > + pl_tex_destroy(s->gpu, &image.planes[i].texture); > + for (int i = 0; i < target.num_planes; i++) > + pl_tex_destroy(s->gpu, &target.planes[i].texture); > + return err; > +} > + > +static int filter_frame(AVFilterLink *link, AVFrame *in) > +{ > + int err; > + AVFilterContext *ctx = link->dst; > + LibplaceboContext *s = ctx->priv; > + AVFilterLink *outlink = ctx->outputs[0]; > + > + AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); > + if (!out) { > + err = AVERROR(ENOMEM); > + goto fail; > + } > + > + if (!s->initialized) > + RET(init_vulkan(ctx)); > + > + RET(av_frame_copy_props(out, in)); > + out->width = outlink->w; > + out->height = outlink->h; > + > + if (s->colorspace >= 0) > + out->colorspace = s->colorspace; > + if (s->color_range >= 0) > + out->color_range = s->color_range; > + if (s->color_trc >= 0) > + out->color_trc = s->color_trc; > + if (s->color_primaries >= 0) > + out->color_primaries = s->color_primaries; > + > + RET(process_frames(ctx, out, in)); > + > + if (s->apply_filmgrain) > + av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS); > + > + av_frame_free(&in); > + > + return ff_filter_frame(outlink, out); > + > +fail: > + av_frame_free(&in); > + av_frame_free(&out); > + return err; > +} > + > +static int libplacebo_config_output(AVFilterLink *outlink) > +{ > + int err; > + AVFilterContext *avctx = outlink->src; > + LibplaceboContext *s = avctx->priv; > + AVFilterLink *inlink = outlink->src->inputs[0]; > + AVHWFramesContext *hwfc; > + AVVulkanFramesContext *vkfc; > + AVRational scale_sar; > + int *out_w = &s->vkctx.output_width; > + int *out_h = &s->vkctx.output_height; > + > + RET(ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, inlink, outlink, > + out_w, out_h)); > + > + ff_scale_adjust_dimensions(inlink, out_w, out_h, > + s->force_original_aspect_ratio, > + s->force_divisible_by); > + > + scale_sar = (AVRational){outlink->h * inlink->w, *out_w * *out_h}; > + if (inlink->sample_aspect_ratio.num) > + scale_sar = av_mul_q(scale_sar, inlink->sample_aspect_ratio); > + > + if (s->normalize_sar) { > + /* Apply all SAR during scaling, so we don't need to set the out > SAR */ > + s->target_sar = scale_sar; > + } else { > + /* This is consistent with other scale_* filters, which only > + * set the outlink SAR to be equal to the scale SAR iff the input > SAR > + * was set to something nonzero */ > + if (inlink->sample_aspect_ratio.num) > + outlink->sample_aspect_ratio = scale_sar; > + } > + > + if (s->out_format_string) { > + s->vkctx.output_format = av_get_pix_fmt(s->out_format_string); > + if (s->vkctx.output_format == AV_PIX_FMT_NONE) { > + av_log(avctx, AV_LOG_ERROR, "Invalid output format.\n"); > + return AVERROR(EINVAL); > + } > + } else { > + /* Default to re-using the input format */ > + s->vkctx.output_format = s->vkctx.input_format; > + } > + > + RET(ff_vk_filter_config_output(outlink)); > + hwfc = (AVHWFramesContext *) outlink->hw_frames_ctx->data; > + vkfc = hwfc->hwctx; > + vkfc->usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; > + > + return 0; > + > +fail: > + return err; > +} > + > +#define OFFSET(x) offsetof(LibplaceboContext, x) > +#define STATIC (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) > +#define DYNAMIC (STATIC | AV_OPT_FLAG_RUNTIME_PARAM) > + > +static const AVOption libplacebo_options[] = { > + { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, > {.str = "iw"}, .flags = STATIC }, > + { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, > {.str = "ih"}, .flags = STATIC }, > + { "format", "Output video format", OFFSET(out_format_string), > AV_OPT_TYPE_STRING, .flags = STATIC }, > + { "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, 2, STATIC, "force_oar" }, > + { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, > STATIC, "force_oar" }, > + { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, > STATIC, "force_oar" }, > + { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, > STATIC, "force_oar" }, > + { "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 }, > + { "normalize_sar", "force SAR normalization to 1:1", > OFFSET(normalize_sar), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, STATIC }, > + { "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 }, > + > + {"colorspace", "select colorspace", OFFSET(colorspace), > AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_SPC_NB-1, DYNAMIC, "colorspace"}, > + {"auto", "keep the same colorspace", 0, AV_OPT_TYPE_CONST, > {.i64=-1}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"gbr", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_RGB}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_BT709}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_BT470BG}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_SMPTE170M}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_SMPTE240M}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"ycgco", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_YCGCO}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_BT2020_NCL}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"bt2020c", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_BT2020_CL}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + {"ictcp", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_SPC_ICTCP}, INT_MIN, INT_MAX, STATIC, "colorspace"}, > + > + {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, > {.i64=-1}, -1, AVCOL_RANGE_NB-1, DYNAMIC, "range"}, > + {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, > {.i64=-1}, 0, 0, STATIC, "range"}, > + {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, STATIC, "range"}, > + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, STATIC, "range"}, > + {"limited", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_MPEG}, 0, 0, STATIC, "range"}, > + {"tv", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_MPEG}, 0, 0, STATIC, "range"}, > + {"mpeg", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_MPEG}, 0, 0, STATIC, "range"}, > + {"full", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, "range"}, > + {"pc", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, "range"}, > + {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_RANGE_JPEG}, 0, 0, STATIC, "range"}, > + > + {"color_primaries", "select color primaries", > OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_NB-1, > DYNAMIC, "color_primaries"}, > + {"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, > {.i64=-1}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_BT709}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_BT470M}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_BT470BG}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_SMPTE170M}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_SMPTE240M}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"film", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_FILM}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_BT2020}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_SMPTE428}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_SMPTE431}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_SMPTE432}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_JEDEC_P22}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_PRI_EBU3213}, INT_MIN, INT_MAX, STATIC, "color_primaries"}, > + > + {"color_trc", "select color transfer", OFFSET(color_trc), > AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_NB-1, DYNAMIC, "color_trc"}, > + {"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, > {.i64=-1}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_BT709}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_UNSPECIFIED}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_GAMMA22}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_GAMMA28}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_SMPTE170M}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_SMPTE240M}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"linear", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_LINEAR}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_IEC61966_2_4}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_BT1361_ECG}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_IEC61966_2_1}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_BT2020_10}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_BT2020_12}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_SMPTE2084}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, > {.i64=AVCOL_TRC_ARIB_STD_B67}, INT_MIN, INT_MAX, STATIC, "color_trc"}, > + > + { "upscaler", "Upscaler function", OFFSET(upscaler), > AV_OPT_TYPE_STRING, {.str = "spline36"}, .flags = DYNAMIC }, > + { "downscaler", "Downscaler function", OFFSET(downscaler), > AV_OPT_TYPE_STRING, {.str = "mitchell"}, .flags = DYNAMIC }, > + { "lut_entries", "Number of scaler LUT entries", OFFSET(lut_entries), > AV_OPT_TYPE_INT, {.i64 = 0}, 0, 256, DYNAMIC }, > + { "antiringing", "Antiringing strength (for non-EWA filters)", > OFFSET(antiringing), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 1.0, DYNAMIC }, > + { "sigmoid", "Enable sigmoid upscaling", OFFSET(sigmoid), > AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC }, > + { "apply_filmgrain", "Apply film grain metadata", > OFFSET(apply_filmgrain), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC }, > + > + { "deband", "Enable debanding", OFFSET(deband), AV_OPT_TYPE_BOOL, > {.i64 = 0}, 0, 1, DYNAMIC }, > + { "deband_iterations", "Deband iterations", > OFFSET(deband_iterations), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 16, DYNAMIC }, > + { "deband_threshold", "Deband threshold", OFFSET(deband_threshold), > AV_OPT_TYPE_FLOAT, {.dbl = 4.0}, 0.0, 1024.0, DYNAMIC }, > + { "deband_radius", "Deband radius", OFFSET(deband_radius), > AV_OPT_TYPE_FLOAT, {.dbl = 16.0}, 0.0, 1024.0, DYNAMIC }, > + { "deband_grain", "Deband grain", OFFSET(deband_grain), > AV_OPT_TYPE_FLOAT, {.dbl = 6.0}, 0.0, 1024.0, DYNAMIC }, > + > + { "brightness", "Brightness boost", OFFSET(brightness), > AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, -1.0, 1.0, DYNAMIC }, > + { "contrast", "Contrast gain", OFFSET(contrast), AV_OPT_TYPE_FLOAT, > {.dbl = 1.0}, 0.0, 16.0, DYNAMIC }, > + { "saturation", "Saturation gain", OFFSET(saturation), > AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 16.0, DYNAMIC }, > + { "hue", "Hue shift", OFFSET(hue), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, > -M_PI, M_PI, DYNAMIC }, > + { "gamma", "Gamma adjustment", OFFSET(gamma), AV_OPT_TYPE_FLOAT, > {.dbl = 1.0}, 0.0, 16.0, DYNAMIC }, > + > + { "peak_detect", "Enable dynamic peak detection for HDR > tone-mapping", OFFSET(peakdetect), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, > DYNAMIC }, > + { "smoothing_period", "Peak detection smoothing period", > OFFSET(smoothing), AV_OPT_TYPE_FLOAT, {.dbl = 100.0}, 0.0, 1000.0, DYNAMIC > }, > + { "minimum_peak", "Peak detection minimum peak", OFFSET(min_peak), > AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 0.0, 100.0, DYNAMIC }, > + { "scene_threshold_low", "Scene change low threshold", > OFFSET(scene_low), AV_OPT_TYPE_FLOAT, {.dbl = 5.5}, -1.0, 100.0, DYNAMIC }, > + { "scene_threshold_high", "Scene change high threshold", > OFFSET(scene_high), AV_OPT_TYPE_FLOAT, {.dbl = 10.0}, -1.0, 100.0, DYNAMIC > }, > + { "overshoot", "Tone-mapping overshoot margin", OFFSET(overshoot), > AV_OPT_TYPE_FLOAT, {.dbl = 0.05}, 0.0, 1.0, DYNAMIC }, > + > + { "intent", "Rendering intent", OFFSET(intent), AV_OPT_TYPE_INT, > {.i64 = PL_INTENT_RELATIVE_COLORIMETRIC}, 0, 3, DYNAMIC, "intent" }, > + { "perceptual", "Perceptual", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_INTENT_PERCEPTUAL}, 0, 0, STATIC, "intent" }, > + { "relative", "Relative colorimetric", 0, AV_OPT_TYPE_CONST, > {.i64 = PL_INTENT_RELATIVE_COLORIMETRIC}, 0, 0, STATIC, "intent" }, > + { "absolute", "Absolute colorimetric", 0, AV_OPT_TYPE_CONST, > {.i64 = PL_INTENT_ABSOLUTE_COLORIMETRIC}, 0, 0, STATIC, "intent" }, > + { "saturation", "Saturation mapping", 0, AV_OPT_TYPE_CONST, {.i64 > = PL_INTENT_SATURATION}, 0, 0, STATIC, "intent" }, > + { "tonemapping", "Tone-mapping algorithm", OFFSET(tonemapping), > AV_OPT_TYPE_INT, {.i64 = PL_TONE_MAPPING_BT_2390}, 0, > PL_TONE_MAPPING_ALGORITHM_COUNT - 1, DYNAMIC, "tonemap" }, > + { "clip", "Hard-clipping", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_TONE_MAPPING_CLIP}, 0, 0, STATIC, "tonemap" }, > + { "mobius", "Mobius tone-mapping", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_TONE_MAPPING_MOBIUS}, 0, 0, STATIC, "tonemap" }, > + { "reinhard", "Reinhard tone-mapping", 0, AV_OPT_TYPE_CONST, > {.i64 = PL_TONE_MAPPING_REINHARD}, 0, 0, STATIC, "tonemap" }, > + { "hable", "Hable/Filmic tone-mapping", 0, AV_OPT_TYPE_CONST, > {.i64 = PL_TONE_MAPPING_HABLE}, 0, 0, STATIC, "tonemap" }, > + { "gamma", "Gamma tone-mapping", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_TONE_MAPPING_GAMMA}, 0, 0, STATIC, "tonemap" }, > + { "linear", "Linear tone-mapping", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_TONE_MAPPING_LINEAR}, 0, 0, STATIC, "tonemap" }, > + { "bt.2390", "ITU-R BT.2390 tone-mapping", 0, AV_OPT_TYPE_CONST, > {.i64 = PL_TONE_MAPPING_BT_2390}, 0, 0, STATIC, "tonemap" }, > + { "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 }, > + { "desaturation_strength", "Desaturation strength", > OFFSET(desat_str), AV_OPT_TYPE_FLOAT, {.dbl = 0.90}, 0.0, 1.0, DYNAMIC }, > + { "desaturation_exponent", "Desaturation exponent", > OFFSET(desat_exp), AV_OPT_TYPE_FLOAT, {.dbl = 0.2}, 0.0, 10.0, DYNAMIC }, > + { "desaturation_base", "Desaturation base", OFFSET(desat_base), > AV_OPT_TYPE_FLOAT, {.dbl = 0.18}, 0.0, 10.0, DYNAMIC }, > + { "max_boost", "Tone-mapping maximum boost", OFFSET(max_boost), > AV_OPT_TYPE_FLOAT, {.dbl = 1.0}, 1.0, 10.0, DYNAMIC }, > + { "gamut_warning", "Highlight out-of-gamut colors", > OFFSET(gamut_warning), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + { "gamut_clipping", "Enable colorimetric gamut clipping", > OFFSET(gamut_clipping), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DYNAMIC }, > + > + { "dithering", "Dither method to use", OFFSET(dithering), > AV_OPT_TYPE_INT, {.i64 = PL_DITHER_BLUE_NOISE}, -1, PL_DITHER_METHOD_COUNT > - 1, DYNAMIC, "dither" }, > + { "none", "Disable dithering", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, > 0, 0, STATIC, "dither" }, > + { "blue", "Blue noise", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_DITHER_BLUE_NOISE}, 0, 0, STATIC, "dither" }, > + { "ordered", "Ordered LUT", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_DITHER_ORDERED_LUT}, 0, 0, STATIC, "dither" }, > + { "ordered_fixed", "Fixed function ordered", 0, > AV_OPT_TYPE_CONST, {.i64 = PL_DITHER_ORDERED_FIXED}, 0, 0, STATIC, "dither" > }, > + { "white", "White noise", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_DITHER_WHITE_NOISE}, 0, 0, STATIC, "dither" }, > + { "dither_lut_size", "Dithering LUT size", OFFSET(dither_lut_size), > AV_OPT_TYPE_INT, {.i64 = 6}, 1, 8, STATIC }, > + { "dither_temporal", "Enable temporal dithering", > OFFSET(dither_temporal), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + > + { "cones", "Colorblindness adaptation model", OFFSET(cones), > AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, PL_CONE_LMS, DYNAMIC, "cone" }, > + { "l", "L cone", 0, AV_OPT_TYPE_CONST, {.i64 = PL_CONE_L}, 0, 0, > STATIC, "cone" }, > + { "m", "M cone", 0, AV_OPT_TYPE_CONST, {.i64 = PL_CONE_M}, 0, 0, > STATIC, "cone" }, > + { "s", "S cone", 0, AV_OPT_TYPE_CONST, {.i64 = PL_CONE_S}, 0, 0, > STATIC, "cone" }, > + { "cone-strength", "Colorblindness adaptation strength", > OFFSET(cone_str), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 10.0, DYNAMIC }, > + > + { "custom_shader_path", "Path to custom user shader (mpv .hook > format)", OFFSET(shader_path), AV_OPT_TYPE_STRING, .flags = STATIC }, > + { "custom_shader_bin", "Custom user shader as binary (mpv .hook > format)", OFFSET(shader_bin), AV_OPT_TYPE_BINARY, .flags = STATIC }, > + > + /* Performance/quality tradeoff options */ > + { "skip_aa", "Skip anti-aliasing", OFFSET(skip_aa), AV_OPT_TYPE_BOOL, > {.i64 = 0}, 0, 0, DYNAMIC }, > + { "polar_cutoff", "Polar LUT cutoff", OFFSET(polar_cutoff), > AV_OPT_TYPE_FLOAT, {.i64 = 0}, 0.0, 1.0, DYNAMIC }, > + { "disable_linear", "Disable linear scaling", OFFSET(disable_linear), > AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + { "disable_builtin", "Disable built-in scalers", > OFFSET(disable_builtin), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + { "force_3dlut", "Force the use of a full 3DLUT", > OFFSET(force_3dlut), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + { "force_dither", "Force dithering", OFFSET(force_dither), > AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + { "disable_fbos", "Force-disable FBOs", OFFSET(disable_fbos), > AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC }, > + { NULL }, > +}; > + > +AVFILTER_DEFINE_CLASS(libplacebo); > + > +static const AVFilterPad libplacebo_inputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_VIDEO, > + .filter_frame = &filter_frame, > + .config_props = &ff_vk_filter_config_input, > + }, > +}; > + > +static const AVFilterPad libplacebo_outputs[] = { > + { > + .name = "default", > + .type = AVMEDIA_TYPE_VIDEO, > + .config_props = &libplacebo_config_output, > + }, > +}; > + > +AVFilter ff_vf_libplacebo = { > + .name = "libplacebo", > + .description = NULL_IF_CONFIG_SMALL("Apply various GPU filters > from libplacebo"), > + .priv_size = sizeof(LibplaceboContext), > + .init = &libplacebo_init, > + .uninit = &libplacebo_uninit, > + .process_command = &ff_filter_process_command, > + FILTER_INPUTS(libplacebo_inputs), > + FILTER_OUTPUTS(libplacebo_outputs), > + FILTER_SINGLE_PIXFMT(AV_PIX_FMT_VULKAN), > + .priv_class = &libplacebo_class, > + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, > +}; > -- > 2.33.1 > > > Hello.
Were you able to build FFmpeg with this filter enabled? So far, building this package does not generate any pkgconfig file in the configured prefix, and FFmpeg's ./configure cannot detect it. I filed the issue on libplacebo's project page, with more details: https://github.com/haasn/libplacebo/issues/110 Warm regards, Dennis. _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".