Skip to content

Commit

Permalink
Add initial Lua scripting support
Browse files Browse the repository at this point in the history
This is preliminary. There are still tons of issues, and any aspect
of scripting may change in the future. I decided to merge this
(preliminary) work now because it makes it easier to develop it, not
because it's done. lua.rst is clear enough about it (plus some
sarcasm).

This requires linking to Lua. Lua has no official pkg-config file, but
there are distribution specific .pc files, all with different names.
Adding a non-pkg-config based configure test was considered, but we'd
rather not.

One major complication is that libquvi links against Lua too, and if
the Lua version is different from mpv's, you will get a crash as soon
as libquvi uses Lua. (libquvi by design always runs when a file is
opened.) I would consider this the problem of distros and whoever
builds mpv, but to make things easier for users, we add a terrible
runtime test to the configure script, which probes whether libquvi
will crash. This is disabled when cross-compiling, but in that case
we hope the user knows what he is doing.
  • Loading branch information
wm4 committed Sep 25, 2013
1 parent b0cc3c2 commit 6048f87
Show file tree
Hide file tree
Showing 22 changed files with 1,238 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
/demux/ebml_defs.c
/demux/ebml_types.h
/sub/osd_font.h
/mpvcore/lua/*.inc
/DOCS/man/*/mpv.1
/DOCS/man/*/mpv.aux
/DOCS/man/*/mpv.log
Expand Down
18 changes: 18 additions & 0 deletions DOCS/man/en/lua.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
LUA SCRIPTING
=============

mpv can load Lua scripts. These scripts can be used to control mpv in a similar
way to slave mode. mpv provides the builtin module ``mp`` (can be loaded
with ``require 'mpv'``), which provides functions to send commands to the
mpv core and to retrieve information about playback state, user settings,
file information, and so on.

.. admonition:: Warning

Lua scripting is work in progress, and it's in a very early stage. When
writing scripts, rely only on the features and functions documented here.
Everything else is subject to change.

.. admonition:: Warning

Nothing is finished and documented yet.
2 changes: 2 additions & 0 deletions DOCS/man/en/mpv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ OPTIONS

.. include:: input.rst

.. include:: lua.rst

.. include:: changes.rst

ENVIRONMENT VARIABLES
Expand Down
4 changes: 4 additions & 0 deletions DOCS/man/en/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,10 @@
looping. If several files are specified on command line, the entire playlist
is looped.

``--lua=<filename>``
Load a Lua script. You can load multiple scripts by separating them with
commas (``,``).

``--mc=<seconds/frame>``
Maximum A-V sync correction per frame (in seconds)

Expand Down
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ SOURCES-$(WAYLAND) += video/out/vo_wayland.c video/out/wayland_comm
SOURCES-$(VF_LAVFI) += video/filter/vf_lavfi.c
SOURCES-$(AF_LAVFI) += audio/filter/af_lavfi.c

SOURCES-$(LUA) += mpvcore/mp_lua.c

ifeq ($(HAVE_AVUTIL_REFCOUNTING),no)
SOURCES-yes += video/decode/lavc_dr1.c
endif
Expand Down Expand Up @@ -397,6 +399,14 @@ sub/osd_libass.c: sub/osd_font.h
sub/osd_font.h: TOOLS/file2string.pl sub/osd_font.otf
./$^ >$@

mpvcore/mp_lua.c: mpvcore/lua/defaults.inc
mpvcore/lua/defaults.inc: TOOLS/file2string.pl mpvcore/lua/defaults.lua

This comment has been minimized.

Copy link
@rofl0r

rofl0r Sep 26, 2013

mpv requires perl to build ? i wasn't aware of that...

./$^ >$@

mpvcore/mp_lua.c: mpvcore/lua/assdraw.inc
mpvcore/lua/assdraw.inc: TOOLS/file2string.pl mpvcore/lua/assdraw.lua
./$^ >$@

# ./configure must be rerun if it changed
config.mak: configure
@echo "############################################################"
Expand Down Expand Up @@ -495,6 +505,8 @@ clean:
-$(RM) video/out/gl_video_shaders.h
-$(RM) video/out/x11_icon.inc
-$(RM) sub/osd_font.h
-$(RM) mpvcore/lua/defaults.inc
-$(RM) mpvcore/lua/assdraw.inc

distclean: clean
-$(RM) config.log config.mak config.h TAGS tags
Expand Down
114 changes: 114 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ Installation directories:
Optional features:
--disable-encoding disable encoding functionality [enable]
--disable-lua disable Lua scripting support [autodetect]
--lua=LUA select Lua package which should be autodetected
Choices: 51 51deb 52 52deb luajit
--disable-libguess disable libguess [autodetect]
--enable-terminfo use terminfo database for key codes [autodetect]
--enable-termcap use termcap database for key codes [autodetect]
Expand Down Expand Up @@ -485,6 +488,7 @@ _pthreads=auto
_ass=auto
_libass_osd=auto
_rpath=no
lua=auto
libpostproc=auto
libavfilter=auto
vf_lavfi=auto
Expand Down Expand Up @@ -679,6 +683,9 @@ for ac_option do
--disable-libavresample) _disable_avresample=yes ;;
--enable-libavresample) _disable_avresample=no ;;

