[vlc-devel] [vlc-commits] lua: convert playlist parser to stream filter
Thomas Guillem
thomas at gllm.fr
Wed May 17 16:54:24 CEST 2017
Hello,
This commit causes every playlist lua scripts to be probed for all
inputs. There are probed from stream_FilterAutoNew() in InputDemuxNew().
This cause a massive performance issue when preparsing a lot of files,
this can double or triple the parse duration for one file.
Also, since lua playlists normally only check the url, a matching lua
"stream-filter" will be added 16 times (because of the loop inside
stream_FilterAutoNew()) and playback will fail since the first filter
will consume the stream data. See
http://git.videolan.org/gitweb.cgi?p=vlc.git;a=blob;f=share/lua/playlist/youtube.lua;h=7b63f91fa84a5da799e4a09a375448661deaf6df;hb=HEAD#l228
for a probe example.
Regards,
Thomas Guillem
On Tue, Apr 18, 2017, at 22:43, Rémi Denis-Courmont wrote:
> vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Apr 18
> 22:35:47 2017 +0300| [ca74826ea7623ba3788c8b5eeb3f8b31dda37012] |
> committer: Rémi Denis-Courmont
>
> lua: convert playlist parser to stream filter
>
> ReadDir() is more logical and simpler than Demux() here.
>
> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ca74826ea7623ba3788c8b5eeb3f8b31dda37012
> ---
>
> modules/lua/demux.c | 259
> ++++++++++++++++++++++++++++++----------------------
> modules/lua/vlc.c | 62 +------------
> modules/lua/vlc.h | 3 -
> 3 files changed, 150 insertions(+), 174 deletions(-)
>
> diff --git a/modules/lua/demux.c b/modules/lua/demux.c
> index 38fee11a43..92224961d2 100644
> --- a/modules/lua/demux.c
> +++ b/modules/lua/demux.c
> @@ -29,35 +29,35 @@
> #endif
>
> #include <assert.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <vlc_common.h>
> +#include <vlc_access.h>
>
> #include "vlc.h"
> #include "libs.h"
>
> -
> -/*****************************************************************************
> - * Local prototypes
> -
> *****************************************************************************/
> -static int Demux( demux_t *p_demux );
> -static int Control( demux_t *p_demux, int i_query, va_list args );
> -
> /*****************************************************************************
> * Demux specific functions
> *****************************************************************************/
> -struct demux_sys_t
> +struct vlclua_playlist
> {
> lua_State *L;
> - char *psz_filename;
> + char *filename;
> + char *access;
> + const char *path;
> };
>
> static int vlclua_demux_peek( lua_State *L )
> {
> - demux_t *p_demux = (demux_t *)vlclua_get_this( L );
> + stream_t *s = (stream_t *)vlclua_get_this(L);
> int n = luaL_checkint( L, 1 );
> const uint8_t *p_peek;
>
> - int i_peek = vlc_stream_Peek( p_demux->s, &p_peek, n );
> - if( i_peek > 0 )
> - lua_pushlstring( L, (const char *)p_peek, i_peek );
> + ssize_t val = vlc_stream_Peek(s->p_source, &p_peek, n);
> + if (val > 0)
> + lua_pushlstring(L, (const char *)p_peek, val);
> else
> lua_pushnil( L );
> return 1;
> @@ -65,16 +65,16 @@ static int vlclua_demux_peek( lua_State *L )
>
> static int vlclua_demux_read( lua_State *L )
> {
> - demux_t *p_demux = (demux_t *)vlclua_get_this( L );
> + stream_t *s = (stream_t *)vlclua_get_this(L);
> const uint8_t *p_read;
> int n = luaL_checkint( L, 1 );
> - int i_read = vlc_stream_Peek( p_demux->s, &p_read, n );
> + ssize_t val = vlc_stream_Peek(s->p_source, &p_read, n);
>
> - if( i_read > 0 )
> + if (val > 0)
> {
> - lua_pushlstring( L, (const char *)p_read, i_read );
> - int i_seek = vlc_stream_Read( p_demux->s, NULL, i_read );
> - assert( i_read == i_seek );
> + lua_pushlstring(L, (const char *)p_read, val);
> + int i_seek = vlc_stream_Read(s->p_source, NULL, val);
> + assert(val == i_seek );
> }
> else
> lua_pushnil( L );
> @@ -84,17 +84,17 @@ static int vlclua_demux_read( lua_State *L )
>
> static int vlclua_demux_readline( lua_State *L )
> {
> - demux_t *p_demux = (demux_t *)vlclua_get_this( L );
> - char *psz_line = vlc_stream_ReadLine( p_demux->s );
> - if( psz_line )
> + stream_t *s = (stream_t *)vlclua_get_this(L);
> + char *line = vlc_stream_ReadLine(s->p_source);
> +
> + if (line != NULL)
> {
> - lua_pushstring( L, psz_line );
> - free( psz_line );
> + lua_pushstring(L, line);
> + free(line);
> }
> else
> - {
> lua_pushnil( L );
> - }
> +
> return 1;
> }
>
> @@ -120,70 +120,71 @@ static const luaL_Reg p_reg_parse[] =
> * Called through lua_scripts_batch_execute to call 'probe' on
> * the script pointed by psz_filename.
> *****************************************************************************/
> -static int probe_luascript( vlc_object_t *p_this, const char *
> psz_filename,
> - const luabatch_context_t *p_context )
> +static int probe_luascript(vlc_object_t *obj, const char *filename,
> + const luabatch_context_t *ctx)
> {
> - VLC_UNUSED(p_context);
> - demux_t * p_demux = (demux_t *)p_this;
> -
> - p_demux->p_sys->psz_filename = strdup(psz_filename);
> + stream_t *s = (stream_t *)obj;
> + struct vlclua_playlist *sys = s->p_sys;
>
> /* Initialise Lua state structure */
> lua_State *L = luaL_newstate();
> if( !L )
> - {
> - msg_Err( p_demux, "Could not create new Lua State" );
> - goto error;
> - }
> - p_demux->p_sys->L = L;
> + return VLC_ENOMEM;
> +
> + sys->L = L;
>
> /* Load Lua libraries */
> luaL_openlibs( L ); /* FIXME: Don't open all the libs? */
>
> - vlclua_set_this( L, p_demux );
> + vlclua_set_this(L, s);
> luaL_register_namespace( L, "vlc", p_reg );
> luaopen_msg( L );
> luaopen_strings( L );
> luaopen_stream( L );
> luaopen_variables( L );
> luaopen_xml( L );
> - lua_pushstring( L, p_demux->psz_location );
> +
> + if (sys->path != NULL)
> + lua_pushstring(L, sys->path);
> + else
> + lua_pushnil(L);
> lua_setfield( L, -2, "path" );
> - lua_pushstring( L, p_demux->psz_access );
> +
> + if (sys->access != NULL)
> + lua_pushstring(L, sys->access);
> + else
> + lua_pushnil(L);
> lua_setfield( L, -2, "access" );
>
> lua_pop( L, 1 );
>
> /* Setup the module search path */
> - if( vlclua_add_modules_path( L, psz_filename ) )
> + if (vlclua_add_modules_path(L, filename))
> {
> - msg_Warn( p_demux, "Error while setting the module search path
> for %s",
> - psz_filename );
> + msg_Warn(s, "error setting the module search path for %s",
> filename);
> goto error;
> }
>
> /* Load and run the script(s) */
> - if( vlclua_dofile( VLC_OBJECT(p_demux), L, psz_filename ) )
> + if (vlclua_dofile(VLC_OBJECT(s), L, filename))
> {
> - msg_Warn( p_demux, "Error loading script %s: %s", psz_filename,
> - lua_tostring( L, lua_gettop( L ) ) );
> + msg_Warn(s, "error loading script %s: %s", filename,
> + lua_tostring(L, lua_gettop(L)));
> goto error;
> }
>
> lua_getglobal( L, "probe" );
> -
> if( !lua_isfunction( L, -1 ) )
> {
> - msg_Warn( p_demux, "Error while running script %s, "
> - "function probe() not found", psz_filename );
> + msg_Warn(s, "error running script %s: function %s(): %s",
> + filename, "probe", "not found");
> goto error;
> }
>
> if( lua_pcall( L, 0, 1, 0 ) )
> {
> - msg_Warn( p_demux, "Error while running script %s, "
> - "function probe(): %s", psz_filename,
> - lua_tostring( L, lua_gettop( L ) ) );
> + msg_Warn(s, "error running script %s: function %s(): %s",
> + filename, "probe", lua_tostring(L, lua_gettop(L)));
> goto error;
> }
>
> @@ -191,92 +192,130 @@ static int probe_luascript( vlc_object_t *p_this,
> const char * psz_filename,
> {
> if( lua_toboolean( L, 1 ) )
> {
> - msg_Dbg( p_demux, "Lua playlist script %s's "
> - "probe() function was successful", psz_filename );
> + msg_Dbg(s, "Lua playlist script %s's "
> + "probe() function was successful", filename );
> lua_pop( L, 1 );
> + sys->filename = strdup(filename);
> return VLC_SUCCESS;
> }
> }
>
> + (void) ctx;
> error:
> lua_pop( L, 1 );
> - lua_close( p_demux->p_sys->L );
> - p_demux->p_sys->L = NULL;
> - FREENULL( p_demux->p_sys->psz_filename );
> + lua_close(sys->L);
> return VLC_EGENERIC;
> }
>
> -/*****************************************************************************
> - * Import_LuaPlaylist: main import function
> -
> *****************************************************************************/
> -int Import_LuaPlaylist( vlc_object_t *p_this )
> +static int ReadDir(stream_t *s, input_item_node_t *node)
> {
> - demux_t *p_demux = (demux_t *)p_this;
> - int ret;
> + struct vlclua_playlist *sys = s->p_sys;
> + lua_State *L = sys->L;
>
> - p_demux->p_sys = calloc( 1, sizeof( demux_sys_t ) );
> - if( !p_demux->p_sys )
> - return VLC_ENOMEM;
> + luaL_register_namespace( L, "vlc", p_reg_parse );
>
> - p_demux->pf_control = Control;
> - p_demux->pf_demux = Demux;
> + lua_getglobal( L, "parse" );
>
> - ret = vlclua_scripts_batch_execute( p_this, "playlist",
> - &probe_luascript, NULL );
> - if( ret )
> - Close_LuaPlaylist( p_this );
> - return ret;
> -}
> + if( !lua_isfunction( L, -1 ) )
> + {
> + msg_Warn(s, "error running script %s: function %s(): %s",
> + sys->filename, "parse", "not found");
> + return VLC_ENOITEM;
> + }
> +
> + if( lua_pcall( L, 0, 1, 0 ) )
> + {
> + msg_Warn(s, "error running script %s: function %s(): %s",
> + sys->filename, "parse", lua_tostring(L,
> lua_gettop(L)));
> + return VLC_ENOITEM;
> + }
>
> + if (!lua_gettop(L))
> + {
> + msg_Err(s, "script went completely foobar");
> + return VLC_ENOITEM;
> + }
>
> -/*****************************************************************************
> - * Deactivate: frees unused data
> -
> *****************************************************************************/
> -void Close_LuaPlaylist( vlc_object_t *p_this )
> -{
> - demux_t *p_demux = (demux_t *)p_this;
> - if( p_demux->p_sys->L )
> - lua_close( p_demux->p_sys->L );
> - free( p_demux->p_sys->psz_filename );
> - free( p_demux->p_sys );
> + if (!lua_istable(L, -1))
> + {
> + msg_Warn(s, "Playlist should be a table.");
> + return VLC_ENOITEM;
> + }
> +
> + lua_pushnil(L);
> +
> + /* playlist nil */
> + while (lua_next(L, -2))
> + {
> + input_item_t *item = vlclua_read_input_item(VLC_OBJECT(s), L);
> + if (item != NULL)
> + {
> + /* copy the original URL to the meta data,
> + * if "URL" is still empty */
> + char *url = input_item_GetURL(item);
> + if (url == NULL && s->psz_url != NULL)
> + input_item_SetURL(item, s->psz_url);
> + free(url);
> +
> + input_item_node_AppendItem(node, item);
> + input_item_Release(item);
> + }
> + /* pop the value, keep the key for the next lua_next() call */
> + lua_pop(L, 1);
> + }
> + /* playlist */
> +
> + return VLC_SUCCESS;
> }
>
> -static int Demux( demux_t *p_demux )
> +/*****************************************************************************
> + * Import_LuaPlaylist: main import function
> +
> *****************************************************************************/
> +int Import_LuaPlaylist(vlc_object_t *obj)
> {
> - lua_State *L = p_demux->p_sys->L;
> - char *psz_filename = p_demux->p_sys->psz_filename;
> -
> - input_item_t *p_current_input = input_GetItem( p_demux->p_input );
> + stream_t *s = (stream_t *)obj;
> + struct vlclua_playlist *sys = malloc(sizeof (*sys));
>
> - luaL_register_namespace( L, "vlc", p_reg_parse );
> + if (unlikely(sys == NULL))
> + return VLC_ENOMEM;
>
> - lua_getglobal( L, "parse" );
> + s->p_sys = sys;
> + sys->access = NULL;
> + sys->path = NULL;
>
> - if( !lua_isfunction( L, -1 ) )
> - {
> - msg_Warn( p_demux, "Error while running script %s, "
> - "function parse() not found", psz_filename );
> - return VLC_DEMUXER_EGENERIC;
> + if (s->psz_url != NULL)
> + { /* Backward compatibility hack: Lua scripts expect the URI
> scheme and
> + * the rest of the URI separately. */
> + const char *p = strstr(s->psz_url, "://");
> + if (p != NULL)
> + {
> + sys->access = strndup(s->psz_url, p - s->psz_url);
> + sys->path = p + 3;
> + }
> }
>
> - if( lua_pcall( L, 0, 1, 0 ) )
> + int ret = vlclua_scripts_batch_execute(VLC_OBJECT(s), "playlist",
> + probe_luascript, NULL);
> + if (ret != VLC_SUCCESS)
> {
> - msg_Warn( p_demux, "Error while running script %s, "
> - "function parse(): %s", psz_filename,
> - lua_tostring( L, lua_gettop( L ) ) );
> - return VLC_DEMUXER_EGENERIC;
> + free(sys->access);
> + free(sys);
> + return ret;
> }
>
> - if( lua_gettop( L ) )
> - vlclua_playlist_add_internal( p_demux, L, p_current_input );
> - else
> - msg_Err( p_demux, "Script went completely foobar" );
> -
> - return VLC_DEMUXER_EOF;
> + s->pf_readdir = ReadDir;
> + s->pf_control = access_vaDirectoryControlHelper;
> + return VLC_SUCCESS;
> }
>
> -static int Control( demux_t *p_demux, int i_query, va_list args )
> +void Close_LuaPlaylist(vlc_object_t *obj)
> {
> - VLC_UNUSED(p_demux); VLC_UNUSED(i_query); VLC_UNUSED(args);
> - return VLC_EGENERIC;
> + stream_t *s = (stream_t *)obj;
> + struct vlclua_playlist *sys = s->p_sys;
> +
> + free(sys->filename);
> + assert(sys->L != NULL);
> + lua_close(sys->L);
> + free(sys->access);
> + free(sys);
> }
> diff --git a/modules/lua/vlc.c b/modules/lua/vlc.c
> index ed95ac039b..441113fe61 100644
> --- a/modules/lua/vlc.c
> +++ b/modules/lua/vlc.c
> @@ -147,7 +147,7 @@ vlc_module_begin ()
> add_shortcut( "luaplaylist" )
> set_shortname( N_("Lua Playlist") )
> set_description( N_("Lua Playlist Parser Interface") )
> - set_capability( "demux", 2 )
> + set_capability( "stream_filter", 2 )
> set_callbacks( Import_LuaPlaylist, Close_LuaPlaylist )
>
> add_submodule ()
> @@ -543,66 +543,6 @@ out:
> return item;
> }
>
> -#undef vlclua_playlist_add_internal
> -void vlclua_playlist_add_internal(vlc_object_t *obj, lua_State *L,
> - input_item_t *parent)
> -{
> - bool post = false;
> -
> - /* playlist */
> - if (!lua_istable(L, -1))
> - {
> - msg_Warn(obj, "Playlist should be a table.");
> - return;
> - }
> -
> - input_item_node_t *node = input_item_node_Create(parent);
> -
> - lua_pushnil(L);
> -
> - /* playlist nil */
> - while (lua_next(L, -2))
> - {
> - input_item_t *item = vlclua_read_input_item(obj, L);
> - if (item != NULL)
> - {
> - /* copy the original URL to the meta data,
> - * if "URL" is still empty */
> - char *url = input_item_GetURL(item);
> - if (url == NULL)
> - {
> - url = input_item_GetURI(parent);
> - if (likely(url != NULL))
> - {
> - EnsureUTF8(url);
> - msg_Dbg(obj, "meta-URL: %s", url);
> - input_item_SetURL(item, url);
> - }
> - }
> - free(url);
> -
> - input_item_CopyOptions(item, parent);
> -
> - if (likely(node != NULL)) /* Add to node */
> - input_item_node_AppendItem(node, item);
> -
> - input_item_Release(item);
> - post = true;
> - }
> - /* pop the value, keep the key for the next lua_next() call */
> - lua_pop(L, 1);
> - }
> - /* playlist */
> -
> - if (likely(node != NULL))
> - {
> - if (post)
> - input_item_node_PostAndDelete(node);
> - else
> - input_item_node_Delete(node);
> - }
> -}
> -
> static int vlc_sd_probe_Open( vlc_object_t *obj )
> {
> vlc_dictionary_t name_d;
> diff --git a/modules/lua/vlc.h b/modules/lua/vlc.h
> index 7b979cd4f1..141f331329 100644
> --- a/modules/lua/vlc.h
> +++ b/modules/lua/vlc.h
> @@ -182,9 +182,6 @@ void vlclua_read_custom_meta_data( vlc_object_t *,
> lua_State *,
> #define vlclua_read_custom_meta_data( a, b, c )
> vlclua_read_custom_meta_data( VLC_OBJECT( a ), b, c )
>
> input_item_t *vlclua_read_input_item(vlc_object_t *, lua_State *);
> -void vlclua_playlist_add_internal(vlc_object_t *, lua_State *,
> input_item_t *);
> -#define vlclua_playlist_add_internal( a, b, c ) \
> - vlclua_playlist_add_internal( VLC_OBJECT( a ), b, c )
>
> int vlclua_add_modules_path( lua_State *, const char *psz_filename );
>
>
> _______________________________________________
> vlc-commits mailing list
> vlc-commits at videolan.org
> https://mailman.videolan.org/listinfo/vlc-commits
More information about the vlc-devel
mailing list