diff --git a/DOCS/man/en/vf.rst b/DOCS/man/en/vf.rst index 4c1423f9d2..ab32cd6907 100644 --- a/DOCS/man/en/vf.rst +++ b/DOCS/man/en/vf.rst @@ -377,7 +377,7 @@ Available filters are: Horizontal deblocking on luminance only, and switch vertical deblocking on or off automatically depending on available CPU time. -``lavfi=graph[:sws_flags[:o=opts]]`` +``lavfi=graph[:sws-flags[:o=opts]]`` Filter video using FFmpeg's libavfilter. ```` @@ -411,7 +411,7 @@ Available filters are: ``'--vf=lavfi=graph="gradfun=radius=30:strength=20,vflip"'`` Same as before, but uses named parameters for everything. - ```` + ```` If libavfilter inserts filters for pixel format conversion, this option gives the flags which should be passed to libswscale. This option is numeric and takes a bit-wise combination of ``SWS_`` flags. diff --git a/video/filter/vf_lavfi.c b/video/filter/vf_lavfi.c index 74f32a9519..9e064f49d9 100644 --- a/video/filter/vf_lavfi.c +++ b/video/filter/vf_lavfi.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ #include "video/sws_utils.h" #include "video/fmt-conversion.h" #include "vf.h" +#include "vf_lavfi.h" #define IS_LIBAV_FORK (LIBAVFILTER_VERSION_MICRO < 100) @@ -74,6 +76,10 @@ struct vf_priv_s { AVRational timebase_out; AVRational par_in; + // for the lw wrapper + void *old_priv; + void (*lw_recreate_cb)(struct vf_instance *vf); + // options char *cfg_graph; int64_t cfg_sws_flags; @@ -120,6 +126,9 @@ static bool recreate_graph(struct vf_instance *vf, int width, int height, struct vf_priv_s *p = vf->priv; AVFilterContext *in = NULL, *out = NULL, *f_format = NULL; + if (vf->priv->lw_recreate_cb) + vf->priv->lw_recreate_cb(vf); + if (bstr0(p->cfg_graph).len == 0) { mp_msg(MSGT_VFILTER, MSGL_FATAL, "lavfi: no filter graph set\n"); return false; @@ -294,15 +303,20 @@ static int filter_ext(struct vf_instance *vf, struct mp_image *mpi) return 0; } -static int control(vf_instance_t *vf, int request, void *data) +static void reset(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; + if (p->graph) { + struct mp_image_params *f = &vf->fmt_in.params; + recreate_graph(vf, f->w, f->h, f->d_w, f->d_h, f->imgfmt); + } +} + +static int control(vf_instance_t *vf, int request, void *data) +{ switch (request) { case VFCTRL_SEEK_RESET: - if (p->graph) { - struct mp_image_params *f = &vf->fmt_in.params; - recreate_graph(vf, f->w, f->h, f->d_w, f->d_h, f->imgfmt); - } + reset(vf); break; } return vf_next_control(vf, request, data); @@ -317,8 +331,10 @@ static void uninit(struct vf_instance *vf) static int vf_open(vf_instance_t *vf, char *args) { + vf->reconfig = NULL; vf->config = config; vf->filter_ext = filter_ext; + vf->filter = NULL; vf->query_format = query_format; vf->control = control; vf->uninit = uninit; @@ -367,7 +383,7 @@ static void print_help(void) #define OPT_BASE_STRUCT struct vf_priv_s static const m_option_t vf_opts_fields[] = { OPT_STRING("graph", cfg_graph, M_OPT_MIN, .min = 1), - OPT_INT64("sws_flags", cfg_sws_flags, 0), + OPT_INT64("sws-flags", cfg_sws_flags, 0), OPT_STRING("o", cfg_avopts, 0), {0} }; @@ -381,3 +397,93 @@ const vf_info_t vf_info_lavfi = { .options = vf_opts_fields, .print_help = print_help, }; + +// The following code is for the old filters wrapper code. + +struct vf_lw_opts { + int enable; + int64_t sws_flags; + char *avopts; +}; + +#undef OPT_BASE_STRUCT +#define OPT_BASE_STRUCT struct vf_lw_opts +const struct m_sub_options vf_lw_conf = { + .opts = (const m_option_t[]) { + OPT_FLAG("lavfi", enable, 0), + OPT_INT64("lavfi-sws-flags", sws_flags, 0), + OPT_STRING("lavfi-o", avopts, 0), + {0} + }, + .defaults = &(const struct vf_lw_opts){ + .enable = 1, + .sws_flags = SWS_BICUBIC, + }, + .size = sizeof(struct vf_lw_opts), +}; + +static bool have_filter(const char *name) +{ + for (const AVFilter *filter = avfilter_next(NULL); filter; + filter = avfilter_next(filter)) + { + if (strcmp(filter->name, name) == 0) + return true; + } + return false; +} + +// This is used by "old" filters for wrapping lavfi if possible. +// On success, this overwrites all vf callbacks and literally takes over the +// old filter and replaces it with vf_lavfi. +// On error (<0), nothing is changed. +int vf_lw_set_graph(struct vf_instance *vf, struct vf_lw_opts *lavfi_opts, + char *filter, char *opts, ...) +{ + if (!lavfi_opts) + lavfi_opts = (struct vf_lw_opts *)vf_lw_conf.defaults; + if (!lavfi_opts->enable || !have_filter(filter)) + return -1; + mp_msg(MSGT_VFILTER, MSGL_V, "Using libavfilter for '%s'\n", vf->info->name); + void *old_priv = vf->priv; + struct vf_priv_s *p = talloc(vf, struct vf_priv_s); + vf->priv = p; + *p = vf_priv_dflt; + p->cfg_sws_flags = lavfi_opts->sws_flags; + p->cfg_avopts = lavfi_opts->avopts; + va_list ap; + va_start(ap, opts); + char *s = talloc_vasprintf(vf, opts, ap); + p->cfg_graph = talloc_asprintf(vf, "%s=%s", filter, s); + talloc_free(s); + va_end(ap); + p->old_priv = old_priv; + // Note: we should be sure vf_open really overwrites _all_ vf callbacks. + if (vf_open(vf, NULL) < 1) + abort(); + return 1; +} + +void *vf_lw_old_priv(struct vf_instance *vf) +{ + struct vf_priv_s *p = vf->priv; + return p->old_priv; +} + +void vf_lw_update_graph(struct vf_instance *vf, char *filter, char *opts, ...) +{ + struct vf_priv_s *p = vf->priv; + va_list ap; + va_start(ap, opts); + char *s = talloc_vasprintf(vf, opts, ap); + talloc_free(p->cfg_graph); + p->cfg_graph = talloc_asprintf(vf, "%s=%s", filter, s); + talloc_free(s); + va_end(ap); +} + +void vf_lw_set_recreate_cb(struct vf_instance *vf, + void (*recreate)(struct vf_instance *vf)) +{ + vf->priv->lw_recreate_cb = recreate; +} diff --git a/video/filter/vf_lavfi.h b/video/filter/vf_lavfi.h new file mode 100644 index 0000000000..45765d9dea --- /dev/null +++ b/video/filter/vf_lavfi.h @@ -0,0 +1,44 @@ +#ifndef MP_VF_LAVFI_H_ +#define MP_VF_LAVFI_H_ + +#include "config.h" + +#include "mpvcore/mp_common.h" +#include "vf.h" + +struct vf_lw_opts; + +#if HAVE_VF_LAVFI + +extern const struct m_sub_options vf_lw_conf; + +int vf_lw_set_graph(struct vf_instance *vf, struct vf_lw_opts *lavfi_opts, + char *filter, char *opts, ...) PRINTF_ATTRIBUTE(4,5); +void *vf_lw_old_priv(struct vf_instance *vf); +void vf_lw_update_graph(struct vf_instance *vf, char *filter, char *opts, ...) + PRINTF_ATTRIBUTE(3,4); +void vf_lw_set_recreate_cb(struct vf_instance *vf, + void (*recreate)(struct vf_instance *vf)); +#else +static inline +int vf_lw_set_graph(struct vf_instance *vf, struct vf_lw_opts *lavfi_opts, + char *filter, char *opts, ...) +{ + return -1; +} +static void *vf_lw_old_priv(struct vf_instance *vf) +{ + return 0; +} +static void vf_lw_update_graph(struct vf_instance *vf, char *filter, char *opts, ...) +{ +} +static void vf_lw_set_recreate_cb(struct vf_instance *vf, + void (*recreate)(struct vf_instance *vf)) +{ +} +#include "mpvcore/m_option.h" +static const struct m_sub_options vf_lw_conf = {0}; +#endif + +#endif