]> git.sesse.net Git - vlc/blob - modules/misc/lua/libs/input.c
37ed82e3ea5f30a48c00f1177139b14cde72667a
[vlc] / modules / misc / lua / libs / input.c
1 /*****************************************************************************
2  * input.c
3  *****************************************************************************
4  * Copyright (C) 2007-2008 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea at videolan tod org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifndef  _GNU_SOURCE
28 #   define  _GNU_SOURCE
29 #endif
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_meta.h>
37 #include <vlc_charset.h>
38
39 #include <vlc_playlist.h>
40
41 #include <lua.h>        /* Low level lua C API */
42 #include <lauxlib.h>    /* Higher level C API */
43 #include <assert.h>
44
45 #include "input.h"
46 #include "playlist.h"
47 #include "../vlc.h"
48 #include "../libs.h"
49
50 static const luaL_Reg vlclua_input_reg[];
51 static const luaL_Reg vlclua_input_item_reg[];
52
53 input_thread_t * vlclua_get_input_internal( lua_State *L )
54 {
55     playlist_t *p_playlist = vlclua_get_playlist_internal( L );
56     input_thread_t *p_input = playlist_CurrentInput( p_playlist );
57     vlclua_release_playlist_internal( p_playlist );
58     return p_input;
59 }
60
61 static int vlclua_input_info( lua_State *L )
62 {
63     input_thread_t * p_input = vlclua_get_input_internal( L );
64     int i_cat;
65     int i;
66     if( !p_input ) return vlclua_error( L );
67     //vlc_mutex_lock( &input_GetItem(p_input)->lock );
68     i_cat = input_GetItem(p_input)->i_categories;
69     lua_createtable( L, 0, i_cat );
70     for( i = 0; i < i_cat; i++ )
71     {
72         info_category_t *p_category = input_GetItem(p_input)->pp_categories[i];
73         int i_infos = p_category->i_infos;
74         int j;
75         lua_pushstring( L, p_category->psz_name );
76         lua_createtable( L, 0, i_infos );
77         for( j = 0; j < i_infos; j++ )
78         {
79             info_t *p_info = p_category->pp_infos[j];
80             lua_pushstring( L, p_info->psz_name );
81             lua_pushstring( L, p_info->psz_value );
82             lua_settable( L, -3 );
83         }
84         lua_settable( L, -3 );
85     }
86     vlc_object_release( p_input );
87     return 1;
88 }
89
90 static int vlclua_input_is_playing( lua_State *L )
91 {
92     input_thread_t * p_input = vlclua_get_input_internal( L );
93     lua_pushboolean( L, !!p_input );
94     if( p_input )
95         vlc_object_release( p_input );
96     return 1;
97 }
98
99 static int vlclua_input_get_title( lua_State *L )
100 {
101     input_thread_t *p_input = vlclua_get_input_internal( L );
102     if( !p_input )
103         lua_pushnil( L );
104     else
105     {
106         lua_pushstring( L, input_GetItem(p_input)->psz_name );
107         vlc_object_release( p_input );
108     }
109     return 1;
110 }
111
112 static int vlclua_input_metas_internal( lua_State *L, input_item_t *p_item )
113 {
114     if( !p_item )
115     {
116         lua_pushnil( L );
117         return 1;
118     }
119
120     lua_newtable( L );
121     char *psz_meta;
122
123     psz_meta = input_item_GetName( p_item );
124     lua_pushstring( L, psz_meta );
125     lua_setfield( L, -2, "filename" );
126     free( psz_meta );
127
128 #define PUSH_META( n, m ) \
129     psz_meta = input_item_GetMeta( p_item, vlc_meta_ ## n ); \
130     lua_pushstring( L, psz_meta ); \
131     lua_setfield( L, -2, m ); \
132     free( psz_meta )
133
134     PUSH_META( Title, "title" );
135     PUSH_META( Artist, "artist" );
136     PUSH_META( Genre, "genre" );
137     PUSH_META( Copyright, "copyright" );
138     PUSH_META( Album, "album" );
139     PUSH_META( TrackNumber, "track_number" );
140     PUSH_META( Description, "description" );
141     PUSH_META( Rating, "rating" );
142     PUSH_META( Date, "date" );
143     PUSH_META( Setting, "setting" );
144     PUSH_META( URL, "url" );
145     PUSH_META( Language, "language" );
146     PUSH_META( NowPlaying, "now_playing" );
147     PUSH_META( Publisher, "publisher" );
148     PUSH_META( EncodedBy, "encoded_by" );
149     PUSH_META( ArtworkURL, "artwork_url" );
150     PUSH_META( TrackID, "track_id" );
151
152 #undef PUSH_META
153
154     vlc_mutex_lock(&p_item->lock);
155     if (p_item->p_meta) {
156         char ** names = vlc_meta_CopyExtraNames(p_item->p_meta);
157         for(int i = 0; names[i]; i++)
158         {
159             const char *meta = vlc_meta_GetExtra(p_item->p_meta, names[i]);
160             lua_pushstring( L, meta );
161             lua_setfield( L, -2, names[i] );
162             free(names[i]);
163         }
164         free(names);
165     }
166     vlc_mutex_unlock(&p_item->lock);
167
168     return 1;
169 }
170
171 static int vlclua_input_metas( lua_State *L )
172 {
173     input_thread_t *p_input = vlclua_get_input_internal( L );
174     input_item_t *p_item = p_input && p_input->p
175                          ? input_GetItem( p_input ) : NULL;
176     vlclua_input_metas_internal( L, p_item );
177     if( p_input )
178         vlc_object_release( p_input );
179     return 1;
180 }
181
182 static int vlclua_input_stats( lua_State *L )
183 {
184     input_thread_t *p_input = vlclua_get_input_internal( L );
185     input_item_t *p_item = p_input && p_input->p
186                          ? input_GetItem( p_input ) : NULL;
187     lua_newtable( L );
188     if( p_item )
189     {
190         vlc_mutex_lock( &p_item->p_stats->lock );
191 #define STATS_INT( n ) lua_pushinteger( L, p_item->p_stats->i_ ## n ); \
192                        lua_setfield( L, -2, #n );
193 #define STATS_FLOAT( n ) lua_pushnumber( L, p_item->p_stats->f_ ## n ); \
194                          lua_setfield( L, -2, #n );
195         STATS_INT( read_bytes )
196         STATS_FLOAT( input_bitrate )
197         STATS_INT( demux_read_bytes )
198         STATS_FLOAT( demux_bitrate )
199         STATS_INT( demux_corrupted )
200         STATS_INT( demux_discontinuity )
201         STATS_INT( decoded_video )
202         STATS_INT( displayed_pictures )
203         STATS_INT( lost_pictures )
204         STATS_INT( decoded_audio )
205         STATS_INT( played_abuffers )
206         STATS_INT( lost_abuffers )
207         STATS_INT( sent_packets )
208         STATS_INT( sent_bytes )
209         STATS_FLOAT( send_bitrate )
210 #undef STATS_INT
211 #undef STATS_FLOAT
212         vlc_mutex_unlock( &p_item->p_stats->lock );
213     }
214     if( p_input )
215         vlc_object_release( p_input );
216     return 1;
217 }
218
219 static int vlclua_input_add_subtitle( lua_State *L )
220 {
221     input_thread_t *p_input = vlclua_get_input_internal( L );
222     if( !p_input )
223         return luaL_error( L, "can't add subtitle: no current input" );
224     if( !lua_isstring( L, 1 ) )
225         return luaL_error( L, "vlc.input.add_subtitle() usage: (url)" );
226     const char *psz_url = luaL_checkstring( L, 1 );
227     input_AddSubtitle( p_input, psz_url, false );
228     vlc_object_release( p_input );
229     return 1;
230 }
231
232 /*****************************************************************************
233  * Input items
234  *****************************************************************************/
235
236 static input_item_t* vlclua_input_item_get_internal( lua_State *L )
237 {
238     input_item_t **pp_item = luaL_checkudata( L, 1, "input_item" );
239     input_item_t *p_item = *pp_item;
240
241     if( !p_item )
242         luaL_error( L, "script went completely foobar" );
243
244     return p_item;
245 }
246
247 /* Garbage collection of an input_item_t */
248 static int vlclua_input_item_delete( lua_State *L )
249 {
250     input_item_t **pp_item = luaL_checkudata( L, 1, "input_item" );
251     input_item_t *p_item = *pp_item;
252
253     if( !p_item )
254         return luaL_error( L, "script went completely foobar" );
255
256     *pp_item = NULL;
257     vlc_gc_decref( p_item );
258
259     return 1;
260 }
261
262 static int vlclua_input_item_get( lua_State *L, input_item_t *p_item )
263 {
264     vlc_gc_incref( p_item );
265     input_item_t **pp = lua_newuserdata( L, sizeof( void* ) );
266     *pp = p_item;
267
268     if( luaL_newmetatable( L, "input_item" ) )
269     {
270         lua_newtable( L );
271         luaL_register( L, NULL, vlclua_input_item_reg );
272         lua_setfield( L, -2, "__index" );
273         lua_pushcfunction( L, vlclua_input_item_delete );
274         lua_setfield( L, -2, "__gc" );
275     }
276
277     lua_setmetatable(L, -2);
278
279     return 1;
280 }
281
282 static int vlclua_input_item_get_current( lua_State *L )
283 {
284     input_thread_t *p_input = vlclua_get_input_internal( L );
285     input_item_t *p_item = ( p_input && p_input->p ) ? input_GetItem( p_input ) : NULL;
286     if( !p_item )
287     {
288         lua_pushnil( L );
289         if( p_input ) vlc_object_release( p_input );
290         return 1;
291     }
292
293     vlclua_input_item_get( L, p_item );
294
295     if( p_input ) vlc_object_release( p_input );
296     return 1;
297 }
298
299 static int vlclua_input_item_metas( lua_State *L )
300 {
301     vlclua_input_metas_internal( L, vlclua_input_item_get_internal( L ) );
302     return 1;
303 }
304
305 static int vlclua_input_item_set_meta( lua_State *L )
306 {
307     input_item_t *p_item = vlclua_input_item_get_internal( L );
308     lua_settop( L, 1 + 2 ); // two arguments
309     const char *psz_name = luaL_checkstring( L, 2 ),
310                *psz_value = luaL_checkstring( L, 3 );
311
312 #define META_TYPE( n, s ) { s, vlc_meta_ ## n },
313     static const struct
314     {
315         const char *psz_name;
316         vlc_meta_type_t type;
317     } pp_meta_types[] = {
318         META_TYPE( Title, "title" )
319         META_TYPE( Artist, "artist" )
320         META_TYPE( Genre, "genre" )
321         META_TYPE( Copyright, "copyright" )
322         META_TYPE( Album, "album" )
323         META_TYPE( TrackNumber, "track_number" )
324         META_TYPE( Description, "description" )
325         META_TYPE( Rating, "rating" )
326         META_TYPE( Date, "date" )
327         META_TYPE( Setting, "setting" )
328         META_TYPE( URL, "url" )
329         META_TYPE( Language, "language" )
330         META_TYPE( NowPlaying, "now_playing" )
331         META_TYPE( Publisher, "publisher" )
332         META_TYPE( EncodedBy, "encoded_by" )
333         META_TYPE( ArtworkURL, "artwork_url" )
334         META_TYPE( TrackID, "track_id" )
335     };
336 #undef META_TYPE
337
338     vlc_meta_type_t type = vlc_meta_Title;
339     for( unsigned i = 0; i < VLC_META_TYPE_COUNT; i++ )
340     {
341         if( !strcasecmp( pp_meta_types[i].psz_name, psz_name ) )
342         {
343             type = pp_meta_types[i].type;
344             input_item_SetMeta( p_item, type, psz_value );
345             return 1;
346         }
347     }
348
349     vlc_meta_AddExtra( p_item->p_meta, psz_name, psz_value );
350     return 1;
351 }
352
353 /*****************************************************************************
354  * Lua bindings
355  *****************************************************************************/
356 static const luaL_Reg vlclua_input_reg[] = {
357     { "info", vlclua_input_info },
358     { "is_playing", vlclua_input_is_playing },
359     { "get_title", vlclua_input_get_title },
360     { "metas", vlclua_input_metas },
361     { "item", vlclua_input_item_get_current },
362     { "stats", vlclua_input_stats },
363     { "add_subtitle", vlclua_input_add_subtitle },
364     { NULL, NULL }
365 };
366
367 void luaopen_input( lua_State *L )
368 {
369     lua_newtable( L );
370     luaL_register( L, NULL, vlclua_input_reg );
371     lua_setfield( L, -2, "input" );
372 }
373
374 static const luaL_Reg vlclua_input_item_reg[] = {
375     { "metas", vlclua_input_item_metas },
376     { "set_meta", vlclua_input_item_set_meta },
377     { NULL, NULL }
378 };
379
380
381 void luaopen_input_item( lua_State *L, input_item_t *item )
382 {
383     assert(item);
384     vlclua_input_item_get( L, item );
385     lua_setfield( L, -2, "item" );
386 }