]> git.sesse.net Git - vlc/blob - src/input/item.c
Add bluray to GuessType()
[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 bool input_item_ShouldPreparseSubItems( input_item_t *p_item )
427 {
428     bool b_ret;
429
430     vlc_mutex_lock( &p_item->lock );
431     b_ret = p_item->i_preparse_depth == -1 ? true : p_item->i_preparse_depth > 0;
432     vlc_mutex_unlock( &p_item->lock );
433
434     return b_ret;
435 }
436
437 input_item_t *input_item_Hold( input_item_t *p_item )
438 {
439     input_item_owner_t *owner = item_owner(p_item);
440
441     atomic_fetch_add( &owner->refs, 1 );
442     return p_item;
443 }
444
445 void input_item_Release( input_item_t *p_item )
446 {
447     input_item_owner_t *owner = item_owner(p_item);
448
449     if( atomic_fetch_sub(&owner->refs, 1) != 1 )
450         return;
451
452     vlc_event_manager_fini( &p_item->event_manager );
453
454     free( p_item->psz_name );
455     free( p_item->psz_uri );
456     if( p_item->p_stats != NULL )
457     {
458         vlc_mutex_destroy( &p_item->p_stats->lock );
459         free( p_item->p_stats );
460     }
461
462     if( p_item->p_meta != NULL )
463         vlc_meta_Delete( p_item->p_meta );
464
465     for( int i = 0; i < p_item->i_options; i++ )
466         free( p_item->ppsz_options[i] );
467     TAB_CLEAN( p_item->i_options, p_item->ppsz_options );
468     free( p_item->optflagv );
469
470     for( int i = 0; i < p_item->i_es; i++ )
471     {
472         es_format_Clean( p_item->es[i] );
473         free( p_item->es[i] );
474     }
475     TAB_CLEAN( p_item->i_es, p_item->es );
476
477     for( int i = 0; i < p_item->i_epg; i++ )
478         vlc_epg_Delete( p_item->pp_epg[i] );
479     TAB_CLEAN( p_item->i_epg, p_item->pp_epg );
480
481     for( int i = 0; i < p_item->i_categories; i++ )
482         info_category_Delete( p_item->pp_categories[i] );
483     TAB_CLEAN( p_item->i_categories, p_item->pp_categories );
484
485     vlc_mutex_destroy( &p_item->lock );
486     free( owner );
487 }
488
489 int input_item_AddOption( input_item_t *p_input, const char *psz_option,
490                           unsigned flags )
491 {
492     int err = VLC_SUCCESS;
493
494     if( psz_option == NULL )
495         return VLC_EGENERIC;
496
497     vlc_mutex_lock( &p_input->lock );
498     if (flags & VLC_INPUT_OPTION_UNIQUE)
499     {
500         for (int i = 0 ; i < p_input->i_options; i++)
501             if( !strcmp( p_input->ppsz_options[i], psz_option ) )
502                 goto out;
503     }
504
505     uint8_t *flagv = realloc (p_input->optflagv, p_input->optflagc + 1);
506     if (flagv == NULL)
507     {
508         err = VLC_ENOMEM;
509         goto out;
510     }
511     p_input->optflagv = flagv;
512     flagv[p_input->optflagc++] = flags;
513
514     INSERT_ELEM( p_input->ppsz_options, p_input->i_options,
515                  p_input->i_options, strdup( psz_option ) );
516 out:
517     vlc_mutex_unlock( &p_input->lock );
518     return err;
519 }
520
521 static info_category_t *InputItemFindCat( input_item_t *p_item,
522                                           int *pi_index, const char *psz_cat )
523 {
524     vlc_assert_locked( &p_item->lock );
525     for( int i = 0; i < p_item->i_categories && psz_cat; i++ )
526     {
527         info_category_t *p_cat = p_item->pp_categories[i];
528
529         if( !strcmp( p_cat->psz_name, psz_cat ) )
530         {
531             if( pi_index )
532                 *pi_index = i;
533             return p_cat;
534         }
535     }
536     return NULL;
537 }
538
539 /**
540  * Get a info item from a given category in a given input item.
541  *
542  * \param p_i The input item to get info from
543  * \param psz_cat String representing the category for the info
544  * \param psz_name String representing the name of the desired info
545  * \return A pointer to the string with the given info if found, or an
546  *         empty string otherwise. The caller should free the returned
547  *         pointer.
548  */
549 char *input_item_GetInfo( input_item_t *p_i,
550                           const char *psz_cat,
551                           const char *psz_name )
552 {
553     vlc_mutex_lock( &p_i->lock );
554
555     const info_category_t *p_cat = InputItemFindCat( p_i, NULL, psz_cat );
556     if( p_cat )
557     {
558         info_t *p_info = info_category_FindInfo( p_cat, NULL, psz_name );
559         if( p_info && p_info->psz_value )
560         {
561             char *psz_ret = strdup( p_info->psz_value );
562             vlc_mutex_unlock( &p_i->lock );
563             return psz_ret;
564         }
565     }
566     vlc_mutex_unlock( &p_i->lock );
567     return strdup( "" );
568 }
569
570 static int InputItemVaAddInfo( input_item_t *p_i,
571                                const char *psz_cat,
572                                const char *psz_name,
573                                const char *psz_format, va_list args )
574 {
575     vlc_assert_locked( &p_i->lock );
576
577     info_category_t *p_cat = InputItemFindCat( p_i, NULL, psz_cat );
578     if( !p_cat )
579     {
580         p_cat = info_category_New( psz_cat );
581         if( !p_cat )
582             return VLC_ENOMEM;
583         INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
584                      p_cat );
585     }
586     info_t *p_info = info_category_VaAddInfo( p_cat, psz_name, psz_format, args );
587     if( !p_info || !p_info->psz_value )
588         return VLC_EGENERIC;
589     return VLC_SUCCESS;
590 }
591
592 static int InputItemAddInfo( input_item_t *p_i,
593                              const char *psz_cat,
594                              const char *psz_name,
595                              const char *psz_format, ... )
596 {
597     va_list args;
598
599     va_start( args, psz_format );
600     const int i_ret = InputItemVaAddInfo( p_i, psz_cat, psz_name, psz_format, args );
601     va_end( args );
602
603     return i_ret;
604 }
605
606 int input_item_AddInfo( input_item_t *p_i,
607                         const char *psz_cat,
608                         const char *psz_name,
609                         const char *psz_format, ... )
610 {
611     va_list args;
612
613     vlc_mutex_lock( &p_i->lock );
614
615     va_start( args, psz_format );
616     const int i_ret = InputItemVaAddInfo( p_i, psz_cat, psz_name, psz_format, args );
617     va_end( args );
618
619     vlc_mutex_unlock( &p_i->lock );
620
621
622     if( !i_ret )
623     {
624         vlc_event_t event;
625
626         event.type = vlc_InputItemInfoChanged;
627         vlc_event_send( &p_i->event_manager, &event );
628     }
629     return i_ret;
630 }
631
632 int input_item_DelInfo( input_item_t *p_i,
633                         const char *psz_cat,
634                         const char *psz_name )
635 {
636     vlc_mutex_lock( &p_i->lock );
637     int i_cat;
638     info_category_t *p_cat = InputItemFindCat( p_i, &i_cat, psz_cat );
639     if( !p_cat )
640     {
641         vlc_mutex_unlock( &p_i->lock );
642         return VLC_EGENERIC;
643     }
644
645     if( psz_name )
646     {
647         /* Remove a specific info */
648         int i_ret = info_category_DeleteInfo( p_cat, psz_name );
649         if( i_ret )
650         {
651             vlc_mutex_unlock( &p_i->lock );
652             return VLC_EGENERIC;
653         }
654     }
655     else
656     {
657         /* Remove the complete categorie */
658         info_category_Delete( p_cat );
659         REMOVE_ELEM( p_i->pp_categories, p_i->i_categories, i_cat );
660     }
661     vlc_mutex_unlock( &p_i->lock );
662
663
664     vlc_event_t event;
665     event.type = vlc_InputItemInfoChanged;
666     vlc_event_send( &p_i->event_manager, &event );
667
668     return VLC_SUCCESS;
669 }
670 void input_item_ReplaceInfos( input_item_t *p_item, info_category_t *p_cat )
671 {
672     vlc_mutex_lock( &p_item->lock );
673     int i_cat;
674     info_category_t *p_old = InputItemFindCat( p_item, &i_cat, p_cat->psz_name );
675     if( p_old )
676     {
677         info_category_Delete( p_old );
678         p_item->pp_categories[i_cat] = p_cat;
679     }
680     else
681     {
682         INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories,
683                      p_cat );
684     }
685     vlc_mutex_unlock( &p_item->lock );
686
687
688     vlc_event_t event;
689     event.type = vlc_InputItemInfoChanged;
690     vlc_event_send( &p_item->event_manager, &event );
691 }
692 void input_item_MergeInfos( input_item_t *p_item, info_category_t *p_cat )
693 {
694     vlc_mutex_lock( &p_item->lock );
695     info_category_t *p_old = InputItemFindCat( p_item, NULL, p_cat->psz_name );
696     if( p_old )
697     {
698         for( int i = 0; i < p_cat->i_infos; i++ )
699             info_category_ReplaceInfo( p_old, p_cat->pp_infos[i] );
700         TAB_CLEAN( p_cat->i_infos, p_cat->pp_infos );
701         info_category_Delete( p_cat );
702     }
703     else
704     {
705         INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories,
706                      p_cat );
707     }
708     vlc_mutex_unlock( &p_item->lock );
709
710
711     vlc_event_t event;
712     event.type = vlc_InputItemInfoChanged;
713     vlc_event_send( &p_item->event_manager, &event );
714 }
715
716 #define EPG_DEBUG
717 void input_item_SetEpg( input_item_t *p_item, const vlc_epg_t *p_update )
718 {
719     vlc_mutex_lock( &p_item->lock );
720
721     /* */
722     vlc_epg_t *p_epg = NULL;
723     for( int i = 0; i < p_item->i_epg; i++ )
724     {
725         vlc_epg_t *p_tmp = p_item->pp_epg[i];
726
727         if( (p_tmp->psz_name == NULL) != (p_update->psz_name == NULL) )
728             continue;
729         if( p_tmp->psz_name && p_update->psz_name && strcmp(p_tmp->psz_name, p_update->psz_name) )
730             continue;
731
732         p_epg = p_tmp;
733         break;
734     }
735
736     /* */
737     if( !p_epg )
738     {
739         p_epg = vlc_epg_New( p_update->psz_name );
740         if( p_epg )
741             TAB_APPEND( p_item->i_epg, p_item->pp_epg, p_epg );
742     }
743     if( p_epg )
744         vlc_epg_Merge( p_epg, p_update );
745
746     vlc_mutex_unlock( &p_item->lock );
747
748     if( !p_epg )
749         return;
750
751 #ifdef EPG_DEBUG
752     char *psz_epg;
753     if( asprintf( &psz_epg, "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 )
754         goto signal;
755
756     input_item_DelInfo( p_item, psz_epg, NULL );
757
758     vlc_mutex_lock( &p_item->lock );
759     for( int i = 0; i < p_epg->i_event; i++ )
760     {
761         const vlc_epg_event_t *p_evt = p_epg->pp_event[i];
762         time_t t_start = (time_t)p_evt->i_start;
763         struct tm tm_start;
764         char psz_start[128];
765
766         localtime_r( &t_start, &tm_start );
767
768         snprintf( psz_start, sizeof(psz_start), "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
769                   1900 + tm_start.tm_year, 1 + tm_start.tm_mon, tm_start.tm_mday,
770                   tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
771         if( p_evt->psz_short_description || p_evt->psz_description )
772             InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s %s",
773                               p_evt->psz_name,
774                               p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
775                               p_evt->psz_short_description ? p_evt->psz_short_description : "" ,
776                               p_evt->psz_description ? p_evt->psz_description : "" );
777         else
778             InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
779                               p_evt->psz_name,
780                               p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
781     }
782     vlc_mutex_unlock( &p_item->lock );
783     free( psz_epg );
784 signal:
785 #endif
786
787     if( p_epg->i_event > 0 )
788     {
789         vlc_event_t event = { .type = vlc_InputItemInfoChanged, };
790         vlc_event_send( &p_item->event_manager, &event );
791     }
792 }
793
794 void input_item_SetEpgOffline( input_item_t *p_item )
795 {
796     vlc_mutex_lock( &p_item->lock );
797     for( int i = 0; i < p_item->i_epg; i++ )
798         vlc_epg_SetCurrent( p_item->pp_epg[i], -1 );
799     vlc_mutex_unlock( &p_item->lock );
800
801 #ifdef EPG_DEBUG
802     vlc_mutex_lock( &p_item->lock );
803     const int i_epg_info = p_item->i_epg;
804     if( i_epg_info > 0 )
805     {
806         char *ppsz_epg_info[i_epg_info];
807         for( int i = 0; i < p_item->i_epg; i++ )
808         {
809             const vlc_epg_t *p_epg = p_item->pp_epg[i];
810             if( asprintf( &ppsz_epg_info[i], "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 )
811                 ppsz_epg_info[i] = NULL;
812         }
813         vlc_mutex_unlock( &p_item->lock );
814
815         for( int i = 0; i < i_epg_info; i++ )
816         {
817             if( !ppsz_epg_info[i] )
818                 continue;
819             input_item_DelInfo( p_item, ppsz_epg_info[i], NULL );
820             free( ppsz_epg_info[i] );
821         }
822     }
823     else
824         vlc_mutex_unlock( &p_item->lock );
825 #endif
826
827     vlc_event_t event = { .type = vlc_InputItemInfoChanged, };
828     vlc_event_send( &p_item->event_manager, &event );
829 }
830
831 input_item_t *input_item_NewExt( const char *psz_uri,
832                                  const char *psz_name,
833                                  int i_options,
834                                  const char *const *ppsz_options,
835                                  unsigned i_option_flags,
836                                  mtime_t i_duration )
837 {
838     return input_item_NewWithType( psz_uri, psz_name,
839                                   i_options, ppsz_options, i_option_flags,
840                                   i_duration, ITEM_TYPE_UNKNOWN );
841 }
842
843
844 input_item_t *
845 input_item_NewWithTypeExt( const char *psz_uri, const char *psz_name,
846                            int i_options, const char *const *ppsz_options,
847                            unsigned flags, mtime_t duration, int type,
848                            int i_net )
849 {
850     static atomic_uint last_input_id = ATOMIC_VAR_INIT(0);
851
852     input_item_owner_t *owner = calloc( 1, sizeof( *owner ) );
853     if( unlikely(owner == NULL) )
854         return NULL;
855
856     atomic_init( &owner->refs, 1 );
857
858     input_item_t *p_input = &owner->item;
859     vlc_event_manager_t * p_em = &p_input->event_manager;
860
861     p_input->i_id = atomic_fetch_add(&last_input_id, 1);
862     vlc_mutex_init( &p_input->lock );
863
864     p_input->psz_name = NULL;
865     if( psz_name )
866         input_item_SetName( p_input, psz_name );
867
868     p_input->psz_uri = NULL;
869     if( psz_uri )
870         input_item_SetURI( p_input, psz_uri );
871     else
872         p_input->i_type = ITEM_TYPE_UNKNOWN;
873
874     TAB_INIT( p_input->i_options, p_input->ppsz_options );
875     p_input->optflagc = 0;
876     p_input->optflagv = NULL;
877     for( int i = 0; i < i_options; i++ )
878         input_item_AddOption( p_input, ppsz_options[i], flags );
879
880     p_input->i_duration = duration;
881     TAB_INIT( p_input->i_categories, p_input->pp_categories );
882     TAB_INIT( p_input->i_es, p_input->es );
883     p_input->p_stats = NULL;
884     p_input->p_meta = NULL;
885     TAB_INIT( p_input->i_epg, p_input->pp_epg );
886
887     vlc_event_manager_init( p_em, p_input );
888     vlc_event_manager_register_event_type( p_em, vlc_InputItemMetaChanged );
889     vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemAdded );
890     vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemTreeAdded );
891     vlc_event_manager_register_event_type( p_em, vlc_InputItemDurationChanged );
892     vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparsedChanged );
893     vlc_event_manager_register_event_type( p_em, vlc_InputItemNameChanged );
894     vlc_event_manager_register_event_type( p_em, vlc_InputItemInfoChanged );
895     vlc_event_manager_register_event_type( p_em, vlc_InputItemErrorWhenReadingChanged );
896     vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparseEnded );
897
898     if( type != ITEM_TYPE_UNKNOWN )
899         p_input->i_type = type;
900     p_input->b_error_when_reading = false;
901
902     if( i_net != -1 )
903         p_input->b_net = !!i_net;
904     else if( p_input->i_type == ITEM_TYPE_STREAM )
905         p_input->b_net = true;
906     return p_input;
907 }
908
909 input_item_t *
910 input_item_NewWithType( const char *psz_uri, const char *psz_name,
911                         int i_options, const char *const *ppsz_options,
912                         unsigned flags, mtime_t duration, int type )
913 {
914     return input_item_NewWithTypeExt( psz_uri, psz_name, i_options,
915                                       ppsz_options, flags, duration, type,
916                                       -1 );
917 }
918
919 input_item_t *input_item_Copy( input_item_t *p_input )
920 {
921     vlc_mutex_lock( &p_input->lock );
922
923     input_item_t *p_new_input =
924         input_item_NewWithType( p_input->psz_uri, p_input->psz_name,
925                                 0, NULL, 0, p_input->i_duration,
926                                 p_input->i_type );
927
928     if( p_new_input )
929     {
930         for( int i = 0 ; i< p_input->i_options; i++ )
931         {
932             input_item_AddOption( p_new_input,
933                                   p_input->ppsz_options[i],
934                                   p_input->optflagv[i] );
935         }
936
937         if( p_input->p_meta )
938         {
939             p_new_input->p_meta = vlc_meta_New();
940             vlc_meta_Merge( p_new_input->p_meta, p_input->p_meta );
941         }
942     }
943
944     vlc_mutex_unlock( &p_input->lock );
945
946     return p_new_input;
947 }
948
949 struct item_type_entry
950 {
951     const char psz_scheme[7];
952     uint8_t    i_type;
953     bool       b_net;
954 };
955
956 static int typecmp( const void *key, const void *entry )
957 {
958     const struct item_type_entry *type = entry;
959     const char *uri = key, *scheme = type->psz_scheme;
960
961     return strncmp( uri, scheme, strlen( scheme ) );
962 }
963
964 /* Guess the type of the item using the beginning of the mrl */
965 static int GuessType( const input_item_t *p_item, bool *p_net )
966 {
967     static const struct item_type_entry tab[] =
968     {   /* /!\ Alphabetical order /!\ */
969         /* Short match work, not just exact match */
970         { "alsa",   ITEM_TYPE_CARD, false },
971         { "atsc",   ITEM_TYPE_CARD, false },
972         { "bluray", ITEM_TYPE_DISC, false },
973         { "bd",     ITEM_TYPE_DISC, false },
974         { "cable",  ITEM_TYPE_CARD, false },
975         { "cdda",   ITEM_TYPE_DISC, false },
976         { "cqam",   ITEM_TYPE_CARD, false },
977         { "dc1394", ITEM_TYPE_CARD, false },
978         { "dccp",   ITEM_TYPE_STREAM, true },
979         { "deckli", ITEM_TYPE_CARD, false }, /* decklink */
980         { "dir",    ITEM_TYPE_DIRECTORY, false },
981         { "dshow",  ITEM_TYPE_CARD, false },
982         { "dv",     ITEM_TYPE_CARD, false },
983         { "dvb",    ITEM_TYPE_CARD, false },
984         { "dvd",    ITEM_TYPE_DISC, false },
985         { "dtv",    ITEM_TYPE_CARD, false },
986         { "eyetv",  ITEM_TYPE_CARD, false },
987         { "fd",     ITEM_TYPE_UNKNOWN, false },
988         { "ftp",    ITEM_TYPE_FILE, true },
989         { "http",   ITEM_TYPE_FILE, true },
990         { "icyx",   ITEM_TYPE_STREAM, true },
991         { "imem",   ITEM_TYPE_UNKNOWN, false },
992         { "itpc",   ITEM_TYPE_PLAYLIST, true },
993         { "jack",   ITEM_TYPE_CARD, false },
994         { "linsys", ITEM_TYPE_CARD, false },
995         { "live",   ITEM_TYPE_STREAM, true }, /* livedotcom */
996         { "mms",    ITEM_TYPE_STREAM, true },
997         { "mtp",    ITEM_TYPE_DISC, false },
998         { "ofdm",   ITEM_TYPE_CARD, false },
999         { "oss",    ITEM_TYPE_CARD, false },
1000         { "pnm",    ITEM_TYPE_STREAM, true },
1001         { "qam",    ITEM_TYPE_CARD, false },
1002         { "qpsk",   ITEM_TYPE_CARD, false },
1003         { "qtcapt", ITEM_TYPE_CARD, false }, /* qtcapture */
1004         { "raw139", ITEM_TYPE_CARD, false }, /* raw1394 */
1005         { "rt",     ITEM_TYPE_STREAM, true }, /* rtp, rtsp, rtmp */
1006         { "satell", ITEM_TYPE_CARD, false }, /* sattelite */
1007         { "screen", ITEM_TYPE_CARD, false },
1008         { "sdp",    ITEM_TYPE_STREAM, true },
1009         { "sftp",   ITEM_TYPE_FILE, true },
1010         { "shm",    ITEM_TYPE_CARD, false },
1011         { "smb",    ITEM_TYPE_FILE, true },
1012         { "svcd",   ITEM_TYPE_DISC, false },
1013         { "tcp",    ITEM_TYPE_STREAM, true },
1014         { "terres", ITEM_TYPE_CARD, false }, /* terrestrial */
1015         { "udp",    ITEM_TYPE_STREAM, true },  /* udplite too */
1016         { "unsv",   ITEM_TYPE_STREAM, true },
1017         { "usdigi", ITEM_TYPE_CARD, false }, /* usdigital */
1018         { "v4l",    ITEM_TYPE_CARD, false },
1019         { "vcd",    ITEM_TYPE_DISC, false },
1020         { "window", ITEM_TYPE_CARD, false },
1021     };
1022     const struct item_type_entry *e;
1023
1024     if( !strstr( p_item->psz_uri, "://" ) )
1025         return ITEM_TYPE_FILE;
1026
1027     e = bsearch( p_item->psz_uri, tab, sizeof( tab ) / sizeof( tab[0] ),
1028                  sizeof( tab[0] ), typecmp );
1029     if( e )
1030     {
1031         *p_net = e->b_net;
1032         return e->i_type;
1033     } else
1034     {
1035         *p_net = false;
1036         return ITEM_TYPE_FILE;
1037     }
1038 }
1039
1040 input_item_node_t *input_item_node_Create( input_item_t *p_input )
1041 {
1042     input_item_node_t* p_node = malloc( sizeof( input_item_node_t ) );
1043     if( !p_node )
1044         return NULL;
1045
1046     assert( p_input );
1047
1048     p_node->p_item = p_input;
1049     vlc_gc_incref( p_input );
1050
1051     p_node->p_parent = NULL;
1052     p_node->i_children = 0;
1053     p_node->pp_children = NULL;
1054
1055     return p_node;
1056 }
1057
1058 static void RecursiveNodeDelete( input_item_node_t *p_node )
1059 {
1060     for( int i = 0; i < p_node->i_children; i++ )
1061         RecursiveNodeDelete( p_node->pp_children[i] );
1062
1063     vlc_gc_decref( p_node->p_item );
1064     free( p_node->pp_children );
1065     free( p_node );
1066 }
1067
1068 void input_item_node_Delete( input_item_node_t *p_node )
1069 {
1070     if( p_node->p_parent )
1071         for( int i = 0; i < p_node->p_parent->i_children; i++ )
1072             if( p_node->p_parent->pp_children[i] == p_node )
1073             {
1074                 REMOVE_ELEM( p_node->p_parent->pp_children,
1075                         p_node->p_parent->i_children,
1076                         i );
1077                 break;
1078             }
1079
1080     RecursiveNodeDelete( p_node );
1081 }
1082
1083 input_item_node_t *input_item_node_AppendItem( input_item_node_t *p_node, input_item_t *p_item )
1084 {
1085     int i_preparse_depth;
1086     input_item_node_t *p_new_child = input_item_node_Create( p_item );
1087     if( !p_new_child ) return NULL;
1088
1089     vlc_mutex_lock( &p_node->p_item->lock );
1090     vlc_mutex_lock( &p_item->lock );
1091     i_preparse_depth = p_node->p_item->i_preparse_depth;
1092     p_item->i_preparse_depth = i_preparse_depth > 0 ?
1093                                i_preparse_depth -1 :
1094                                i_preparse_depth;
1095     vlc_mutex_unlock( &p_item->lock );
1096     vlc_mutex_unlock( &p_node->p_item->lock );
1097
1098     input_item_node_AppendNode( p_node, p_new_child );
1099     return p_new_child;
1100 }
1101
1102 void input_item_node_AppendNode( input_item_node_t *p_parent, input_item_node_t *p_child )
1103 {
1104     assert( p_parent && p_child && p_child->p_parent == NULL );
1105     INSERT_ELEM( p_parent->pp_children,
1106                  p_parent->i_children,
1107                  p_parent->i_children,
1108                  p_child );
1109     p_child->p_parent = p_parent;
1110 }
1111
1112 void input_item_node_PostAndDelete( input_item_node_t *p_root )
1113 {
1114     post_subitems( p_root );
1115
1116     vlc_event_t event;
1117     event.type = vlc_InputItemSubItemTreeAdded;
1118     event.u.input_item_subitem_tree_added.p_root = p_root;
1119     vlc_event_send( &p_root->p_item->event_manager, &event );
1120
1121     input_item_node_Delete( p_root );
1122 }
1123
1124 /* Called by es_out when a new Elementary Stream is added or updated. */
1125 void input_item_UpdateTracksInfo(input_item_t *item, const es_format_t *fmt)
1126 {
1127     int i;
1128     es_format_t *fmt_copy = malloc(sizeof *fmt_copy);
1129     if (!fmt_copy)
1130         return;
1131
1132     es_format_Copy(fmt_copy, fmt);
1133     /* XXX: we could free p_extra to save memory, we will likely not need
1134      * the decoder specific data */
1135
1136     vlc_mutex_lock( &item->lock );
1137
1138     for( i = 0; i < item->i_es; i++ )
1139     {
1140         if (item->es[i]->i_id != fmt->i_id)
1141             continue;
1142
1143         /* We've found the right ES, replace it */
1144         es_format_Clean(item->es[i]);
1145         free(item->es[i]);
1146         item->es[i] = fmt_copy;
1147         vlc_mutex_unlock( &item->lock );
1148         return;
1149     }
1150
1151     /* ES not found, insert it */
1152     TAB_APPEND(item->i_es, item->es, fmt_copy);
1153     vlc_mutex_unlock( &item->lock );
1154 }