summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-05-13 01:14:07 +0200
committerwm4 <wm4@nowhere>2014-05-13 02:39:37 +0200
commit2279f718de746d5fed3b64df74e9c47af98975b5 (patch)
tree57aa74740fcd067a5e87cb9810b2888b0548aeee
parent2a2dd8aac2d68db1471bbb4fd852f85f3fcf9c24 (diff)
downloadmpv-2279f718de746d5fed3b64df74e9c47af98975b5.tar.bz2
mpv-2279f718de746d5fed3b64df74e9c47af98975b5.tar.xz
player: reorganize how lua scripts are loaded
Make loading of scripts independent of Lua. Move some of the loading code from lua.c to scripting.c, and make it easier to add new scripting backends.
-rw-r--r--old-makefile1
-rw-r--r--options/options.c2
-rw-r--r--player/client.c5
-rw-r--r--player/client.h1
-rw-r--r--player/command.c1
-rw-r--r--player/core.h7
-rw-r--r--player/lua.c125
-rw-r--r--player/lua.h10
-rw-r--r--player/main.c7
-rw-r--r--player/scripting.c179
-rw-r--r--wscript_build.py1
11 files changed, 209 insertions, 130 deletions
diff --git a/old-makefile b/old-makefile
index 1d3b45a8cc..b54c147eb6 100644
--- a/old-makefile
+++ b/old-makefile
@@ -227,6 +227,7 @@ SOURCES = audio/audio.c \
player/osd.c \
player/playloop.c \
player/screenshot.c \
+ player/scripting.c \
player/sub.c \
player/video.c \
player/timeline/tl_matroska.c \
diff --git a/options/options.c b/options/options.c
index 5674c7dc0d..d3a10457a8 100644
--- a/options/options.c
+++ b/options/options.c
@@ -680,7 +680,9 @@ const struct MPOpts mp_default_opts = {
.osd_bar_h = 3.125,
.osd_scale = 1,
.osd_scale_by_window = 1,
+#if HAVE_LUA
.lua_load_osc = 1,
+#endif
.auto_load_scripts = 1,
.loop_times = -1,
.ordered_chapters = 1,
diff --git a/player/client.c b/player/client.c
index 45ba680e84..31a32b5616 100644
--- a/player/client.c
+++ b/player/client.c
@@ -205,6 +205,11 @@ struct mp_log *mp_client_get_log(struct mpv_handle *ctx)
return ctx->log;
}
+struct MPContext *mp_client_get_core(struct mpv_handle *ctx)
+{
+ return ctx->mpctx;
+}
+
static void wakeup_client(struct mpv_handle *ctx)
{
pthread_cond_signal(&ctx->wakeup);
diff --git a/player/client.h b/player/client.h
index 6e078e9d7b..e9d41d8c09 100644
--- a/player/client.h
+++ b/player/client.h
@@ -21,5 +21,6 @@ void mp_client_property_change(struct MPContext *mpctx, const char **list);
struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name);
struct mp_log *mp_client_get_log(struct mpv_handle *ctx);
+struct MPContext *mp_client_get_core(struct mpv_handle *ctx);
#endif
diff --git a/player/command.c b/player/command.c
index ec05e8cc40..512f2b478a 100644
--- a/player/command.c
+++ b/player/command.c
@@ -75,7 +75,6 @@
#include "osdep/io.h"
#include "core.h"
-#include "lua.h"
struct command_ctx {
double last_seek_time;
diff --git a/player/core.h b/player/core.h
index 18a749376b..891c14792d 100644
--- a/player/core.h
+++ b/player/core.h
@@ -449,6 +449,13 @@ void idle_loop(struct MPContext *mpctx);
void handle_force_window(struct MPContext *mpctx, bool reconfig);
void add_frame_pts(struct MPContext *mpctx, double pts);
+// scripting.c
+struct mp_scripting {
+ const char *file_ext; // e.g. "lua"
+ int (*load)(struct mpv_handle *client, const char *filename);
+};
+void mp_load_scripts(struct MPContext *mpctx);
+
// sub.c
void reset_subtitles(struct MPContext *mpctx, int order);
void uninit_subs(struct demuxer *demuxer);
diff --git a/player/lua.c b/player/lua.c
index 0c8c415630..1c8a5c6cb5 100644
--- a/player/lua.c
+++ b/player/lua.c
@@ -44,7 +44,6 @@
#include "command.h"
#include "client.h"
#include "libmpv/client.h"
-#include "lua.h"
// List of builtin modules and their contents as strings.
// All these are generated from player/lua/*.lua
@@ -55,7 +54,7 @@ static const char *builtin_lua_scripts[][2] = {
{"mp.assdraw",
# include "player/lua/assdraw.inc"
},
- {"@osc",
+ {"@osc.lua",
# include "player/lua/osc.inc"
},
{0}
@@ -140,27 +139,6 @@ static int run_event_loop(lua_State *L)
static void add_functions(struct script_ctx *ctx);
-static char *script_name_from_filename(void *talloc_ctx, 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] = '_';
- }
- return talloc_asprintf(talloc_ctx, "%s", name);
-}
-
static int load_file(struct script_ctx *ctx, const char *fname)
{
int r = 0;
@@ -206,20 +184,10 @@ static bool require(lua_State *L, const char *name)
return true;
}
-struct thread_arg {
- struct MPContext *mpctx;
- mpv_handle *client;
- const char *fname;
-};
-
-static void *lua_thread(void *p)
+static int load_lua(struct mpv_handle *client, const char *fname)
{
- pthread_detach(pthread_self());
-
- struct thread_arg *arg = p;
- struct MPContext *mpctx = arg->mpctx;
- const char *fname = arg->fname;
- mpv_handle *client = arg->client;
+ struct MPContext *mpctx = mp_client_get_core(client);
+ int r = -1;
struct script_ctx *ctx = talloc_ptrtype(NULL, ctx);
*ctx = (struct script_ctx) {
@@ -301,40 +269,15 @@ static void *lua_thread(void *p)
if (mp_cpcall(L, run_event_loop, 0) != 0)
report_error(L);
+ r = 0;
+
error_out:
- MP_VERBOSE(ctx, "exiting.\n");
if (ctx->suspended)
mpv_resume(ctx->client);
if (ctx->state)
lua_close(ctx->state);
- mpv_destroy(ctx->client);
talloc_free(ctx);
- talloc_free(arg);
- return NULL;
-}
-
-static void mp_lua_load_script(struct MPContext *mpctx, const char *fname)
-{
- struct thread_arg *arg = talloc_ptrtype(NULL, arg);
- char *name = script_name_from_filename(arg, fname);
- *arg = (struct thread_arg){
- .mpctx = mpctx,
- .fname = talloc_strdup(arg, fname),
- // Create the client before creating the thread; otherwise a race
- // condition could happen, where MPContext is destroyed while the
- // thread tries to create the client.
- .client = mp_new_client(mpctx->clients, name),
- };
- if (!arg->client) {
- talloc_free(arg);
- return;
- }
-
- pthread_t thread;
- if (pthread_create(&thread, NULL, lua_thread, arg))
- talloc_free(arg);
-
- return;
+ return r;
}
static int check_loglevel(lua_State *L, int arg)
@@ -1099,53 +1042,7 @@ static void add_functions(struct script_ctx *ctx)
lua_setfield(L, -2, "get_property_osd");
}
-static int compare_filename(const void *pa, const void *pb)
-{
- char *a = (char *)pa;
- char *b = (char *)pb;
- return strcmp(a, b);
-}
-
-static char **list_lua_files(void *talloc_ctx, char *path)
-{
- char **files = NULL;
- int count = 0;
- DIR *dp = opendir(path);
- if (!dp)
- return NULL;
- struct dirent *ep;
- while ((ep = readdir(dp))) {
- char *ext = mp_splitext(ep->d_name, NULL);
- if (!ext || strcasecmp(ext, "lua") != 0)
- continue;
- char *fname = mp_path_join(talloc_ctx, bstr0(path), bstr0(ep->d_name));
- MP_TARRAY_APPEND(talloc_ctx, files, count, fname);
- }
- closedir(dp);
- qsort(files, count, sizeof(char *), compare_filename);
- MP_TARRAY_APPEND(talloc_ctx, files, count, NULL);
- return files;
-}
-
-void mp_lua_init(struct MPContext *mpctx)
-{
- // 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]);
- }
- if (!mpctx->opts->auto_load_scripts)
- return;
- // Load ~/.mpv/lua/*
- void *tmp = talloc_new(NULL);
- char *lua_path = mp_find_user_config_file(tmp, mpctx->global, "lua");
- if (lua_path) {
- files = list_lua_files(tmp, lua_path);
- for (int n = 0; files && files[n]; n++)
- mp_lua_load_script(mpctx, files[n]);
- }
- talloc_free(tmp);
-}
+const struct mp_scripting mp_scripting_lua = {
+ .file_ext = "lua",
+ .load = load_lua,
+};
diff --git a/player/lua.h b/player/lua.h
deleted file mode 100644
index cb4a7f95ec..0000000000
--- a/player/lua.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef MP_LUA_H
-#define MP_LUA_H
-
-#include <stdbool.h>
-
-struct MPContext;
-
-void mp_lua_init(struct MPContext *mpctx);
-
-#endif
diff --git a/player/main.c b/player/main.c
index 097e51e11c..8c5e90a0d7 100644
--- a/player/main.c
+++ b/player/main.c
@@ -61,7 +61,6 @@
#include "core.h"
#include "client.h"
-#include "lua.h"
#include "command.h"
#include "screenshot.h"
@@ -450,11 +449,9 @@ int mp_initialize(struct MPContext *mpctx)
mpctx->initialized_flags |= INITIALIZED_VO;
}
-#if HAVE_LUA
- // Lua user scripts can call arbitrary functions. Load them at a point
+ // Lua user scripts (etc.) can call arbitrary functions. Load them at a point
// where this is safe.
- mp_lua_init(mpctx);
-#endif
+ mp_load_scripts(mpctx);
if (opts->shuffle)
playlist_shuffle(mpctx->playlist);
diff --git a/player/scripting.c b/player/scripting.c
new file mode 100644
index 0000000000..ed7a1c2d3b
--- /dev/null
+++ b/player/scripting.c
@@ -0,0 +1,179 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpv 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <math.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include "config.h"
+
+#include "osdep/io.h"
+
+#include "common/common.h"
+#include "common/msg.h"
+#include "options/path.h"
+#include "bstr/bstr.h"
+#include "core.h"
+#include "client.h"
+#include "libmpv/client.h"
+
+extern const struct mp_scripting mp_scripting_lua;
+
+static const struct mp_scripting *scripting_backends[] = {
+#if HAVE_LUA
+ &mp_scripting_lua,
+#endif
+ NULL
+};
+
+static char *script_name_from_filename(void *talloc_ctx, const char *fname)
+{
+ fname = mp_basename(fname);
+ if (fname[0] == '@')
+ fname += 1;
+ char *name = talloc_strdup(talloc_ctx, fname);
+ // Drop file 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] = '_';
+ }
+ return talloc_asprintf(talloc_ctx, "%s", name);
+}
+
+struct thread_arg {
+ const struct mp_scripting *backend;
+ mpv_handle *client;
+ const char *fname;
+};
+
+static void *script_thread(void *p)
+{
+ pthread_detach(pthread_self());
+
+ struct thread_arg *arg = p;
+ struct mp_log *log = mp_client_get_log(arg->client);
+
+ mp_verbose(log, "Loading script...\n");
+
+ if (arg->backend->load(arg->client, arg->fname) < 0)
+ mp_err(log, "Could not load script %s\n", arg->fname);
+
+ mp_verbose(log, "Exiting...\n");
+
+ mpv_destroy(arg->client);
+ talloc_free(arg);
+ return NULL;
+}
+
+static void mp_load_script(struct MPContext *mpctx, const char *fname)
+{
+ char *ext = mp_splitext(fname, NULL);
+ const struct mp_scripting *backend = NULL;
+ for (int n = 0; scripting_backends[n]; n++) {
+ const struct mp_scripting *b = scripting_backends[n];
+ if (ext && strcasecmp(ext, b->file_ext) == 0) {
+ backend = b;
+ break;
+ }
+ }
+
+ if (!backend) {
+ MP_WARN(mpctx, "Can't load unknown script: %s\n", fname);
+ return;
+ }
+
+ struct thread_arg *arg = talloc_ptrtype(NULL, arg);
+ char *name = script_name_from_filename(arg, fname);
+ *arg = (struct thread_arg){
+ .fname = talloc_strdup(arg, fname),
+ .backend = backend,
+ // Create the client before creating the thread; otherwise a race
+ // condition could happen, where MPContext is destroyed while the
+ // thread tries to create the client.
+ .client = mp_new_client(mpctx->clients, name),
+ };
+ if (!arg->client) {
+ talloc_free(arg);
+ return;
+ }
+
+ pthread_t thread;
+ if (pthread_create(&thread, NULL, script_thread, arg))
+ talloc_free(arg);
+
+ return;
+}
+
+static int compare_filename(const void *pa, const void *pb)
+{
+ char *a = (char *)pa;
+ char *b = (char *)pb;
+ return strcmp(a, b);
+}
+
+static char **list_script_files(void *talloc_ctx, char *path)
+{
+ char **files = NULL;
+ int count = 0;
+ DIR *dp = opendir(path);
+ if (!dp)
+ return NULL;
+ struct dirent *ep;
+ while ((ep = readdir(dp))) {
+ char *fname = mp_path_join(talloc_ctx, bstr0(path), bstr0(ep->d_name));
+ struct stat s;
+ if (!mp_stat(fname, &s) && S_ISREG(s.st_mode))
+ MP_TARRAY_APPEND(talloc_ctx, files, count, fname);
+ }
+ closedir(dp);
+ qsort(files, count, sizeof(char *), compare_filename);
+ MP_TARRAY_APPEND(talloc_ctx, files, count, NULL);
+ return files;
+}
+
+void mp_load_scripts(struct MPContext *mpctx)
+{
+ // Load scripts from options
+ if (mpctx->opts->lua_load_osc)
+ mp_load_script(mpctx, "@osc.lua");
+ char **files = mpctx->opts->lua_files;
+ for (int n = 0; files && files[n]; n++) {
+ if (files[n][0])
+ mp_load_script(mpctx, files[n]);
+ }
+ if (!mpctx->opts->auto_load_scripts)
+ return;
+ // Load ~/.mpv/lua/*
+ void *tmp = talloc_new(NULL);
+ char *script_path = mp_find_user_config_file(tmp, mpctx->global, "lua");
+ if (script_path) {
+ files = list_script_files(tmp, script_path);
+ for (int n = 0; files && files[n]; n++)
+ mp_load_script(mpctx, files[n]);
+ }
+ talloc_free(tmp);
+}
diff --git a/wscript_build.py b/wscript_build.py
index c8058b6fe6..fe711b554f 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -216,6 +216,7 @@ def build(ctx):
( "player/osd.c" ),
( "player/playloop.c" ),
( "player/screenshot.c" ),
+ ( "player/scripting.c" ),
( "player/sub.c" ),
( "player/timeline/tl_cue.c" ),
( "player/timeline/tl_mpv_edl.c" ),