vf_vapourynth: remove Lua backend

I once created this because someone wanted to use vapoursynth without
the Python dependency. No idea if anyone ever actually used it. It's
sort of icky (it calls itself "lazy" to preempt complaints about how
much it sucks), and complicates the build process. Kill it.

It seems much more promising to have something like this:

https://github.com/vapoursynth/vapoursynth/issues/386

This would either solve the build distribution problem by relaxing the
Python dependency, and/or allow a Lua backend to be included without
pain.
This commit is contained in:
wm4 2019-06-30 01:20:06 +02:00
parent c8b8fe9981
commit fb8d240c4d
6 changed files with 4 additions and 283 deletions

View File

@ -443,31 +443,6 @@ Available mpv-only filters are:
``display_fps``
Refresh rate of the current display. Note that this value can be 0.
``vapoursynth-lazy``
The same as ``vapoursynth``, but doesn't load Python scripts. Instead, a
custom backend using Lua and the raw VapourSynth API is used. The syntax
is completely different, and absolutely no convenience features are
provided. There's no type checking either, and you can trigger crashes.
.. admonition:: Example:
::
video_out = invoke("morpho", "Open", {clip = video_in})
The special variable ``video_in`` is the mpv video source, while the
special variable ``video_out`` is used to read video from. The 1st argument
is the plugin (queried with ``getPluginByNs``), the 2nd is the filter name,
and the 3rd argument is a table with the arguments. Positional arguments
are not supported. The types must match exactly. Since Lua is terrible and
can't distinguish integers and floats, integer arguments must be prefixed
with ``i_``, in which case the prefix is removed and the argument is cast
to an integer. Should the argument's name start with ``i_``, you're out of
luck.
Clips (VSNodeRef) are passed as light userdata, so trying to pass any
other userdata type will result in hard crashes.
``vavpp``
VA-API video post processing. Requires the system to support VA-API,
i.e. Linux/BSD only. Works with ``--vo=vaapi`` and ``--vo=gpu`` only.

View File

