On date Thursday 2016-02-04 19:40:18 +0100, Paul B Mahol encoded: > On 2/2/16, Paul B Mahol <one...@gmail.com> wrote: > > Hi, > > > > patch attached. > > > > Much more useful version attached. > > Simple demo demonstrating functionality currently missing in lavfi:
I toyed with this idea three years ago, and I'll show you my (crappy) POC patch which assumes a different design (resuming: I wanted to implement a lua function to filter the media buffer, and possibly add other hooks to call during configuration). Sample lua script file: frame = 0 function init() print "hello world!" print(l_sin(239)) end function filter_frame() print(string.format('frame number %d', frame)) frame = frame + 1 end I gave up because I realized that with that approach I also needed to script most FFmpeg functions, that is I needed to script FFmpeg as a whole, which hugely extended the scope of the task. > > lavfi.log(0, "Lavfi script example", lavfi.script_name, lavfi.frame_count(0)); > if (lavfi.frame_count(0) >= 50) then > lavfi.filter({"aa"}, "vflip", nil, {"a"}) > lavfi.filter({"bb"}, "hflip", nil, {"b"}) > else > lavfi.filter({"aa"}, "negate", nil, {"a"}) > lavfi.filter({"bb"}, "vflip", nil, {"b"}) > end > > lavfi.filter({"a", "b"}, "hstack", "2", {"out0"}); Can you shortly give a description of how this code interface with lua? (alternatively write docs, assuming you plan to land a committable version) > From a84f155924b2235162d690664c97b55477d0a4c2 Mon Sep 17 00:00:00 2001 > From: Paul B Mahol <one...@gmail.com> > Date: Tue, 2 Feb 2016 10:09:50 +0100 > Subject: [PATCH] avfilter: add luascript filter > > Signed-off-by: Paul B Mahol <one...@gmail.com> > --- > configure | 4 + > libavfilter/Makefile | 1 + > libavfilter/allfilters.c | 1 + > libavfilter/src_luascript.c | 793 > ++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 799 insertions(+) > create mode 100644 libavfilter/src_luascript.c [...] -- FFmpeg = Free and Frightening Maxi Portentous Evangelical Glue
>From eedbafe05e4947b0030399597c4aeb4d898b390c Mon Sep 17 00:00:00 2001 From: Stefano Sabatini <stefa...@gmail.com> Date: Sat, 1 Jun 2013 16:43:31 +0200 Subject: [PATCH] lavfi: add lua filter --- configure | 4 + libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_lua.c | 261 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 267 insertions(+) create mode 100644 libavfilter/vf_lua.c diff --git a/configure b/configure index 93970a1..35f3d79 100755 --- a/configure +++ b/configure @@ -205,6 +205,7 @@ External library support: --enable-libgsm enable GSM de/encoding via libgsm [no] --enable-libiec61883 enable iec61883 via libiec61883 [no] --enable-libilbc enable iLBC de/encoding via libilbc [no] + --enable-liblua enable Lua scripting [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] --enable-libnut enable NUT (de)muxing via libnut, @@ -1169,6 +1170,7 @@ EXTERNAL_LIBRARY_LIST=" libgsm libiec61883 libilbc + liblua libmodplug libmp3lame libnut @@ -2154,6 +2156,7 @@ histeq_filter_deps="gpl" hqdn3d_filter_deps="gpl" hue_filter_deps="gpl" interlace_filter_deps="gpl" +lua_filter_deps="liblua" kerndeint_filter_deps="gpl" mcdeint_filter_deps="avcodec gpl" movie_filter_deps="avcodec avformat" @@ -4116,6 +4119,7 @@ enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do check_lib "${gsm_hdr}" gsm_create -lgsm && break; done || die "ERROR: libgsm not found"; } enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc +enabled liblua && require_pkg_config lua5.1 lua.h lua_newstate enabled libmodplug && require libmodplug libmodplug/modplug.h ModPlug_Load -lmodplug enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame enabled libnut && require libnut libnut.h nut_demuxer_init -lnut diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 2d2ea45..fdb5ce8 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -148,6 +148,7 @@ OBJS-$(CONFIG_IL_FILTER) += vf_il.o OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o +OBJS-$(CONFIG_LUA_FILTER) += vf_lua.o OBJS-$(CONFIG_LUT3D_FILTER) += vf_lut3d.o OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index f9d9391..10a1fb0 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -144,6 +144,7 @@ void avfilter_register_all(void) REGISTER_FILTER(INTERLACE, interlace, vf); REGISTER_FILTER(INTERLEAVE, interleave, vf); REGISTER_FILTER(KERNDEINT, kerndeint, vf); + REGISTER_FILTER(LUA, lua, vf); REGISTER_FILTER(LUT3D, lut3d, vf); REGISTER_FILTER(LUT, lut, vf); REGISTER_FILTER(LUTRGB, lutrgb, vf); diff --git a/libavfilter/vf_lua.c b/libavfilter/vf_lua.c new file mode 100644 index 0000000..e9106d4 --- /dev/null +++ b/libavfilter/vf_lua.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2013 Stefano Sabatini + * + * 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 + */ + +/** + * @file + * lua scripting filter + */ + +#include "libavutil/opt.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" + +typedef struct { + const AVClass *class; + lua_State *state; + char *filename; +} LuaContext; + +#define OFFSET(x) offsetof(LuaContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption lua_options[] = { + { "file", "set lua script file", OFFSET(filename), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lua); + +static int l_sin(lua_State *l) +{ + double d = lua_tonumber(l, 1); /* get argument from stack */ + lua_pushnumber(l, sin(d)); /* push result to the stack */ + return 1; /* number of results */ +} + +static int l_cos(lua_State *l) +{ + double d = lua_tonumber(l, 1); /* get argument from stack */ + lua_pushnumber(l, cos(d)); /* push result to the stack */ + return 1; /* number of results */ +} + +/* static int l_send_command(lua_State *l) */ +/* { */ +/* char buf[128]; */ +/* char *target = lua_tostring(l, 1); */ +/* char *command = lua_tostring(l, 2); */ +/* char *arg = lua_tostring(l, 3); */ +/* int ret; */ + +/* ret = avfilter_graph_send_command(inlink->graph, */ +/* target, command, arg, buf, sizeof(buf), */ +/* AVFILTER_CMD_FLAG_ONE); */ +/* lua_pushnumber(l, ret); */ +/* return 1; */ +/* } */ + +static const struct luaL_reg lavfi[] = { + { "sin", l_sin}, + { "cos", l_cos}, +// { "send_command", l_send_command }, + { NULL, NULL } +}; + +static int l_open_lavfi(lua_State *l) +{ + luaL_openlib(l, "lavfi", lavfi, 0); + return 1; +} + +static av_cold int init(AVFilterContext *ctx) +{ + LuaContext *lua = ctx->priv; + + lua->state = luaL_newstate(); + luaL_openlibs(lua->state); + + /* register l_sin function */ + /* lua_pushcfunction(lua->state, l_sin); */ + /* lua_setglobal(lua->state, "l_sin"); */ + /* lua_pushcfunction(lua->state, l_send_command); */ + /* lua_setglobal(lua->state, "l_send_command"); */ + + if (!lua->filename) { + av_log(ctx, AV_LOG_ERROR, "No script specified, aborting\n"); + return AVERROR(EINVAL); + } + + if (luaL_loadfile(lua->state, lua->filename) != 0) { + av_log(ctx, AV_LOG_ERROR, "Could not load lua script '%s': %s\n", + lua->filename, lua_tostring(lua->state, -1)); + return AVERROR_EXTERNAL; + } + + if (lua_pcall(lua->state, 0, 0, 0) != 0) { + av_log(ctx, AV_LOG_ERROR, "Could not call function: %s\n", + lua_tostring(lua->state, -1)); + return AVERROR_EXTERNAL; + } + + /* call a function `f' defined in Lua */ + /* double f (double x, double y) { */ + + /* load function and push it on the stack */ + lua_getglobal(lua->state, "init"); + + /* pass arguments to init */ + /* lua_pushnumber(L, x); /\* push 1st argument *\/ */ + /* lua_pushnumber(L, y); /\* push 2nd argument *\/ */ + + /* call init function, 0 arguments, 1 result */ + if (lua_pcall(lua->state, 0, 1, 0) != 0) + av_log(ctx, AV_LOG_ERROR, "Error running init function: %s", + lua_tostring(lua->state, -1)); + + /* retrieve result */ + /* if (!lua_isnumber(L, -1)) */ + /* error(L, "function `f' must return a number"); */ + /* z = lua_tonumber(L, -1); */ + /* lua_pop(L, 1); /\* pop returned value *\/ */ + /* return z; */ + /* } */ + + /* lua_getglobal(lua->state, "result"); */ + /* av_log(ctx, AV_LOG_INFO, "result is: %f\n", lua_tonumber(lua->state, -1)); */ + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + LuaContext *lua = ctx->priv; + + if (lua->state) + lua_close(lua->state); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + LuaContext *lua = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + int ret; + + /* load function and push it on the stack */ + lua_getglobal(lua->state, "filter_frame"); + + /* TODO: pass arguments to function, in particular inlink and frame */ + if (lua_pcall(lua->state, 0, 1, 0) != 0) + av_log(ctx, AV_LOG_ERROR, "Error running filter_frame function: %s", + lua_tostring(lua->state, -1)); + ret = lua_tointeger(lua->state, -1); + if (ret < 0) + return ret; + + return ff_filter_frame(outlink, frame); +} + +static const AVFilterPad lua_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad lua_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter avfilter_vf_lua = { + .name = "lua", + .description = NULL_IF_CONFIG_SMALL("Execute lua script."), + .priv_size = sizeof(LuaContext), + .priv_class = &lua_class, + .init = init, + .uninit = uninit, + .inputs = lua_inputs, + .outputs = lua_outputs, +}; + + +/* /\* Variable arg function callable from a Lua script as: */ +/* * say_something('A', 'gaggle', 'of', 5, 'args') */ +/* *\/ */ +/* static int */ +/* say_something(lua_State* luaVM) { */ +/* int n = lua_gettop(luaVM); */ +/* int i; */ + +/* if (n == 0) { */ +/* printf("no arguments"); */ +/* return 0; */ +/* } */ + +/* for (i = 1; i <= n; i++) { */ +/* if (!lua_isstring(luaVM, i)) { */ +/* lua_pushstring(luaVM, "[ERROR] argument must be a string or a number"); */ +/* lua_error(luaVM); */ +/* } */ +/* printf("%s\n", lua_tostring(luaVM, i)); */ +/* } */ + +/* return 0; */ +/* } */ + +/* int */ +/* main(int argc, char** argv) { */ +/* if (!check_args(argc, argv)) return(EXIT_FAILURE); */ + +/* /\* Initialize Lua *\/ */ +/* lua_State* luaVM = luaL_newstate(); */ +/* if (luaVM == NULL) { */ +/* err_message("Cannot initialize Lua; exiting..."); */ +/* return EXIT_FAILURE; */ +/* } */ + +/* /\* Stop the GC during Lua library (all std) initialization and function */ +/* * registrations. C functions that are callable from a Lua script must be */ +/* * registered with Lua. */ +/* *\/ */ +/* lua_gc(luaVM, LUA_GCSTOP, 0); */ +/* luaL_openlibs(luaVM); */ +/* lua_register(luaVM, "say_something", say_something); */ +/* lua_gc(luaVM, LUA_GCRESTART, 0); */ + +/* /\* Execute the Lua script *\/ */ +/* if (luaL_dofile(luaVM, argv[1])) err_message("Problem running script."); */ + +/* /\* Lua cleanup *\/ */ +/* lua_close(luaVM); */ + +/* return EXIT_SUCCESS; */ +/* } */ -- 1.9.1
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel