1 /*****************************************************************************
2 * item.c: input_item management
3 *****************************************************************************
4 * Copyright (C) 1998-2004 VLC authors and VideoLAN
7 * Authors: Clément Stenac <zorglub@videolan.org>
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.
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.
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 *****************************************************************************/
30 #include <vlc_common.h>
32 #include <vlc_interface.h>
33 #include <vlc_charset.h>
38 struct input_item_opaque
40 struct input_item_opaque *next;
45 static int GuessType( const input_item_t *p_item, bool *p_net );
47 void input_item_SetErrorWhenReading( input_item_t *p_i, bool b_error )
51 vlc_mutex_lock( &p_i->lock );
53 b_changed = p_i->b_error_when_reading != b_error;
54 p_i->b_error_when_reading = b_error;
56 vlc_mutex_unlock( &p_i->lock );
62 event.type = vlc_InputItemErrorWhenReadingChanged;
63 event.u.input_item_error_when_reading_changed.new_value = b_error;
64 vlc_event_send( &p_i->event_manager, &event );
67 void input_item_SignalPreparseEnded( input_item_t *p_i )
70 event.type = vlc_InputItemPreparseEnded;
71 vlc_event_send( &p_i->event_manager, &event );
74 void input_item_SetPreparsed( input_item_t *p_i, bool b_preparsed )
76 bool b_send_event = false;
78 vlc_mutex_lock( &p_i->lock );
81 p_i->p_meta = vlc_meta_New();
83 int status = vlc_meta_GetStatus(p_i->p_meta);
86 new_status = status | ITEM_PREPARSED;
88 new_status = status & ~ITEM_PREPARSED;
89 if( status != new_status )
91 vlc_meta_SetStatus(p_i->p_meta, new_status);
95 vlc_mutex_unlock( &p_i->lock );
100 event.type = vlc_InputItemPreparsedChanged;
101 event.u.input_item_preparsed_changed.new_status = new_status;
102 vlc_event_send( &p_i->event_manager, &event );
106 void input_item_SetArtNotFound( input_item_t *p_i, bool b_not_found )
108 vlc_mutex_lock( &p_i->lock );
111 p_i->p_meta = vlc_meta_New();
113 int status = vlc_meta_GetStatus(p_i->p_meta);
116 status |= ITEM_ART_NOTFOUND;
118 status &= ~ITEM_ART_NOTFOUND;
120 vlc_meta_SetStatus(p_i->p_meta, status);
122 vlc_mutex_unlock( &p_i->lock );
125 void input_item_SetArtFetched( input_item_t *p_i, bool b_art_fetched )
127 vlc_mutex_lock( &p_i->lock );
130 p_i->p_meta = vlc_meta_New();
132 int status = vlc_meta_GetStatus(p_i->p_meta);
135 status |= ITEM_ART_FETCHED;
137 status &= ~ITEM_ART_FETCHED;
139 vlc_meta_SetStatus(p_i->p_meta, status);
141 vlc_mutex_unlock( &p_i->lock );
144 void input_item_SetMeta( input_item_t *p_i, vlc_meta_type_t meta_type, const char *psz_val )
148 vlc_mutex_lock( &p_i->lock );
150 p_i->p_meta = vlc_meta_New();
151 vlc_meta_Set( p_i->p_meta, meta_type, psz_val );
152 vlc_mutex_unlock( &p_i->lock );
154 /* Notify interested third parties */
155 event.type = vlc_InputItemMetaChanged;
156 event.u.input_item_meta_changed.meta_type = meta_type;
157 vlc_event_send( &p_i->event_manager, &event );
160 /* FIXME GRRRRRRRRRR args should be in the reverse order to be
161 * consistent with (nearly?) all or copy funcs */
162 void input_item_CopyOptions( input_item_t *p_parent,
163 input_item_t *p_child )
165 vlc_mutex_lock( &p_parent->lock );
167 for( int i = 0 ; i< p_parent->i_options; i++ )
169 if( !strcmp( p_parent->ppsz_options[i], "meta-file" ) )
172 input_item_AddOption( p_child,
173 p_parent->ppsz_options[i],
174 p_parent->optflagv[i] );
177 vlc_mutex_unlock( &p_parent->lock );
180 static void post_subitems( input_item_node_t *p_node )
182 for( int i = 0; i < p_node->i_children; i++ )
185 event.type = vlc_InputItemSubItemAdded;
186 event.u.input_item_subitem_added.p_new_child = p_node->pp_children[i]->p_item;
187 vlc_event_send( &p_node->p_item->event_manager, &event );
189 post_subitems( p_node->pp_children[i] );
193 /* This won't hold the item, but can tell to interested third parties
194 * Like the playlist, that there is a new sub item. With this design
195 * It is not the input item's responsability to keep all the ref of
196 * the input item children. */
197 void input_item_PostSubItem( input_item_t *p_parent, input_item_t *p_child )
199 input_item_node_t *p_node = input_item_node_Create( p_parent );
200 input_item_node_AppendItem( p_node, p_child );
201 input_item_node_PostAndDelete( p_node );
204 bool input_item_HasErrorWhenReading( input_item_t *p_item )
206 vlc_mutex_lock( &p_item->lock );
208 bool b_error = p_item->b_error_when_reading;
210 vlc_mutex_unlock( &p_item->lock );
215 bool input_item_MetaMatch( input_item_t *p_i,
216 vlc_meta_type_t meta_type, const char *psz )
218 vlc_mutex_lock( &p_i->lock );
222 vlc_mutex_unlock( &p_i->lock );
225 const char *psz_meta = vlc_meta_Get( p_i->p_meta, meta_type );
226 bool b_ret = psz_meta && strcasestr( psz_meta, psz );
228 vlc_mutex_unlock( &p_i->lock );
233 char *input_item_GetMeta( input_item_t *p_i, vlc_meta_type_t meta_type )
235 vlc_mutex_lock( &p_i->lock );
239 vlc_mutex_unlock( &p_i->lock );
244 if( vlc_meta_Get( p_i->p_meta, meta_type ) )
245 psz = strdup( vlc_meta_Get( p_i->p_meta, meta_type ) );
247 vlc_mutex_unlock( &p_i->lock );
251 /* Get the title of a given item or fallback to the name if the title is empty */
252 char *input_item_GetTitleFbName( input_item_t *p_item )
255 vlc_mutex_lock( &p_item->lock );
257 if( !p_item->p_meta )
259 psz_ret = p_item->psz_name ? strdup( p_item->psz_name ) : NULL;
260 vlc_mutex_unlock( &p_item->lock );
264 const char *psz_title = vlc_meta_Get( p_item->p_meta, vlc_meta_Title );
265 if( !EMPTY_STR( psz_title ) )
266 psz_ret = strdup( psz_title );
268 psz_ret = p_item->psz_name ? strdup( p_item->psz_name ) : NULL;
270 vlc_mutex_unlock( &p_item->lock );
274 char *input_item_GetName( input_item_t *p_item )
276 vlc_mutex_lock( &p_item->lock );
278 char *psz_name = p_item->psz_name ? strdup( p_item->psz_name ) : NULL;
280 vlc_mutex_unlock( &p_item->lock );
283 void input_item_SetName( input_item_t *p_item, const char *psz_name )
285 vlc_mutex_lock( &p_item->lock );
287 free( p_item->psz_name );
288 p_item->psz_name = strdup( psz_name );
290 vlc_mutex_unlock( &p_item->lock );
293 char *input_item_GetURI( input_item_t *p_i )
295 vlc_mutex_lock( &p_i->lock );
297 char *psz_s = p_i->psz_uri ? strdup( p_i->psz_uri ) : NULL;
299 vlc_mutex_unlock( &p_i->lock );
303 void input_item_SetURI( input_item_t *p_i, const char *psz_uri )
307 if( !strstr( psz_uri, "://" )
308 || strchr( psz_uri, ' ' ) || strchr( psz_uri, '"' ) )
309 fprintf( stderr, "Warning: %s(\"%s\"): file path instead of URL.\n",
312 vlc_mutex_lock( &p_i->lock );
313 free( p_i->psz_uri );
314 p_i->psz_uri = strdup( psz_uri );
316 p_i->i_type = GuessType( p_i, &p_i->b_net );
321 if( p_i->i_type == ITEM_TYPE_FILE || p_i->i_type == ITEM_TYPE_DIRECTORY )
323 const char *psz_filename = strrchr( p_i->psz_uri, '/' );
325 if( psz_filename && *psz_filename == '/' )
327 if( psz_filename && *psz_filename )
328 p_i->psz_name = strdup( psz_filename );
330 /* Make the name more readable */
333 decode_URI( p_i->psz_name );
334 EnsureUTF8( p_i->psz_name );
338 { /* Strip login and password from title */
342 vlc_UrlParse( &url, psz_uri );
343 if( url.psz_protocol )
346 r=asprintf( &p_i->psz_name, "%s://%s:%d%s", url.psz_protocol,
347 url.psz_host, url.i_port,
348 url.psz_path ? url.psz_path : "" );
350 r=asprintf( &p_i->psz_name, "%s://%s%s", url.psz_protocol,
351 url.psz_host ? url.psz_host : "",
352 url.psz_path ? url.psz_path : "" );
357 r=asprintf( &p_i->psz_name, "%s:%d%s", url.psz_host, url.i_port,
358 url.psz_path ? url.psz_path : "" );
360 r=asprintf( &p_i->psz_name, "%s%s", url.psz_host,
361 url.psz_path ? url.psz_path : "" );
363 vlc_UrlClean( &url );
365 p_i->psz_name=NULL; /* recover from undefined value */
368 vlc_mutex_unlock( &p_i->lock );
371 mtime_t input_item_GetDuration( input_item_t *p_i )
373 vlc_mutex_lock( &p_i->lock );
375 mtime_t i_duration = p_i->i_duration;
377 vlc_mutex_unlock( &p_i->lock );
381 void input_item_SetDuration( input_item_t *p_i, mtime_t i_duration )
383 bool b_send_event = false;
385 vlc_mutex_lock( &p_i->lock );
386 if( p_i->i_duration != i_duration )
388 p_i->i_duration = i_duration;
391 vlc_mutex_unlock( &p_i->lock );
397 event.type = vlc_InputItemDurationChanged;
398 event.u.input_item_duration_changed.new_duration = i_duration;
399 vlc_event_send( &p_i->event_manager, &event );
403 char *input_item_GetNowPlayingFb( input_item_t *p_item )
405 char *psz_meta = input_item_GetMeta( p_item, vlc_meta_NowPlaying );
406 if( !psz_meta || strlen( psz_meta ) == 0 )
409 return input_item_GetMeta( p_item, vlc_meta_ESNowPlaying );
415 bool input_item_IsPreparsed( input_item_t *p_item )
417 vlc_mutex_lock( &p_item->lock );
418 bool b_preparsed = p_item->p_meta ? ( vlc_meta_GetStatus(p_item->p_meta) & ITEM_PREPARSED ) != 0 : false;
419 vlc_mutex_unlock( &p_item->lock );
424 bool input_item_IsArtFetched( input_item_t *p_item )
426 vlc_mutex_lock( &p_item->lock );
427 bool b_fetched = p_item->p_meta ? ( vlc_meta_GetStatus(p_item->p_meta) & ITEM_ART_FETCHED ) != 0 : false;
428 vlc_mutex_unlock( &p_item->lock );
433 bool input_item_ShouldPreparseSubItems( input_item_t *p_item )
437 vlc_mutex_lock( &p_item->lock );
438 b_ret = p_item->i_preparse_depth == -1 ? true : p_item->i_preparse_depth > 0;
439 vlc_mutex_unlock( &p_item->lock );
444 input_item_t *input_item_Hold( input_item_t *p_item )
446 input_item_owner_t *owner = item_owner(p_item);
448 atomic_fetch_add( &owner->refs, 1 );
452 void input_item_Release( input_item_t *p_item )
454 input_item_owner_t *owner = item_owner(p_item);
456 if( atomic_fetch_sub(&owner->refs, 1) != 1 )
459 vlc_event_manager_fini( &p_item->event_manager );
461 free( p_item->psz_name );
462 free( p_item->psz_uri );
463 if( p_item->p_stats != NULL )
465 vlc_mutex_destroy( &p_item->p_stats->lock );
466 free( p_item->p_stats );
469 if( p_item->p_meta != NULL )
470 vlc_meta_Delete( p_item->p_meta );
472 for( input_item_opaque_t *o = p_item->opaques, *next; o != NULL; o = next )
478 for( int i = 0; i < p_item->i_options; i++ )
479 free( p_item->ppsz_options[i] );
480 TAB_CLEAN( p_item->i_options, p_item->ppsz_options );
481 free( p_item->optflagv );
483 for( int i = 0; i < p_item->i_es; i++ )
485 es_format_Clean( p_item->es[i] );
486 free( p_item->es[i] );
488 TAB_CLEAN( p_item->i_es, p_item->es );
490 for( int i = 0; i < p_item->i_epg; i++ )
491 vlc_epg_Delete( p_item->pp_epg[i] );
492 TAB_CLEAN( p_item->i_epg, p_item->pp_epg );
494 for( int i = 0; i < p_item->i_categories; i++ )
495 info_category_Delete( p_item->pp_categories[i] );
496 TAB_CLEAN( p_item->i_categories, p_item->pp_categories );
498 vlc_mutex_destroy( &p_item->lock );
502 int input_item_AddOption( input_item_t *p_input, const char *psz_option,
505 int err = VLC_SUCCESS;
507 if( psz_option == NULL )
510 vlc_mutex_lock( &p_input->lock );
511 if (flags & VLC_INPUT_OPTION_UNIQUE)
513 for (int i = 0 ; i < p_input->i_options; i++)
514 if( !strcmp( p_input->ppsz_options[i], psz_option ) )
518 uint8_t *flagv = realloc (p_input->optflagv, p_input->optflagc + 1);
524 p_input->optflagv = flagv;
525 flagv[p_input->optflagc++] = flags;
527 INSERT_ELEM( p_input->ppsz_options, p_input->i_options,
528 p_input->i_options, strdup( psz_option ) );
530 vlc_mutex_unlock( &p_input->lock );
534 int input_item_AddOpaque(input_item_t *item, const char *name, void *value)
536 assert(name != NULL);
538 size_t namelen = strlen(name);
539 input_item_opaque_t *entry = malloc(sizeof (*entry) + namelen);
540 if (unlikely(entry == NULL))
543 memcpy(entry->name, name, namelen + 1);
544 entry->value = value;
546 vlc_mutex_lock(&item->lock);
547 entry->next = item->opaques;
548 item->opaques = entry;
549 vlc_mutex_unlock(&item->lock);
553 void input_item_ApplyOptions(vlc_object_t *obj, input_item_t *item)
555 vlc_mutex_lock(&item->lock);
556 assert(item->optflagc == (unsigned)item->i_options);
558 for (unsigned i = 0; i < (unsigned)item->i_options; i++)
559 var_OptionParse(obj, item->ppsz_options[i],
560 !!(item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED));
562 for (const input_item_opaque_t *o = item->opaques; o != NULL; o = o->next)
564 var_Create(obj, o->name, VLC_VAR_ADDRESS);
565 var_SetAddress(obj, o->name, o->value);
568 vlc_mutex_unlock(&item->lock);
571 static info_category_t *InputItemFindCat( input_item_t *p_item,
572 int *pi_index, const char *psz_cat )
574 vlc_assert_locked( &p_item->lock );
575 for( int i = 0; i < p_item->i_categories && psz_cat; i++ )
577 info_category_t *p_cat = p_item->pp_categories[i];
579 if( !strcmp( p_cat->psz_name, psz_cat ) )
590 * Get a info item from a given category in a given input item.
592 * \param p_i The input item to get info from
593 * \param psz_cat String representing the category for the info
594 * \param psz_name String representing the name of the desired info
595 * \return A pointer to the string with the given info if found, or an
596 * empty string otherwise. The caller should free the returned
599 char *input_item_GetInfo( input_item_t *p_i,
601 const char *psz_name )
603 vlc_mutex_lock( &p_i->lock );
605 const info_category_t *p_cat = InputItemFindCat( p_i, NULL, psz_cat );
608 info_t *p_info = info_category_FindInfo( p_cat, NULL, psz_name );
609 if( p_info && p_info->psz_value )
611 char *psz_ret = strdup( p_info->psz_value );
612 vlc_mutex_unlock( &p_i->lock );
616 vlc_mutex_unlock( &p_i->lock );
620 static int InputItemVaAddInfo( input_item_t *p_i,
622 const char *psz_name,
623 const char *psz_format, va_list args )
625 vlc_assert_locked( &p_i->lock );
627 info_category_t *p_cat = InputItemFindCat( p_i, NULL, psz_cat );
630 p_cat = info_category_New( psz_cat );
633 INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
636 info_t *p_info = info_category_VaAddInfo( p_cat, psz_name, psz_format, args );
637 if( !p_info || !p_info->psz_value )
642 static int InputItemAddInfo( input_item_t *p_i,
644 const char *psz_name,
645 const char *psz_format, ... )
649 va_start( args, psz_format );
650 const int i_ret = InputItemVaAddInfo( p_i, psz_cat, psz_name, psz_format, args );
656 int input_item_AddInfo( input_item_t *p_i,
658 const char *psz_name,
659 const char *psz_format, ... )
663 vlc_mutex_lock( &p_i->lock );
665 va_start( args, psz_format );
666 const int i_ret = InputItemVaAddInfo( p_i, psz_cat, psz_name, psz_format, args );
669 vlc_mutex_unlock( &p_i->lock );
676 event.type = vlc_InputItemInfoChanged;
677 vlc_event_send( &p_i->event_manager, &event );
682 int input_item_DelInfo( input_item_t *p_i,
684 const char *psz_name )
686 vlc_mutex_lock( &p_i->lock );
688 info_category_t *p_cat = InputItemFindCat( p_i, &i_cat, psz_cat );
691 vlc_mutex_unlock( &p_i->lock );
697 /* Remove a specific info */
698 int i_ret = info_category_DeleteInfo( p_cat, psz_name );
701 vlc_mutex_unlock( &p_i->lock );
707 /* Remove the complete categorie */
708 info_category_Delete( p_cat );
709 REMOVE_ELEM( p_i->pp_categories, p_i->i_categories, i_cat );
711 vlc_mutex_unlock( &p_i->lock );
715 event.type = vlc_InputItemInfoChanged;
716 vlc_event_send( &p_i->event_manager, &event );
720 void input_item_ReplaceInfos( input_item_t *p_item, info_category_t *p_cat )
722 vlc_mutex_lock( &p_item->lock );
724 info_category_t *p_old = InputItemFindCat( p_item, &i_cat, p_cat->psz_name );
727 info_category_Delete( p_old );
728 p_item->pp_categories[i_cat] = p_cat;
732 INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories,
735 vlc_mutex_unlock( &p_item->lock );
739 event.type = vlc_InputItemInfoChanged;
740 vlc_event_send( &p_item->event_manager, &event );
742 void input_item_MergeInfos( input_item_t *p_item, info_category_t *p_cat )
744 vlc_mutex_lock( &p_item->lock );
745 info_category_t *p_old = InputItemFindCat( p_item, NULL, p_cat->psz_name );
748 for( int i = 0; i < p_cat->i_infos; i++ )
749 info_category_ReplaceInfo( p_old, p_cat->pp_infos[i] );
750 TAB_CLEAN( p_cat->i_infos, p_cat->pp_infos );
751 info_category_Delete( p_cat );
755 INSERT_ELEM( p_item->pp_categories, p_item->i_categories, p_item->i_categories,
758 vlc_mutex_unlock( &p_item->lock );
762 event.type = vlc_InputItemInfoChanged;
763 vlc_event_send( &p_item->event_manager, &event );
767 void input_item_SetEpg( input_item_t *p_item, const vlc_epg_t *p_update )
769 vlc_mutex_lock( &p_item->lock );
772 vlc_epg_t *p_epg = NULL;
773 for( int i = 0; i < p_item->i_epg; i++ )
775 vlc_epg_t *p_tmp = p_item->pp_epg[i];
777 if( (p_tmp->psz_name == NULL) != (p_update->psz_name == NULL) )
779 if( p_tmp->psz_name && p_update->psz_name && strcmp(p_tmp->psz_name, p_update->psz_name) )
789 p_epg = vlc_epg_New( p_update->psz_name );
791 TAB_APPEND( p_item->i_epg, p_item->pp_epg, p_epg );
794 vlc_epg_Merge( p_epg, p_update );
796 vlc_mutex_unlock( &p_item->lock );
803 if( asprintf( &psz_epg, "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 )
806 input_item_DelInfo( p_item, psz_epg, NULL );
808 vlc_mutex_lock( &p_item->lock );
809 for( int i = 0; i < p_epg->i_event; i++ )
811 const vlc_epg_event_t *p_evt = p_epg->pp_event[i];
812 time_t t_start = (time_t)p_evt->i_start;
816 localtime_r( &t_start, &tm_start );
818 snprintf( psz_start, sizeof(psz_start), "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
819 1900 + tm_start.tm_year, 1 + tm_start.tm_mon, tm_start.tm_mday,
820 tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
821 if( p_evt->psz_short_description || p_evt->psz_description )
822 InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s %s",
824 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
825 p_evt->psz_short_description ? p_evt->psz_short_description : "" ,
826 p_evt->psz_description ? p_evt->psz_description : "" );
828 InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
830 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
832 vlc_mutex_unlock( &p_item->lock );
837 if( p_epg->i_event > 0 )
839 vlc_event_t event = { .type = vlc_InputItemInfoChanged, };
840 vlc_event_send( &p_item->event_manager, &event );
844 void input_item_SetEpgOffline( input_item_t *p_item )
846 vlc_mutex_lock( &p_item->lock );
847 for( int i = 0; i < p_item->i_epg; i++ )
848 vlc_epg_SetCurrent( p_item->pp_epg[i], -1 );
849 vlc_mutex_unlock( &p_item->lock );
852 vlc_mutex_lock( &p_item->lock );
853 const int i_epg_info = p_item->i_epg;
856 char *ppsz_epg_info[i_epg_info];
857 for( int i = 0; i < p_item->i_epg; i++ )
859 const vlc_epg_t *p_epg = p_item->pp_epg[i];
860 if( asprintf( &ppsz_epg_info[i], "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 )
861 ppsz_epg_info[i] = NULL;
863 vlc_mutex_unlock( &p_item->lock );
865 for( int i = 0; i < i_epg_info; i++ )
867 if( !ppsz_epg_info[i] )
869 input_item_DelInfo( p_item, ppsz_epg_info[i], NULL );
870 free( ppsz_epg_info[i] );
874 vlc_mutex_unlock( &p_item->lock );
877 vlc_event_t event = { .type = vlc_InputItemInfoChanged, };
878 vlc_event_send( &p_item->event_manager, &event );
881 input_item_t *input_item_NewExt( const char *psz_uri,
882 const char *psz_name,
884 const char *const *ppsz_options,
885 unsigned i_option_flags,
888 return input_item_NewWithType( psz_uri, psz_name,
889 i_options, ppsz_options, i_option_flags,
890 i_duration, ITEM_TYPE_UNKNOWN );
895 input_item_NewWithTypeExt( const char *psz_uri, const char *psz_name,
896 int i_options, const char *const *ppsz_options,
897 unsigned flags, mtime_t duration, int type,
900 static atomic_uint last_input_id = ATOMIC_VAR_INIT(0);
902 input_item_owner_t *owner = calloc( 1, sizeof( *owner ) );
903 if( unlikely(owner == NULL) )
906 atomic_init( &owner->refs, 1 );
908 input_item_t *p_input = &owner->item;
909 vlc_event_manager_t * p_em = &p_input->event_manager;
911 p_input->i_id = atomic_fetch_add(&last_input_id, 1);
912 vlc_mutex_init( &p_input->lock );
914 p_input->psz_name = NULL;
916 input_item_SetName( p_input, psz_name );
918 p_input->psz_uri = NULL;
920 input_item_SetURI( p_input, psz_uri );
922 p_input->i_type = ITEM_TYPE_UNKNOWN;
924 TAB_INIT( p_input->i_options, p_input->ppsz_options );
925 p_input->optflagc = 0;
926 p_input->optflagv = NULL;
927 for( int i = 0; i < i_options; i++ )
928 input_item_AddOption( p_input, ppsz_options[i], flags );
929 p_input->opaques = NULL;
931 p_input->i_duration = duration;
932 TAB_INIT( p_input->i_categories, p_input->pp_categories );
933 TAB_INIT( p_input->i_es, p_input->es );
934 p_input->p_stats = NULL;
935 p_input->p_meta = NULL;
936 TAB_INIT( p_input->i_epg, p_input->pp_epg );
938 vlc_event_manager_init( p_em, p_input );
939 vlc_event_manager_register_event_type( p_em, vlc_InputItemMetaChanged );
940 vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemAdded );
941 vlc_event_manager_register_event_type( p_em, vlc_InputItemSubItemTreeAdded );
942 vlc_event_manager_register_event_type( p_em, vlc_InputItemDurationChanged );
943 vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparsedChanged );
944 vlc_event_manager_register_event_type( p_em, vlc_InputItemNameChanged );
945 vlc_event_manager_register_event_type( p_em, vlc_InputItemInfoChanged );
946 vlc_event_manager_register_event_type( p_em, vlc_InputItemErrorWhenReadingChanged );
947 vlc_event_manager_register_event_type( p_em, vlc_InputItemPreparseEnded );
949 if( type != ITEM_TYPE_UNKNOWN )
950 p_input->i_type = type;
951 p_input->b_error_when_reading = false;
954 p_input->b_net = !!i_net;
955 else if( p_input->i_type == ITEM_TYPE_STREAM )
956 p_input->b_net = true;
961 input_item_NewWithType( const char *psz_uri, const char *psz_name,
962 int i_options, const char *const *ppsz_options,
963 unsigned flags, mtime_t duration, int type )
965 return input_item_NewWithTypeExt( psz_uri, psz_name, i_options,
966 ppsz_options, flags, duration, type,
970 input_item_t *input_item_Copy( input_item_t *p_input )
972 vlc_mutex_lock( &p_input->lock );
974 input_item_t *p_new_input =
975 input_item_NewWithType( p_input->psz_uri, p_input->psz_name,
976 0, NULL, 0, p_input->i_duration,
981 for( int i = 0 ; i< p_input->i_options; i++ )
983 input_item_AddOption( p_new_input,
984 p_input->ppsz_options[i],
985 p_input->optflagv[i] );
988 if( p_input->p_meta )
990 p_new_input->p_meta = vlc_meta_New();
991 vlc_meta_Merge( p_new_input->p_meta, p_input->p_meta );
995 vlc_mutex_unlock( &p_input->lock );
1000 struct item_type_entry
1002 const char psz_scheme[7];
1007 static int typecmp( const void *key, const void *entry )
1009 const struct item_type_entry *type = entry;
1010 const char *uri = key, *scheme = type->psz_scheme;
1012 return strncmp( uri, scheme, strlen( scheme ) );
1015 /* Guess the type of the item using the beginning of the mrl */
1016 static int GuessType( const input_item_t *p_item, bool *p_net )
1018 static const struct item_type_entry tab[] =
1019 { /* /!\ Alphabetical order /!\ */
1020 /* Short match work, not just exact match */
1021 { "alsa", ITEM_TYPE_CARD, false },
1022 { "atsc", ITEM_TYPE_CARD, false },
1023 { "bluray", ITEM_TYPE_DISC, false },
1024 { "bd", ITEM_TYPE_DISC, false },
1025 { "cable", ITEM_TYPE_CARD, false },
1026 { "cdda", ITEM_TYPE_DISC, false },
1027 { "cqam", ITEM_TYPE_CARD, false },
1028 { "dc1394", ITEM_TYPE_CARD, false },
1029 { "dccp", ITEM_TYPE_STREAM, true },
1030 { "deckli", ITEM_TYPE_CARD, false }, /* decklink */
1031 { "dir", ITEM_TYPE_DIRECTORY, false },
1032 { "dshow", ITEM_TYPE_CARD, false },
1033 { "dv", ITEM_TYPE_CARD, false },
1034 { "dvb", ITEM_TYPE_CARD, false },
1035 { "dvd", ITEM_TYPE_DISC, false },
1036 { "dtv", ITEM_TYPE_CARD, false },
1037 { "eyetv", ITEM_TYPE_CARD, false },
1038 { "fd", ITEM_TYPE_UNKNOWN, false },
1039 { "ftp", ITEM_TYPE_FILE, true },
1040 { "http", ITEM_TYPE_FILE, true },
1041 { "icyx", ITEM_TYPE_STREAM, true },
1042 { "imem", ITEM_TYPE_UNKNOWN, false },
1043 { "itpc", ITEM_TYPE_PLAYLIST, true },
1044 { "jack", ITEM_TYPE_CARD, false },
1045 { "linsys", ITEM_TYPE_CARD, false },
1046 { "live", ITEM_TYPE_STREAM, true }, /* livedotcom */
1047 { "mms", ITEM_TYPE_STREAM, true },
1048 { "mtp", ITEM_TYPE_DISC, false },
1049 { "ofdm", ITEM_TYPE_CARD, false },
1050 { "oss", ITEM_TYPE_CARD, false },
1051 { "pnm", ITEM_TYPE_STREAM, true },
1052 { "qam", ITEM_TYPE_CARD, false },
1053 { "qpsk", ITEM_TYPE_CARD, false },
1054 { "qtcapt", ITEM_TYPE_CARD, false }, /* qtcapture */
1055 { "raw139", ITEM_TYPE_CARD, false }, /* raw1394 */
1056 { "rt", ITEM_TYPE_STREAM, true }, /* rtp, rtsp, rtmp */
1057 { "satell", ITEM_TYPE_CARD, false }, /* sattelite */
1058 { "screen", ITEM_TYPE_CARD, false },
1059 { "sdp", ITEM_TYPE_STREAM, true },
1060 { "sftp", ITEM_TYPE_FILE, true },
1061 { "shm", ITEM_TYPE_CARD, false },
1062 { "smb", ITEM_TYPE_FILE, true },
1063 { "svcd", ITEM_TYPE_DISC, false },
1064 { "tcp", ITEM_TYPE_STREAM, true },
1065 { "terres", ITEM_TYPE_CARD, false }, /* terrestrial */
1066 { "udp", ITEM_TYPE_STREAM, true }, /* udplite too */
1067 { "unsv", ITEM_TYPE_STREAM, true },
1068 { "usdigi", ITEM_TYPE_CARD, false }, /* usdigital */
1069 { "v4l", ITEM_TYPE_CARD, false },
1070 { "vcd", ITEM_TYPE_DISC, false },
1071 { "window", ITEM_TYPE_CARD, false },
1073 const struct item_type_entry *e;
1075 if( !strstr( p_item->psz_uri, "://" ) )
1076 return ITEM_TYPE_FILE;
1078 e = bsearch( p_item->psz_uri, tab, sizeof( tab ) / sizeof( tab[0] ),
1079 sizeof( tab[0] ), typecmp );
1087 return ITEM_TYPE_FILE;
1091 input_item_node_t *input_item_node_Create( input_item_t *p_input )
1093 input_item_node_t* p_node = malloc( sizeof( input_item_node_t ) );
1099 p_node->p_item = p_input;
1100 vlc_gc_incref( p_input );
1102 p_node->p_parent = NULL;
1103 p_node->i_children = 0;
1104 p_node->pp_children = NULL;
1105 p_node->b_can_loop = false;
1110 static void RecursiveNodeDelete( input_item_node_t *p_node )
1112 for( int i = 0; i < p_node->i_children; i++ )
1113 RecursiveNodeDelete( p_node->pp_children[i] );
1115 vlc_gc_decref( p_node->p_item );
1116 free( p_node->pp_children );
1120 void input_item_node_Delete( input_item_node_t *p_node )
1122 if( p_node->p_parent )
1123 for( int i = 0; i < p_node->p_parent->i_children; i++ )
1124 if( p_node->p_parent->pp_children[i] == p_node )
1126 REMOVE_ELEM( p_node->p_parent->pp_children,
1127 p_node->p_parent->i_children,
1132 RecursiveNodeDelete( p_node );
1135 input_item_node_t *input_item_node_AppendItem( input_item_node_t *p_node, input_item_t *p_item )
1137 int i_preparse_depth;
1138 input_item_node_t *p_new_child = input_item_node_Create( p_item );
1139 if( !p_new_child ) return NULL;
1141 vlc_mutex_lock( &p_node->p_item->lock );
1142 vlc_mutex_lock( &p_item->lock );
1143 i_preparse_depth = p_node->p_item->i_preparse_depth;
1144 p_item->i_preparse_depth = i_preparse_depth > 0 ?
1145 i_preparse_depth -1 :
1147 vlc_mutex_unlock( &p_item->lock );
1148 vlc_mutex_unlock( &p_node->p_item->lock );
1150 input_item_node_AppendNode( p_node, p_new_child );
1154 void input_item_node_AppendNode( input_item_node_t *p_parent, input_item_node_t *p_child )
1156 assert( p_parent && p_child && p_child->p_parent == NULL );
1157 INSERT_ELEM( p_parent->pp_children,
1158 p_parent->i_children,
1159 p_parent->i_children,
1161 p_child->p_parent = p_parent;
1164 static int compar_node( const void *p1, const void *p2 )
1166 input_item_node_t *p_node1 = *((input_item_node_t **) p1);
1167 input_item_node_t *p_node2 = *((input_item_node_t **) p2);
1169 assert( p_node1->p_parent && p_node1->p_parent == p_node2->p_parent &&
1170 p_node1->p_parent->compar_cb );
1172 input_item_compar_cb compar_cb = p_node1->p_parent->compar_cb;
1173 return compar_cb( p_node1->p_item, p_node2->p_item );
1176 static void sort_subitems( input_item_node_t *p_node,
1177 input_item_compar_cb compar_cb )
1179 if( p_node->i_children <= 0 || !compar_cb )
1182 p_node->compar_cb = compar_cb;
1184 /* Lock first all children. This avoids to lock/unlock them from each
1185 * compar callback call */
1186 for( int i = 0; i < p_node->i_children; i++ )
1187 vlc_mutex_lock( &p_node->pp_children[i]->p_item->lock );
1189 /* Sort current node */
1190 qsort( p_node->pp_children, p_node->i_children,
1191 sizeof(input_item_node_t *), compar_node );
1193 /* Unlock all children */
1194 for( int i = 0; i < p_node->i_children; i++ )
1195 vlc_mutex_unlock( &p_node->pp_children[i]->p_item->lock );
1197 p_node->compar_cb = NULL;
1199 /* Sort all children */
1200 for( int i = 0; i < p_node->i_children; i++ )
1201 sort_subitems( p_node->pp_children[i], compar_cb );
1204 void input_item_node_Sort( input_item_node_t *p_node,
1205 input_item_compar_cb compar_cb )
1207 sort_subitems( p_node, compar_cb );
1210 void input_item_node_PostAndDelete( input_item_node_t *p_root )
1212 post_subitems( p_root );
1215 event.type = vlc_InputItemSubItemTreeAdded;
1216 event.u.input_item_subitem_tree_added.p_root = p_root;
1217 vlc_event_send( &p_root->p_item->event_manager, &event );
1219 input_item_node_Delete( p_root );
1222 /* Called by es_out when a new Elementary Stream is added or updated. */
1223 void input_item_UpdateTracksInfo(input_item_t *item, const es_format_t *fmt)
1226 es_format_t *fmt_copy = malloc(sizeof *fmt_copy);
1230 es_format_Copy(fmt_copy, fmt);
1231 /* XXX: we could free p_extra to save memory, we will likely not need
1232 * the decoder specific data */
1234 vlc_mutex_lock( &item->lock );
1236 for( i = 0; i < item->i_es; i++ )
1238 if (item->es[i]->i_id != fmt->i_id)
1241 /* We've found the right ES, replace it */
1242 es_format_Clean(item->es[i]);
1244 item->es[i] = fmt_copy;
1245 vlc_mutex_unlock( &item->lock );
1249 /* ES not found, insert it */
1250 TAB_APPEND(item->i_es, item->es, fmt_copy);
1251 vlc_mutex_unlock( &item->lock );