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 *****************************************************************************/
31 #include <vlc_common.h>
33 #include <vlc_interface.h>
34 #include <vlc_charset.h>
38 #include "input_internal.h"
40 struct input_item_opaque
42 struct input_item_opaque
*next
;
47 static int GuessType( const input_item_t
*p_item
, bool *p_net
);
49 void input_item_SetErrorWhenReading( input_item_t
*p_i
, bool b_error
)
53 vlc_mutex_lock( &p_i
->lock
);
55 b_changed
= p_i
->b_error_when_reading
!= b_error
;
56 p_i
->b_error_when_reading
= b_error
;
58 vlc_mutex_unlock( &p_i
->lock
);
62 vlc_event_send( &p_i
->event_manager
, &(vlc_event_t
) {
63 .type
= vlc_InputItemErrorWhenReadingChanged
,
64 .u
.input_item_error_when_reading_changed
.new_value
= b_error
} );
67 void input_item_SignalPreparseEnded( input_item_t
*p_i
, int status
)
69 vlc_event_send( &p_i
->event_manager
, &(vlc_event_t
) {
70 .type
= vlc_InputItemPreparseEnded
,
71 .u
.input_item_preparse_ended
.new_status
= status
} );
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
);
99 vlc_event_send( &p_i
->event_manager
, &(vlc_event_t
) {
100 .type
= vlc_InputItemPreparsedChanged
,
101 .u
.input_item_preparsed_changed
.new_status
= new_status
} );
105 void input_item_SetArtNotFound( input_item_t
*p_i
, bool b_not_found
)
107 vlc_mutex_lock( &p_i
->lock
);
110 p_i
->p_meta
= vlc_meta_New();
112 int status
= vlc_meta_GetStatus(p_i
->p_meta
);
115 status
|= ITEM_ART_NOTFOUND
;
117 status
&= ~ITEM_ART_NOTFOUND
;
119 vlc_meta_SetStatus(p_i
->p_meta
, status
);
121 vlc_mutex_unlock( &p_i
->lock
);
124 void input_item_SetArtFetched( input_item_t
*p_i
, bool b_art_fetched
)
126 vlc_mutex_lock( &p_i
->lock
);
129 p_i
->p_meta
= vlc_meta_New();
131 int status
= vlc_meta_GetStatus(p_i
->p_meta
);
134 status
|= ITEM_ART_FETCHED
;
136 status
&= ~ITEM_ART_FETCHED
;
138 vlc_meta_SetStatus(p_i
->p_meta
, status
);
140 vlc_mutex_unlock( &p_i
->lock
);
143 void input_item_SetMeta( input_item_t
*p_i
, vlc_meta_type_t meta_type
, const char *psz_val
)
145 vlc_mutex_lock( &p_i
->lock
);
147 p_i
->p_meta
= vlc_meta_New();
148 vlc_meta_Set( p_i
->p_meta
, meta_type
, psz_val
);
149 vlc_mutex_unlock( &p_i
->lock
);
151 /* Notify interested third parties */
152 vlc_event_send( &p_i
->event_manager
, &(vlc_event_t
) {
153 .type
= vlc_InputItemMetaChanged
,
154 .u
.input_item_meta_changed
.meta_type
= meta_type
} );
157 void input_item_CopyOptions( input_item_t
*p_child
,
158 input_item_t
*p_parent
)
161 uint8_t *flagv
= NULL
;
163 char **optv_realloc
= NULL
;
164 uint8_t *flagv_realloc
= NULL
;
166 vlc_mutex_lock( &p_parent
->lock
);
168 if( p_parent
->i_options
> 0 )
170 optv
= malloc( p_parent
->i_options
* sizeof (*optv
) );
172 flagv
= malloc( p_parent
->i_options
* sizeof (*flagv
) );
176 for( int i
= 0; i
< p_parent
->i_options
; i
++ )
178 char *psz_dup
= strdup( p_parent
->ppsz_options
[i
] );
179 if( likely(psz_dup
) )
181 flagv
[optc
] = p_parent
->optflagv
[i
];
182 optv
[optc
++] = psz_dup
;
188 vlc_mutex_unlock( &p_parent
->lock
);
190 if( likely(optv
&& flagv
&& optc
) )
192 vlc_mutex_lock( &p_child
->lock
);
194 if( INT_MAX
- p_child
->i_options
>= optc
&&
195 SIZE_MAX
/ sizeof (*flagv
) >= (size_t) (p_child
->i_options
+ optc
) )
196 flagv_realloc
= realloc( p_child
->optflagv
,
197 (p_child
->i_options
+ optc
) * sizeof (*flagv
) );
198 if( likely(flagv_realloc
) )
200 p_child
->optflagv
= flagv_realloc
;
201 if( SIZE_MAX
/ sizeof (*optv
) >= (size_t) (p_child
->i_options
+ optc
) )
202 optv_realloc
= realloc( p_child
->ppsz_options
,
203 (p_child
->i_options
+ optc
) * sizeof (*optv
) );
204 if( likely(optv_realloc
) )
206 p_child
->ppsz_options
= optv_realloc
;
207 memcpy( p_child
->ppsz_options
+ p_child
->i_options
, optv
,
208 optc
* sizeof (*optv
) );
209 memcpy( p_child
->optflagv
+ p_child
->i_options
, flagv
,
210 optc
* sizeof (*flagv
) );
211 p_child
->i_options
+= optc
;
212 p_child
->optflagc
+= optc
;
216 vlc_mutex_unlock( &p_child
->lock
);
219 if( unlikely(!flagv_realloc
|| !optv_realloc
) )
221 /* Didn't copy pointers, so need to free the strdup() */
222 for( int i
=0; i
<optc
; i
++ )
230 bool input_item_HasErrorWhenReading( input_item_t
*p_item
)
232 vlc_mutex_lock( &p_item
->lock
);
234 bool b_error
= p_item
->b_error_when_reading
;
236 vlc_mutex_unlock( &p_item
->lock
);
241 bool input_item_MetaMatch( input_item_t
*p_i
,
242 vlc_meta_type_t meta_type
, const char *psz
)
244 vlc_mutex_lock( &p_i
->lock
);
248 vlc_mutex_unlock( &p_i
->lock
);
251 const char *psz_meta
= vlc_meta_Get( p_i
->p_meta
, meta_type
);
252 bool b_ret
= psz_meta
&& strcasestr( psz_meta
, psz
);
254 vlc_mutex_unlock( &p_i
->lock
);
259 char *input_item_GetMeta( input_item_t
*p_i
, vlc_meta_type_t meta_type
)
261 vlc_mutex_lock( &p_i
->lock
);
265 vlc_mutex_unlock( &p_i
->lock
);
270 if( vlc_meta_Get( p_i
->p_meta
, meta_type
) )
271 psz
= strdup( vlc_meta_Get( p_i
->p_meta
, meta_type
) );
273 vlc_mutex_unlock( &p_i
->lock
);
277 /* Get the title of a given item or fallback to the name if the title is empty */
278 char *input_item_GetTitleFbName( input_item_t
*p_item
)
281 vlc_mutex_lock( &p_item
->lock
);
283 if( !p_item
->p_meta
)
285 psz_ret
= p_item
->psz_name
? strdup( p_item
->psz_name
) : NULL
;
286 vlc_mutex_unlock( &p_item
->lock
);
290 const char *psz_title
= vlc_meta_Get( p_item
->p_meta
, vlc_meta_Title
);
291 if( !EMPTY_STR( psz_title
) )
292 psz_ret
= strdup( psz_title
);
294 psz_ret
= p_item
->psz_name
? strdup( p_item
->psz_name
) : NULL
;
296 vlc_mutex_unlock( &p_item
->lock
);
300 char *input_item_GetName( input_item_t
*p_item
)
302 vlc_mutex_lock( &p_item
->lock
);
304 char *psz_name
= p_item
->psz_name
? strdup( p_item
->psz_name
) : NULL
;
306 vlc_mutex_unlock( &p_item
->lock
);
309 void input_item_SetName( input_item_t
*p_item
, const char *psz_name
)
311 vlc_mutex_lock( &p_item
->lock
);
313 free( p_item
->psz_name
);
314 p_item
->psz_name
= strdup( psz_name
);
316 vlc_mutex_unlock( &p_item
->lock
);
319 char *input_item_GetURI( input_item_t
*p_i
)
321 vlc_mutex_lock( &p_i
->lock
);
323 char *psz_s
= p_i
->psz_uri
? strdup( p_i
->psz_uri
) : NULL
;
325 vlc_mutex_unlock( &p_i
->lock
);
329 void input_item_SetURI( input_item_t
*p_i
, const char *psz_uri
)
333 if( !strstr( psz_uri
, "://" )
334 || strchr( psz_uri
, ' ' ) || strchr( psz_uri
, '"' ) )
335 fprintf( stderr
, "Warning: %s(\"%s\"): file path instead of URL.\n",
338 vlc_mutex_lock( &p_i
->lock
);
339 free( p_i
->psz_uri
);
340 p_i
->psz_uri
= strdup( psz_uri
);
342 p_i
->i_type
= GuessType( p_i
, &p_i
->b_net
);
347 if( p_i
->i_type
== ITEM_TYPE_FILE
|| p_i
->i_type
== ITEM_TYPE_DIRECTORY
)
349 const char *psz_filename
= strrchr( p_i
->psz_uri
, '/' );
351 if( psz_filename
&& *psz_filename
== '/' )
353 if( psz_filename
&& *psz_filename
)
354 p_i
->psz_name
= strdup( psz_filename
);
356 /* Make the name more readable */
359 vlc_uri_decode( p_i
->psz_name
);
360 EnsureUTF8( p_i
->psz_name
);
364 { /* Strip login and password from title */
368 vlc_UrlParse( &url
, psz_uri
);
369 if( url
.psz_protocol
)
372 r
=asprintf( &p_i
->psz_name
, "%s://%s:%d%s", url
.psz_protocol
,
373 url
.psz_host
, url
.i_port
,
374 url
.psz_path
? url
.psz_path
: "" );
376 r
=asprintf( &p_i
->psz_name
, "%s://%s%s", url
.psz_protocol
,
377 url
.psz_host
? url
.psz_host
: "",
378 url
.psz_path
? url
.psz_path
: "" );
383 r
=asprintf( &p_i
->psz_name
, "%s:%d%s", url
.psz_host
, url
.i_port
,
384 url
.psz_path
? url
.psz_path
: "" );
386 r
=asprintf( &p_i
->psz_name
, "%s%s", url
.psz_host
,
387 url
.psz_path
? url
.psz_path
: "" );
389 vlc_UrlClean( &url
);
391 p_i
->psz_name
=NULL
; /* recover from undefined value */
394 vlc_mutex_unlock( &p_i
->lock
);
397 mtime_t
input_item_GetDuration( input_item_t
*p_i
)
399 vlc_mutex_lock( &p_i
->lock
);
401 mtime_t i_duration
= p_i
->i_duration
;
403 vlc_mutex_unlock( &p_i
->lock
);
407 void input_item_SetDuration( input_item_t
*p_i
, mtime_t i_duration
)
409 bool b_send_event
= false;
411 vlc_mutex_lock( &p_i
->lock
);
412 if( p_i
->i_duration
!= i_duration
)
414 p_i
->i_duration
= i_duration
;
417 vlc_mutex_unlock( &p_i
->lock
);
421 vlc_event_send( &p_i
->event_manager
, &(vlc_event_t
) {
422 .type
= vlc_InputItemDurationChanged
,
423 .u
.input_item_duration_changed
.new_duration
= i_duration
} );
427 char *input_item_GetNowPlayingFb( input_item_t
*p_item
)
429 char *psz_meta
= input_item_GetMeta( p_item
, vlc_meta_NowPlaying
);
430 if( !psz_meta
|| strlen( psz_meta
) == 0 )
433 return input_item_GetMeta( p_item
, vlc_meta_ESNowPlaying
);
439 bool input_item_IsPreparsed( input_item_t
*p_item
)
441 vlc_mutex_lock( &p_item
->lock
);
442 bool b_preparsed
= p_item
->p_meta
? ( vlc_meta_GetStatus(p_item
->p_meta
) & ITEM_PREPARSED
) != 0 : false;
443 vlc_mutex_unlock( &p_item
->lock
);
448 bool input_item_IsArtFetched( input_item_t
*p_item
)
450 vlc_mutex_lock( &p_item
->lock
);
451 bool b_fetched
= p_item
->p_meta
? ( vlc_meta_GetStatus(p_item
->p_meta
) & ITEM_ART_FETCHED
) != 0 : false;
452 vlc_mutex_unlock( &p_item
->lock
);
457 bool input_item_ShouldPreparseSubItems( input_item_t
*p_item
)
461 vlc_mutex_lock( &p_item
->lock
);
462 b_ret
= p_item
->i_preparse_depth
== -1 ? true : p_item
->i_preparse_depth
> 0;
463 vlc_mutex_unlock( &p_item
->lock
);
468 input_item_t
*input_item_Hold( input_item_t
*p_item
)
470 input_item_owner_t
*owner
= item_owner(p_item
);
472 atomic_fetch_add( &owner
->refs
, 1 );
476 void input_item_Release( input_item_t
*p_item
)
478 input_item_owner_t
*owner
= item_owner(p_item
);
480 if( atomic_fetch_sub(&owner
->refs
, 1) != 1 )
483 vlc_event_manager_fini( &p_item
->event_manager
);
485 free( p_item
->psz_name
);
486 free( p_item
->psz_uri
);
487 if( p_item
->p_stats
!= NULL
)
489 vlc_mutex_destroy( &p_item
->p_stats
->lock
);
490 free( p_item
->p_stats
);
493 if( p_item
->p_meta
!= NULL
)
494 vlc_meta_Delete( p_item
->p_meta
);
496 for( input_item_opaque_t
*o
= p_item
->opaques
, *next
; o
!= NULL
; o
= next
)
502 for( int i
= 0; i
< p_item
->i_options
; i
++ )
503 free( p_item
->ppsz_options
[i
] );
504 TAB_CLEAN( p_item
->i_options
, p_item
->ppsz_options
);
505 free( p_item
->optflagv
);
507 for( int i
= 0; i
< p_item
->i_es
; i
++ )
509 es_format_Clean( p_item
->es
[i
] );
510 free( p_item
->es
[i
] );
512 TAB_CLEAN( p_item
->i_es
, p_item
->es
);
514 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
515 vlc_epg_Delete( p_item
->pp_epg
[i
] );
516 TAB_CLEAN( p_item
->i_epg
, p_item
->pp_epg
);
518 for( int i
= 0; i
< p_item
->i_categories
; i
++ )
519 info_category_Delete( p_item
->pp_categories
[i
] );
520 TAB_CLEAN( p_item
->i_categories
, p_item
->pp_categories
);
522 for( int i
= 0; i
< p_item
->i_slaves
; i
++ )
523 input_item_slave_Delete( p_item
->pp_slaves
[i
] );
524 TAB_CLEAN( p_item
->i_slaves
, p_item
->pp_slaves
);
526 vlc_mutex_destroy( &p_item
->lock
);
530 int input_item_AddOption( input_item_t
*p_input
, const char *psz_option
,
533 int err
= VLC_SUCCESS
;
535 if( psz_option
== NULL
)
538 vlc_mutex_lock( &p_input
->lock
);
539 if (flags
& VLC_INPUT_OPTION_UNIQUE
)
541 for (int i
= 0 ; i
< p_input
->i_options
; i
++)
542 if( !strcmp( p_input
->ppsz_options
[i
], psz_option
) )
546 uint8_t *flagv
= realloc (p_input
->optflagv
, p_input
->optflagc
+ 1);
553 p_input
->optflagv
= flagv
;
555 char* psz_option_dup
= strdup( psz_option
);
556 if( unlikely( !psz_option_dup
) )
562 TAB_APPEND(p_input
->i_options
, p_input
->ppsz_options
, psz_option_dup
);
564 flagv
[p_input
->optflagc
++] = flags
;
567 vlc_mutex_unlock( &p_input
->lock
);
571 int input_item_AddOptions( input_item_t
*p_item
, int i_options
,
572 const char *const *ppsz_options
,
575 int i_ret
= VLC_SUCCESS
;
576 for( int i
= 0; i
< i_options
&& i_ret
== VLC_SUCCESS
; i
++ )
577 i_ret
= input_item_AddOption( p_item
, ppsz_options
[i
], i_flags
);
581 int input_item_AddOpaque(input_item_t
*item
, const char *name
, void *value
)
583 assert(name
!= NULL
);
585 size_t namelen
= strlen(name
);
586 input_item_opaque_t
*entry
= malloc(sizeof (*entry
) + namelen
);
587 if (unlikely(entry
== NULL
))
590 memcpy(entry
->name
, name
, namelen
+ 1);
591 entry
->value
= value
;
593 vlc_mutex_lock(&item
->lock
);
594 entry
->next
= item
->opaques
;
595 item
->opaques
= entry
;
596 vlc_mutex_unlock(&item
->lock
);
600 void input_item_ApplyOptions(vlc_object_t
*obj
, input_item_t
*item
)
602 vlc_mutex_lock(&item
->lock
);
603 assert(item
->optflagc
== (unsigned)item
->i_options
);
605 for (unsigned i
= 0; i
< (unsigned)item
->i_options
; i
++)
606 var_OptionParse(obj
, item
->ppsz_options
[i
],
607 !!(item
->optflagv
[i
] & VLC_INPUT_OPTION_TRUSTED
));
609 for (const input_item_opaque_t
*o
= item
->opaques
; o
!= NULL
; o
= o
->next
)
611 var_Create(obj
, o
->name
, VLC_VAR_ADDRESS
);
612 var_SetAddress(obj
, o
->name
, o
->value
);
615 vlc_mutex_unlock(&item
->lock
);
618 bool input_item_slave_GetType(const char *psz_filename
,
619 enum slave_type
*p_slave_type
)
621 static const char *const ppsz_sub_exts
[] = { SLAVE_SPU_EXTENSIONS
, NULL
};
622 static const char *const ppsz_audio_exts
[] = { SLAVE_AUDIO_EXTENSIONS
, NULL
};
625 enum slave_type i_type
;
626 const char *const *ppsz_exts
;
628 { SLAVE_TYPE_SPU
, ppsz_sub_exts
},
629 { SLAVE_TYPE_AUDIO
, ppsz_audio_exts
},
632 const char *psz_ext
= strrchr(psz_filename
, '.');
633 if (psz_ext
== NULL
|| *(++psz_ext
) == '\0')
636 for (unsigned int i
= 0; i
< sizeof(p_slave_list
) / sizeof(*p_slave_list
); ++i
)
638 for (const char *const *ppsz_slave_ext
= p_slave_list
[i
].ppsz_exts
;
639 *ppsz_slave_ext
!= NULL
; ppsz_slave_ext
++)
641 if (!strcasecmp(psz_ext
, *ppsz_slave_ext
))
643 *p_slave_type
= p_slave_list
[i
].i_type
;
651 input_item_slave_t
*input_item_slave_New(const char *psz_uri
, enum slave_type i_type
,
652 enum slave_priority i_priority
)
657 input_item_slave_t
*p_slave
= malloc( sizeof( *p_slave
) + strlen( psz_uri
) + 1 );
661 p_slave
->i_type
= i_type
;
662 p_slave
->i_priority
= i_priority
;
663 p_slave
->b_forced
= false;
664 strcpy( p_slave
->psz_uri
, psz_uri
);
669 int input_item_AddSlave(input_item_t
*p_item
, input_item_slave_t
*p_slave
)
671 if( p_item
== NULL
|| p_slave
== NULL
672 || p_slave
->i_priority
< SLAVE_PRIORITY_MATCH_NONE
)
675 vlc_mutex_lock( &p_item
->lock
);
677 TAB_APPEND(p_item
->i_slaves
, p_item
->pp_slaves
, p_slave
);
679 vlc_mutex_unlock( &p_item
->lock
);
683 static info_category_t
*InputItemFindCat( input_item_t
*p_item
,
684 int *pi_index
, const char *psz_cat
)
686 vlc_assert_locked( &p_item
->lock
);
687 for( int i
= 0; i
< p_item
->i_categories
&& psz_cat
; i
++ )
689 info_category_t
*p_cat
= p_item
->pp_categories
[i
];
691 if( !strcmp( p_cat
->psz_name
, psz_cat
) )
702 * Get a info item from a given category in a given input item.
704 * \param p_i The input item to get info from
705 * \param psz_cat String representing the category for the info
706 * \param psz_name String representing the name of the desired info
707 * \return A pointer to the string with the given info if found, or an
708 * empty string otherwise. The caller should free the returned
711 char *input_item_GetInfo( input_item_t
*p_i
,
713 const char *psz_name
)
715 vlc_mutex_lock( &p_i
->lock
);
717 const info_category_t
*p_cat
= InputItemFindCat( p_i
, NULL
, psz_cat
);
720 info_t
*p_info
= info_category_FindInfo( p_cat
, NULL
, psz_name
);
721 if( p_info
&& p_info
->psz_value
)
723 char *psz_ret
= strdup( p_info
->psz_value
);
724 vlc_mutex_unlock( &p_i
->lock
);
728 vlc_mutex_unlock( &p_i
->lock
);
732 static int InputItemVaAddInfo( input_item_t
*p_i
,
734 const char *psz_name
,
735 const char *psz_format
, va_list args
)
737 vlc_assert_locked( &p_i
->lock
);
739 info_category_t
*p_cat
= InputItemFindCat( p_i
, NULL
, psz_cat
);
742 p_cat
= info_category_New( psz_cat
);
745 TAB_APPEND(p_i
->i_categories
, p_i
->pp_categories
, p_cat
);
747 info_t
*p_info
= info_category_VaAddInfo( p_cat
, psz_name
, psz_format
, args
);
748 if( !p_info
|| !p_info
->psz_value
)
753 int input_item_AddInfo( input_item_t
*p_i
,
755 const char *psz_name
,
756 const char *psz_format
, ... )
760 vlc_mutex_lock( &p_i
->lock
);
762 va_start( args
, psz_format
);
763 const int i_ret
= InputItemVaAddInfo( p_i
, psz_cat
, psz_name
, psz_format
, args
);
766 vlc_mutex_unlock( &p_i
->lock
);
770 vlc_event_send( &p_i
->event_manager
, &(vlc_event_t
) {
771 .type
= vlc_InputItemInfoChanged
} );
776 int input_item_DelInfo( input_item_t
*p_i
,
778 const char *psz_name
)
780 vlc_mutex_lock( &p_i
->lock
);
782 info_category_t
*p_cat
= InputItemFindCat( p_i
, &i_cat
, psz_cat
);
785 vlc_mutex_unlock( &p_i
->lock
);
791 /* Remove a specific info */
792 int i_ret
= info_category_DeleteInfo( p_cat
, psz_name
);
795 vlc_mutex_unlock( &p_i
->lock
);
801 /* Remove the complete categorie */
802 info_category_Delete( p_cat
);
803 TAB_ERASE(p_i
->i_categories
, p_i
->pp_categories
, i_cat
);
805 vlc_mutex_unlock( &p_i
->lock
);
807 vlc_event_send( &p_i
->event_manager
,
808 &(vlc_event_t
) { .type
= vlc_InputItemInfoChanged
} );
812 void input_item_ReplaceInfos( input_item_t
*p_item
, info_category_t
*p_cat
)
814 vlc_mutex_lock( &p_item
->lock
);
816 info_category_t
*p_old
= InputItemFindCat( p_item
, &i_cat
, p_cat
->psz_name
);
819 info_category_Delete( p_old
);
820 p_item
->pp_categories
[i_cat
] = p_cat
;
823 TAB_APPEND(p_item
->i_categories
, p_item
->pp_categories
, p_cat
);
824 vlc_mutex_unlock( &p_item
->lock
);
826 vlc_event_send( &p_item
->event_manager
,
827 &(vlc_event_t
) { .type
= vlc_InputItemInfoChanged
} );
830 void input_item_MergeInfos( input_item_t
*p_item
, info_category_t
*p_cat
)
832 vlc_mutex_lock( &p_item
->lock
);
833 info_category_t
*p_old
= InputItemFindCat( p_item
, NULL
, p_cat
->psz_name
);
836 for( int i
= 0; i
< p_cat
->i_infos
; i
++ )
837 info_category_ReplaceInfo( p_old
, p_cat
->pp_infos
[i
] );
838 TAB_CLEAN( p_cat
->i_infos
, p_cat
->pp_infos
);
839 info_category_Delete( p_cat
);
842 TAB_APPEND(p_item
->i_categories
, p_item
->pp_categories
, p_cat
);
843 vlc_mutex_unlock( &p_item
->lock
);
845 vlc_event_send( &p_item
->event_manager
,
846 &(vlc_event_t
) { .type
= vlc_InputItemInfoChanged
} );
849 void input_item_SetEpgEvent( input_item_t
*p_item
, const vlc_epg_event_t
*p_epg_evt
)
851 bool b_changed
= false;
852 vlc_mutex_lock( &p_item
->lock
);
854 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
856 vlc_epg_t
*p_epg
= p_item
->pp_epg
[i
];
857 for( size_t j
= 0; j
< p_epg
->i_event
; j
++ )
859 /* Same event can exist in more than one table */
860 if( p_epg
->pp_event
[j
]->i_id
== p_epg_evt
->i_id
)
862 vlc_epg_event_t
*p_dup
= vlc_epg_event_Duplicate( p_epg_evt
);
865 if( p_epg
->p_current
== p_epg
->pp_event
[j
] )
866 p_epg
->p_current
= p_dup
;
867 vlc_epg_event_Delete( p_epg
->pp_event
[j
] );
868 p_epg
->pp_event
[j
] = p_dup
;
875 vlc_mutex_unlock( &p_item
->lock
);
879 vlc_event_send( &p_item
->event_manager
,
880 &(vlc_event_t
) { .type
= vlc_InputItemInfoChanged
} );
886 static int InputItemAddInfo( input_item_t
*p_i
,
888 const char *psz_name
,
889 const char *psz_format
, ... )
893 va_start( args
, psz_format
);
894 const int i_ret
= InputItemVaAddInfo( p_i
, psz_cat
, psz_name
, psz_format
, args
);
901 void input_item_SetEpg( input_item_t
*p_item
, const vlc_epg_t
*p_update
, bool b_current_source
)
903 vlc_epg_t
*p_epg
= vlc_epg_Duplicate( p_update
);
907 vlc_mutex_lock( &p_item
->lock
);
910 vlc_epg_t
**pp_epg
= NULL
;
911 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
913 if( p_item
->pp_epg
[i
]->i_source_id
== p_update
->i_source_id
&&
914 p_item
->pp_epg
[i
]->i_id
== p_update
->i_id
)
916 pp_epg
= &p_item
->pp_epg
[i
];
921 /* replace with new version */
924 vlc_epg_Delete( *pp_epg
);
925 if( *pp_epg
== p_item
->p_epg_table
) /* current table can have changed */
926 p_item
->p_epg_table
= NULL
;
931 TAB_APPEND( p_item
->i_epg
, p_item
->pp_epg
, p_epg
);
934 if( b_current_source
&& p_epg
->b_present
)
935 p_item
->p_epg_table
= p_epg
;
937 vlc_mutex_unlock( &p_item
->lock
);
941 if( asprintf( &psz_epg
, "EPG %s", p_epg
->psz_name
? p_epg
->psz_name
: "unknown" ) < 0 )
944 input_item_DelInfo( p_item
, psz_epg
, NULL
);
946 vlc_mutex_lock( &p_item
->lock
);
947 for( size_t i
= 0; i
< p_epg
->i_event
; i
++ )
949 const vlc_epg_event_t
*p_evt
= p_epg
->pp_event
[i
];
950 time_t t_start
= (time_t)p_evt
->i_start
;
954 localtime_r( &t_start
, &tm_start
);
956 snprintf( psz_start
, sizeof(psz_start
), "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
957 1900 + tm_start
.tm_year
, 1 + tm_start
.tm_mon
, tm_start
.tm_mday
,
958 tm_start
.tm_hour
, tm_start
.tm_min
, tm_start
.tm_sec
);
959 if( p_evt
->psz_short_description
|| p_evt
->psz_description
)
960 InputItemAddInfo( p_item
, psz_epg
, psz_start
, "%s (%2.2d:%2.2d) - %s %s",
962 p_evt
->i_duration
/60/60, (p_evt
->i_duration
/60)%60,
963 p_evt
->psz_short_description
? p_evt
->psz_short_description
: "" ,
964 p_evt
->psz_description
? p_evt
->psz_description
: "" );
966 InputItemAddInfo( p_item
, psz_epg
, psz_start
, "%s (%2.2d:%2.2d)",
968 p_evt
->i_duration
/60/60, (p_evt
->i_duration
/60)%60 );
970 vlc_mutex_unlock( &p_item
->lock
);
974 vlc_event_send( &p_item
->event_manager
,
975 &(vlc_event_t
){ .type
= vlc_InputItemInfoChanged
, } );
978 void input_item_ChangeEPGSource( input_item_t
*p_item
, int i_source_id
)
980 vlc_mutex_lock( &p_item
->lock
);
981 p_item
->p_epg_table
= NULL
;
982 if( i_source_id
> 0 )
984 /* Update pointer to current/next table in the full schedule */
985 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
987 if( p_item
->pp_epg
[i
]->i_source_id
== i_source_id
&&
988 p_item
->pp_epg
[i
]->b_present
)
990 p_item
->p_epg_table
= p_item
->pp_epg
[i
];
995 vlc_mutex_unlock( &p_item
->lock
);
998 void input_item_SetEpgTime( input_item_t
*p_item
, int64_t i_time
)
1000 vlc_mutex_lock( &p_item
->lock
);
1001 p_item
->i_epg_time
= i_time
;
1002 vlc_mutex_unlock( &p_item
->lock
);
1005 void input_item_SetEpgOffline( input_item_t
*p_item
)
1007 input_item_ChangeEPGSource( p_item
, -1 );
1010 vlc_mutex_lock( &p_item
->lock
);
1011 const int i_epg_info
= p_item
->i_epg
;
1012 if( i_epg_info
> 0 )
1014 char *ppsz_epg_info
[i_epg_info
];
1015 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1017 const vlc_epg_t
*p_epg
= p_item
->pp_epg
[i
];
1018 if( asprintf( &ppsz_epg_info
[i
], "EPG %s", p_epg
->psz_name
? p_epg
->psz_name
: "unknown" ) < 0 )
1019 ppsz_epg_info
[i
] = NULL
;
1021 vlc_mutex_unlock( &p_item
->lock
);
1023 for( int i
= 0; i
< i_epg_info
; i
++ )
1025 if( !ppsz_epg_info
[i
] )
1027 input_item_DelInfo( p_item
, ppsz_epg_info
[i
], NULL
);
1028 free( ppsz_epg_info
[i
] );
1032 vlc_mutex_unlock( &p_item
->lock
);
1035 vlc_event_send( &p_item
->event_manager
,
1036 &(vlc_event_t
) { .type
= vlc_InputItemInfoChanged
} );
1040 input_item_NewExt( const char *psz_uri
, const char *psz_name
,
1041 mtime_t duration
, int type
, enum input_item_net_type i_net
)
1043 input_item_owner_t
*owner
= calloc( 1, sizeof( *owner
) );
1044 if( unlikely(owner
== NULL
) )
1047 atomic_init( &owner
->refs
, 1 );
1049 input_item_t
*p_input
= &owner
->item
;
1050 vlc_event_manager_t
* p_em
= &p_input
->event_manager
;
1052 vlc_mutex_init( &p_input
->lock
);
1054 p_input
->psz_name
= NULL
;
1056 input_item_SetName( p_input
, psz_name
);
1058 p_input
->psz_uri
= NULL
;
1060 input_item_SetURI( p_input
, psz_uri
);
1063 p_input
->i_type
= ITEM_TYPE_UNKNOWN
;
1064 p_input
->b_net
= false;
1067 TAB_INIT( p_input
->i_options
, p_input
->ppsz_options
);
1068 p_input
->optflagc
= 0;
1069 p_input
->optflagv
= NULL
;
1070 p_input
->opaques
= NULL
;
1072 p_input
->i_duration
= duration
;
1073 TAB_INIT( p_input
->i_categories
, p_input
->pp_categories
);
1074 TAB_INIT( p_input
->i_es
, p_input
->es
);
1075 p_input
->p_stats
= NULL
;
1076 p_input
->p_meta
= NULL
;
1077 TAB_INIT( p_input
->i_epg
, p_input
->pp_epg
);
1078 TAB_INIT( p_input
->i_slaves
, p_input
->pp_slaves
);
1080 vlc_event_manager_init( p_em
, p_input
);
1082 if( type
!= ITEM_TYPE_UNKNOWN
)
1083 p_input
->i_type
= type
;
1084 p_input
->b_error_when_reading
= false;
1086 if( i_net
!= ITEM_NET_UNKNOWN
)
1087 p_input
->b_net
= i_net
== ITEM_NET
;
1091 input_item_t
*input_item_Copy( input_item_t
*p_input
)
1093 vlc_meta_t
*meta
= NULL
;
1097 vlc_mutex_lock( &p_input
->lock
);
1099 item
= input_item_NewExt( p_input
->psz_uri
, p_input
->psz_name
,
1100 p_input
->i_duration
, p_input
->i_type
,
1102 if( likely(item
!= NULL
) && p_input
->p_meta
!= NULL
)
1104 meta
= vlc_meta_New();
1105 vlc_meta_Merge( meta
, p_input
->p_meta
);
1107 b_net
= p_input
->b_net
;
1108 vlc_mutex_unlock( &p_input
->lock
);
1110 if( likely(item
!= NULL
) )
1111 { /* No need to lock; no other thread has seen this new item yet. */
1112 input_item_CopyOptions( item
, p_input
);
1113 item
->p_meta
= meta
;
1114 item
->b_net
= b_net
;
1120 struct item_type_entry
1122 const char *psz_scheme
;
1127 static int typecmp( const void *key
, const void *entry
)
1129 const struct item_type_entry
*type
= entry
;
1130 const char *uri
= key
, *scheme
= type
->psz_scheme
;
1132 return strncmp( uri
, scheme
, strlen( scheme
) );
1135 /* Guess the type of the item using the beginning of the mrl */
1136 static int GuessType( const input_item_t
*p_item
, bool *p_net
)
1138 static const struct item_type_entry tab
[] =
1139 { /* /!\ Alphabetical order /!\ */
1140 /* Short match work, not just exact match */
1141 { "alsa", ITEM_TYPE_CARD
, false },
1142 { "atsc", ITEM_TYPE_CARD
, false },
1143 { "bd", ITEM_TYPE_DISC
, false },
1144 { "bluray", ITEM_TYPE_DISC
, false },
1145 { "cable", ITEM_TYPE_CARD
, false },
1146 { "cdda", ITEM_TYPE_DISC
, false },
1147 { "cqam", ITEM_TYPE_CARD
, false },
1148 { "dc1394", ITEM_TYPE_CARD
, false },
1149 { "dccp", ITEM_TYPE_STREAM
, true },
1150 { "deckli", ITEM_TYPE_CARD
, false }, /* decklink */
1151 { "dir", ITEM_TYPE_DIRECTORY
, false },
1152 { "dshow", ITEM_TYPE_CARD
, false },
1153 { "dtv", ITEM_TYPE_CARD
, false },
1154 { "dvb", ITEM_TYPE_CARD
, false },
1155 { "dvd", ITEM_TYPE_DISC
, false },
1156 { "eyetv", ITEM_TYPE_CARD
, false },
1157 { "fd", ITEM_TYPE_UNKNOWN
, false },
1158 { "file", ITEM_TYPE_FILE
, false },
1159 { "ftp", ITEM_TYPE_FILE
, true },
1160 { "http", ITEM_TYPE_FILE
, true },
1161 { "icyx", ITEM_TYPE_STREAM
, true },
1162 { "imem", ITEM_TYPE_UNKNOWN
, false },
1163 { "isdb-", ITEM_TYPE_CARD
, false },
1164 { "itpc", ITEM_TYPE_PLAYLIST
, true },
1165 { "jack", ITEM_TYPE_CARD
, false },
1166 { "linsys", ITEM_TYPE_CARD
, false },
1167 { "live", ITEM_TYPE_STREAM
, true }, /* livedotcom */
1168 { "mms", ITEM_TYPE_STREAM
, true },
1169 { "mtp", ITEM_TYPE_DISC
, false },
1170 { "nfs", ITEM_TYPE_FILE
, true },
1171 { "ofdm", ITEM_TYPE_CARD
, false },
1172 { "oss", ITEM_TYPE_CARD
, false },
1173 { "pnm", ITEM_TYPE_STREAM
, true },
1174 { "pulse", ITEM_TYPE_CARD
, false },
1175 { "qam", ITEM_TYPE_CARD
, false },
1176 { "qpsk", ITEM_TYPE_CARD
, false },
1177 { "qtcapt", ITEM_TYPE_CARD
, false }, /* qtcapture */
1178 { "qtsound",ITEM_TYPE_CARD
, false },
1179 { "raw139", ITEM_TYPE_CARD
, false }, /* raw1394 */
1180 { "rt", ITEM_TYPE_STREAM
, true }, /* rtp, rtsp, rtmp */
1181 { "satell", ITEM_TYPE_CARD
, false }, /* satellite */
1182 { "satip", ITEM_TYPE_STREAM
, true }, /* satellite over ip */
1183 { "screen", ITEM_TYPE_CARD
, false },
1184 { "sdp", ITEM_TYPE_STREAM
, true },
1185 { "sftp", ITEM_TYPE_FILE
, true },
1186 { "shm", ITEM_TYPE_CARD
, false },
1187 { "smb", ITEM_TYPE_FILE
, true },
1188 { "stream", ITEM_TYPE_STREAM
, false },
1189 { "svcd", ITEM_TYPE_DISC
, false },
1190 { "tcp", ITEM_TYPE_STREAM
, true },
1191 { "terres", ITEM_TYPE_CARD
, false }, /* terrestrial */
1192 { "udp", ITEM_TYPE_STREAM
, true }, /* udplite too */
1193 { "unsv", ITEM_TYPE_STREAM
, true },
1194 { "upnp", ITEM_TYPE_FILE
, true },
1195 { "usdigi", ITEM_TYPE_CARD
, false }, /* usdigital */
1196 { "v4l", ITEM_TYPE_CARD
, false },
1197 { "vcd", ITEM_TYPE_DISC
, false },
1198 { "vdr", ITEM_TYPE_STREAM
, true },
1199 { "wasapi", ITEM_TYPE_CARD
, false },
1200 { "window", ITEM_TYPE_CARD
, false },
1204 for( size_t i
= 1; i
< ARRAY_SIZE( tab
); i
++ )
1205 assert( typecmp( (tab
+ i
)->psz_scheme
, tab
+ i
- 1 ) > 0 );
1210 if( strstr( p_item
->psz_uri
, "://" ) == NULL
)
1211 return ITEM_TYPE_UNKNOWN
; /* invalid URI */
1213 const struct item_type_entry
*e
=
1214 bsearch( p_item
->psz_uri
, tab
, ARRAY_SIZE( tab
),
1215 sizeof( tab
[0] ), typecmp
);
1217 return ITEM_TYPE_UNKNOWN
;
1223 input_item_node_t
*input_item_node_Create( input_item_t
*p_input
)
1225 input_item_node_t
* p_node
= malloc( sizeof( input_item_node_t
) );
1231 p_node
->p_item
= p_input
;
1232 input_item_Hold( p_input
);
1234 p_node
->i_children
= 0;
1235 p_node
->pp_children
= NULL
;
1240 void input_item_node_Delete( input_item_node_t
*p_node
)
1242 for( int i
= 0; i
< p_node
->i_children
; i
++ )
1243 input_item_node_Delete( p_node
->pp_children
[i
] );
1245 input_item_Release( p_node
->p_item
);
1246 free( p_node
->pp_children
);
1250 input_item_node_t
*input_item_node_AppendItem( input_item_node_t
*p_node
, input_item_t
*p_item
)
1252 int i_preparse_depth
;
1253 input_item_node_t
*p_new_child
= input_item_node_Create( p_item
);
1254 if( !p_new_child
) return NULL
;
1256 vlc_mutex_lock( &p_node
->p_item
->lock
);
1257 i_preparse_depth
= p_node
->p_item
->i_preparse_depth
;
1258 vlc_mutex_unlock( &p_node
->p_item
->lock
);
1260 vlc_mutex_lock( &p_item
->lock
);
1261 p_item
->i_preparse_depth
= i_preparse_depth
> 0 ?
1262 i_preparse_depth
-1 :
1264 vlc_mutex_unlock( &p_item
->lock
);
1266 input_item_node_AppendNode( p_node
, p_new_child
);
1270 void input_item_node_AppendNode( input_item_node_t
*p_parent
,
1271 input_item_node_t
*p_child
)
1273 assert(p_parent
!= NULL
);
1274 assert(p_child
!= NULL
);
1275 TAB_APPEND(p_parent
->i_children
, p_parent
->pp_children
, p_child
);
1278 void input_item_node_RemoveNode( input_item_node_t
*parent
,
1279 input_item_node_t
*child
)
1281 TAB_REMOVE(parent
->i_children
, parent
->pp_children
, child
);
1284 void input_item_node_PostAndDelete( input_item_node_t
*p_root
)
1286 vlc_event_send( &p_root
->p_item
->event_manager
, &(vlc_event_t
) {
1287 .type
= vlc_InputItemSubItemTreeAdded
,
1288 .u
.input_item_subitem_tree_added
.p_root
= p_root
} );
1290 input_item_node_Delete( p_root
);
1293 /* Called by es_out when a new Elementary Stream is added or updated. */
1294 void input_item_UpdateTracksInfo(input_item_t
*item
, const es_format_t
*fmt
)
1297 es_format_t
*fmt_copy
= malloc(sizeof *fmt_copy
);
1301 es_format_Copy(fmt_copy
, fmt
);
1303 vlc_mutex_lock( &item
->lock
);
1305 for( i
= 0; i
< item
->i_es
; i
++ )
1307 if (item
->es
[i
]->i_id
!= fmt
->i_id
)
1310 /* We've found the right ES, replace it */
1311 es_format_Clean(item
->es
[i
]);
1313 item
->es
[i
] = fmt_copy
;
1314 vlc_mutex_unlock( &item
->lock
);
1318 /* ES not found, insert it */
1319 TAB_APPEND(item
->i_es
, item
->es
, fmt_copy
);
1320 vlc_mutex_unlock( &item
->lock
);