From eedbafe05e4947b0030399597c4aeb4d898b390c Mon Sep 17 00:00:00 2001
From: Stefano Sabatini <[email protected]>
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&#40;lua->state, lua->filename&#41; != 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",
 +    .descripti 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&#40;luaVM, argv[1]&#41;) err_message("Problem running script."); */
+
+/*     /\* Lua cleanup *\/ */
+/*     lua_close(luaVM); */
+
+/*     return EXIT_SUCCESS; */
+/* } */
-- 
1.8.1.2

Add a code snippet to your website: www.paste.org