--enable-lua) lua=yes ;;
--disable-lua) lua=no ;;
--lua=*) lua_pkg=$(echo $ac_option | cut -d '=' -f 2) ;;
--enable-lirc) _lirc=yes ;;
--disable-lirc) _lirc=no ;;
--enable-lircc) _lircc=yes ;;
Expand Down Expand Up @@ -2982,6 +2989,111 @@ fi
echores "$_pvr"


# Note: Lua has no official .pc file, so there are different OS-specific ones.
# Also, we support luajit, which is compatible to 5.1.
# The situation is further complicated by distros supporting multiple Lua
# versions, without ensuring libraries linking to conflicting Lua libs don't
# cause issues. This is a real problem with libquvi.

cat > $TMPC << EOF
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
EOF
# abuse $TMPH file as second temp file
cat > $TMPH << EOF
void test_lua(void) {
lua_State *L = luaL_newstate();
lua_pushstring(L, "test");
lua_setglobal(L, "test");
}
void test_other(void) {
EOF

# test all other Lua using packages (hack that gives us time)
if test "$_libquvi4" = yes ; then

echo "#include <quvi/quvi.h>" >> $TMPC
cat >> $TMPH << EOF
quvi_t q;
if (quvi_init(&q) == QUVI_OK)
quvi_supported(q, "http://nope");
EOF

fi

if test "$_libquvi9" = yes ; then

echo "#include <quvi.h>" >> $TMPC
cat >> $TMPH << EOF
quvi_t q = quvi_new();
if (quvi_ok(q))
quvi_supports(q, "http://nope", QUVI_SUPPORTS_MODE_OFFLINE, QUVI_SUPPORTS_TYPE_MEDIA);
EOF

fi

cat >> $TMPH << EOF
}
int main(void) {
test_lua();
test_other();
return 0;
}
EOF

cat $TMPH >> $TMPC

test_lua() {
# changed by pkg_config_add
old_extra_cflags="$extra_cflags"
old_libs_mplayer="$libs_mplayer"
echocheck "Lua $2 ($1)"
if test "$lua" = yes ; then
echores "no"
return 1
fi
if test "x$lua_pkg" != "x" && test "$lua_pkg" != "$1" ; then
echores "no"
return 1
fi
if pkg_config_add "$2" ; then
if test $_cross_compile = no ; then
if cc_check && tmp_run ; then
echo > /dev/null # idiot NOP
else
extra_cflags="$old_extra_cflags"
libs_mplayer="$old_libs_mplayer"
echores "no - does not run"
return 1
fi
fi
lua=yes
fi
echores "$lua"
test "$lua" = yes
return $?
}

if test "$lua" = auto ; then

lua=no
test_lua 51 "lua >= 5.1.0 lua < 5.2.0"
test_lua 51deb "lua5.1 >= 5.1.0" # debian
test_lua luajit "luajit >= 2.0.0"
# assume all our dependencies (libquvi in particular) link with 5.1
test_lua 52 "lua >= 5.2.0"
test_lua 52deb "lua5.2 >= 5.2.0" # debian

fi

if test "$lua" = yes ; then
def_lua='#define CONFIG_LUA 1'
else
def_lua='#undef CONFIG_LUA'
fi

echocheck "encoding"
if test "$_encoding" = yes ; then
def_encoding="#define CONFIG_ENCODING 1"
Expand Down Expand Up @@ -3155,6 +3267,7 @@ DUMMY_OSD = $_dummy_osd
LIBBLURAY = $_bluray
LIBBS2B = $_libbs2b
LCMS2 = $_lcms2
LUA = $lua
LIBPOSTPROC = $libpostproc
LIBAVDEVICE = $libavdevice
LIBAVFILTER = $libavfilter
Expand Down Expand Up @@ -3341,6 +3454,7 @@ $def_libquvi9
$def_libguess
$def_lcms2
$def_lua
/* libvo options */
Expand Down
72 changes: 72 additions & 0 deletions mpvcore/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@

#include "mpvcore/mp_core.h"

#include "mp_lua.h"

