]> git.sesse.net Git - vlc/blob - src/input/item.c
input: add b_net variable in item
[vlc] / src / input / item.c
1 /*****************************************************************************
2  * item.c: input_item management
3  *****************************************************************************
4  * Copyright (C) 1998-2004 VLC authors and VideoLAN
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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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 #include <time.h>
29
30 #include <vlc_common.h>
31 #include <vlc_url.h>
32 #include <vlc_interface.h>
33 #include <vlc_charset.h>
34
35 #include "item.h"
36 #include "info.h"
37
38 static int GuessType( const input_item_t *p_item, bool *p_net );
39
40 void input_item_SetErrorWhenReading( input_item_t *p_i, bool b_error )
41 {
42     bool b_changed;
43
44     vlc_mutex_lock( &p_i->lock );
45
46     b_changed = p_i->b_error_when_reading != b_error;
47     p_i->b_error_when_reading = b_error;
48
49     vlc_mutex_unlock( &p_i->lock );
50
51     if( b_changed )
52     {
53         vlc_event_t event;
54
55         event.type = vlc_InputItemErrorWhenReadingChanged;
56         event.u.input_item_error_when_reading_changed.new_value = b_error;
57         vlc_event_send( &p_i->event_manager, &event );
58     }
59 }
60 void input_item_SignalPreparseEnded( input_item_t *p_i )
61 {
62     vlc_event_t event;
63     event.type = vlc_InputItemPreparseEnded;
64     vlc_event_send( &p_i->event_manager, &event );
65 }
66
67 void input_item_SetPreparsed( input_item_t *p_i, bool b_preparsed )
68 {
69     bool b_send_event = false;
70
71     vlc_mutex_lock( &p_i->lock );
72
73     if( !p_i->p_meta )
74         p_i->p_meta = vlc_meta_New();
75
76     int status = vlc_meta_GetStatus(p_i->p_meta);
77     int new_status;
78     if( b_preparsed )
79         new_status = status | ITEM_PREPARSED;
80     else
81         new_status = status & ~ITEM_PREPARSED;
82     if( status != new_status )
83     {
84         vlc_meta_SetStatus(p_i->p_meta, new_status);
85         b_send_event = true;
86     }
87
88     vlc_mutex_unlock( &p_i->lock );
89
90     if( b_send_event )
91     {
92         vlc_event_t event;
93         event.type = vlc_InputItemPreparsedChanged;
94         event.u.input_item_preparsed_changed.new_status = new_status;
95         vlc_event_send( &p_i->event_manager, &event );
96     }
97 }
98
99 void input_item_SetArtNotFound( input_item_t *p_i, bool b_not_found )
100 {
101     vlc_mutex_lock( &p_i->lock );
102
103     if( !p_i->p_meta )
104         p_i->p_meta = vlc_meta_New();
105
106     int status = vlc_meta_GetStatus(p_i->p_meta);
107
108     if( b_not_found )
109         status |= ITEM_ART_NOTFOUND;
110     else
111         status &= ~ITEM_ART_NOTFOUND;
112
113     vlc_meta_SetStatus(p_i->p_meta, status);
114
115     vlc_mutex_unlock( &p_i->lock );
116 }
117
118 void input_item_SetArtFetched( input_item_t *p_i, bool b_art_fetched )
119 {
120     vlc_mutex_lock( &p_i->lock );
121
122     if( !p_i->p_meta )
123         p_i->p_meta = vlc_meta_New();
124
125     int status = vlc_meta_GetStatus(p_i->p_meta);
126
127     if( b_art_fetched )
128         status |= ITEM_ART_FETCHED;
129     else
130         status &= ~ITEM_ART_FETCHED;
131
132     vlc_meta_SetStatus(p_i->p_meta, status);
133
134     vlc_mutex_unlock( &p_i->lock );
135 }
136
137 void input_item_SetMeta( input_item_t *p_i, vlc_meta_type_t meta_type, const char *psz_val )
138 {
139     vlc_event_t event;
140
141     vlc_mutex_lock( &p_i->lock );
142     if( !p_i->p_meta )
143         p_i->p_meta = vlc_meta_New();
144     vlc_meta_Set( p_i->p_meta, meta_type, psz_val );
145     vlc_mutex_unlock( &p_i->lock );
146
147     /* Notify interested third parties */
148     event.type = vlc_InputItemMetaChanged;
149     event.u.input_item_meta_changed.meta_type = meta_type;
150     vlc_event_send( &p_i->event_manager, &event );
151 }
152
153 /* FIXME GRRRRRRRRRR args should be in the reverse order to be
154  * consistent with (nearly?) all or copy funcs */
155 void input_item_CopyOptions( input_item_t *p_parent,
156                              input_item_t *p_child )
157 {
158     vlc_mutex_lock( &p_parent->lock );
159
160     for( int i = 0 ; i< p_parent->i_options; i++ )
161     {
162         if( !strcmp( p_parent->ppsz_options[i], "meta-file" ) )
163             continue;
164
165         input_item_AddOption( p_child,
166                               p_parent->ppsz_options[i],
167                               p_parent->optflagv[i] );
168     }
169
170     vlc_mutex_unlock( &p_parent->lock );
171 }
172
173 static void post_subitems( input_item_node_t *p_node )
174 {
175     for( int i = 0; i < p_node->i_children; i++ )
176     {
177         vlc_event_t event;
178         event.type = vlc_InputItemSubItemAdded;
179         event.u.input_item_subitem_added.p_new_child = p_node->pp_children[i]->p_item;
180         vlc_event_send( &p_node->p_item->event_manager, &event );
181
182         post_subitems( p_node->pp_children[i] );
183     }
184 }
185
186 /* This won't hold the item, but can tell to interested third parties
187  * Like the playlist, that there is a new sub item. With this design
188  * It is not the input item's responsability to keep all the ref of
189  * the input item children. */
190 void input_item_PostSubItem( input_item_t *p_parent, input_item_t *p_child )
191 {
192     input_item_node_t *p_node = input_item_node_Create( p_parent );
193     input_item_node_AppendItem( p_node, p_child );
194     input_item_node_PostAndDelete( p_node );
195 }
196
197 bool input_item_HasErrorWhenReading( input_item_t *p_item )
198 {
199     vlc_mutex_lock( &p_item->lock );
200
201     bool b_error = p_item->b_error_when_reading;
202
203     vlc_mutex_unlock( &p_item->lock );
204
205     return b_error;
206 }
207
208 bool input_item_MetaMatch( input_item_t *p_i,
209                            vlc_meta_type_t meta_type, const char *psz )
210 {
211     vlc_mutex_lock( &p_i->lock );
212
213     if( !p_i->p_meta )
214     {
215         vlc_mutex_unlock( &p_i->lock );
216         return false;
217     }
218     const char *psz_meta = vlc_meta_Get( p_i->p_meta, meta_type );
219     bool b_ret = psz_meta && strcasestr( psz_meta, psz );
220
221     vlc_mutex_unlock( &p_i->lock );
222
223     return b_ret;
224 }
225
226 char *input_item_GetMeta( input_item_t *p_i, vlc_meta_type_t meta_type )
227 {
228     vlc_mutex_lock( &p_i->lock );
229
230     if( !p_i->p_meta )
231     {
232         vlc_mutex_unlock( &p_i->lock );
233         return NULL;
234     }
235
236     char *psz = NULL;
237     if( vlc_meta_Get( p_i->p_meta, meta_type ) )
238         psz = strdup( vlc_meta_Get( p_i->p_meta, meta_type ) );
239
240     vlc_mutex_unlock( &p_i->lock );
241     return psz;
242 }
243
244 /* Get the title of a given item or fallback to the name if the title is empty */
245 char *input_item_GetTitleFbName( input_item_t *p_item )
246 {
247     char *psz_ret;
248     vlc_mutex_lock( &p_item->lock );
249
250     if( !p_item->p_meta )
251     {
252         psz_ret = p_item->psz_name ? strdup( p_item->psz_name ) : NULL;
253         vlc_mutex_unlock( &p_item->lock );
254         return psz_ret;
255     }
256
257     const char *psz_title = vlc_meta_Get( p_item->p_meta, vlc_meta_Title );
258     if( !EMPTY_STR( psz_title ) )
259         psz_ret = strdup( psz_title );
260     else
261         psz_ret = p_item->psz_name ? strdup( p_item->psz_name ) : NULL;
262
263     vlc_mutex_unlock( &p_item->lock );
264     return psz_ret;
265 }
266
267 char *input_item_GetName( input_item_t *p_item )
268 {
269     vlc_mutex_lock( &p_item->lock );
270
271     char *psz_name = p_item->psz_name ? strdup( p_item->psz_name ) : NULL;
272
273     vlc_mutex_unlock( &p_item->lock );
274     return psz_name;
275 }
276 void input_item_SetName( input_item_t *p_item, const char *psz_name )
277 {
278     vlc_mutex_lock( &p_item->lock );
279
280     free( p_item->psz_name );
281     p_item->psz_name = strdup( psz_name );
282
283     vlc_mutex_unlock( &p_item->lock );
284 }
285
286 char *input_item_GetURI( input_item_t *p_i )
287 {
288     vlc_mutex_lock( &p_i->lock );
289
290     char *psz_s = p_i->psz_uri ? strdup( p_i->psz_uri ) : NULL;
291
292     vlc_mutex_unlock( &p_i->lock );
293     return psz_s;
294 }
295
296 void input_item_SetURI( input_item_t *p_i, const char *psz_uri )
297 {
298     assert( psz_uri );
299 #ifndef NDEBUG
300     if( !strstr( psz_uri, "://" )
301      || strchr( psz_uri, ' ' ) || strchr( psz_uri, '"' ) )
302         fprintf( stderr, "Warning: %s(\"%s\"): file path instead of URL.\n",
303                  __func__, psz_uri );
304 #endif
305     vlc_mutex_lock( &p_i->lock );
306     free( p_i->psz_uri );
307     p_i->psz_uri = strdup( psz_uri );
308
309     p_i->i_type = GuessType( p_i, &p_i->b_net );
310
311     if( p_i->psz_name )
312         ;
313     else
314     if( p_i->i_type == ITEM_TYPE_FILE || p_i->i_type == ITEM_TYPE_DIRECTORY )
315     {
316         const char *psz_filename = strrchr( p_i->psz_uri, '/' );
317
318         if( psz_filename && *psz_filename == '/' )
319             psz_filename++;
320         if( psz_filename && *psz_filename )
321             p_i->psz_name = strdup( psz_filename );
322
323         /* Make the name more readable */
324         if( p_i->psz_name )
325         {
326             decode_URI( p_i->psz_name );
327             EnsureUTF8( p_i->psz_name );
328         }
329     }
330     else
331     {   /* Strip login and password from title */
332         int r;
333         vlc_url_t url;
334
335         vlc_UrlParse( &url, psz_uri, 0 );
336         if( url.psz_protocol )
337         {
338             if( url.i_port > 0 )
339                 r=asprintf( &p_i->psz_name, "%s://%s:%d%s", url.psz_protocol,
340                           url.psz_host, url.i_port,
341                           url.psz_path ? url.psz_path : "" );
342             else
343                 r=asprintf( &p_i->psz_name, "%s://%s%s", url.psz_protocol,
344                           url.psz_host ? url.psz_host : "",
345                           url.psz_path ? url.psz_path : "" );
346         }
347         else
348         {
349             if( url.i_port > 0 )
350                 r=asprintf( &p_i->psz_name, "%s:%d%s", url.psz_host, url.i_port,
351                           url.psz_path ? url.psz_path : "" );
352             else
353                 r=asprintf( &p_i->psz_name, "%s%s", url.psz_host,
354                           url.psz_path ? url.psz_path : "" );
355         }
356         vlc_UrlClean( &url );
357         if( -1==r )
358             p_i->psz_name=NULL; /* recover from undefined value */
359     }
360
361     vlc_mutex_unlock( &p_i->lock );
362 }
363
364 mtime_t input_item_GetDuration( input_item_t *p_i )
365 {
366     vlc_mutex_lock( &p_i->lock );
367
368     mtime_t i_duration = p_i->i_duration;
369
370     vlc_mutex_unlock( &p_i->lock );
371     return i_duration;
372 }
373
374 void input_item_SetDuration( input_item_t *p_i, mtime_t i_duration )
375 {
376     bool b_send_event = false;
377
378     vlc_mutex_lock( &p_i->lock );
379     if( p_i->i_duration != i_duration )
380     {
381         p_i->i_duration = i_duration;
382         b_send_event = true;
383     }
384     vlc_mutex_unlock( &p_i->lock );
385
386     if( b_send_event )
387     {
388         vlc_event_t event;
389
390         event.type = vlc_InputItemDurationChanged;
391         event.u.input_item_duration_changed.new_duration = i_duration;
392         vlc_event_send( &p_i->event_manager, &event );
393     }
394 }
395
396 char *input_item_GetNowPlayingFb( input_item_t *p_item )
397 {
398     char *psz_meta = input_item_GetMeta( p_item, vlc_meta_NowPlaying );
399     if( !psz_meta || strlen( psz_meta ) == 0 )
400     {
401         free( psz_meta );
402         return input_item_GetMeta( p_item, vlc_meta_ESNowPlaying );
403     }
404
405     return psz_meta;
406 }
407
408 bool input_item_IsPreparsed( input_item_t *p_item )
409 {
410     vlc_mutex_lock( &p_item->lock );
411     bool b_preparsed = p_item->p_meta ? ( vlc_meta_GetStatus(p_item->p_meta) & ITEM_PREPARSED ) != 0 : false;
412     vlc_mutex_unlock( &p_item->lock );
413
414     return b_preparsed;
415 }
416
417 bool input_item_IsArtFetched( input_item_t *p_item )
418 {
419     vlc_mutex_lock( &p_item->lock );
420     bool b_fetched = p_item->p_meta ? ( vlc_meta_GetStatus(p_item->p_meta) & ITEM_ART_FETCHED ) != 0 : false;
421     vlc_mutex_unlock( &p_item->lock );
422
423     return b_fetched;
424 }
425
426 input_item_t *input_item_Hold( input_item_t *p_item )
427 {
428     input_item_owner_t *owner = item_owner(p_item);
429
430     atomic_fetch_add( &owner->refs, 1 );
431     return p_item;
432 }
433
434 void input_item_Release( input_item_t *p_item )
435 {
436     input_item_owner_t *owner = item_owner(p_item);
437
438     if( atomic_fetch_sub(&owner->refs, 1) != 1 )
439         return;
440
441     vlc_event_manager_fini( &p_item->event_manager );
442
443     free( p_item->psz_name );
444     free( p_item->psz_uri );
445     if( p_item->p_stats != NULL )
446     {
447         vlc_mutex_destroy( &p_item->p_stats->lock );
448         free( p_item->p_stats );
449     }
450
451     if( p_item->p_meta != NULL )
452         vlc_meta_Delete( p_item->p_meta );
453
454     for( int i = 0; i < p_item->i_options; i++ )
455         free( p_item->ppsz_options[i] );
456     TAB_CLEAN( p_item->i_options, p_item->ppsz_options );
457     free( p_item->optflagv );
458
459     for( int i = 0; i < p_item->i_es; i++ )
460     {
461         es_format_Clean( p_item->es[i] );
462         free( p_item->es[i] );
463     }
464     TAB_CLEAN( p_item->i_es, p_item->es );
465
466     for( int i = 0; i < p_item->i_epg; i++ )
467         vlc_epg_Delete( p_item->pp_epg[i] );
468     TAB_CLEAN( p_item->i_epg, p_item->pp_epg );
469
470     for( int i = 0; i < p_item->i_categories; i++ )
471         info_category_Delete( p_item->pp_categories[i] );
472     TAB_CLEAN( p_item->i_categories, p_item->pp_categories );
473
474     vlc_mutex_destroy( &p_item->lock );
475     free( owner );
476 }
477
478 int input_item_AddOption( input_item_t *p_input, const char *psz_option,
479                           unsigned flags )
480 {
481     int err = VLC_SUCCESS;
482
483     if( psz_option == NULL )
484         return VLC_EGENERIC;
485
486     vlc_mutex_lock( &p_input->lock );
487     if (flags & VLC_INPUT_OPTION_UNIQUE)
488     {
489         for (int i = 0 ; i < p_input->i_options; i++)
490             if( !strcmp( p_input->ppsz_options[i], psz_option ) )
491                 goto out;
492     }
493
494     uint8_t *flagv = realloc (p_input->optflagv, p_input->optflagc + 1);
495     if (flagv == NULL)
496     {
497         err = VLC_ENOMEM;
498         goto out;
499     }
500     p_input->optflagv = flagv;
501     flagv[p_input->optflagc++] = flags;
502
503     INSERT_ELEM( p_input->ppsz_options, p_input->i_options,
504                  p_input->i_options, strdup( psz_option ) );
505 out:
506     vlc_mutex_unlock( &p_input->lock );
507     return err;
508 }
509
510 static info_category_t *InputItemFindCat( input_item_t *p_item,
511                                           int *pi_index, const char *psz_cat )
512 {
513     vlc_assert_locked( &p_item->lock );
514     for( int i = 0; i < p_item->i_categories && psz_cat; i++ )
515     {
516         info_category_t *p_cat = p_item->pp_categories[i];
517
518         if( !strcmp( p_cat->psz_name, psz_cat ) )
519         {
520             if( pi_index )
521                 *pi_index = i;
522             return p_cat;
523         }
524     }
525     return NULL;
526 }
527
528 /**
529  * Get a info item from a given category in a given input item.
530  *
531  * \param p_i The input item to get info from
532  * \param psz_cat String representing the category for the info
533  * \param psz_name String representing the name of the desired info
534  * \return A pointer to the string with the given info if found, or an
535  *         empty string otherwise. The caller should free the returned
536  *         pointer.
537  */
538 char *input_item_GetInfo( input_item_t *p_i,
539                           const char *psz_cat,
540                           const char *psz_name )
541 {
542     vlc_mutex_lock( &p_i->lock );
543
544     const info_category_t *p_cat = InputItemFindCat( p_i, NULL, psz_cat );
545     if( p_cat )
546     {
547         info_t *p_info = info_category_FindInfo( p_cat, NULL, psz_name );
548         if( p_info && p_info->psz_value )
549         {
550             char *psz_ret = strdup( p_info->psz_value );
551             vlc_mutex_unlock( &p_i->lock );
552             return psz_ret;
553         }
554     }
555     vlc_mutex_unlock( &p_i->lock );
556     return strdup( "" );
557 }
558
559 static int InputItemVaAddInfo( input_item_t *p_i,
560                                const char *psz_cat,
561                                const char *psz_name,
562                                const char *psz_format, va_list args )
563 {
564     vlc_assert_locked( &p_i->lock );
565
566     info_category_t *p_cat = InputItemFindCat( p_i, NULL, psz_cat );
567     if( !p_cat )
568     {
569         p_cat = info_category_New( psz_cat );
570         if( !p_cat )
571             return VLC_ENOMEM;
572         INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
573                      p_cat );
574     }
575     info_t *p_info = info_category_VaAddInfo( p_cat, psz_name, psz_format, args );
576     if( !p_info || !p_info->psz_value )
577         return VLC_EGENERIC;
578     return VLC_SUCCESS;
579 }
580
581 static int InputItemAddInfo( input_item_t *p_i,
582                              const char *psz_cat,
583                              const char *psz_name,
584                              const char *psz_format, ... )
585 {
586     va_list args;
587
588     va_start( args, psz_format );
589     const int i_ret = InputItemVaAddInfo( p_i, psz_cat, psz_name, psz_format, args );
590     va_end( args );
591
592     return i_ret;
593 }
594
595 int input_item_AddInfo( input_item_t *p_i,
596                         const char *psz_cat,
597                         const char *psz_name,
598                         const char *psz_format, ... )
599 {
600     va_list args;
601
602     vlc_mutex_lock( &p_i->lock );
603
604     va_start( args, psz_format );
605     const int i_ret = InputItemVaAddInfo( p_i, psz_cat, psz_name, psz_format, args );
606     va_end( args );
607
608     vlc_mutex_unlock( &p_i->lock );
609
610
611     if( !i_ret )
612     {
613         vlc_event_t event;
614
615         event.type = vlc_InputItemInfoChanged;
616         vlc_event_send( &p_i->event_manager, &event );
617     }
618     return i_ret;
619 }
620
621 int input_item_DelInfo( input_item_t *p_i,
622                         const char *psz_cat,
623                         const char *psz_name )
624 {
625     vlc_mutex_lock( &p_i->lock );
626     int i_cat;
627     info_category_t *p_cat = InputItemFindCat( p_i, &i_cat, psz_cat );
628     if( !p_cat )
629     {
630         vlc_mutex_unlock( &p_i->lock );
631         return VLC_EGENERIC;
632     }
633
634     if( psz_name )
635     {
636         /* Remove a specific info */
637         int i_ret = info_category_DeleteInfo( p_cat, psz_name );
638         if( i_ret )
639         {
640             vlc_mutex_unlock( &p_i->lock );
641             return VLC_EGENERIC;
642         }
643     }
644     else
645     {
646         /* Remove the complete categorie */
647         info_category_Delete( p_cat );
648         REMOVE_ELEM( p_i->pp_categories, p_i->i_categories, i_cat );
649     }
650     vlc_mutex_unlock( &p_i->lock );
651
652
653     vlc_event_t event;
654     event.type = vlc_InputItemInfoChanged;
655     vlc_event_send( &p_i->event_manager, &event );
656
657     return VLC_SUCCESS;
658 }
659 void input_item_ReplaceInfos( input_item_t *p_item, info_category_t *p_cat )
660 {
661     vlc_mutex_lock( &p_item->lock );
662     int i_cat;
663     info_category_t *p_old = InputItemFindCat( p_item, &i_cat, p_cat->psz_name );
664     if( p_old )
665     {
666         info_category_Delete( p_old );
667         p_item->pp_categories[i_cat] = p_cat;
668     }
669     else
670     {
671         INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories,
672                      p_cat );
673     }
674     vlc_mutex_unlock( &p_item->lock );
675
676
677     vlc_event_t event;
678     event.type = vlc_InputItemInfoChanged;
679     vlc_event_send( &p_item->event_manager, &event );
680 }
681 void input_item_MergeInfos( input_item_t *p_item, info_category_t *p_cat )
682 {
683     vlc_mutex_lock( &p_item->lock );
684     info_category_t *p_old = InputItemFindCat( p_item, NULL, p_cat->psz_name );
685     if( p_old )
686     {
687         for( int i = 0; i < p_cat->i_infos; i++ )
688             info_category_ReplaceInfo( p_old, p_cat->pp_infos[i] );
689         TAB_CLEAN( p_cat->i_infos, p_cat->pp_infos );
690         info_category_Delete( p_cat );
691     }
692     else
693     {
694         INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories,
695                      p_cat );
696     }
697     vlc_mutex_unlock( &p_item->lock );
698
699
700     vlc_event_t event;
701     event.type = vlc_InputItemInfoChanged;
702     vlc_event_send( &p_item->event_manager, &event );
703 }
704
705 #define EPG_DEBUG
706 void input_item_SetEpg( input_item_t *p_item, const vlc_epg_t *p_update )
707 {
708     vlc_mutex_lock( &p_item->lock );
709
710     /* */
711     vlc_epg_t *p_epg = NULL;
712     for( int i = 0; i < p_item->i_epg; i++ )
713     {
714         vlc_epg_t *p_tmp = p_item->pp_epg[i];
715
716         if( (p_tmp->psz_name == NULL) != (p_update->psz_name == NULL) )
717             continue;
718         if( p_tmp->psz_name && p_update->psz_name && strcmp(p_tmp->psz_name, p_update->psz_name) )
719             continue;
720
721         p_epg = p_tmp;
722         break;
723     }
724
725     /* */
726     if( !p_epg )
727     {
728         p_epg = vlc_epg_New( p_update->psz_name );
729         if( p_epg )
730             TAB_APPEND( p_item->i_epg, p_item->pp_epg, p_epg );
731     }
732     if( p_epg )
733         vlc_epg_Merge( p_epg, p_update );
734
735     vlc_mutex_unlock( &p_item->lock );
736
737     if( !p_epg )
738         return;
739
740 #ifdef EPG_DEBUG
741     char *psz_epg;
742     if( asprintf( &psz_epg, "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 )
743         goto signal;
744
745     input_item_DelInfo( p_item, psz_epg, NULL );
746
747     vlc_mutex_lock( &p_item->lock );
748     for( int i = 0; i < p_epg->i_event; i++ )
749     {
750         const vlc_epg_event_t *p_evt = p_epg->pp_event[i];
751         time_t t_start = (time_t)p_evt->i_start;
752         struct tm tm_start;
753         char psz_start[128];
754
755         localtime_r( &t_start, &tm_start );
756
757         snprintf( psz_start, sizeof(psz_start), "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
758                   1900 + tm_start.tm_year, 1 + tm_start.tm_mon, tm_start.tm_mday,
759                   tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
760         if( p_evt->psz_short_description || p_evt->psz_description )
761             InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s %s",
762                               p_evt->psz_name,
763                               p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
764                               p_evt->psz_short_description ? p_evt->psz_short_description : "" ,
765                               p_evt->psz_description ? p_evt->psz_description : "" );
766         else
767             InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
768                               p_evt->psz_name,
769                               p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
770     }
771     vlc_mutex_unlock( &p_item->lock );
772     free( psz_epg );
773 signal:
774 #endif
775
776     if( p_epg->i_event > 0 )
777     {
778         vlc_event_t event = { .type = vlc_InputItemInfoChanged, };
779         vlc_event_send( &p_item->event_manager, &event );
780     }
781 }
782
783 void input_item_SetEpgOffline( input_item_t *p_item )
784 {
785     vlc_mutex_lock( &p_item->lock );
786     for( int i = 0; i < p_item->i_epg; i++ )
787         vlc_epg_SetCurrent( p_item->pp_epg[i], -1 );
788     vlc_mutex_unlock( &p_item->lock );
789
790 #ifdef EPG_DEBUG
791     vlc_mutex_lock( &p_item->lock );
792     const int i_epg_info = p_item->i_epg;
793     if( i_epg_info > 0 )
794     {
795         char *ppsz_epg_info[i_epg_info];
796         for( int i = 0; i < p_item->i_epg; i++ )
797         {
798             const vlc_epg_t *p_epg = p_item->pp_epg[i];
799             if( asprintf( &ppsz_epg_info[i], "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 )
800                 ppsz_epg_info[i] = NULL;
801         }
802         vlc_mutex_unlock( &p_item->lock );
803
804         for( int i = 0; i < i_epg_info; i++ )
805         {
806             if( !ppsz_epg_info[i] )
807                 continue;
808             input_item_DelInfo( p_item, ppsz_epg_info[i], NULL );
809             free( ppsz_epg_info[i] );
810         }
811     }
812     else
813         vlc_mutex_unlock( &p_item->lock );
814 #endif
815
816     vlc_event_t event = { .type = vlc_InputItemInfoChanged, };
817     vlc_event_send( &p_item->event_manager, &event );
818 }
819
820 input_item_t *input_item_NewExt( const char *psz_uri,
821                                  const char *psz_name,
822                                  int i_options,
823                                  const char *const *ppsz_options,
824                                  unsigned i_option_flags,
825                                  mtime_t i_duration )
826 {
827     return input_item_NewWithType( psz_uri, psz_name,
828                                   i_options, ppsz_options, i_option_flags,
829                                   i_duration, ITEM_TYPE_UNKNOWN );
830 }
831
832
833 input_item_t *
834 input_item_NewWithTypeExt( const char *psz_uri, const char *psz_name,
835                            int i_options, const char *const *ppsz_options,
836                            unsigned flags, mtime_t duration, int type,
837                            int i_net )
838 {
839     static atomic_uint last_input_id = ATOMIC_VAR_INIT(0);
840
841     input_item_owner_t *owner = calloc( 1, sizeof( *owner ) );
842     if( unlikely(owner == NULL) )
843         return NULL;
844
845     atomic_init( &owner->refs, 1 );
846
847     input_item_t *p_input = &owner->item;
848     vlc_event_manager_t * p_em = &p_input->event_manager;
849
850     p_input->i_id = atomic_fetch_add(&last_input_id, 1);
851     vlc_mutex_init( &p_input->lock );
852
853     p_input->psz_name = NULL;
854     if( psz_name )
855         input_item_SetName( p_input, psz_name );
856
857     p_input->psz_uri = NULL;
858     if( psz_uri )
859         input_item_SetURI( p_input, psz_uri );
860     else
861         p_input->i_type = ITEM_TYPE_UNKNOWN;
862
863     TAB_INIT( p_input->i_options, p_input->ppsz_options );
864     p_input->optflagc = 0;
865     p_input->optflagv = NULL;
866     for( int i = 0; i < i_options; i++ )
867         input_item_AddOption( p_input, ppsz_options[i], flags );
868
869     p_input->i_duration = duration;
870     TAB_INIT( p_input->i_categories, p_input->pp_categories );
871     TAB_INIT( p_input->i_es, p_input->es );
872     p_input->p_stats = NULL;
873     p_input->p_meta = NULL;
874     TAB_INIT( p_input->i_epg, p_input->pp_epg );
875
876     vlc_event_manager_init( p_em, p_input );
877     vlc_event_manager_register_event_type( p_em, vlc_InputItemMetaChanged );
878     vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemAdded );
879     vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemTreeAdded );
880     vlc_event_manager_register_event_type( p_em, vlc_InputItemDurationChanged );
881     vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparsedChanged );
882     vlc_event_manager_register_event_type( p_em, vlc_InputItemNameChanged );
883     vlc_event_manager_register_event_type( p_em, vlc_InputItemInfoChanged );
884     vlc_event_manager_register_event_type( p_em, vlc_InputItemErrorWhenReadingChanged );
885     vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparseEnded );
886
887     if( type != ITEM_TYPE_UNKNOWN )
888         p_input->i_type = type;
889     p_input->b_error_when_reading = false;
890
891     if( i_net != -1 )
892         p_input->b_net = !!i_net;
893     else if( p_input->i_type == ITEM_TYPE_STREAM )
894         p_input->b_net = true;
895     return p_input;
896 }
897
898 input_item_t *
899 input_item_NewWithType( const char *psz_uri, const char *psz_name,
900                         int i_options, const char *const *ppsz_options,
901                         unsigned flags, mtime_t duration, int type )
902 {
903     return input_item_NewWithTypeExt( psz_uri, psz_name, i_options,
904                                       ppsz_options, flags, duration, type,
905                                       -1 );
906 }
907
908 input_item_t *input_item_Copy( input_item_t *p_input )
909 {
910     vlc_mutex_lock( &p_input->lock );
911
912     input_item_t *p_new_input =
913         input_item_NewWithType( p_input->psz_uri, p_input->psz_name,
914                                 0, NULL, 0, p_input->i_duration,
915                                 p_input->i_type );
916
917     if( p_new_input )
918     {
919         for( int i = 0 ; i< p_input->i_options; i++ )
920         {
921             input_item_AddOption( p_new_input,
922                                   p_input->ppsz_options[i],
923                                   p_input->optflagv[i] );
924         }
925
926         if( p_input->p_meta )
927         {
928             p_new_input->p_meta = vlc_meta_New();
929             vlc_meta_Merge( p_new_input->p_meta, p_input->p_meta );
930         }
931     }
932
933     vlc_mutex_unlock( &p_input->lock );
934
935     return p_new_input;
936 }
937
938 struct item_type_entry
939 {
940     const char psz_scheme[7];
941     uint8_t    i_type;
942     bool       b_net;
943 };
944
945 static int typecmp( const void *key, const void *entry )
946 {
947     const struct item_type_entry *type = entry;
948     const char *uri = key, *scheme = type->psz_scheme;
949
950     return strncmp( uri, scheme, strlen( scheme ) );
951 }
952
953 /* Guess the type of the item using the beginning of the mrl */
954 static int GuessType( const input_item_t *p_item, bool *p_net )
955 {
956     static const struct item_type_entry tab[] =
957     {   /* /!\ Alphabetical order /!\ */
958         /* Short match work, not just exact match */
959         { "alsa",   ITEM_TYPE_CARD, false },
960         { "atsc",   ITEM_TYPE_CARD, false },
961         { "bd",     ITEM_TYPE_DISC, false },
962         { "cable",  ITEM_TYPE_CARD, false },
963         { "cdda",   ITEM_TYPE_CDDA, false },
964         { "cqam",   ITEM_TYPE_CARD, false },
965         { "dc1394", ITEM_TYPE_CARD, false },
966         { "dccp",   ITEM_TYPE_STREAM, true },
967         { "deckli", ITEM_TYPE_CARD, false }, /* decklink */
968         { "dir",    ITEM_TYPE_DIRECTORY, false },
969         { "dshow",  ITEM_TYPE_CARD, false },
970         { "dv",     ITEM_TYPE_CARD, false },
971         { "dvb",    ITEM_TYPE_CARD, false },
972         { "dvd",    ITEM_TYPE_DISC, false },
973         { "dtv",    ITEM_TYPE_CARD, false },
974         { "eyetv",  ITEM_TYPE_CARD, false },
975         { "fd",     ITEM_TYPE_UNKNOWN, false },
976         { "ftp",    ITEM_TYPE_FILE, true },
977         { "http",   ITEM_TYPE_FILE, true },
978         { "icyx",   ITEM_TYPE_STREAM, true },
979         { "imem",   ITEM_TYPE_UNKNOWN, false },
980         { "itpc",   ITEM_TYPE_PLAYLIST, true },
981         { "jack",   ITEM_TYPE_CARD, false },
982         { "linsys", ITEM_TYPE_CARD, false },
983         { "live",   ITEM_TYPE_STREAM, true }, /* livedotcom */
984         { "mms",    ITEM_TYPE_STREAM, true },
985         { "mtp",    ITEM_TYPE_DISC, false },
986         { "ofdm",   ITEM_TYPE_CARD, false },
987         { "oss",    ITEM_TYPE_CARD, false },
988         { "pnm",    ITEM_TYPE_STREAM, true },
989         { "qam",    ITEM_TYPE_CARD, false },
990         { "qpsk",   ITEM_TYPE_CARD, false },
991         { "qtcapt", ITEM_TYPE_CARD, false }, /* qtcapture */
992         { "raw139", ITEM_TYPE_CARD, false }, /* raw1394 */
993         { "rt",     ITEM_TYPE_STREAM, true }, /* rtp, rtsp, rtmp */
994         { "satell", ITEM_TYPE_CARD, false }, /* sattelite */
995         { "screen", ITEM_TYPE_CARD, false },
996         { "sdp",    ITEM_TYPE_STREAM, true },
997         { "sftp",   ITEM_TYPE_FILE, true },
998         { "shm",    ITEM_TYPE_CARD, false },
999         { "smb",    ITEM_TYPE_FILE, true },
1000         { "svcd",   ITEM_TYPE_DISC, false },
1001         { "tcp",    ITEM_TYPE_STREAM, true },
1002         { "terres", ITEM_TYPE_CARD, false }, /* terrestrial */
1003         { "udp",    ITEM_TYPE_STREAM, true },  /* udplite too */
1004         { "unsv",   ITEM_TYPE_STREAM, true },
1005         { "usdigi", ITEM_TYPE_CARD, false }, /* usdigital */
1006         { "v4l",    ITEM_TYPE_CARD, false },
1007         { "vcd",    ITEM_TYPE_DISC, false },
1008         { "window", ITEM_TYPE_CARD, false },
1009     };
1010     const struct item_type_entry *e;
1011
1012     if( !strstr( p_item->psz_uri, "://" ) )
1013         return ITEM_TYPE_FILE;
1014
1015     e = bsearch( p_item->psz_uri, tab, sizeof( tab ) / sizeof( tab[0] ),
1016                  sizeof( tab[0] ), typecmp );
1017     if( e )
1018     {
1019         *p_net = e->b_net;
1020         return e->i_type;
1021     } else
1022     {
1023         *p_net = false;
1024         return ITEM_TYPE_FILE;
1025     }
1026 }
1027
1028 input_item_node_t *input_item_node_Create( input_item_t *p_input )
1029 {
1030     input_item_node_t* p_node = malloc( sizeof( input_item_node_t ) );
1031     if( !p_node )
1032         return NULL;
1033
1034     assert( p_input );
1035
1036     p_node->p_item = p_input;
1037     vlc_gc_incref( p_input );
1038
1039     p_node->p_parent = NULL;
1040     p_node->i_children = 0;
1041     p_node->pp_children = NULL;
1042
1043     return p_node;
1044 }
1045
1046 static void RecursiveNodeDelete( input_item_node_t *p_node )
1047 {
1048     for( int i = 0; i < p_node->i_children; i++ )
1049         RecursiveNodeDelete( p_node->pp_children[i] );
1050
1051     vlc_gc_decref( p_node->p_item );
1052     free( p_node->pp_children );
1053     free( p_node );
1054 }
1055
1056 void input_item_node_Delete( input_item_node_t *p_node )
1057 {
1058     if( p_node->p_parent )
1059         for( int i = 0; i < p_node->p_parent->i_children; i++ )
1060             if( p_node->p_parent->pp_children[i] == p_node )
1061             {
1062                 REMOVE_ELEM( p_node->p_parent->pp_children,
1063                         p_node->p_parent->i_children,
1064                         i );
1065                 break;
1066             }
1067
1068     RecursiveNodeDelete( p_node );
1069 }
1070
1071 input_item_node_t *input_item_node_AppendItem( input_item_node_t *p_node, input_item_t *p_item )
1072 {
1073     input_item_node_t *p_new_child = input_item_node_Create( p_item );
1074     if( !p_new_child ) return NULL;
1075     input_item_node_AppendNode( p_node, p_new_child );
1076     return p_new_child;
1077 }
1078
1079 void input_item_node_AppendNode( input_item_node_t *p_parent, input_item_node_t *p_child )
1080 {
1081     assert( p_parent && p_child && p_child->p_parent == NULL );
1082     INSERT_ELEM( p_parent->pp_children,
1083                  p_parent->i_children,
1084                  p_parent->i_children,
1085                  p_child );
1086     p_child->p_parent = p_parent;
1087 }
1088
1089 void input_item_node_PostAndDelete( input_item_node_t *p_root )
1090 {
1091     post_subitems( p_root );
1092
1093     vlc_event_t event;
1094     event.type = vlc_InputItemSubItemTreeAdded;
1095     event.u.input_item_subitem_tree_added.p_root = p_root;
1096     vlc_event_send( &p_root->p_item->event_manager, &event );
1097
1098     input_item_node_Delete( p_root );
1099 }
1100
1101 /* Called by es_out when a new Elementary Stream is added or updated. */
1102 void input_item_UpdateTracksInfo(input_item_t *item, const es_format_t *fmt)
1103 {
1104     int i;
1105     es_format_t *fmt_copy = malloc(sizeof *fmt_copy);
1106     if (!fmt_copy)
1107         return;
1108
1109     es_format_Copy(fmt_copy, fmt);
1110     /* XXX: we could free p_extra to save memory, we will likely not need
1111      * the decoder specific data */
1112
1113     vlc_mutex_lock( &item->lock );
1114
1115     for( i = 0; i < item->i_es; i++ )
1116     {
1117         if (item->es[i]->i_id != fmt->i_id)
1118             continue;
1119
1120         /* We've found the right ES, replace it */
1121         es_format_Clean(item->es[i]);
1122         free(item->es[i]);
1123         item->es[i] = fmt_copy;
1124         vlc_mutex_unlock( &item->lock );
1125         return;
1126     }
1127
1128     /* ES not found, insert it */
1129     TAB_APPEND(item->i_es, item->es, fmt_copy);
1130     vlc_mutex_unlock( &item->lock );
1131 }