vf_lavfi: export a wrapper function

This will allow old filter to run libavfilter instead by calling
vf_lw_set_graph(), which turns the filter into a wrapper, using a given
libavfilter graph.

Later commits use that to automatically "reroute" a bunch of filters to
libavfilter. We want to get rid of the old MPlayer filter code, because
it's bad an unmaintained, but we still don't want to force everyone to
use vf_lavfi, so this solution will do for a while.
This commit is contained in:
wm4 2013-12-03 22:19:27 +01:00
parent 733c2369d3
commit 25635a62c3
3 changed files with 158 additions and 8 deletions

View File

@ -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.
``<graph>``
@ -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.
``<sws_flags>``
``<sws-flags>``
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.

View File

@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <stdarg.h>
#include <assert.h>
#include <libavutil/avstring.h>
@ -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;
}

44
video/filter/vf_lavfi.h Normal file
View File

@ -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