Commit 95addd57 authored by Antoine Cellerier's avatar Antoine Cellerier

Implement Lua objects in the C code directly. Fix most type checks. Move every thing arround.

parent e9315c82
SOURCES_lua = playlist.c meta.c intf.c vlc.c vlc.h callbacks.c objects.c variables.c configuration.c net.c vlm.c httpd.c acl.c sd.c
SOURCES_lua = \
intf.c \
meta.c \
demux.c \
vlc.c \
vlc.h \
libs.h \
libs/acl.c \
libs/configuration.c \
libs/httpd.c \
libs/input.c \
libs/input.h \
libs/messages.c \
libs/misc.c \
libs/net.c \
libs/objects.c \
libs/objects.h \
libs/osd.c \
libs/playlist.c \
libs/playlist.h \
libs/sd.c \
libs/stream.c \
libs/strings.c \
libs/variables.c \
libs/variables.h \
libs/video.c \
libs/vlm.c \
libs/volume.c \
$(NULL)
libvlc_LTLIBRARIES += liblua_plugin.la
/*****************************************************************************
* playlist.c : Lua playlist demux module
* demux.c : Lua playlist demux module
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* Copyright (C) 2007-2008 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
......@@ -40,6 +40,7 @@
#endif
#include "vlc.h"
#include "libs.h"
/*****************************************************************************
......@@ -49,7 +50,7 @@ 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
{
......@@ -57,10 +58,6 @@ struct demux_sys_t
char *psz_filename;
};
/*****************************************************************************
*
*****************************************************************************/
static int vlclua_demux_peek( lua_State *L )
{
demux_t *p_demux = (demux_t *)vlclua_get_this( L );
......@@ -97,17 +94,13 @@ static int vlclua_demux_readline( lua_State *L )
return 1;
}
/*****************************************************************************
*
*****************************************************************************/
/* Functions to register */
static luaL_Reg p_reg[] =
{
{ "peek", vlclua_demux_peek },
{ "decode_uri", vlclua_decode_uri },
{ "resolve_xml_special_chars", vlclua_resolve_xml_special_chars },
{ "msg_dbg", vlclua_msg_dbg },
{ "msg_warn", vlclua_msg_warn },
{ "msg_err", vlclua_msg_err },
{ "msg_info", vlclua_msg_info },
{ NULL, NULL }
};
......@@ -215,6 +208,8 @@ int Import_LuaPlaylist( vlc_object_t *p_this )
luaL_openlibs( L ); /* FIXME: Don't open all the libs? */
luaL_register( L, "vlc", p_reg );
luaopen_msg( L );
luaopen_strings( L );
lua_pushlightuserdata( L, p_demux );
lua_setfield( L, -2, "private" );
lua_pushstring( L, p_demux->psz_path );
......
/*****************************************************************************
* intf.c: Generic lua interface functions
*****************************************************************************
* Copyright (C) 2007 the VideoLAN team
* Copyright (C) 2007-2008 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
......@@ -39,882 +39,33 @@
#include <vlc_interface.h>
#include <vlc_playlist.h>
#include <vlc_aout.h>
#include <vlc_vout.h>
#include <vlc_osd.h>
#include <lua.h> /* Low level lua C API */
#include <lauxlib.h> /* Higher level C API */
#include <lualib.h> /* Lua libs */
#include "vlc.h"
#include "libs.h"
/*****************************************************************************
* Prototypes
*****************************************************************************/
struct intf_sys_t
{
char *psz_filename;
lua_State *L;
};
/*****************************************************************************
* Internal lua<->vlc utils
*****************************************************************************/
playlist_t *vlclua_get_playlist_internal( lua_State *L )
{
vlc_object_t *p_this = vlclua_get_this( L );
return pl_Yield( p_this );
}
static input_thread_t * vlclua_get_input_internal( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
input_thread_t *p_input = p_playlist->p_input;
if( p_input ) vlc_object_yield( p_input );
vlc_object_release( p_playlist );
return p_input;
}
/* FIXME: This is high level logic. Should be implemented in lua */
#define vlclua_var_toggle_or_set(a,b,c) \
__vlclua_var_toggle_or_set(a,VLC_OBJECT(b),c)
static int __vlclua_var_toggle_or_set( lua_State *L, vlc_object_t *p_obj,
const char *psz_name )
{
bool b_bool;
if( lua_gettop( L ) > 1 ) return vlclua_error( L );
if( lua_gettop( L ) == 0 )
b_bool = !var_GetBool( p_obj, psz_name );
else /* lua_gettop( L ) == 1 */
{
b_bool = luaL_checkboolean( L, -1 )?true:false;
lua_pop( L, 1 );
}
if( b_bool != var_GetBool( p_obj, psz_name ) )
var_SetBool( p_obj, psz_name, b_bool );
lua_pushboolean( L, b_bool );
return 1;
}
/*****************************************************************************
* Libvlc TODO: move to vlc.c
*****************************************************************************/
static int vlclua_get_libvlc( lua_State *L )
{
vlclua_push_vlc_object( L, vlclua_get_this( L )->p_libvlc,
NULL );
return 1;
}
/*****************************************************************************
* Input handling
*****************************************************************************/
static int vlclua_get_input( lua_State *L )
{
input_thread_t *p_input = vlclua_get_input_internal( L );
if( p_input )
{
vlclua_push_vlc_object( L, p_input, vlclua_gc_release );
}
else lua_pushnil( L );
return 1;
}
static int vlclua_input_info( lua_State *L )
{
input_thread_t * p_input = vlclua_get_input_internal( L );
int i_cat;
int i;
if( !p_input ) return vlclua_error( L );
//vlc_mutex_lock( &input_GetItem(p_input)->lock );
i_cat = input_GetItem(p_input)->i_categories;
lua_createtable( L, 0, i_cat );
for( i = 0; i < i_cat; i++ )
{
info_category_t *p_category = input_GetItem(p_input)->pp_categories[i];
int i_infos = p_category->i_infos;
int j;
lua_pushstring( L, p_category->psz_name );
lua_createtable( L, 0, i_infos );
for( j = 0; j < i_infos; j++ )
{
info_t *p_info = p_category->pp_infos[j];
lua_pushstring( L, p_info->psz_name );
lua_pushstring( L, p_info->psz_value );
lua_settable( L, -3 );
}
lua_settable( L, -3 );
}
//vlc_object_release( p_input );
return 1;
}
static int vlclua_is_playing( lua_State *L )
{
input_thread_t * p_input = vlclua_get_input_internal( L );
lua_pushboolean( L, !!p_input );
return 1;
}
static int vlclua_get_title( lua_State *L )
{
input_thread_t *p_input = vlclua_get_input_internal( L );
if( !p_input )
lua_pushnil( L );
else
{
lua_pushstring( L, input_GetItem(p_input)->psz_name );
vlc_object_release( p_input );
}
return 1;
}
static int vlclua_input_stats( lua_State *L )
{
input_thread_t *p_input = vlclua_get_input_internal( L );
input_item_t *p_item = p_input && p_input->p ? input_GetItem( p_input ) : NULL;
lua_newtable( L );
if( p_item )
{
#define STATS_INT( n ) lua_pushinteger( L, p_item->p_stats->i_ ## n ); \
lua_setfield( L, -2, #n );
#define STATS_FLOAT( n ) lua_pushnumber( L, p_item->p_stats->f_ ## n ); \
lua_setfield( L, -2, #n );
STATS_INT( read_bytes )
STATS_FLOAT( input_bitrate )
STATS_INT( demux_read_bytes )
STATS_FLOAT( demux_bitrate )
STATS_INT( decoded_video )
STATS_INT( displayed_pictures )
STATS_INT( lost_pictures )
STATS_INT( decoded_audio )
STATS_INT( played_abuffers )
STATS_INT( lost_abuffers )
STATS_INT( sent_packets )
STATS_INT( sent_bytes )
STATS_FLOAT( send_bitrate )
#undef STATS_INT
#undef STATS_FLOAT
}
return 1;
}
/*****************************************************************************
* Vout control
*****************************************************************************/
static int vlclua_fullscreen( lua_State *L )
{
vout_thread_t *p_vout;
int i_ret;
input_thread_t * p_input = vlclua_get_input_internal( L );
if( !p_input ) return vlclua_error( L );
p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD );
if( !p_vout ) return vlclua_error( L );
i_ret = vlclua_var_toggle_or_set( L, p_vout, "fullscreen" );
vlc_object_release( p_vout );
vlc_object_release( p_input );
return i_ret;
}
static int vlc_osd_icon_from_string( const char *psz_name )
{
static const struct
{
int i_icon;
const char *psz_name;
} pp_icons[] =
{ { OSD_PAUSE_ICON, "pause" },
{ OSD_PLAY_ICON, "play" },
{ OSD_SPEAKER_ICON, "speaker" },
{ OSD_MUTE_ICON, "mute" },
{ 0, NULL } };
int i;
for( i = 0; pp_icons[i].psz_name; i++ )
{
if( !strcmp( psz_name, pp_icons[i].psz_name ) )
return pp_icons[i].i_icon;
}
return 0;
}
static int vlclua_osd_icon( lua_State *L )
{
const char *psz_icon = luaL_checkstring( L, 1 );
int i_icon = vlc_osd_icon_from_string( psz_icon );
int i_chan = luaL_optint( L, 2, DEFAULT_CHAN );
if( !i_icon )
return luaL_error( L, "\"%s\" is not a valid osd icon.", psz_icon );
else
{
vlc_object_t *p_this = vlclua_get_this( L );
vout_OSDIcon( p_this, i_chan, i_icon );
return 0;
}
}
static int vlclua_osd_message( lua_State *L )
{
const char *psz_message = luaL_checkstring( L, 1 );
int i_chan = luaL_optint( L, 2, DEFAULT_CHAN );
vlc_object_t *p_this = vlclua_get_this( L );
vout_OSDMessage( p_this, i_chan, psz_message );
return 0;
}
static int vlc_osd_slider_type_from_string( const char *psz_name )
{
static const struct
{
int i_type;
const char *psz_name;
} pp_types[] =
{ { OSD_HOR_SLIDER, "horizontal" },
{ OSD_VERT_SLIDER, "vertical" },
{ 0, NULL } };
int i;
for( i = 0; pp_types[i].psz_name; i++ )
{
if( !strcmp( psz_name, pp_types[i].psz_name ) )
return pp_types[i].i_type;
}
return 0;
}
static int vlclua_osd_slider( lua_State *L )
{
int i_position = luaL_checkint( L, 1 );
const char *psz_type = luaL_checkstring( L, 2 );
int i_type = vlc_osd_slider_type_from_string( psz_type );
int i_chan = luaL_optint( L, 3, DEFAULT_CHAN );
if( !i_type )
return luaL_error( L, "\"%s\" is not a valid slider type.",
psz_type );
else
{
vlc_object_t *p_this = vlclua_get_this( L );
vout_OSDSlider( p_this, i_chan, i_position, i_type );
return 0;
}
}
static int vlclua_spu_channel_register( lua_State *L )
{
int i_chan;
vlc_object_t *p_this = vlclua_get_this( L );
vout_thread_t *p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT,
FIND_ANYWHERE );
if( !p_vout )
return luaL_error( L, "Unable to find vout." );
spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER, &i_chan );
vlc_object_release( p_vout );
lua_pushinteger( L, i_chan );
return 1;
}
static int vlclua_spu_channel_clear( lua_State *L )
{
int i_chan = luaL_checkint( L, 1 );
vlc_object_t *p_this = vlclua_get_this( L );
vout_thread_t *p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT,
FIND_ANYWHERE );
if( !p_vout )
return luaL_error( L, "Unable to find vout." );
spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, i_chan );
vlc_object_release( p_vout );
return 0;
}
static void Run( intf_thread_t *p_intf );
/*****************************************************************************
* Playlist control
*
*****************************************************************************/
static int vlclua_get_playlist( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
if( p_playlist )
{
vlclua_push_vlc_object( L, p_playlist, vlclua_gc_release );
}
else lua_pushnil( L );
return 1;
}
static int vlclua_playlist_prev( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Prev( p_playlist );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_next( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Next( p_playlist );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_skip( lua_State * L )
{
int i_skip = luaL_checkint( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Skip( p_playlist, i_skip );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_play( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Play( p_playlist );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_pause( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Pause( p_playlist );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_stop( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Stop( p_playlist );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_clear( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
playlist_Stop( p_playlist ); /* Isn't this already implied by Clear? */
playlist_Clear( p_playlist, false );
vlc_object_release( p_playlist );
return 0;
}
static int vlclua_playlist_repeat( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = vlclua_var_toggle_or_set( L, p_playlist, "repeat" );
vlc_object_release( p_playlist );
return i_ret;
}
static int vlclua_playlist_loop( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = vlclua_var_toggle_or_set( L, p_playlist, "loop" );
vlc_object_release( p_playlist );
return i_ret;
}
static int vlclua_playlist_random( lua_State * L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = vlclua_var_toggle_or_set( L, p_playlist, "random" );
vlc_object_release( p_playlist );
return i_ret;
}
static int vlclua_playlist_goto( lua_State * L )
{
int i_id = luaL_checkint( L, 1 );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int i_ret = playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
true, NULL,
playlist_ItemGetById( p_playlist, i_id,
true ) );
vlc_object_release( p_playlist );
return vlclua_push_ret( L, i_ret );
}
static int vlclua_playlist_add( lua_State *L )
{
int i_count;
vlc_object_t *p_this = vlclua_get_this( L );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
i_count = vlclua_playlist_add_internal( p_this, L, p_playlist,
NULL, true );
vlc_object_release( p_playlist );
lua_pushinteger( L, i_count );
return 1;
}
static int vlclua_playlist_enqueue( lua_State *L )
{
int i_count;
vlc_object_t *p_this = vlclua_get_this( L );
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
i_count = vlclua_playlist_add_internal( p_this, L, p_playlist,
NULL, false );
vlc_object_release( p_playlist );
lua_pushinteger( L, i_count );
return 1;
}
static void push_playlist_item( lua_State *L, playlist_item_t *p_item );
static void push_playlist_item( lua_State *L, playlist_item_t *p_item )
{
input_item_t *p_input = p_item->p_input;
int i_flags = p_item->i_flags;
lua_newtable( L );
lua_pushinteger( L, p_item->i_id );
lua_setfield( L, -2, "id" );
lua_newtable( L );
#define CHECK_AND_SET_FLAG( name, label ) \
if( i_flags & PLAYLIST_ ## name ## _FLAG ) \
{ \
lua_pushboolean( L, 1 ); \
lua_setfield( L, -2, #label ); \
}
CHECK_AND_SET_FLAG( SAVE, save )
CHECK_AND_SET_FLAG( SKIP, skip )
CHECK_AND_SET_FLAG( DBL, disabled )
CHECK_AND_SET_FLAG( RO, ro )
CHECK_AND_SET_FLAG( REMOVE, remove )
CHECK_AND_SET_FLAG( EXPANDED, expanded )
#undef CHECK_AND_SET_FLAG
lua_setfield( L, -2, "flags" );
if( p_input )
{
lua_pushstring( L, p_input->psz_name );
lua_setfield( L, -2, "name" );
lua_pushstring( L, p_input->psz_uri );
lua_setfield( L, -2, "path" );
if( p_input->i_duration < 0 )
lua_pushnumber( L, -1 );
else
lua_pushnumber( L, ((double)p_input->i_duration)*1e-6 );
lua_setfield( L, -2, "duration" );
lua_pushinteger( L, p_input->i_nb_played );
lua_setfield( L, -2, "nb_played" );
/* TODO: add (optional) info categories, meta, options, es */
}
if( p_item->i_children >= 0 )
{
int i;
lua_createtable( L, p_item->i_children, 0 );
for( i = 0; i < p_item->i_children; i++ )
{
push_playlist_item( L, p_item->pp_children[i] );
lua_rawseti( L, -2, i+1 );
}
lua_setfield( L, -2, "children" );
}
}
static int vlclua_playlist_get( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
int b_category = luaL_optboolean( L, 2, 1 ); /* Default to tree playlist (discared when 1st argument is a playlist_item's id) */
playlist_item_t *p_item = NULL;
if( lua_isnumber( L, 1 ) )
{
int i_id = lua_tointeger( L, 1 );
p_item = playlist_ItemGetById( p_playlist, i_id, true );
if( !p_item )
{
vlc_object_release( p_playlist );
return 0; /* Should we return an error instead? */
}
}
else if( lua_isstring( L, 1 ) )
{
const char *psz_what = lua_tostring( L, 1 );
if( !strcasecmp( psz_what, "normal" )
|| !strcasecmp( psz_what, "playlist" ) )
p_item = b_category ? p_playlist->p_local_category
: p_playlist->p_local_onelevel;
else if( !strcasecmp( psz_what, "ml" )
|| !strcasecmp( psz_what, "media library" ) )
p_item = b_category ? p_playlist->p_ml_category
: p_playlist->p_ml_onelevel;
else if( !strcasecmp( psz_what, "root" ) )
p_item = b_category ? p_playlist->p_root_category
: p_playlist->p_root_onelevel;
else
{
int i;
for( i = 0; i < p_playlist->i_sds; i++ )
{
if( !strcasecmp( psz_what,
p_playlist->pp_sds[i]->p_sd->psz_module ) )
{
p_item = b_category ? p_playlist->pp_sds[i]->p_cat
: p_playlist->pp_sds[i]->p_one;
break;
}
}
if( !p_item )
{
vlc_object_release( p_playlist );
return 0; /* Should we return an error instead? */
}
}
}
else
{
p_item = b_category ? p_playlist->p_root_category
: p_playlist->p_root_onelevel;
}
push_playlist_item( L, p_item );
vlc_object_release( p_playlist );
return 1;
}
static int vlclua_playlist_search( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
const char *psz_string = luaL_optstring( L, 1, "" );
int b_category = luaL_optboolean( L, 2, 1 ); /* default to category */
playlist_item_t *p_item = b_category ? p_playlist->p_root_category
: p_playlist->p_root_onelevel;
playlist_LiveSearchUpdate( p_playlist, p_item, psz_string );
push_playlist_item( L, p_item );
vlc_object_release( p_playlist );
return 1;
}
static int vlclua_playlist_current( lua_State *L )
{
playlist_t *p_playlist = vlclua_get_playlist_internal( L );
lua_pushinteger( L, var_GetInteger( p_playlist, "playlist-current" ) );
vlc_object_release( p_playlist );
return 1;
}
static int vlc_sort_key_from_string( const char *psz_name )
{
static const struct
{
const char *psz_name;
int i_key;
} pp_keys[] =
{ { "id", SORT_ID },