static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype,
const char *cmd, const char *arg);
static int set_filters(struct MPContext *mpctx, enum stream_type mediatype,
Expand Down Expand Up @@ -1913,6 +1915,11 @@ static const m_option_t mp_properties[] = {
{0},
};

const struct m_option *mp_get_property_list(void)
{
return mp_properties;
}

int mp_property_do(const char *name, int action, void *val,
struct MPContext *ctx)
{
Expand Down Expand Up @@ -2729,6 +2736,15 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
cmd->args[1].v.s, msg_osd);
break;

case MP_CMD_SCRIPT_DISPATCH:
if (mpctx->lua_ctx) {
#ifdef CONFIG_LUA
mp_lua_script_dispatch(mpctx, cmd->args[0].v.s, cmd->args[1].v.i,
cmd->key_up_follows ? "keyup_follows" : "press");
#endif
}
break;

case MP_CMD_COMMAND_LIST: {
for (struct mp_cmd *sub = cmd->args[0].v.p; sub; sub = sub->queue_next)
run_command(mpctx, sub);
Expand All @@ -2755,3 +2771,59 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
break;
}
}

struct command_ctx {
int events;
};

void command_init(struct MPContext *mpctx)
{
mpctx->command_ctx = talloc_zero(mpctx, struct command_ctx);
}

// Notify that a property might have changed.
void mp_notify_property(struct MPContext *mpctx, const char *property)
{
mp_notify(mpctx, MP_EVENT_PROPERTY, (void *)property);
}

void mp_notify(struct MPContext *mpctx, enum mp_event event, void *arg)
{
struct command_ctx *ctx = mpctx->command_ctx;
ctx->events |= 1u << event;
}

static void handle_script_event(struct MPContext *mpctx, const char *name,
const char *arg)
{
#ifdef CONFIG_LUA
mp_lua_event(mpctx, name, arg);
#endif
}

void mp_flush_events(struct MPContext *mpctx)
{
struct command_ctx *ctx = mpctx->command_ctx;

ctx->events |= (1u << MP_EVENT_TICK);

for (int n = 0; n < 16; n++) {
enum mp_event event = n;
unsigned mask = 1 << event;
if (ctx->events & mask) {
// The event handler could set event flags again; in this case let
// the next mp_flush_events() call handle it to avoid infinite loops.
ctx->events &= ~mask;
const char *name = NULL;
switch (event) {
case MP_EVENT_TICK: name = "tick"; break;
case MP_EVENT_TRACKS_CHANGED: name = "track-layout"; break;
case MP_EVENT_START_FILE: name = "start"; break;
case MP_EVENT_END_FILE: name = "end"; break;
default: ;
}
if (name)
handle_script_event(mpctx, name, "");
}
}
}
18 changes: 18 additions & 0 deletions mpvcore/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
struct MPContext;
struct mp_cmd;

void command_init(struct MPContext *mpctx);

void mp_get_osd_mouse_pos(struct MPContext *mpctx, float *x, float *y);

void run_command(struct MPContext *mpctx, struct mp_cmd *cmd);
Expand All @@ -30,4 +32,20 @@ void property_print_help(void);
int mp_property_do(const char* name, int action, void* val,
struct MPContext *mpctx);

const struct m_option *mp_get_property_list(void);

enum mp_event {
MP_EVENT_NONE,
MP_EVENT_TICK,
MP_EVENT_PROPERTY, // char*, property that is changed
MP_EVENT_TRACKS_CHANGED,
MP_EVENT_START_FILE,
MP_EVENT_END_FILE,
};

void mp_notify(struct MPContext *mpctx, enum mp_event event, void *arg);
void mp_notify_property(struct MPContext *mpctx, const char *property);

void mp_flush_events(struct MPContext *mpctx);

#endif /* MPLAYER_COMMAND_H */
5 changes: 5 additions & 0 deletions mpvcore/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ static const mp_cmd_t mp_cmds[] = {

{ MP_CMD_VO_CMDLINE, "vo_cmdline", { ARG_STRING } },

{ MP_CMD_SCRIPT_DISPATCH, "script_dispatch", { ARG_STRING, ARG_INT } },

{0}
};

Expand Down Expand Up @@ -528,6 +530,7 @@ struct input_ctx {
// Autorepeat stuff
short ar_state;
int64_t last_ar;

// Autorepeat config
unsigned int ar_delay;
unsigned int ar_rate;
Expand Down Expand Up @@ -1455,6 +1458,8 @@ static void remove_key_down(struct input_ctx *ictx, int code)
static bool key_updown_ok(enum mp_command_type cmd)
{
switch (cmd) {
case MP_CMD_SCRIPT_DISPATCH:
return true;
default:
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions mpvcore/input/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ enum mp_command_type {
/// Video output commands
MP_CMD_VO_CMDLINE,

/// Internal for Lua scripts
MP_CMD_SCRIPT_DISPATCH,

// Internal
MP_CMD_COMMAND_LIST, // list of sub-commands in args[0].v.p
};
Expand Down
Loading

0 comments on commit 6048f87

Please sign in to comment.