]> git.sesse.net Git - vlc/blob - src/input/item.c
27f7a09db80f598b9918a083d7bb8f5ae9728cda
[vlc] / src / input / item.c
1 /*****************************************************************************
2  * item.c: input_item management
3  *****************************************************************************
4  * Copyright (C) 1998-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.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 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <assert.h>
28
29 #include <vlc_common.h>
30 #include "vlc_playlist.h"
31 #include "vlc_interface.h"
32
33 #include "input_internal.h"
34
35 static void GuessType( input_item_t *p_item );
36
37 /** Stuff moved out of vlc_input.h -- FIXME: should probably not be inline
38  * anyway. */
39 static inline void input_ItemInit( vlc_object_t *p_o, input_item_t *p_i )
40 {
41     memset( p_i, 0, sizeof(input_item_t) );
42     p_i->psz_name = NULL;
43     p_i->psz_uri = NULL;
44     TAB_INIT( p_i->i_es, p_i->es );
45     TAB_INIT( p_i->i_options, p_i->ppsz_options );
46     p_i->optflagv = NULL, p_i->optflagc = 0;
47     TAB_INIT( p_i->i_categories, p_i->pp_categories );
48
49     p_i->i_type = ITEM_TYPE_UNKNOWN;
50     p_i->b_fixed_name = true;
51
52     p_i->p_stats = NULL;
53     p_i->p_meta = NULL;
54
55     vlc_mutex_init( &p_i->lock );
56     vlc_event_manager_init( &p_i->event_manager, p_i, p_o );
57     vlc_event_manager_register_event_type( &p_i->event_manager,
58         vlc_InputItemMetaChanged );
59     vlc_event_manager_register_event_type( &p_i->event_manager,
60         vlc_InputItemSubItemAdded );
61     vlc_event_manager_register_event_type( &p_i->event_manager,
62         vlc_InputItemDurationChanged );
63     vlc_event_manager_register_event_type( &p_i->event_manager,
64         vlc_InputItemPreparsedChanged );
65     vlc_event_manager_register_event_type( &p_i->event_manager,
66         vlc_InputItemNameChanged );
67     vlc_event_manager_register_event_type( &p_i->event_manager,
68         vlc_InputItemInfoChanged );
69 }
70
71 static inline void input_ItemClean( input_item_t *p_i )
72 {
73     int i;
74
75     vlc_event_manager_fini( &p_i->event_manager );
76
77     free( p_i->psz_name );
78     free( p_i->psz_uri );
79     if( p_i->p_stats )
80     {
81         vlc_mutex_destroy( &p_i->p_stats->lock );
82         free( p_i->p_stats );
83     }
84
85     if( p_i->p_meta )
86         vlc_meta_Delete( p_i->p_meta );
87
88     for( i = 0; i < p_i->i_options; i++ )
89         free( p_i->ppsz_options[i] );
90     TAB_CLEAN( p_i->i_options, p_i->ppsz_options );
91     free( p_i->optflagv);
92
93     for( i = 0; i < p_i->i_es; i++ )
94     {
95         es_format_Clean( p_i->es[i] );
96         free( p_i->es[i] );
97     }
98     TAB_CLEAN( p_i->i_es, p_i->es );
99
100     for( i = 0; i < p_i->i_categories; i++ )
101     {
102         info_category_t *p_category = p_i->pp_categories[i];
103         int j;
104
105         for( j = 0; j < p_category->i_infos; j++ )
106         {
107             struct info_t *p_info = p_category->pp_infos[j];
108
109             free( p_info->psz_name);
110             free( p_info->psz_value );
111             free( p_info );
112         }
113         TAB_CLEAN( p_category->i_infos, p_category->pp_infos );
114
115         free( p_category->psz_name );
116         free( p_category );
117     }
118     TAB_CLEAN( p_i->i_categories, p_i->pp_categories );
119
120     vlc_mutex_destroy( &p_i->lock );
121 }
122
123 void input_item_SetMeta( input_item_t *p_i, vlc_meta_type_t meta_type, const char *psz_val )
124 {
125     vlc_event_t event;
126
127     vlc_mutex_lock( &p_i->lock );
128     if( !p_i->p_meta )
129         p_i->p_meta = vlc_meta_New();
130     vlc_meta_Set( p_i->p_meta, meta_type, psz_val );
131     vlc_mutex_unlock( &p_i->lock );
132
133     /* Notify interested third parties */
134     event.type = vlc_InputItemMetaChanged;
135     event.u.input_item_meta_changed.meta_type = meta_type;
136     vlc_event_send( &p_i->event_manager, &event );
137 }
138
139 /**
140  * Get the item from an input thread
141  */
142 input_item_t *input_GetItem( input_thread_t *p_input )
143 {
144     assert( p_input && p_input->p );
145     return p_input->p->input.p_item;
146 }
147
148 /**
149  * Get a info item from a given category in a given input item.
150  *
151  * \param p_i The input item to get info from
152  * \param psz_cat String representing the category for the info
153  * \param psz_name String representing the name of the desired info
154  * \return A pointer to the string with the given info if found, or an
155  *         empty string otherwise. The caller should free the returned
156  *         pointer.
157  */
158 char *input_ItemGetInfo( input_item_t *p_i,
159                               const char *psz_cat,
160                               const char *psz_name )
161 {
162     int i,j;
163
164     vlc_mutex_lock( &p_i->lock );
165
166     for( i = 0 ; i< p_i->i_categories  ; i++ )
167     {
168         info_category_t *p_cat = p_i->pp_categories[i];
169
170         if( !psz_cat || strcmp( p_cat->psz_name, psz_cat ) )
171             continue;
172
173         for( j = 0; j < p_cat->i_infos ; j++ )
174         {
175             if( !strcmp( p_cat->pp_infos[j]->psz_name, psz_name ) )
176             {
177                 char *psz_ret = strdup( p_cat->pp_infos[j]->psz_value );
178                 vlc_mutex_unlock( &p_i->lock );
179                 return psz_ret;
180             }
181         }
182     }
183     vlc_mutex_unlock( &p_i->lock );
184     return strdup( "" );
185 }
186
187 static void input_ItemDestroy ( gc_object_t *p_this )
188 {
189     vlc_object_t *p_obj = (vlc_object_t *)p_this->p_destructor_arg;
190     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
191     input_item_t *p_input = (input_item_t *) p_this;
192     int i;
193
194     input_ItemClean( p_input );
195
196     vlc_object_lock( p_obj->p_libvlc );
197
198     ARRAY_BSEARCH( priv->input_items,->i_id, int, p_input->i_id, i);
199     if( i != -1 )
200         ARRAY_REMOVE( priv->input_items, i);
201
202     vlc_object_unlock( p_obj->p_libvlc );
203
204     free( p_input );
205 }
206
207 int input_ItemAddOpt( input_item_t *p_input, const char *psz_option,
208                       unsigned flags )
209 {
210     int err = VLC_SUCCESS;
211
212     if( psz_option == NULL )
213         return VLC_EGENERIC;
214
215     vlc_mutex_lock( &p_input->lock );
216     if (flags & VLC_INPUT_OPTION_UNIQUE)
217     {
218         for (int i = 0 ; i < p_input->i_options; i++)
219             if( !strcmp( p_input->ppsz_options[i], psz_option ) )
220                 goto out;
221     }
222
223     uint8_t *flagv = realloc (p_input->optflagv, p_input->optflagc + 1);
224     if (flagv == NULL)
225     {
226         err = VLC_ENOMEM;
227         goto out;
228     }
229     p_input->optflagv = flagv;
230     flagv[p_input->optflagc++] = flags;
231
232     INSERT_ELEM( p_input->ppsz_options, p_input->i_options,
233                  p_input->i_options, strdup( psz_option ) );
234 out:
235     vlc_mutex_unlock( &p_input->lock );
236     return err;
237 }
238
239 int input_ItemAddInfo( input_item_t *p_i,
240                             const char *psz_cat,
241                             const char *psz_name,
242                             const char *psz_format, ... )
243 {
244     va_list args;
245     int i;
246     info_t *p_info = NULL;
247     info_category_t *p_cat = NULL ;
248
249     vlc_mutex_lock( &p_i->lock );
250
251     for( i = 0 ; i < p_i->i_categories ; i ++ )
252     {
253         if( !strcmp( p_i->pp_categories[i]->psz_name, psz_cat ) )
254         {
255             p_cat = p_i->pp_categories[i];
256             break;
257         }
258     }
259     if( !p_cat )
260     {
261         if( !(p_cat = (info_category_t *)malloc( sizeof(info_category_t) )) )
262         {
263             vlc_mutex_unlock( &p_i->lock );
264             return VLC_ENOMEM;
265         }
266         p_cat->psz_name = strdup( psz_cat );
267         p_cat->i_infos = 0;
268         p_cat->pp_infos = 0;
269         INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
270                      p_cat );
271     }
272
273     for( i = 0; i< p_cat->i_infos; i++ )
274     {
275         if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
276         {
277             p_info = p_cat->pp_infos[i];
278             break;
279         }
280     }
281
282     if( !p_info )
283     {
284         if( ( p_info = (info_t *)malloc( sizeof( info_t ) ) ) == NULL )
285         {
286             vlc_mutex_unlock( &p_i->lock );
287             return VLC_ENOMEM;
288         }
289         INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos, p_cat->i_infos, p_info );
290         p_info->psz_name = strdup( psz_name );
291     }
292     else
293     {
294         free( p_info->psz_value );
295     }
296
297     va_start( args, psz_format );
298     if( vasprintf( &p_info->psz_value, psz_format, args) == -1 )
299         p_info->psz_value = NULL;
300     va_end( args );
301
302     vlc_mutex_unlock( &p_i->lock );
303
304     return p_info->psz_value ? VLC_SUCCESS : VLC_ENOMEM;
305 }
306
307 input_item_t *__input_ItemGetById( vlc_object_t *p_obj, int i_id )
308 {
309     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
310     input_item_t * p_ret = NULL;
311     int i;
312
313     vlc_object_lock( p_obj->p_libvlc );
314
315     ARRAY_BSEARCH( priv->input_items, ->i_id, int, i_id, i);
316     if( i != -1 )
317         p_ret = ARRAY_VAL( priv->input_items, i);
318
319     vlc_object_unlock( p_obj->p_libvlc );
320
321     return p_ret;
322 }
323
324 input_item_t *__input_ItemNewExt( vlc_object_t *p_obj, const char *psz_uri,
325                                   const char *psz_name,
326                                   int i_options,
327                                   const char *const *ppsz_options,
328                                   mtime_t i_duration )
329 {
330     return input_ItemNewWithType( p_obj, psz_uri, psz_name,
331                                   i_options, ppsz_options,
332                                   i_duration, ITEM_TYPE_UNKNOWN );
333 }
334
335
336 input_item_t *input_ItemNewWithType( vlc_object_t *p_obj, const char *psz_uri,
337                                 const char *psz_name,
338                                 int i_options,
339                                 const char *const *ppsz_options,
340                                 mtime_t i_duration,
341                                 int i_type )
342 {
343     libvlc_priv_t *priv = libvlc_priv (p_obj->p_libvlc);
344
345     DECMALLOC_NULL( p_input, input_item_t );
346
347     input_ItemInit( p_obj, p_input );
348     vlc_gc_init( p_input, input_ItemDestroy, (void *)p_obj->p_libvlc );
349
350     vlc_object_lock( p_obj->p_libvlc );
351     p_input->i_id = ++priv->i_last_input_id;
352     ARRAY_APPEND( priv->input_items, p_input );
353     vlc_object_unlock( p_obj->p_libvlc );
354
355     p_input->b_fixed_name = false;
356
357     if( psz_uri )
358         p_input->psz_uri = strdup( psz_uri );
359     else
360         p_input->psz_uri = NULL;
361
362     p_input->i_type = i_type;
363
364     if( p_input->i_type == ITEM_TYPE_UNKNOWN )
365         GuessType( p_input );
366
367     if( psz_name != NULL )
368         p_input->psz_name = strdup( psz_name );
369     else if( p_input->i_type == ITEM_TYPE_FILE && p_input->psz_uri )
370     {
371         const char *psz_filename = strrchr( p_input->psz_uri, DIR_SEP_CHAR );
372         if( psz_filename && *psz_filename == DIR_SEP_CHAR )
373             psz_filename++;
374         p_input->psz_name = strdup( psz_filename && *psz_filename
375                                     ? psz_filename : p_input->psz_uri );
376     }
377     else
378         p_input->psz_name = p_input->psz_uri ? strdup( p_input->psz_uri ) : NULL;
379
380     p_input->i_duration = i_duration;
381
382     for( int i = 0; i < i_options; i++ )
383         input_ItemAddOption( p_input, ppsz_options[i] );
384     return p_input;
385 }
386
387 /* Guess the type of the item using the beginning of the mrl */
388 static void GuessType( input_item_t *p_item)
389 {
390     int i;
391     static struct { const char *psz_search; int i_type; }  types_array[] =
392     {
393         { "http", ITEM_TYPE_NET },
394         { "dvd", ITEM_TYPE_DISC },
395         { "cdda", ITEM_TYPE_CDDA },
396         { "mms", ITEM_TYPE_NET },
397         { "rtsp", ITEM_TYPE_NET },
398         { "udp", ITEM_TYPE_NET },
399         { "rtp", ITEM_TYPE_NET },
400         { "vcd", ITEM_TYPE_DISC },
401         { "v4l", ITEM_TYPE_CARD },
402         { "dshow", ITEM_TYPE_CARD },
403         { "pvr", ITEM_TYPE_CARD },
404         { "dvb", ITEM_TYPE_CARD },
405         { "qpsk", ITEM_TYPE_CARD },
406         { "sdp", ITEM_TYPE_NET },
407         { NULL, 0 }
408     };
409
410     if( !p_item->psz_uri )
411     {
412         p_item->i_type = ITEM_TYPE_FILE;
413         return;
414     }
415
416     for( i = 0; types_array[i].psz_search != NULL; i++ )
417     {
418         if( !strncmp( p_item->psz_uri, types_array[i].psz_search,
419                       strlen( types_array[i].psz_search ) ) )
420         {
421             p_item->i_type = types_array[i].i_type;
422             return;
423         }
424     }
425     p_item->i_type = ITEM_TYPE_FILE;
426 }