@ -64,12 +64,9 @@ const struct mp_user_filter_entry *vf_list[] = {
&vf_lavfi,
&vf_lavfi_bridge,
&vf_sub,
#if HAVE_VAPOURSYNTH_CORE && HAVE_VAPOURSYNTH
#if HAVE_VAPOURSYNTH
&vf_vapoursynth,
#endif
#if HAVE_VAPOURSYNTH_CORE && HAVE_VAPOURSYNTH_LAZY
&vf_vapoursynth_lazy,
#endif
#if HAVE_VDPAU
&vf_vdpaupp,
#endif

View File

@ -29,7 +29,6 @@ extern const struct mp_user_filter_entry vf_lavfi;
extern const struct mp_user_filter_entry vf_lavfi_bridge;
extern const struct mp_user_filter_entry vf_sub;
extern const struct mp_user_filter_entry vf_vapoursynth;
extern const struct mp_user_filter_entry vf_vapoursynth_lazy;
extern const struct mp_user_filter_entry vf_format;
extern const struct mp_user_filter_entry vf_vdpaupp;
extern const struct mp_user_filter_entry vf_vavpp;

View File

@ -812,8 +812,6 @@ static const m_option_t vf_opts_fields[] = {
{0}
};
#if HAVE_VAPOURSYNTH
#include <VSScript.h>
static int drv_vss_init(struct priv *p)
@ -872,7 +870,7 @@ static const struct script_driver drv_vss = {
const struct mp_user_filter_entry vf_vapoursynth = {
.desc = {
.description = "VapourSynth bridge (Python)",
.description = "VapourSynth bridge",
.name = "vapoursynth",
.priv_size = sizeof(OPT_BASE_STRUCT),
.priv_defaults = &(const OPT_BASE_STRUCT){
@ -882,241 +880,3 @@ const struct mp_user_filter_entry vf_vapoursynth = {
},
.create = vf_vapoursynth_create,
};
#endif
#if HAVE_VAPOURSYNTH_LAZY
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#if LUA_VERSION_NUM <= 501
#define mp_cpcall lua_cpcall
#define FUCKYOUOHGODWHY(L) lua_pushvalue(L, LUA_GLOBALSINDEX)
#else
// Curse whoever had this stupid idea. Curse whoever thought it would be a good
// idea not to include an emulated lua_cpcall() even more.
static int mp_cpcall (lua_State *L, lua_CFunction func, void *ud)
{
lua_pushcfunction(L, func); // doesn't allocate in 5.2 (but does in 5.1)
lua_pushlightuserdata(L, ud);
return lua_pcall(L, 1, 0, 0);
}
// Hey, let's replace old mechanisms with something slightly different!
#define FUCKYOUOHGODWHY lua_pushglobaltable
#endif
static int drv_lazy_init(struct priv *p)
{
p->ls = luaL_newstate();
if (!p->ls)
return -1;
luaL_openlibs(p->ls);
p->vsapi = getVapourSynthAPI(VAPOURSYNTH_API_VERSION);
p->vscore = p->vsapi ? p->vsapi->createCore(0) : NULL;
if (!p->vscore) {
MP_FATAL(p, "Could not load VapourSynth.\n");
lua_close(p->ls);
return -1;
}
return 0;
}
static void drv_lazy_uninit(struct priv *p)
{
lua_close(p->ls);
p->vsapi->freeCore(p->vscore);
}
static int drv_lazy_load_core(struct priv *p)
{
// not needed
return 0;
}
static struct priv *get_priv(lua_State *L)
{
lua_getfield(L, LUA_REGISTRYINDEX, "p"); // p
struct priv *p = lua_touserdata(L, -1); // p
lua_pop(L, 1); // -
return p;
}
static void vsmap_to_table(lua_State *L, int index, VSMap *map)
{
struct priv *p = get_priv(L);
const VSAPI *vsapi = p->vsapi;
for (int n = 0; n < vsapi->propNumKeys(map); n++) {
const char *key = vsapi->propGetKey(map, n);
VSPropTypes t = vsapi->propGetType(map, key);
switch (t) {
case ptInt:
lua_pushnumber(L, vsapi->propGetInt(map, key, 0, NULL));
break;
case ptFloat:
lua_pushnumber(L, vsapi->propGetFloat(map, key, 0, NULL));
break;
case ptNode: {
VSNodeRef *r = vsapi->propGetNode(map, key, 0, NULL);
MP_TARRAY_APPEND(p, p->gc_noderef, p->num_gc_noderef, r);
lua_pushlightuserdata(L, r);
break;
}
default:
luaL_error(L, "unknown map type");
}
lua_setfield(L, index, key);
}
}
static VSMap *table_to_vsmap(lua_State *L, int index)
{
struct priv *p = get_priv(L);
const VSAPI *vsapi = p->vsapi;
assert(index > 0);
VSMap *map = vsapi->createMap();
MP_TARRAY_APPEND(p, p->gc_map, p->num_gc_map, map);
if (!map)
luaL_error(L, "out of memory");
lua_pushnil(L); // nil
while (lua_next(L, index) != 0) { // key value
if (lua_type(L, -2) != LUA_TSTRING) {
luaL_error(L, "key must be a string, but got %s",
lua_typename(L, -2));
}
const char *key = lua_tostring(L, -2);
switch (lua_type(L, -1)) {
case LUA_TNUMBER: {
// gross hack because we hate everything
if (strncmp(key, "i_", 2) == 0) {
vsapi->propSetInt(map, key + 2, lua_tointeger(L, -1), 0);
} else {
vsapi->propSetFloat(map, key, lua_tonumber(L, -1), 0);
}
break;
}
case LUA_TSTRING: {
const char *s = lua_tostring(L, -1);
vsapi->propSetData(map, key, s, strlen(s), 0);
break;
}
case LUA_TLIGHTUSERDATA: { // assume it's VSNodeRef*
VSNodeRef *node = lua_touserdata(L, -1);
vsapi->propSetNode(map, key, node, 0);
break;
}
default:
luaL_error(L, "unknown type");
break;
}
lua_pop(L, 1); // key
}
return map;
}
static int l_invoke(lua_State *L)
{
struct priv *p = get_priv(L);
const VSAPI *vsapi = p->vsapi;
VSPlugin *plugin = vsapi->getPluginByNs(luaL_checkstring(L, 1), p->vscore);
if (!plugin)
luaL_error(L, "plugin not found");
VSMap *map = table_to_vsmap(L, 3);
VSMap *r = vsapi->invoke(plugin, luaL_checkstring(L, 2), map);
MP_TARRAY_APPEND(p, p->gc_map, p->num_gc_map, r);
if (!r)
luaL_error(L, "?");
const char *err = vsapi->getError(r);
if (err)
luaL_error(L, "error calling invoke(): %s", err);
int err2 = 0;
VSNodeRef *node = vsapi->propGetNode(r, "clip", 0, &err2);
MP_TARRAY_APPEND(p, p->gc_noderef, p->num_gc_noderef, node);
if (node)
lua_pushlightuserdata(L, node);
return 1;
}
struct load_ctx {
struct priv *p;
VSMap *vars;
int status;
};
static int load_stuff(lua_State *L)
{
struct load_ctx *ctx = lua_touserdata(L, -1);
lua_pop(L, 1); // -
struct priv *p = ctx->p;
// setup stuff; should be idempotent
lua_pushlightuserdata(L, p);
lua_setfield(L, LUA_REGISTRYINDEX, "p"); // -
lua_pushcfunction(L, l_invoke);
lua_setglobal(L, "invoke");
FUCKYOUOHGODWHY(L);
vsmap_to_table(L, lua_gettop(L), ctx->vars);
if (luaL_dofile(L, p->opts->file))
lua_error(L);
lua_pop(L, 1);
lua_getglobal(L, "video_out"); // video_out
if (!lua_islightuserdata(L, -1))
luaL_error(L, "video_out not set or has wrong type");
p->out_node = p->vsapi->cloneNodeRef(lua_touserdata(L, -1));
return 0;
}
static int drv_lazy_load(struct priv *p, VSMap *vars)
{
struct load_ctx ctx = {p, vars, 0};
if (mp_cpcall(p->ls, load_stuff, &ctx)) {
MP_FATAL(p, "filter creation failed: %s\n", lua_tostring(p->ls, -1));
lua_pop(p->ls, 1);
ctx.status = -1;
}
assert(lua_gettop(p->ls) == 0);
return ctx.status;
}
static void drv_lazy_unload(struct priv *p)
{
for (int n = 0; n < p->num_gc_noderef; n++) {
VSNodeRef *ref = p->gc_noderef[n];
if (ref)
p->vsapi->freeNode(ref);
}
p->num_gc_noderef = 0;
for (int n = 0; n < p->num_gc_map; n++) {
VSMap *map = p->gc_map[n];
if (map)
p->vsapi->freeMap(map);
}
p->num_gc_map = 0;
}
static const struct script_driver drv_lazy = {
.init = drv_lazy_init,
.uninit = drv_lazy_uninit,
.load_core = drv_lazy_load_core,
.load = drv_lazy_load,
.unload = drv_lazy_unload,
};
const struct mp_user_filter_entry vf_vapoursynth_lazy = {
.desc = {
.description = "VapourSynth bridge (Lua)",
.name = "vapoursynth-lazy",
.priv_size = sizeof(OPT_BASE_STRUCT),
.priv_defaults = &(const OPT_BASE_STRUCT){
.drv = &drv_lazy,
},
.options = vf_opts_fields,
},
.create = vf_vapoursynth_create,
};
#endif

12
wscript
View File

@ -392,19 +392,9 @@ iconv support use --disable-iconv.",
'func': check_pkg_config('lcms2', '>= 2.6'),
}, {
'name': '--vapoursynth',
'desc': 'VapourSynth filter bridge (Python)',
'desc': 'VapourSynth filter bridge',
'func': check_pkg_config('vapoursynth', '>= 24',
'vapoursynth-script', '>= 23'),
}, {
'name': '--vapoursynth-lazy',
'desc': 'VapourSynth filter bridge (Lazy Lua)',
'deps': 'lua',
'func': check_pkg_config('vapoursynth', '>= 24'),
}, {
'name': 'vapoursynth-core',
'desc': 'VapourSynth filter bridge (core)',
'deps': 'vapoursynth || vapoursynth-lazy',
'func': check_true,
}, {
'name': '--libarchive',
'desc': 'libarchive wrapper for reading zip files and more',

View File

@ -391,7 +391,7 @@ def build(ctx):
( "video/filter/vf_d3d11vpp.c", "d3d-hwaccel" ),
( "video/filter/vf_format.c" ),
( "video/filter/vf_sub.c" ),
( "video/filter/vf_vapoursynth.c", "vapoursynth-core" ),
( "video/filter/vf_vapoursynth.c", "vapoursynth" ),
( "video/filter/vf_vavpp.c", "vaapi" ),
( "video/filter/vf_vdpaupp.c", "vdpau" ),
( "video/fmt-conversion.c" ),