summaryrefslogtreecommitdiffstats
path: root/mpvcore/player/mp_lua.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-12-17 00:53:22 +0100
committerwm4 <wm4@nowhere>2013-12-17 00:53:22 +0100
commite44911142914783c9ec717f329bd9b6a8bb9b70e (patch)
tree92bb653f7d56553ffd3bb6e5a22ffc0db91142e8 /mpvcore/player/mp_lua.c
parent7dc7b900c622235d595337c988a0c75280084b7c (diff)
downloadmpv-e44911142914783c9ec717f329bd9b6a8bb9b70e.tar.bz2
mpv-e44911142914783c9ec717f329bd9b6a8bb9b70e.tar.xz
Move mpvcore/player/ to player/
Diffstat (limited to 'mpvcore/player/mp_lua.c')
-rw-r--r--mpvcore/player/mp_lua.c683
1 files changed, 0 insertions, 683 deletions
diff --git a/mpvcore/player/mp_lua.c b/mpvcore/player/mp_lua.c
deleted file mode 100644
index 03e21bf535..0000000000
--- a/mpvcore/player/mp_lua.c
+++ /dev/null
@@ -1,683 +0,0 @@
-#include <assert.h>
-#include <string.h>
-
-#include <lua.h>
-#include <lualib.h>
-#include <lauxlib.h>
-
-#include "talloc.h"
-
-#include "mpvcore/mp_common.h"
-#include "mpvcore/m_property.h"
-#include "mpvcore/mp_msg.h"
-#include "mpvcore/m_option.h"
-#include "mpvcore/input/input.h"
-#include "mpvcore/path.h"
-#include "mpvcore/bstr.h"
-#include "osdep/timer.h"
-#include "sub/osd.h"
-#include "mp_core.h"
-#include "command.h"
-#include "mp_lua.h"
-
-// List of builtin modules and their contents as strings.
-// All these are generated from mpvcore/lua/*.lua
-static const char *builtin_lua_scripts[][2] = {
- {"mp.defaults",
-# include "mpvcore/player/lua/defaults.inc"
- },
- {"mp.assdraw",
-# include "mpvcore/player/lua/assdraw.inc"
- },
- {"@osc",
-# include "mpvcore/player/lua/osc.inc"
- },
- {0}
-};
-
-// Represents a loaded script. Each has its own Lua state.
-struct script_ctx {
- const char *name;
- lua_State *state;
- struct mp_log *log;
- struct MPContext *mpctx;
-};
-
-struct lua_ctx {
- struct script_ctx **scripts;
- int num_scripts;
-};
-
-static struct script_ctx *find_script(struct lua_ctx *lctx, const char *name)
-{
- for (int n = 0; n < lctx->num_scripts; n++) {
- if (strcmp(lctx->scripts[n]->name, name) == 0)
- return lctx->scripts[n];
- }
- return NULL;
-}
-
-static struct script_ctx *get_ctx(lua_State *L)
-{
- lua_getfield(L, LUA_REGISTRYINDEX, "ctx");
- struct script_ctx *ctx = lua_touserdata(L, -1);
- lua_pop(L, 1);
- assert(ctx);
- return ctx;
-}
-
-static struct MPContext *get_mpctx(lua_State *L)
-{
- return get_ctx(L)->mpctx;
-}
-
-static int wrap_cpcall(lua_State *L)
-{
- lua_CFunction fn = lua_touserdata(L, -1);
- lua_pop(L, 1);
- return fn(L);
-}
-
-// Call the given function fn under a Lua error handler (similar to lua_cpcall).
-// Pass the given number of args from the Lua stack to fn.
-// Returns 0 (and empty stack) on success.
-// Returns LUA_ERR[RUN|MEM|ERR] otherwise, with the error value on the stack.
-static int mp_cpcall(lua_State *L, lua_CFunction fn, int args)
-{
- // Don't use lua_pushcfunction() - it allocates memory on Lua 5.1.
- // Instead, emulate C closures by making wrap_cpcall call fn.
- lua_pushlightuserdata(L, fn); // args... fn
- // Will always succeed if mp_lua_init() set it up correctly.
- lua_getfield(L, LUA_REGISTRYINDEX, "wrap_cpcall"); // args... fn wrap_cpcall
- lua_insert(L, -(args + 2)); // wrap_cpcall args... fn
- return lua_pcall(L, args + 1, 0, 0);
-}
-
-static void report_error(lua_State *L)
-{
- const char *err = lua_tostring(L, -1);
- mp_msg(MSGT_CPLAYER, MSGL_WARN, "[lua] Error: %s\n",
- err ? err : "[unknown]");
- lua_pop(L, 1);
-}
-
-static void add_functions(struct script_ctx *ctx);
-
-static char *script_name_from_filename(void *talloc_ctx, struct lua_ctx *lctx,
- const char *fname)
-{
- fname = mp_basename(fname);
- if (fname[0] == '@')
- fname += 1;
- char *name = talloc_strdup(talloc_ctx, fname);
- // Drop .lua extension
- char *dot = strrchr(name, '.');
- if (dot)
- *dot = '\0';
- // Turn it into a safe identifier - this is used with e.g. dispatching
- // input via: "send scriptname ..."
- for (int n = 0; name[n]; n++) {
- char c = name[n];
- if (!(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') &&
- !(c >= '0' && c <= '9'))
- name[n] = '_';
- }
- // Make unique (stupid but simple)
- while (find_script(lctx, name))
- name = talloc_strdup_append(name, "_");
- return name;
-}
-
-static int load_file(struct script_ctx *ctx, const char *fname)
-{
- int r = 0;
- lua_State *L = ctx->state;
- if (luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0)) {
- report_error(L);
- r = -1;
- }
- assert(lua_gettop(L) == 0);
- return r;
-}
-
-static int load_builtin(lua_State *L)
-{
- const char *name = luaL_checkstring(L, 1);
- for (int n = 0; builtin_lua_scripts[n][0]; n++) {
- if (strcmp(name, builtin_lua_scripts[n][0]) == 0) {
- if (luaL_loadstring(L, builtin_lua_scripts[n][1]))
- lua_error(L);
- lua_call(L, 0, 1);
- return 1;
- }
- }
- return 0;
-}
-
-// Execute "require " .. name
-static bool require(lua_State *L, const char *name)
-{
- char buf[80];
- // Lazy, but better than calling the "require" function manually
- snprintf(buf, sizeof(buf), "require '%s'", name);
- if (luaL_loadstring(L, buf) || lua_pcall(L, 0, 0, 0)) {
- report_error(L);
- return false;
- }
- return true;
-}
-
-static void mp_lua_load_script(struct MPContext *mpctx, const char *fname)
-{
- struct lua_ctx *lctx = mpctx->lua_ctx;
- struct script_ctx *ctx = talloc_ptrtype(NULL, ctx);
- *ctx = (struct script_ctx) {
- .mpctx = mpctx,
- .name = script_name_from_filename(ctx, lctx, fname),
- };
- char *log_name = talloc_asprintf(ctx, "lua/%s", ctx->name);
- ctx->log = mp_log_new(ctx, mpctx->log, log_name);
-
- lua_State *L = ctx->state = luaL_newstate();
- if (!L)
- goto error_out;
-
- // used by get_ctx()
- lua_pushlightuserdata(L, ctx); // ctx
- lua_setfield(L, LUA_REGISTRYINDEX, "ctx"); // -
-
- lua_pushcfunction(L, wrap_cpcall); // closure
- lua_setfield(L, LUA_REGISTRYINDEX, "wrap_cpcall"); // -
-
- luaL_openlibs(L);
-
- lua_newtable(L); // mp
- lua_pushvalue(L, -1); // mp mp
- lua_setglobal(L, "mp"); // mp
-
- add_functions(ctx); // mp
-
- lua_pushstring(L, ctx->name); // mp name
- lua_setfield(L, -2, "script_name"); // mp
-
- lua_pop(L, 1); // -
-
- // Add a preloader for each builtin Lua module
- lua_getglobal(L, "package"); // package
- assert(lua_type(L, -1) == LUA_TTABLE);
- lua_getfield(L, -1, "preload"); // package preload
- assert(lua_type(L, -1) == LUA_TTABLE);
- for (int n = 0; builtin_lua_scripts[n][0]; n++) {
- lua_pushcfunction(L, load_builtin); // package preload load_builtin
- lua_setfield(L, -2, builtin_lua_scripts[n][0]);
- }
- lua_pop(L, 2); // -
-
- assert(lua_gettop(L) == 0);
-
- if (!require(L, "mp.defaults")) {
- report_error(L);
- goto error_out;
- }
-
- assert(lua_gettop(L) == 0);
-
- if (fname[0] == '@') {
- if (!require(L, fname))
- goto error_out;
- } else {
- if (load_file(ctx, fname) < 0)
- goto error_out;
- }
-
- MP_TARRAY_APPEND(lctx, lctx->scripts, lctx->num_scripts, ctx);
- return;
-
-error_out:
- if (ctx->state)
- lua_close(ctx->state);
- talloc_free(ctx);
-}
-
-static void kill_script(struct script_ctx *ctx)
-{
- if (!ctx)
- return;
- struct lua_ctx *lctx = ctx->mpctx->lua_ctx;
- lua_close(ctx->state);
- for (int n = 0; n < lctx->num_scripts; n++) {
- if (lctx->scripts[n] == ctx) {
- MP_TARRAY_REMOVE_AT(lctx->scripts, lctx->num_scripts, n);
- break;
- }
- }
- talloc_free(ctx);
-}
-
-static const char *log_level[] = {
- [MSGL_FATAL] = "fatal",
- [MSGL_ERR] = "error",
- [MSGL_WARN] = "warn",
- [MSGL_INFO] = "info",
- [MSGL_V] = "verbose",
- [MSGL_DBG2] = "debug",
-};
-
-static int script_log(lua_State *L)
-{
- struct script_ctx *ctx = get_ctx(L);
-
- const char *level = luaL_checkstring(L, 1);
- int msgl = -1;
- for (int n = 0; n < MP_ARRAY_SIZE(log_level); n++) {
- if (log_level[n] && strcasecmp(log_level[n], level) == 0) {
- msgl = n;
- break;
- }
- }
- if (msgl < 0)
- luaL_error(L, "Invalid log level '%s'", level);
-
- int last = lua_gettop(L);
- lua_getglobal(L, "tostring"); // args... tostring
- for (int i = 2; i <= last; i++) {
- lua_pushvalue(L, -1); // args... tostring tostring
- lua_pushvalue(L, i); // args... tostring tostring args[i]
- lua_call(L, 1, 1); // args... tostring str
- const char *s = lua_tostring(L, -1);
- if (s == NULL)
- return luaL_error(L, "Invalid argument");
- mp_msg_log(ctx->log, msgl, "%s%s", s, i > 0 ? " " : "");
- lua_pop(L, 1); // args... tostring
- }
- mp_msg_log(ctx->log, msgl, "\n");
-
- return 0;
-}
-
-static int script_find_config_file(lua_State *L)
-{
- const char *s = luaL_checkstring(L, 1);
- char *path = mp_find_user_config_file(s);
- if (path) {
- lua_pushstring(L, path);
- } else {
- lua_pushnil(L);
- }
- talloc_free(path);
- return 1;
-}
-
-static int run_event(lua_State *L)
-{
- lua_getglobal(L, "mp_event"); // name arg mp_event
- if (lua_isnil(L, -1))
- return 0;
- lua_insert(L, -3); // mp_event name arg
- lua_call(L, 2, 0);
- return 0;
-}
-
-void mp_lua_event(struct MPContext *mpctx, const char *name, const char *arg)
-{
- // There is no proper subscription mechanism yet, so all scripts get it.
- struct lua_ctx *lctx = mpctx->lua_ctx;
- for (int n = 0; n < lctx->num_scripts; n++) {
- struct script_ctx *ctx = lctx->scripts[n];
- lua_State *L = ctx->state;
- lua_pushstring(L, name);
- if (arg) {
- lua_pushstring(L, arg);
- } else {
- lua_pushnil(L);
- }
- if (mp_cpcall(L, run_event, 2) != 0)
- report_error(L);
- }
-}
-
-static int run_script_dispatch(lua_State *L)
-{
- int id = lua_tointeger(L, 1);
- const char *event = lua_tostring(L, 2);
- lua_getglobal(L, "mp_script_dispatch");
- if (lua_isnil(L, -1))
- return 0;
- lua_pushinteger(L, id);
- lua_pushstring(L, event);
- lua_call(L, 2, 0);
- return 0;
-}
-
-void mp_lua_script_dispatch(struct MPContext *mpctx, char *script_name,
- int id, char *event)
-{
- struct script_ctx *ctx = find_script(mpctx->lua_ctx, script_name);
- if (!ctx) {
- mp_msg(MSGT_CPLAYER, MSGL_V,
- "Can't find script '%s' when handling input.\n", script_name);
- return;
- }
- lua_State *L = ctx->state;
- lua_pushinteger(L, id);
- lua_pushstring(L, event);
- if (mp_cpcall(L, run_script_dispatch, 2) != 0)
- report_error(L);
-}
-
-static int script_send_command(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- const char *s = luaL_checkstring(L, 1);
-
- mp_cmd_t *cmd = mp_input_parse_cmd(mpctx->input, bstr0((char*)s), "<lua>");
- if (!cmd)
- luaL_error(L, "error parsing command");
- mp_input_queue_cmd(mpctx->input, cmd);
-
- return 0;
-}
-
-static int script_property_list(lua_State *L)
-{
- const struct m_option *props = mp_get_property_list();
- lua_newtable(L);
- for (int i = 0; props[i].name; i++) {
- lua_pushinteger(L, i + 1);
- lua_pushstring(L, props[i].name);
- lua_settable(L, -3);
- }
- return 1;
-}
-
-static int script_property_string(lua_State *L)
-{
- const struct m_option *props = mp_get_property_list();
- struct MPContext *mpctx = get_mpctx(L);
- const char *name = luaL_checkstring(L, 1);
- int type = lua_tointeger(L, lua_upvalueindex(1))
- ? M_PROPERTY_PRINT : M_PROPERTY_GET_STRING;
-
- char *result = NULL;
- if (m_property_do(props, name, type, &result, mpctx) >= 0 && result) {
- lua_pushstring(L, result);
- talloc_free(result);
- return 1;
- }
- if (type == M_PROPERTY_PRINT) {
- lua_pushstring(L, "");
- return 1;
- }
- return 0;
-}
-
-static int script_set_osd_ass(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- int res_x = luaL_checkinteger(L, 1);
- int res_y = luaL_checkinteger(L, 2);
- const char *text = luaL_checkstring(L, 3);
- if (!mpctx->osd->external ||
- strcmp(mpctx->osd->external, text) != 0 ||
- mpctx->osd->external_res_x != res_x ||
- mpctx->osd->external_res_y != res_y)
- {
- talloc_free(mpctx->osd->external);
- mpctx->osd->external = talloc_strdup(mpctx->osd, text);
- mpctx->osd->external_res_x = res_x;
- mpctx->osd->external_res_y = res_y;
- osd_changed(mpctx->osd, OSDTYPE_EXTERNAL);
- }
- return 0;
-}
-
-static int script_get_osd_resolution(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- int w, h;
- osd_object_get_resolution(mpctx->osd, mpctx->osd->objs[OSDTYPE_EXTERNAL],
- &w, &h);
- lua_pushnumber(L, w);
- lua_pushnumber(L, h);
- return 2;
-}
-
-static int script_get_screen_size(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- struct osd_object *obj = mpctx->osd->objs[OSDTYPE_EXTERNAL];
- double aspect = 1.0 * obj->vo_res.w / MPMAX(obj->vo_res.h, 1) /
- obj->vo_res.display_par;
- lua_pushnumber(L, obj->vo_res.w);
- lua_pushnumber(L, obj->vo_res.h);
- lua_pushnumber(L, aspect);
- return 3;
-}
-
-static int script_get_mouse_pos(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- int px, py;
- mp_input_get_mouse_pos(mpctx->input, &px, &py);
- double sw, sh;
- osd_object_get_scale_factor(mpctx->osd, mpctx->osd->objs[OSDTYPE_EXTERNAL],
- &sw, &sh);
- lua_pushnumber(L, px * sw);
- lua_pushnumber(L, py * sh);
- return 2;
-}
-
-static int script_get_timer(lua_State *L)
-{
- lua_pushnumber(L, mp_time_sec());
- return 1;
-}
-
-static int script_get_chapter_list(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- lua_newtable(L); // list
- int num = get_chapter_count(mpctx);
- for (int n = 0; n < num; n++) {
- double time = chapter_start_time(mpctx, n);
- char *name = chapter_display_name(mpctx, n);
- lua_newtable(L); // list ch
- lua_pushnumber(L, time); // list ch time
- lua_setfield(L, -2, "time"); // list ch
- lua_pushstring(L, name); // list ch name
- lua_setfield(L, -2, "name"); // list ch
- lua_pushinteger(L, n + 1); // list ch n1
- lua_insert(L, -2); // list n1 ch
- lua_settable(L, -3); // list
- talloc_free(name);
- }
- return 1;
-}
-
-static const char *stream_type(enum stream_type t)
-{
- switch (t) {
- case STREAM_VIDEO: return "video";
- case STREAM_AUDIO: return "audio";
- case STREAM_SUB: return "sub";
- default: return "unknown";
- }
-}
-
-static int script_get_track_list(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- lua_newtable(L); // list
- for (int n = 0; n < mpctx->num_tracks; n++) {
- struct track *track = mpctx->tracks[n];
- lua_newtable(L); // list track
-
- lua_pushstring(L, stream_type(track->type));
- lua_setfield(L, -2, "type");
- lua_pushinteger(L, track->user_tid);
- lua_setfield(L, -2, "id");
- lua_pushboolean(L, track->default_track);
- lua_setfield(L, -2, "default");
- lua_pushboolean(L, track->attached_picture);
- lua_setfield(L, -2, "attached_picture");
- if (track->lang) {
- lua_pushstring(L, track->lang);
- lua_setfield(L, -2, "language");
- }
- if (track->title) {
- lua_pushstring(L, track->title);
- lua_setfield(L, -2, "title");
- }
- lua_pushboolean(L, track->is_external);
- lua_setfield(L, -2, "external");
- if (track->external_filename) {
- lua_pushstring(L, track->external_filename);
- lua_setfield(L, -2, "external_filename");
- }
- lua_pushboolean(L, track->auto_loaded);
- lua_setfield(L, -2, "auto_loaded");
-
- lua_pushinteger(L, n + 1); // list track n1
- lua_insert(L, -2); // list n1 track
- lua_settable(L, -3); // list
- }
- return 1;
-}
-
-static int script_input_define_section(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- char *section = (char *)luaL_checkstring(L, 1);
- char *contents = (char *)luaL_checkstring(L, 2);
- mp_input_define_section(mpctx->input, section, "<script>", contents, true);
- return 0;
-}
-
-static int script_input_enable_section(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- char *section = (char *)luaL_checkstring(L, 1);
- char *sflags = (char *)luaL_optstring(L, 2, "");
- bstr bflags = bstr0(sflags);
- int flags = 0;
- while (bflags.len) {
- bstr val;
- bstr_split_tok(bflags, "|", &val, &bflags);
- if (bstr_equals0(val, "allow-hide-cursor")) {
- flags |= MP_INPUT_ALLOW_HIDE_CURSOR;
- } else if (bstr_equals0(val, "allow-vo-dragging")) {
- flags |= MP_INPUT_ALLOW_VO_DRAGGING;
- } else if (bstr_equals0(val, "exclusive")) {
- flags |= MP_INPUT_EXCLUSIVE;
- } else {
- luaL_error(L, "invalid flag: '%.*s'", BSTR_P(val));
- }
- }
- mp_input_enable_section(mpctx->input, section, flags);
- return 0;
-}
-
-static int script_input_disable_section(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
- char *section = (char *)luaL_checkstring(L, 1);
- mp_input_disable_section(mpctx->input, section);
- return 0;
-}
-
-static int script_input_set_section_mouse_area(lua_State *L)
-{
- struct MPContext *mpctx = get_mpctx(L);
-
- double sw, sh;
- struct osd_object *obj = mpctx->osd->objs[OSDTYPE_EXTERNAL];
- osd_object_get_scale_factor(mpctx->osd, obj, &sw, &sh);
-
- char *section = (char *)luaL_checkstring(L, 1);
- int x0 = luaL_checkinteger(L, 2) / sw;
- int y0 = luaL_checkinteger(L, 3) / sh;
- int x1 = luaL_checkinteger(L, 4) / sw;
- int y1 = luaL_checkinteger(L, 5) / sh;
- mp_input_set_section_mouse_area(mpctx->input, section, x0, y0, x1, y1);
- return 0;
-}
-
-static int script_format_time(lua_State *L)
-{
- double t = luaL_checknumber(L, 1);
- const char *fmt = luaL_optstring(L, 2, "%H:%M:%S");
- char *r = mp_format_time_fmt(fmt, t);
- if (!r)
- luaL_error(L, "Invalid time format string '%s'", fmt);
- lua_pushstring(L, r);
- talloc_free(r);
- return 1;
-}
-
-struct fn_entry {
- const char *name;
- int (*fn)(lua_State *L);
-};
-
-#define FN_ENTRY(name) {#name, script_ ## name}
-
-static struct fn_entry fn_list[] = {
- FN_ENTRY(log),
- FN_ENTRY(find_config_file),
- FN_ENTRY(send_command),
- FN_ENTRY(property_list),
- FN_ENTRY(set_osd_ass),
- FN_ENTRY(get_osd_resolution),
- FN_ENTRY(get_screen_size),
- FN_ENTRY(get_mouse_pos),
- FN_ENTRY(get_timer),
- FN_ENTRY(get_chapter_list),
- FN_ENTRY(get_track_list),
- FN_ENTRY(input_define_section),
- FN_ENTRY(input_enable_section),
- FN_ENTRY(input_disable_section),
- FN_ENTRY(input_set_section_mouse_area),
- FN_ENTRY(format_time),
-};
-
-// On stack: mp table
-static void add_functions(struct script_ctx *ctx)
-{
- lua_State *L = ctx->state;
-
- for (int n = 0; n < MP_ARRAY_SIZE(fn_list); n++) {
- lua_pushcfunction(L, fn_list[n].fn);
- lua_setfield(L, -2, fn_list[n].name);
- }
-
- lua_pushinteger(L, 0);
- lua_pushcclosure(L, script_property_string, 1);
- lua_setfield(L, -2, "property_get");
-
- lua_pushinteger(L, 1);
- lua_pushcclosure(L, script_property_string, 1);
- lua_setfield(L, -2, "property_get_string");
-}
-
-void mp_lua_init(struct MPContext *mpctx)
-{
- mpctx->lua_ctx = talloc_zero(NULL, struct lua_ctx);
- // Load scripts from options
- if (mpctx->opts->lua_load_osc)
- mp_lua_load_script(mpctx, "@osc");
- char **files = mpctx->opts->lua_files;
- for (int n = 0; files && files[n]; n++) {
- if (files[n][0])
- mp_lua_load_script(mpctx, files[n]);
- }
-}
-
-void mp_lua_uninit(struct MPContext *mpctx)
-{
- if (mpctx->lua_ctx) {
- while (mpctx->lua_ctx->num_scripts)
- kill_script(mpctx->lua_ctx->scripts[0]);
- talloc_free(mpctx->lua_ctx);
- mpctx->lua_ctx = NULL;
- }
-}