summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-02-26 22:33:23 +0100
committerwm4 <wm4@nowhere>2014-02-26 22:38:34 +0100
commitc1cb0dd7eeb1c77bbc4c2270de54759b367ad741 (patch)
tree7bc4a03eaee193b78855e3656257e1540e9efb06
parent15134935602a546103a26f4b3ecc72da25896f09 (diff)
downloadmpv-c1cb0dd7eeb1c77bbc4c2270de54759b367ad741.tar.bz2
mpv-c1cb0dd7eeb1c77bbc4c2270de54759b367ad741.tar.xz
lua: add set_property_native function
Probably completely useless, at least for now. Also not very well tested, but initial test seems successful.
-rw-r--r--DOCS/man/en/lua.rst14
-rw-r--r--player/lua.c135
2 files changed, 144 insertions, 5 deletions
diff --git a/DOCS/man/en/lua.rst b/DOCS/man/en/lua.rst
index 338ffec6af..b520c36284 100644
--- a/DOCS/man/en/lua.rst
+++ b/DOCS/man/en/lua.rst
@@ -116,8 +116,6 @@ The ``mp`` module is preloaded, although it can be loaded manually with
Returns a value on success, or ``def, error`` on error. Note that ``nil``
might be a possible, valid value too in some corner cases.
- (There is no ``mp.set_property_native`` yet.)
-
``mp.set_property(name, value)``
Set the given property to the given string value. See ``mp.get_property``
and `Properties`_ for more information about properties.
@@ -137,6 +135,18 @@ The ``mp`` module is preloaded, although it can be loaded manually with
represented as integer, and if so, it will pass an integer value to mpv,
otherwise a double float.
+``mp.set_property_native(name, value)``
+ Similar to ``mp.set_property``, but set the given property using its native
+ type.
+
+ Since there are several data types which can not represented natively in
+ Lua, this might not always work as expected. For example, while the Lua
+ wrapper can do some guesswork to decide whether a Lua table is an array
+ or a map, this would fail with empty tables. Also, there are not many
+ properties for which it makes sense to use this, instead of
+ ``set_property``, ``set_property_bool``, ``set_property_number``.
+ For these reasons, this function should probably be avoided for now.
+
``mp.get_time()``
Return the current mpv internal time in seconds as a number. This is
basically the system time, with an arbitrary offset.
diff --git a/player/lua.c b/player/lua.c
index 27e411e7fe..e12a5f533e 100644
--- a/player/lua.c
+++ b/player/lua.c
@@ -542,6 +542,12 @@ static int script_set_property_bool(lua_State *L)
return check_error(L, mpv_set_property(ctx->client, p, MPV_FORMAT_FLAG, &v));
}
+static bool is_int(double d)
+{
+ int64_t v = d;
+ return d == (double)v;
+}
+
static int script_set_property_number(lua_State *L)
{
struct script_ctx *ctx = get_ctx(L);
@@ -550,16 +556,138 @@ static int script_set_property_number(lua_State *L)
// If the number might be an integer, then set it as integer. The mpv core
// will (probably) convert INT64 to DOUBLE when setting, but not the other
// way around.
- int64_t v = d;
int res;
- if (d == (double)v) {
- res = mpv_set_property(ctx->client, p, MPV_FORMAT_INT64, &v);
+ if (is_int(d)) {
+ res = mpv_set_property(ctx->client, p, MPV_FORMAT_INT64, &(int64_t){d});
} else {
res = mpv_set_property(ctx->client, p, MPV_FORMAT_DOUBLE, &d);
}
return check_error(L, res);
}
+static void makenode(void *tmp, mpv_node *dst, lua_State *L, int t)
+{
+ if (t < 0)
+ t = lua_gettop(L) + (t + 1);
+ switch (lua_type(L, t)) {
+ case LUA_TNIL:
+ dst->format = MPV_FORMAT_NONE;
+ break;
+ case LUA_TNUMBER: {
+ double d = lua_tonumber(L, t);
+ if (is_int(d)) {
+ dst->format = MPV_FORMAT_INT64;
+ dst->u.int64 = d;
+ } else {
+ dst->format = MPV_FORMAT_DOUBLE;
+ dst->u.double_ = d;
+ }
+ break;
+ }
+ case LUA_TBOOLEAN:
+ dst->format = MPV_FORMAT_FLAG;
+ dst->u.flag = !!lua_toboolean(L, t);
+ break;
+ case LUA_TSTRING:
+ dst->format = MPV_FORMAT_STRING;
+ dst->u.string = talloc_strdup(tmp, lua_tostring(L, t));
+ break;
+ case LUA_TTABLE: {
+ // Lua uses the same type for arrays and maps, so guess the correct one.
+ int format = MPV_FORMAT_NONE;
+ if (lua_getmetatable(L, t)) { // mt
+ lua_getfield(L, -1, "type"); // mt val
+ if (lua_type(L, -1) == LUA_TSTRING) {
+ const char *type = lua_tostring(L, -1);
+ if (strcmp(type, "MAP") == 0) {
+ format = MPV_FORMAT_NODE_MAP;
+ } else if (strcmp(type, "ARRAY") == 0) {
+ format = MPV_FORMAT_NODE_ARRAY;
+ }
+ }
+ }
+ if (format == MPV_FORMAT_NONE) {
+ // If all keys are integers, and they're in sequence, take it
+ // as an array.
+ int count = 0;
+ for (int n = 1; ; n++) {
+ lua_pushinteger(L, n); // n
+ lua_gettable(L, t); // t[n]
+ bool empty = lua_isnil(L, -1); // t[n]
+ lua_pop(L, 1); // -
+ if (empty) {
+ count = n;
+ break;
+ }
+ }
+ if (count > 0)
+ format = MPV_FORMAT_NODE_ARRAY;
+ lua_pushnil(L); // nil
+ while (lua_next(L, t) != 0) { // key value
+ count--;
+ lua_pop(L, 1); // key
+ if (count < 0) {
+ lua_pop(L, 1); // -
+ format = MPV_FORMAT_NODE_MAP;
+ break;
+ }
+ }
+ }
+ if (format == MPV_FORMAT_NONE)
+ format = MPV_FORMAT_NODE_ARRAY; // probably empty table; assume array
+ mpv_node_list *list = talloc_zero(tmp, mpv_node_list);
+ dst->format = format;
+ dst->u.list = list;
+ if (format == MPV_FORMAT_NODE_ARRAY) {
+ for (int n = 0; ; n++) {
+ lua_pushinteger(L, n + 1); // n1
+ lua_gettable(L, t); // t[n1]
+ if (lua_isnil(L, -1))
+ break;
+ MP_TARRAY_GROW(tmp, list->values, list->num);
+ makenode(tmp, &list->values[n], L, -1);
+ list->num++;
+ lua_pop(L, 1); // -
+ }
+ lua_pop(L, 1); // -
+ } else {
+ lua_pushnil(L); // nil
+ while (lua_next(L, t) != 0) { // key value
+ MP_TARRAY_GROW(tmp, list->values, list->num);
+ MP_TARRAY_GROW(tmp, list->keys, list->num);
+ makenode(tmp, &list->values[list->num], L, -1);
+ if (lua_type(L, -2) != LUA_TSTRING) {
+ talloc_free(tmp);
+ luaL_error(L, "key must be a string, but got %s",
+ lua_typename(L, -2));
+ }
+ list->keys[list->num] = talloc_strdup(tmp, lua_tostring(L, -2));
+ list->num++;
+ lua_pop(L, 1); // key
+ }
+ }
+ break;
+ }
+ default:
+ // unknown type
+ talloc_free(tmp);
+ luaL_error(L, "disallowed Lua type found: %s\n", lua_typename(L, t));
+ }
+}
+
+static int script_set_property_native(lua_State *L)
+{
+ struct script_ctx *ctx = get_ctx(L);
+ const char *p = luaL_checkstring(L, 1);
+ struct mpv_node node;
+ void *tmp = talloc_new(NULL);
+ makenode(tmp, &node, L, 2);
+ int res = mpv_set_property(ctx->client, p, MPV_FORMAT_NODE, &node);
+ talloc_free(tmp);
+ return check_error(L, res);
+
+}
+
static int script_property_list(lua_State *L)
{
const struct m_option *props = mp_get_property_list();
@@ -860,6 +988,7 @@ static struct fn_entry fn_list[] = {
FN_ENTRY(set_property),
FN_ENTRY(set_property_bool),
FN_ENTRY(set_property_number),
+ FN_ENTRY(set_property_native),
FN_ENTRY(property_list),
FN_ENTRY(set_osd_ass),
FN_ENTRY(get_osd_resolution),