]> git.sesse.net Git - vlc/blob - src/input/input.c
Moved "sub-margin" to vout.
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  *****************************************************************************
4  * Copyright (C) 1998-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33
34 #include <limits.h>
35 #include <assert.h>
36 #include <errno.h>
37
38 #include "input_internal.h"
39 #include "event.h"
40 #include "es_out.h"
41 #include "es_out_timeshift.h"
42 #include "access.h"
43 #include "demux.h"
44 #include "stream.h"
45 #include "item.h"
46 #include "resource.h"
47
48 #include <vlc_sout.h>
49 #include "../stream_output/stream_output.h"
50
51 #include <vlc_dialog.h>
52 #include <vlc_url.h>
53 #include <vlc_charset.h>
54 #include <vlc_fs.h>
55 #include <vlc_strings.h>
56
57 #ifdef HAVE_SYS_STAT_H
58 #   include <sys/stat.h>
59 #endif
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static void Destructor( input_thread_t * p_input );
65
66 static  void *Run            ( vlc_object_t *p_this );
67
68 static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
69                                   const char *, bool, input_resource_t * );
70 static  int             Init    ( input_thread_t *p_input );
71 static void             End     ( input_thread_t *p_input );
72 static void             MainLoop( input_thread_t *p_input, bool b_interactive );
73
74 static void ObjectKillChildrens( input_thread_t *, vlc_object_t * );
75
76 static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline, bool b_postpone_seek );
77 static void       ControlRelease( int i_type, vlc_value_t val );
78 static bool       ControlIsSeekRequest( int i_type );
79 static bool       Control( input_thread_t *, int, vlc_value_t );
80
81 static int  UpdateTitleSeekpointFromAccess( input_thread_t * );
82 static void UpdateGenericFromAccess( input_thread_t * );
83
84 static int  UpdateTitleSeekpointFromDemux( input_thread_t * );
85 static void UpdateGenericFromDemux( input_thread_t * );
86
87 static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
88
89 static input_source_t *InputSourceNew( input_thread_t *);
90 static int  InputSourceInit( input_thread_t *, input_source_t *,
91                              const char *, const char *psz_forced_demux );
92 static void InputSourceClean( input_source_t * );
93 static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );
94
95 /* TODO */
96 //static void InputGetAttachments( input_thread_t *, input_source_t * );
97 static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled );
98 static void SlaveSeek( input_thread_t *p_input );
99
100 static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
101 static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta );
102 static void InputGetExtraFiles( input_thread_t *p_input,
103                                 int *pi_list, char ***pppsz_list,
104                                 const char *psz_access, const char *psz_path );
105
106 static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
107                               int i_new, input_attachment_t **pp_new );
108
109 static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_forced );
110
111 static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */
112
113 #undef input_Create
114 /**
115  * Create a new input_thread_t.
116  *
117  * You need to call input_Start on it when you are done
118  * adding callback on the variables/events you want to monitor.
119  *
120  * \param p_parent a vlc_object
121  * \param p_item an input item
122  * \param psz_log an optional prefix for this input logs
123  * \param p_resource an optional input ressource
124  * \return a pointer to the spawned input thread
125  */
126 input_thread_t *input_Create( vlc_object_t *p_parent,
127                               input_item_t *p_item,
128                               const char *psz_log, input_resource_t *p_resource )
129 {
130     return Create( p_parent, p_item, psz_log, false, p_resource );
131 }
132
133 #undef input_CreateAndStart
134 /**
135  * Create a new input_thread_t and start it.
136  *
137  * Provided for convenience.
138  *
139  * \see input_Create
140  */
141 input_thread_t *input_CreateAndStart( vlc_object_t *p_parent,
142                                       input_item_t *p_item, const char *psz_log )
143 {
144     input_thread_t *p_input = input_Create( p_parent, p_item, psz_log, NULL );
145
146     if( input_Start( p_input ) )
147     {
148         vlc_object_release( p_input );
149         return NULL;
150     }
151     return p_input;
152 }
153
154 #undef input_Read
155 /**
156  * Initialize an input thread and run it until it stops by itself.
157  *
158  * \param p_parent a vlc_object
159  * \param p_item an input item
160  * \return an error code, VLC_SUCCESS on success
161  */
162 int input_Read( vlc_object_t *p_parent, input_item_t *p_item )
163 {
164     input_thread_t *p_input = Create( p_parent, p_item, NULL, false, NULL );
165     if( !p_input )
166         return VLC_EGENERIC;
167
168     if( !Init( p_input ) )
169     {
170         MainLoop( p_input, false );
171         End( p_input );
172     }
173
174     vlc_object_release( p_input );
175     return VLC_SUCCESS;
176 }
177
178 /**
179  * Initialize an input and initialize it to preparse the item
180  * This function is blocking. It will only accept parsing regular files.
181  *
182  * \param p_parent a vlc_object_t
183  * \param p_item an input item
184  * \return VLC_SUCCESS or an error
185  */
186 int input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
187 {
188     input_thread_t *p_input;
189
190     /* Allocate descriptor */
191     p_input = Create( p_parent, p_item, NULL, true, NULL );
192     if( !p_input )
193         return VLC_EGENERIC;
194
195     if( !Init( p_input ) )
196         End( p_input );
197
198     vlc_object_release( p_input );
199
200     return VLC_SUCCESS;
201 }
202
203 /**
204  * Start a input_thread_t created by input_Create.
205  *
206  * You must not start an already running input_thread_t.
207  *
208  * \param the input thread to start
209  */
210 int input_Start( input_thread_t *p_input )
211 {
212     /* Create thread and wait for its readiness. */
213     if( vlc_thread_create( p_input, "input", Run,
214                            VLC_THREAD_PRIORITY_INPUT ) )
215     {
216         input_ChangeState( p_input, ERROR_S );
217         msg_Err( p_input, "cannot create input thread" );
218         return VLC_EGENERIC;
219     }
220     return VLC_SUCCESS;
221 }
222
223 /**
224  * Request a running input thread to stop and die
225  *
226  * b_abort must be true when a user stop is requested and not because you have
227  * detected an error or an eof. It will be used to properly send the
228  * INPUT_EVENT_ABORT event.
229  *
230  * \param p_input the input thread to stop
231  * \param b_abort true if the input has been aborted by a user request
232  */
233 void input_Stop( input_thread_t *p_input, bool b_abort )
234 {
235     /* Set die for input and ALL of this childrens (even (grand-)grand-childrens)
236      * It is needed here even if it is done in INPUT_CONTROL_SET_DIE handler to
237      * unlock the control loop */
238     ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );
239
240     vlc_mutex_lock( &p_input->p->lock_control );
241     p_input->p->b_abort |= b_abort;
242     vlc_mutex_unlock( &p_input->p->lock_control );
243
244     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
245 }
246
247 /**
248  * Get the item from an input thread
249  * FIXME it does not increase ref count of the item.
250  * if it is used after p_input is destroyed nothing prevent it from
251  * being freed.
252  */
253 input_item_t *input_GetItem( input_thread_t *p_input )
254 {
255     assert( p_input && p_input->p );
256     return p_input->p->p_item;
257 }
258
259 /*****************************************************************************
260  * ObjectKillChildrens
261  *****************************************************************************/
262 static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
263 {
264     vlc_list_t *p_list;
265     int i;
266
267     /* FIXME ObjectKillChildrens seems a very bad idea in fact */
268     i = vlc_internals( p_obj )->i_object_type;
269     if( i == VLC_OBJECT_VOUT ||i == VLC_OBJECT_AOUT ||
270         p_obj == VLC_OBJECT(p_input->p->p_sout) ||
271         i == VLC_OBJECT_DECODER )
272         return;
273
274     vlc_object_kill( p_obj );
275
276     p_list = vlc_list_children( p_obj );
277     for( i = 0; i < p_list->i_count; i++ )
278         ObjectKillChildrens( p_input, p_list->p_values[i].p_object );
279     vlc_list_release( p_list );
280 }
281
282 /*****************************************************************************
283  * This function creates a new input, and returns a pointer
284  * to its description. On error, it returns NULL.
285  *
286  * XXX Do not forget to update vlc_input.h if you add new variables.
287  *****************************************************************************/
288 static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
289                                const char *psz_header, bool b_quick,
290                                input_resource_t *p_resource )
291 {
292     static const char input_name[] = "input";
293     input_thread_t *p_input = NULL;                 /* thread descriptor */
294     int i;
295
296     /* Allocate descriptor */
297     p_input = vlc_custom_create( p_parent, sizeof( *p_input ),
298                                  VLC_OBJECT_INPUT, input_name );
299     if( p_input == NULL )
300         return NULL;
301
302     vlc_object_attach( p_input, p_parent );
303
304     /* Construct a nice name for the input timer */
305     char psz_timer_name[255];
306     char * psz_name = input_item_GetName( p_item );
307     snprintf( psz_timer_name, sizeof(psz_timer_name),
308               "input launching for '%s'", psz_name );
309
310     msg_Dbg( p_input, "Creating an input for '%s'", psz_name);
311
312     free( psz_name );
313
314     /* Start a timer to mesure how long it takes
315      * to launch an input */
316     stats_TimerStart( p_input, psz_timer_name,
317         STATS_TIMER_INPUT_LAUNCHING );
318
319     p_input->p = calloc( 1, sizeof( input_thread_private_t ) );
320     if( !p_input->p )
321         return NULL;
322
323     /* Parse input options */
324     vlc_mutex_lock( &p_item->lock );
325     assert( (int)p_item->optflagc == p_item->i_options );
326     for( i = 0; i < p_item->i_options; i++ )
327         var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
328                          !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
329     vlc_mutex_unlock( &p_item->lock );
330
331     p_input->b_preparsing = b_quick;
332     p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
333
334     /* Init Common fields */
335     p_input->b_eof = false;
336     p_input->p->b_can_pace_control = true;
337     p_input->p->i_start = 0;
338     p_input->p->i_time  = 0;
339     p_input->p->i_stop  = 0;
340     p_input->p->i_run   = 0;
341     p_input->p->i_title = 0;
342     p_input->p->title = NULL;
343     p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
344     p_input->p->i_state = INIT_S;
345     double f_rate = var_InheritFloat( p_input, "rate" );
346     if( f_rate <= 0. )
347     {
348         msg_Warn( p_input, "Negative or zero rate values are forbidden" );
349         f_rate = 1.;
350     }
351     p_input->p->i_rate = INPUT_RATE_DEFAULT / f_rate;
352     p_input->p->b_recording = false;
353     memset( &p_input->p->bookmark, 0, sizeof(p_input->p->bookmark) );
354     TAB_INIT( p_input->p->i_bookmark, p_input->p->pp_bookmark );
355     TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
356     p_input->p->p_sout   = NULL;
357     p_input->p->b_out_pace_control = false;
358
359     vlc_gc_incref( p_item ); /* Released in Destructor() */
360     p_input->p->p_item = p_item;
361
362     /* Init Input fields */
363     p_input->p->input.p_access = NULL;
364     p_input->p->input.p_stream = NULL;
365     p_input->p->input.p_demux  = NULL;
366     p_input->p->input.b_title_demux = false;
367     p_input->p->input.i_title  = 0;
368     p_input->p->input.title    = NULL;
369     p_input->p->input.i_title_offset = p_input->p->input.i_seekpoint_offset = 0;
370     p_input->p->input.b_can_pace_control = true;
371     p_input->p->input.b_can_rate_control = true;
372     p_input->p->input.b_rescale_ts = true;
373     p_input->p->input.b_eof = false;
374
375     vlc_mutex_lock( &p_item->lock );
376
377     if( !p_item->p_stats )
378         p_item->p_stats = stats_NewInputStats( p_input );
379     vlc_mutex_unlock( &p_item->lock );
380
381     /* No slave */
382     p_input->p->i_slave = 0;
383     p_input->p->slave   = NULL;
384
385     /* */
386     if( p_resource )
387     {
388         p_input->p->p_resource_private = NULL;
389         p_input->p->p_resource = p_resource;
390     }
391     else
392     {
393         p_input->p->p_resource_private = input_resource_New( VLC_OBJECT( p_input ) );
394         p_input->p->p_resource = p_input->p->p_resource_private;
395     }
396     input_resource_SetInput( p_input->p->p_resource, p_input );
397
398     /* Init control buffer */
399     vlc_mutex_init( &p_input->p->lock_control );
400     vlc_cond_init( &p_input->p->wait_control );
401     p_input->p->i_control = 0;
402     p_input->p->b_abort = false;
403
404     /* Create Object Variables for private use only */
405     input_ConfigVarInit( p_input );
406
407     /* Create Objects variables for public Get and Set */
408     input_ControlVarInit( p_input );
409
410     /* */
411     if( !p_input->b_preparsing )
412     {
413         char *psz_bookmarks = var_GetNonEmptyString( p_input, "bookmarks" );
414         if( psz_bookmarks )
415         {
416             /* FIXME: have a common cfg parsing routine used by sout and others */
417             char *psz_parser, *psz_start, *psz_end;
418             psz_parser = psz_bookmarks;
419             while( (psz_start = strchr( psz_parser, '{' ) ) )
420             {
421                  seekpoint_t *p_seekpoint;
422                  char backup;
423                  psz_start++;
424                  psz_end = strchr( psz_start, '}' );
425                  if( !psz_end ) break;
426                  psz_parser = psz_end + 1;
427                  backup = *psz_parser;
428                  *psz_parser = 0;
429                  *psz_end = ',';
430
431                  p_seekpoint = vlc_seekpoint_New();
432                  while( (psz_end = strchr( psz_start, ',' ) ) )
433                  {
434                      *psz_end = 0;
435                      if( !strncmp( psz_start, "name=", 5 ) )
436                      {
437                          p_seekpoint->psz_name = strdup(psz_start + 5);
438                      }
439                      else if( !strncmp( psz_start, "bytes=", 6 ) )
440                      {
441                          p_seekpoint->i_byte_offset = atoll(psz_start + 6);
442                      }
443                      else if( !strncmp( psz_start, "time=", 5 ) )
444                      {
445                          p_seekpoint->i_time_offset = atoll(psz_start + 5) *
446                                                         1000000;
447                      }
448                      psz_start = psz_end + 1;
449                 }
450                 msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
451                                   p_seekpoint->psz_name, p_seekpoint->i_byte_offset,
452                                   p_seekpoint->i_time_offset );
453                 input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
454                 vlc_seekpoint_Delete( p_seekpoint );
455                 *psz_parser = backup;
456             }
457             free( psz_bookmarks );
458         }
459     }
460
461     /* Remove 'Now playing' info as it is probably outdated */
462     input_item_SetNowPlaying( p_item, NULL );
463     input_SendEventMeta( p_input );
464
465     /* */
466     if( p_input->b_preparsing )
467         p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
468
469     /* Make sure the interaction option is honored */
470     if( !var_InheritBool( p_input, "interact" ) )
471         p_input->i_flags |= OBJECT_FLAGS_NOINTERACT;
472
473     /* */
474     memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
475     vlc_mutex_init( &p_input->p->counters.counters_lock );
476
477     p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
478     p_input->p->p_es_out = NULL;
479
480     /* Set the destructor when we are sure we are initialized */
481     vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );
482
483     return p_input;
484 }
485
486 /**
487  * Input destructor (called when the object's refcount reaches 0).
488  */
489 static void Destructor( input_thread_t * p_input )
490 {
491 #ifndef NDEBUG
492     char * psz_name = input_item_GetName( p_input->p->p_item );
493     msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
494     free( psz_name );
495 #endif
496
497     stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING );
498     stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING );
499
500     if( p_input->p->p_es_out_display )
501         es_out_Delete( p_input->p->p_es_out_display );
502
503     if( p_input->p->p_resource_private )
504         input_resource_Delete( p_input->p->p_resource_private );
505
506     vlc_gc_decref( p_input->p->p_item );
507
508     vlc_mutex_destroy( &p_input->p->counters.counters_lock );
509
510     for( int i = 0; i < p_input->p->i_control; i++ )
511     {
512         input_control_t *p_ctrl = &p_input->p->control[i];
513         ControlRelease( p_ctrl->i_type, p_ctrl->val );
514     }
515
516     vlc_cond_destroy( &p_input->p->wait_control );
517     vlc_mutex_destroy( &p_input->p->lock_control );
518     free( p_input->p );
519 }
520
521 /*****************************************************************************
522  * Run: main thread loop
523  * This is the "normal" thread that spawns the input processing chain,
524  * reads the stream, cleans up and waits
525  *****************************************************************************/
526 static void *Run( vlc_object_t *p_this )
527 {
528     input_thread_t *p_input = (input_thread_t *)p_this;
529     const int canc = vlc_savecancel();
530
531     if( Init( p_input ) )
532         goto exit;
533
534     MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */
535
536     /* Clean up */
537     End( p_input );
538
539 exit:
540     /* Tell we're dead */
541     vlc_mutex_lock( &p_input->p->lock_control );
542     const bool b_abort = p_input->p->b_abort;
543     vlc_mutex_unlock( &p_input->p->lock_control );
544
545     if( b_abort )
546         input_SendEventAbort( p_input );
547     input_SendEventDead( p_input );
548
549     vlc_restorecancel( canc );
550     return NULL;
551 }
552
553 /*****************************************************************************
554  * Main loop: Fill buffers from access, and demux
555  *****************************************************************************/
556
557 /**
558  * MainLoopDemux
559  * It asks the demuxer to demux some data
560  */
561 static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_demux_polled, mtime_t i_start_mdate )
562 {
563     int i_ret;
564
565     *pb_changed = false;
566     *pb_demux_polled = p_input->p->input.p_demux->pf_demux != NULL;
567
568     if( ( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop ) ||
569         ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) )
570         i_ret = 0; /* EOF */
571     else
572         i_ret = demux_Demux( p_input->p->input.p_demux );
573
574     if( i_ret > 0 )
575     {
576         if( p_input->p->input.p_demux->info.i_update )
577         {
578             if( p_input->p->input.b_title_demux )
579             {
580                 i_ret = UpdateTitleSeekpointFromDemux( p_input );
581                 *pb_changed = true;
582             }
583             UpdateGenericFromDemux( p_input );
584         }
585         else if( p_input->p->input.p_access &&
586                  p_input->p->input.p_access->info.i_update )
587         {
588             if( !p_input->p->input.b_title_demux )
589             {
590                 i_ret = UpdateTitleSeekpointFromAccess( p_input );
591                 *pb_changed = true;
592             }
593             UpdateGenericFromAccess( p_input );
594         }
595     }
596
597     if( i_ret == 0 )    /* EOF */
598     {
599         msg_Dbg( p_input, "EOF reached" );
600         p_input->p->input.b_eof = true;
601     }
602     else if( i_ret < 0 )
603     {
604         input_ChangeState( p_input, ERROR_S );
605     }
606
607     if( i_ret > 0 && p_input->p->i_slave > 0 )
608     {
609         bool b_demux_polled;
610         SlaveDemux( p_input, &b_demux_polled );
611
612         *pb_demux_polled |= b_demux_polled;
613     }
614 }
615
616 static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate )
617 {
618     int i_repeat = var_GetInteger( p_input, "input-repeat" );
619     if( i_repeat == 0 )
620         return VLC_EGENERIC;
621
622     vlc_value_t val;
623
624     msg_Dbg( p_input, "repeating the same input (%d)", i_repeat );
625     if( i_repeat > 0 )
626     {
627         i_repeat--;
628         var_SetInteger( p_input, "input-repeat", i_repeat );
629     }
630
631     /* Seek to start title/seekpoint */
632     val.i_int = p_input->p->input.i_title_start -
633         p_input->p->input.i_title_offset;
634     if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title )
635         val.i_int = 0;
636     input_ControlPush( p_input,
637                        INPUT_CONTROL_SET_TITLE, &val );
638
639     val.i_int = p_input->p->input.i_seekpoint_start -
640         p_input->p->input.i_seekpoint_offset;
641     if( val.i_int > 0 /* TODO: check upper boundary */ )
642         input_ControlPush( p_input,
643                            INPUT_CONTROL_SET_SEEKPOINT, &val );
644
645     /* Seek to start position */
646     if( p_input->p->i_start > 0 )
647     {
648         val.i_time = p_input->p->i_start;
649         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val );
650     }
651     else
652     {
653         val.f_float = 0.0;
654         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
655     }
656
657     /* */
658     *pi_start_mdate = mdate();
659     return VLC_SUCCESS;
660 }
661
662 /**
663  * MainLoopInterface
664  * It update the variables used by the interfaces
665  */
666 static void MainLoopInterface( input_thread_t *p_input )
667 {
668     double f_position = 0.0;
669     mtime_t i_time = 0;
670     mtime_t i_length = 0;
671
672     /* update input status variables */
673     if( demux_Control( p_input->p->input.p_demux,
674                        DEMUX_GET_POSITION, &f_position ) )
675         f_position = 0.0;
676
677     if( demux_Control( p_input->p->input.p_demux,
678                        DEMUX_GET_TIME, &i_time ) )
679         i_time = 0;
680     p_input->p->i_time = i_time;
681
682     if( demux_Control( p_input->p->input.p_demux,
683                        DEMUX_GET_LENGTH, &i_length ) )
684         i_length = 0;
685
686     es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
687
688     /* update current bookmark */
689     vlc_mutex_lock( &p_input->p->p_item->lock );
690     p_input->p->bookmark.i_time_offset = i_time;
691     if( p_input->p->input.p_stream )
692         p_input->p->bookmark.i_byte_offset = stream_Tell( p_input->p->input.p_stream );
693     vlc_mutex_unlock( &p_input->p->p_item->lock );
694 }
695
696 /**
697  * MainLoopStatistic
698  * It updates the globals statics
699  */
700 static void MainLoopStatistic( input_thread_t *p_input )
701 {
702     stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
703     input_SendEventStatistics( p_input );
704 }
705
706 /**
707  * MainLoop
708  * The main input loop.
709  */
710 static void MainLoop( input_thread_t *p_input, bool b_interactive )
711 {
712     mtime_t i_start_mdate = mdate();
713     mtime_t i_intf_update = 0;
714     mtime_t i_statistic_update = 0;
715     mtime_t i_last_seek_mdate = 0;
716     bool b_pause_after_eof = b_interactive &&
717                              var_CreateGetBool( p_input, "play-and-pause" );
718
719     /* Start the timer */
720     stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING );
721
722     while( vlc_object_alive( p_input ) && !p_input->b_error )
723     {
724         bool b_force_update;
725         vlc_value_t val;
726         mtime_t i_current;
727         mtime_t i_wakeup;
728         bool b_paused;
729         bool b_demux_polled;
730
731         /* Demux data */
732         b_force_update = false;
733         i_wakeup = 0;
734         /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
735          * is paused -> this may cause problem with some of them
736          * The same problem can be seen when seeking while paused */
737         b_paused = p_input->p->i_state == PAUSE_S &&
738                    ( !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof );
739
740         b_demux_polled = true;
741         if( !b_paused )
742         {
743             if( !p_input->p->input.b_eof )
744             {
745                 MainLoopDemux( p_input, &b_force_update, &b_demux_polled, i_start_mdate );
746
747                 i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
748             }
749             else if( !es_out_GetEmpty( p_input->p->p_es_out ) )
750             {
751                 msg_Dbg( p_input, "waiting decoder fifos to empty" );
752                 i_wakeup = mdate() + INPUT_IDLE_SLEEP;
753             }
754             /* Pause after eof only if the input is pausable.
755              * This way we won't trigger timeshifting for nothing */
756             else if( b_pause_after_eof && p_input->p->b_can_pause )
757             {
758                 msg_Dbg( p_input, "pausing at EOF (pause after each)");
759                 val.i_int = PAUSE_S;
760                 Control( p_input, INPUT_CONTROL_SET_STATE, val );
761
762                 b_pause_after_eof = false;
763                 b_paused = true;
764             }
765             else
766             {
767                 if( MainLoopTryRepeat( p_input, &i_start_mdate ) )
768                     break;
769                 b_pause_after_eof = var_GetBool( p_input, "play-and-pause" );
770             }
771         }
772
773         /* */
774         do {
775             mtime_t i_deadline = i_wakeup;
776             if( b_paused || !b_demux_polled )
777                 i_deadline = __MIN( i_intf_update, i_statistic_update );
778
779             /* Handle control */
780             for( ;; )
781             {
782                 mtime_t i_limit = i_deadline;
783
784                 /* We will postpone the execution of a seek until we have
785                  * finished the ES bufferisation (postpone is limited to
786                  * 125ms) */
787                 bool b_buffering = es_out_GetBuffering( p_input->p->p_es_out ) &&
788                                    !p_input->p->input.b_eof;
789                 if( b_buffering )
790                 {
791                     /* When postpone is in order, check the ES level every 20ms */
792                     mtime_t i_current = mdate();
793                     if( i_last_seek_mdate + INT64_C(125000) >= i_current )
794                         i_limit = __MIN( i_deadline, i_current + INT64_C(20000) );
795                 }
796
797                 int i_type;
798                 if( ControlPop( p_input, &i_type, &val, i_limit, b_buffering ) )
799                 {
800                     if( b_buffering && i_limit < i_deadline )
801                         continue;
802                     break;
803                 }
804
805                 msg_Dbg( p_input, "control type=%d", i_type );
806
807                 if( Control( p_input, i_type, val ) )
808                 {
809                     if( ControlIsSeekRequest( i_type ) )
810                         i_last_seek_mdate = mdate();
811                     b_force_update = true;
812                 }
813             }
814
815             /* Update interface and statistics */
816             i_current = mdate();
817             if( i_intf_update < i_current || b_force_update )
818             {
819                 MainLoopInterface( p_input );
820                 i_intf_update = i_current + INT64_C(250000);
821                 b_force_update = false;
822             }
823             if( i_statistic_update < i_current )
824             {
825                 MainLoopStatistic( p_input );
826                 i_statistic_update = i_current + INT64_C(1000000);
827             }
828
829             /* Update the wakeup time */
830             if( i_wakeup != 0 )
831                 i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
832         } while( i_current < i_wakeup );
833     }
834
835     if( !p_input->b_error )
836         input_ChangeState( p_input, END_S );
837 }
838
839 static void InitStatistics( input_thread_t * p_input )
840 {
841     if( p_input->b_preparsing ) return;
842
843     /* Prepare statistics */
844 #define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
845  stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
846     if( libvlc_stats( p_input ) )
847     {
848         INIT_COUNTER( read_bytes, INTEGER, COUNTER );
849         INIT_COUNTER( read_packets, INTEGER, COUNTER );
850         INIT_COUNTER( demux_read, INTEGER, COUNTER );
851         INIT_COUNTER( input_bitrate, FLOAT, DERIVATIVE );
852         INIT_COUNTER( demux_bitrate, FLOAT, DERIVATIVE );
853         INIT_COUNTER( demux_corrupted, INTEGER, COUNTER );
854         INIT_COUNTER( demux_discontinuity, INTEGER, COUNTER );
855         INIT_COUNTER( played_abuffers, INTEGER, COUNTER );
856         INIT_COUNTER( lost_abuffers, INTEGER, COUNTER );
857         INIT_COUNTER( displayed_pictures, INTEGER, COUNTER );
858         INIT_COUNTER( lost_pictures, INTEGER, COUNTER );
859         INIT_COUNTER( decoded_audio, INTEGER, COUNTER );
860         INIT_COUNTER( decoded_video, INTEGER, COUNTER );
861         INIT_COUNTER( decoded_sub, INTEGER, COUNTER );
862         p_input->p->counters.p_sout_send_bitrate = NULL;
863         p_input->p->counters.p_sout_sent_packets = NULL;
864         p_input->p->counters.p_sout_sent_bytes = NULL;
865         if( p_input->p->counters.p_demux_bitrate )
866             p_input->p->counters.p_demux_bitrate->update_interval = 1000000;
867         if( p_input->p->counters.p_input_bitrate )
868             p_input->p->counters.p_input_bitrate->update_interval = 1000000;
869     }
870 }
871
872 #ifdef ENABLE_SOUT
873 static int InitSout( input_thread_t * p_input )
874 {
875     if( p_input->b_preparsing )
876         return VLC_SUCCESS;
877
878     /* Find a usable sout and attach it to p_input */
879     char *psz = var_GetNonEmptyString( p_input, "sout" );
880     if( psz && strncasecmp( p_input->p->p_item->psz_uri, "vlc:", 4 ) )
881     {
882         p_input->p->p_sout  = input_resource_RequestSout( p_input->p->p_resource, NULL, psz );
883         if( !p_input->p->p_sout )
884         {
885             input_ChangeState( p_input, ERROR_S );
886             msg_Err( p_input, "cannot start stream output instance, " \
887                               "aborting" );
888             free( psz );
889             return VLC_EGENERIC;
890         }
891         if( libvlc_stats( p_input ) )
892         {
893             INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
894             INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER );
895             INIT_COUNTER( sout_send_bitrate, FLOAT, DERIVATIVE );
896             if( p_input->p->counters.p_sout_send_bitrate )
897                  p_input->p->counters.p_sout_send_bitrate->update_interval =
898                          1000000;
899         }
900     }
901     else
902     {
903         input_resource_RequestSout( p_input->p->p_resource, NULL, NULL );
904     }
905     free( psz );
906
907     return VLC_SUCCESS;
908 }
909 #endif
910
911 static void InitTitle( input_thread_t * p_input )
912 {
913     input_source_t *p_master = &p_input->p->input;
914
915     if( p_input->b_preparsing )
916         return;
917
918     /* Create global title (from master) */
919     p_input->p->i_title = p_master->i_title;
920     p_input->p->title   = p_master->title;
921     p_input->p->i_title_offset = p_master->i_title_offset;
922     p_input->p->i_seekpoint_offset = p_master->i_seekpoint_offset;
923     if( p_input->p->i_title > 0 )
924     {
925         /* Setup variables */
926         input_ControlVarNavigation( p_input );
927         input_SendEventTitle( p_input, 0 );
928     }
929
930     /* Global flag */
931     p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
932     p_input->p->b_can_pause        = p_master->b_can_pause;
933     p_input->p->b_can_rate_control = p_master->b_can_rate_control;
934 }
935
936 static void StartTitle( input_thread_t * p_input )
937 {
938     vlc_value_t val;
939
940     /* Start title/chapter */
941     val.i_int = p_input->p->input.i_title_start -
942                 p_input->p->input.i_title_offset;
943     if( val.i_int > 0 && val.i_int < p_input->p->input.i_title )
944         input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
945
946     val.i_int = p_input->p->input.i_seekpoint_start -
947                 p_input->p->input.i_seekpoint_offset;
948     if( val.i_int > 0 /* TODO: check upper boundary */ )
949         input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
950
951     /* Start/stop/run time */
952     p_input->p->i_start = (int64_t)(1000000.0
953                                      * var_GetFloat( p_input, "start-time" ));
954     p_input->p->i_stop  = (int64_t)(1000000.0
955                                      * var_GetFloat( p_input, "stop-time" ));
956     p_input->p->i_run   = (int64_t)(1000000.0
957                                      * var_GetFloat( p_input, "run-time" ));
958     if( p_input->p->i_run < 0 )
959     {
960         msg_Warn( p_input, "invalid run-time ignored" );
961         p_input->p->i_run = 0;
962     }
963
964     if( p_input->p->i_start > 0 )
965     {
966         vlc_value_t s;
967
968         msg_Dbg( p_input, "starting at time: %ds",
969                  (int)( p_input->p->i_start / INT64_C(1000000) ) );
970
971         s.i_time = p_input->p->i_start;
972         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
973     }
974     if( p_input->p->i_stop > 0 && p_input->p->i_stop <= p_input->p->i_start )
975     {
976         msg_Warn( p_input, "invalid stop-time ignored" );
977         p_input->p->i_stop = 0;
978     }
979     p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
980 }
981
982 static void LoadSubtitles( input_thread_t *p_input )
983 {
984     /* Load subtitles */
985     /* Get fps and set it if not already set */
986     const double f_fps = p_input->p->f_fps;
987     if( f_fps > 1.0 )
988     {
989         float f_requested_fps;
990
991         var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
992         var_SetFloat( p_input, "sub-original-fps", f_fps );
993
994         f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
995         if( f_requested_fps != f_fps )
996         {
997             var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
998                                             VLC_VAR_DOINHERIT );
999             var_SetFloat( p_input, "sub-fps", f_requested_fps );
1000         }
1001     }
1002
1003     const int i_delay = var_CreateGetInteger( p_input, "sub-delay" );
1004     if( i_delay != 0 )
1005         var_SetTime( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
1006
1007     /* Look for and add subtitle files */
1008     bool b_forced = true;
1009
1010     char *psz_subtitle = var_GetNonEmptyString( p_input, "sub-file" );
1011     if( psz_subtitle != NULL )
1012     {
1013         msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
1014         SubtitleAdd( p_input, psz_subtitle, b_forced );
1015         b_forced = false;
1016     }
1017
1018     if( var_GetBool( p_input, "sub-autodetect-file" ) )
1019     {
1020         char *psz_autopath = var_GetNonEmptyString( p_input, "sub-autodetect-path" );
1021         char **ppsz_subs = subtitles_Detect( p_input, psz_autopath,
1022                                              p_input->p->p_item->psz_uri );
1023         free( psz_autopath );
1024
1025         for( int i = 0; ppsz_subs && ppsz_subs[i]; i++ )
1026         {
1027             if( !psz_subtitle || strcmp( psz_subtitle, ppsz_subs[i] ) )
1028             {
1029                 SubtitleAdd( p_input, ppsz_subs[i], b_forced );
1030                 b_forced = false;
1031             }
1032
1033             free( ppsz_subs[i] );
1034         }
1035         free( ppsz_subs );
1036     }
1037     free( psz_subtitle );
1038
1039     /* Load subtitles from attachments */
1040     int i_attachment = 0;
1041     input_attachment_t **pp_attachment = NULL;
1042
1043     vlc_mutex_lock( &p_input->p->p_item->lock );
1044     for( int i = 0; i < p_input->p->i_attachment; i++ )
1045     {
1046         const input_attachment_t *a = p_input->p->attachment[i];
1047         if( !strcmp( a->psz_mime, "application/x-srt" ) )
1048             TAB_APPEND( i_attachment, pp_attachment,
1049                         vlc_input_attachment_New( a->psz_name, NULL,
1050                                                   a->psz_description, NULL, 0 ) );
1051     }
1052     vlc_mutex_unlock( &p_input->p->p_item->lock );
1053
1054     if( i_attachment > 0 )
1055         var_Create( p_input, "sub-description", VLC_VAR_STRING );
1056     for( int i = 0; i < i_attachment; i++ )
1057     {
1058         input_attachment_t *a = pp_attachment[i];
1059         if( !a )
1060             continue;
1061         char *psz_mrl;
1062         if( a->psz_name[i] &&
1063             asprintf( &psz_mrl, "attachment://%s", a->psz_name ) >= 0 )
1064         {
1065             var_SetString( p_input, "sub-description", a->psz_description ? a->psz_description : "");
1066
1067             SubtitleAdd( p_input, psz_mrl, b_forced );
1068
1069             b_forced = false;
1070             free( psz_mrl );
1071         }
1072         vlc_input_attachment_Delete( a );
1073     }
1074     free( pp_attachment );
1075     if( i_attachment > 0 )
1076         var_Destroy( p_input, "sub-description" );
1077 }
1078
1079 static void LoadSlaves( input_thread_t *p_input )
1080 {
1081     char *psz = var_GetNonEmptyString( p_input, "input-slave" );
1082     if( !psz )
1083         return;
1084
1085     char *psz_org = psz;
1086     while( psz && *psz )
1087     {
1088         while( *psz == ' ' || *psz == '#' )
1089             psz++;
1090
1091         char *psz_delim = strchr( psz, '#' );
1092         if( psz_delim )
1093             *psz_delim++ = '\0';
1094
1095         if( *psz == 0 )
1096             break;
1097
1098         msg_Dbg( p_input, "adding slave input '%s'", psz );
1099
1100         input_source_t *p_slave = InputSourceNew( p_input );
1101         if( p_slave && !InputSourceInit( p_input, p_slave, psz, NULL ) )
1102             TAB_APPEND( p_input->p->i_slave, p_input->p->slave, p_slave );
1103         else
1104             free( p_slave );
1105
1106         psz = psz_delim;
1107     }
1108     free( psz_org );
1109 }
1110
1111 static void UpdatePtsDelay( input_thread_t *p_input )
1112 {
1113     input_thread_private_t *p_sys = p_input->p;
1114
1115     /* Get max pts delay from input source */
1116     mtime_t i_pts_delay = p_sys->input.i_pts_delay;
1117     for( int i = 0; i < p_sys->i_slave; i++ )
1118         i_pts_delay = __MAX( i_pts_delay, p_sys->slave[i]->i_pts_delay );
1119
1120     if( i_pts_delay < 0 )
1121         i_pts_delay = 0;
1122
1123     /* Take care of audio/spu delay */
1124     const mtime_t i_audio_delay = var_GetTime( p_input, "audio-delay" );
1125     const mtime_t i_spu_delay   = var_GetTime( p_input, "spu-delay" );
1126     const mtime_t i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
1127     if( i_extra_delay < 0 )
1128         i_pts_delay -= i_extra_delay;
1129
1130     /* Update cr_average depending on the caching */
1131     const int i_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY;
1132
1133     /* */
1134     es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, i_audio_delay );
1135     es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, i_spu_delay );
1136     es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, 0, i_cr_average );
1137 }
1138
1139 static void InitPrograms( input_thread_t * p_input )
1140 {
1141     int i_es_out_mode;
1142     vlc_value_t val;
1143
1144     /* Compute correct pts_delay */
1145     UpdatePtsDelay( p_input );
1146
1147     /* Set up es_out */
1148     i_es_out_mode = ES_OUT_MODE_AUTO;
1149     if( p_input->p->p_sout )
1150     {
1151         if( var_GetBool( p_input, "sout-all" ) )
1152         {
1153             i_es_out_mode = ES_OUT_MODE_ALL;
1154         }
1155         else
1156         {
1157             var_Get( p_input, "programs", &val );
1158             if( val.p_list && val.p_list->i_count )
1159             {
1160                 i_es_out_mode = ES_OUT_MODE_PARTIAL;
1161                 /* Note : we should remove the "program" callback. */
1162             }
1163             else
1164             {
1165                 var_FreeList( &val, NULL );
1166             }
1167         }
1168     }
1169     es_out_SetMode( p_input->p->p_es_out, i_es_out_mode );
1170
1171     /* Inform the demuxer about waited group (needed only for DVB) */
1172     if( i_es_out_mode == ES_OUT_MODE_ALL )
1173     {
1174         demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, -1, NULL );
1175     }
1176     else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
1177     {
1178         demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, -1,
1179                         val.p_list );
1180     }
1181     else
1182     {
1183         demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP,
1184                        (int) var_GetInteger( p_input, "program" ), NULL );
1185     }
1186 }
1187
1188 static int Init( input_thread_t * p_input )
1189 {
1190     vlc_meta_t *p_meta;
1191     int i;
1192
1193     for( i = 0; i < p_input->p->p_item->i_options; i++ )
1194     {
1195         if( !strncmp( p_input->p->p_item->ppsz_options[i], "meta-file", 9 ) )
1196         {
1197             msg_Dbg( p_input, "Input is a meta file: disabling unneeded options" );
1198             var_SetString( p_input, "sout", "" );
1199             var_SetBool( p_input, "sout-all", false );
1200             var_SetString( p_input, "input-slave", "" );
1201             var_SetInteger( p_input, "input-repeat", 0 );
1202             var_SetString( p_input, "sub-file", "" );
1203             var_SetBool( p_input, "sub-autodetect-file", false );
1204         }
1205     }
1206
1207     InitStatistics( p_input );
1208 #ifdef ENABLE_SOUT
1209     if( InitSout( p_input ) )
1210         goto error;
1211 #endif
1212
1213     /* Create es out */
1214     p_input->p->p_es_out = input_EsOutTimeshiftNew( p_input, p_input->p->p_es_out_display, p_input->p->i_rate );
1215
1216     /* */
1217     input_ChangeState( p_input, OPENING_S );
1218     input_SendEventCache( p_input, 0.0 );
1219
1220     /* */
1221     if( InputSourceInit( p_input, &p_input->p->input,
1222                          p_input->p->p_item->psz_uri, NULL ) )
1223     {
1224         goto error;
1225     }
1226
1227     InitTitle( p_input );
1228
1229     /* Load master infos */
1230     /* Init length */
1231     mtime_t i_length;
1232     if( demux_Control( p_input->p->input.p_demux, DEMUX_GET_LENGTH,
1233                          &i_length ) )
1234         i_length = 0;
1235     if( i_length <= 0 )
1236         i_length = input_item_GetDuration( p_input->p->p_item );
1237     input_SendEventLength( p_input, i_length );
1238
1239     input_SendEventPosition( p_input, 0.0, 0 );
1240
1241     if( !p_input->b_preparsing )
1242     {
1243         StartTitle( p_input );
1244         LoadSubtitles( p_input );
1245         LoadSlaves( p_input );
1246         InitPrograms( p_input );
1247     }
1248
1249     if( !p_input->b_preparsing && p_input->p->p_sout )
1250     {
1251         p_input->p->b_out_pace_control = (p_input->p->p_sout->i_out_pace_nocontrol > 0);
1252
1253         if( p_input->p->b_can_pace_control && p_input->p->b_out_pace_control )
1254         {
1255             /* We don't want a high input priority here or we'll
1256              * end-up sucking up all the CPU time */
1257             vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
1258         }
1259
1260         msg_Dbg( p_input, "starting in %s mode",
1261                  p_input->p->b_out_pace_control ? "async" : "sync" );
1262     }
1263
1264     p_meta = vlc_meta_New();
1265     if( p_meta )
1266     {
1267         /* Get meta data from users */
1268         InputMetaUser( p_input, p_meta );
1269
1270         /* Get meta data from master input */
1271         InputSourceMeta( p_input, &p_input->p->input, p_meta );
1272
1273         /* And from slave */
1274         for( int i = 0; i < p_input->p->i_slave; i++ )
1275             InputSourceMeta( p_input, p_input->p->slave[i], p_meta );
1276
1277         /* */
1278         InputUpdateMeta( p_input, p_meta );
1279     }
1280
1281     msg_Dbg( p_input, "`%s' successfully opened",
1282              p_input->p->p_item->psz_uri );
1283
1284     /* initialization is complete */
1285     input_ChangeState( p_input, PLAYING_S );
1286
1287     return VLC_SUCCESS;
1288
1289 error:
1290     input_ChangeState( p_input, ERROR_S );
1291
1292     if( p_input->p->p_es_out )
1293         es_out_Delete( p_input->p->p_es_out );
1294     es_out_SetMode( p_input->p->p_es_out_display, ES_OUT_MODE_END );
1295     if( p_input->p->p_resource )
1296     {
1297         if( p_input->p->p_sout )
1298             input_resource_RequestSout( p_input->p->p_resource,
1299                                          p_input->p->p_sout, NULL );
1300         input_resource_SetInput( p_input->p->p_resource, NULL );
1301         if( p_input->p->p_resource_private )
1302             input_resource_Terminate( p_input->p->p_resource_private );
1303     }
1304
1305     if( !p_input->b_preparsing && libvlc_stats( p_input ) )
1306     {
1307 #define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
1308                                    stats_CounterClean( p_input->p->counters.p_##c );\
1309                                p_input->p->counters.p_##c = NULL; } while(0)
1310         EXIT_COUNTER( read_bytes );
1311         EXIT_COUNTER( read_packets );
1312         EXIT_COUNTER( demux_read );
1313         EXIT_COUNTER( input_bitrate );
1314         EXIT_COUNTER( demux_bitrate );
1315         EXIT_COUNTER( demux_corrupted );
1316         EXIT_COUNTER( demux_discontinuity );
1317         EXIT_COUNTER( played_abuffers );
1318         EXIT_COUNTER( lost_abuffers );
1319         EXIT_COUNTER( displayed_pictures );
1320         EXIT_COUNTER( lost_pictures );
1321         EXIT_COUNTER( decoded_audio );
1322         EXIT_COUNTER( decoded_video );
1323         EXIT_COUNTER( decoded_sub );
1324
1325         if( p_input->p->p_sout )
1326         {
1327             EXIT_COUNTER( sout_sent_packets );
1328             EXIT_COUNTER( sout_sent_bytes );
1329             EXIT_COUNTER( sout_send_bitrate );
1330         }
1331 #undef EXIT_COUNTER
1332     }
1333
1334     /* Mark them deleted */
1335     p_input->p->input.p_demux = NULL;
1336     p_input->p->input.p_stream = NULL;
1337     p_input->p->input.p_access = NULL;
1338     p_input->p->p_es_out = NULL;
1339     p_input->p->p_sout = NULL;
1340
1341     return VLC_EGENERIC;
1342 }
1343
1344 /*****************************************************************************
1345  * End: end the input thread
1346  *****************************************************************************/
1347 static void End( input_thread_t * p_input )
1348 {
1349     int i;
1350
1351     /* We are at the end */
1352     input_ChangeState( p_input, END_S );
1353
1354     /* Clean control variables */
1355     input_ControlVarStop( p_input );
1356
1357     /* Stop es out activity */
1358     es_out_SetMode( p_input->p->p_es_out, ES_OUT_MODE_NONE );
1359
1360     /* Clean up master */
1361     InputSourceClean( &p_input->p->input );
1362
1363     /* Delete slave */
1364     for( i = 0; i < p_input->p->i_slave; i++ )
1365     {
1366         InputSourceClean( p_input->p->slave[i] );
1367         free( p_input->p->slave[i] );
1368     }
1369     free( p_input->p->slave );
1370
1371     /* Unload all modules */
1372     if( p_input->p->p_es_out )
1373         es_out_Delete( p_input->p->p_es_out );
1374     es_out_SetMode( p_input->p->p_es_out_display, ES_OUT_MODE_END );
1375
1376     if( !p_input->b_preparsing )
1377     {
1378 #define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
1379         if( libvlc_stats( p_input ) )
1380         {
1381             /* make sure we are up to date */
1382             stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
1383             CL_CO( read_bytes );
1384             CL_CO( read_packets );
1385             CL_CO( demux_read );
1386             CL_CO( input_bitrate );
1387             CL_CO( demux_bitrate );
1388             CL_CO( demux_corrupted );
1389             CL_CO( demux_discontinuity );
1390             CL_CO( played_abuffers );
1391             CL_CO( lost_abuffers );
1392             CL_CO( displayed_pictures );
1393             CL_CO( lost_pictures );
1394             CL_CO( decoded_audio) ;
1395             CL_CO( decoded_video );
1396             CL_CO( decoded_sub) ;
1397         }
1398
1399         /* Close optional stream output instance */
1400         if( p_input->p->p_sout )
1401         {
1402             CL_CO( sout_sent_packets );
1403             CL_CO( sout_sent_bytes );
1404             CL_CO( sout_send_bitrate );
1405         }
1406 #undef CL_CO
1407     }
1408
1409     vlc_mutex_lock( &p_input->p->p_item->lock );
1410     if( p_input->p->i_attachment > 0 )
1411     {
1412         for( i = 0; i < p_input->p->i_attachment; i++ )
1413             vlc_input_attachment_Delete( p_input->p->attachment[i] );
1414         TAB_CLEAN( p_input->p->i_attachment, p_input->p->attachment );
1415     }
1416     vlc_mutex_unlock( &p_input->p->p_item->lock );
1417
1418     /* */
1419     input_resource_RequestSout( p_input->p->p_resource,
1420                                  p_input->p->p_sout, NULL );
1421     input_resource_SetInput( p_input->p->p_resource, NULL );
1422     if( p_input->p->p_resource_private )
1423         input_resource_Terminate( p_input->p->p_resource_private );
1424 }
1425
1426 /*****************************************************************************
1427  * Control
1428  *****************************************************************************/
1429 void input_ControlPush( input_thread_t *p_input,
1430                         int i_type, vlc_value_t *p_val )
1431 {
1432     vlc_mutex_lock( &p_input->p->lock_control );
1433     if( i_type == INPUT_CONTROL_SET_DIE )
1434     {
1435         /* Special case, empty the control */
1436         for( int i = 0; i < p_input->p->i_control; i++ )
1437         {
1438             input_control_t *p_ctrl = &p_input->p->control[i];
1439             ControlRelease( p_ctrl->i_type, p_ctrl->val );
1440         }
1441         p_input->p->i_control = 0;
1442     }
1443
1444     if( p_input->p->i_control >= INPUT_CONTROL_FIFO_SIZE )
1445     {
1446         msg_Err( p_input, "input control fifo overflow, trashing type=%d",
1447                  i_type );
1448         if( p_val )
1449             ControlRelease( i_type, *p_val );
1450     }
1451     else
1452     {
1453         input_control_t c;
1454         c.i_type = i_type;
1455         if( p_val )
1456             c.val = *p_val;
1457         else
1458             memset( &c.val, 0, sizeof(c.val) );
1459
1460         p_input->p->control[p_input->p->i_control++] = c;
1461     }
1462     vlc_cond_signal( &p_input->p->wait_control );
1463     vlc_mutex_unlock( &p_input->p->lock_control );
1464 }
1465
1466 static int ControlGetReducedIndexLocked( input_thread_t *p_input )
1467 {
1468     const int i_lt = p_input->p->control[0].i_type;
1469     int i;
1470     for( i = 1; i < p_input->p->i_control; i++ )
1471     {
1472         const int i_ct = p_input->p->control[i].i_type;
1473
1474         if( i_lt == i_ct &&
1475             ( i_ct == INPUT_CONTROL_SET_STATE ||
1476               i_ct == INPUT_CONTROL_SET_RATE ||
1477               i_ct == INPUT_CONTROL_SET_POSITION ||
1478               i_ct == INPUT_CONTROL_SET_TIME ||
1479               i_ct == INPUT_CONTROL_SET_PROGRAM ||
1480               i_ct == INPUT_CONTROL_SET_TITLE ||
1481               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
1482               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
1483         {
1484             continue;
1485         }
1486         else
1487         {
1488             /* TODO but that's not that important
1489                 - merge SET_X with SET_X_CMD
1490                 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1491                 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1492                 - ?
1493                 */
1494             break;
1495         }
1496     }
1497     return i - 1;
1498 }
1499
1500
1501 static inline int ControlPop( input_thread_t *p_input,
1502                               int *pi_type, vlc_value_t *p_val,
1503                               mtime_t i_deadline, bool b_postpone_seek )
1504 {
1505     input_thread_private_t *p_sys = p_input->p;
1506
1507     vlc_mutex_lock( &p_sys->lock_control );
1508     while( p_sys->i_control <= 0 ||
1509            ( b_postpone_seek && ControlIsSeekRequest( p_sys->control[0].i_type ) ) )
1510     {
1511         if( !vlc_object_alive( p_input ) || i_deadline < 0 )
1512         {
1513             vlc_mutex_unlock( &p_sys->lock_control );
1514             return VLC_EGENERIC;
1515         }
1516
1517         if( vlc_cond_timedwait( &p_sys->wait_control, &p_sys->lock_control,
1518                                 i_deadline ) )
1519         {
1520             vlc_mutex_unlock( &p_sys->lock_control );
1521             return VLC_EGENERIC;
1522         }
1523     }
1524
1525     /* */
1526     const int i_index = ControlGetReducedIndexLocked( p_input );
1527
1528     /* */
1529     *pi_type = p_sys->control[i_index].i_type;
1530     *p_val   = p_sys->control[i_index].val;
1531
1532     p_sys->i_control -= i_index + 1;
1533     if( p_sys->i_control > 0 )
1534         memmove( &p_sys->control[0], &p_sys->control[i_index+1],
1535                  sizeof(*p_sys->control) * p_sys->i_control );
1536     vlc_mutex_unlock( &p_sys->lock_control );
1537
1538     return VLC_SUCCESS;
1539 }
1540 static bool ControlIsSeekRequest( int i_type )
1541 {
1542     switch( i_type )
1543     {
1544     case INPUT_CONTROL_SET_POSITION:
1545     case INPUT_CONTROL_SET_TIME:
1546     case INPUT_CONTROL_SET_TITLE:
1547     case INPUT_CONTROL_SET_TITLE_NEXT:
1548     case INPUT_CONTROL_SET_TITLE_PREV:
1549     case INPUT_CONTROL_SET_SEEKPOINT:
1550     case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1551     case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1552     case INPUT_CONTROL_SET_BOOKMARK:
1553         return true;
1554     default:
1555         return false;
1556     }
1557 }
1558
1559 static void ControlRelease( int i_type, vlc_value_t val )
1560 {
1561     switch( i_type )
1562     {
1563     case INPUT_CONTROL_ADD_SUBTITLE:
1564     case INPUT_CONTROL_ADD_SLAVE:
1565         free( val.psz_string );
1566         break;
1567
1568     default:
1569         break;
1570     }
1571 }
1572
1573 /* Pause input */
1574 static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
1575 {
1576     int i_ret = VLC_SUCCESS;
1577     int i_state = PAUSE_S;
1578
1579     if( p_input->p->b_can_pause )
1580     {
1581         if( p_input->p->input.p_access )
1582             i_ret = access_Control( p_input->p->input.p_access,
1583                                      ACCESS_SET_PAUSE_STATE, true );
1584         else
1585             i_ret = demux_Control( p_input->p->input.p_demux,
1586                                     DEMUX_SET_PAUSE_STATE, true );
1587
1588         if( i_ret )
1589         {
1590             msg_Warn( p_input, "cannot set pause state" );
1591             return;
1592         }
1593     }
1594
1595     /* */
1596     i_ret = es_out_SetPauseState( p_input->p->p_es_out,
1597                                   p_input->p->b_can_pause, true,
1598                                   i_control_date );
1599     if( i_ret )
1600     {
1601         msg_Warn( p_input, "cannot set pause state at es_out level" );
1602         return;
1603     }
1604
1605     /* Switch to new state */
1606     input_ChangeState( p_input, i_state );
1607 }
1608
1609 static void ControlUnpause( input_thread_t *p_input, mtime_t i_control_date )
1610 {
1611     int i_ret = VLC_SUCCESS;
1612
1613     if( p_input->p->b_can_pause )
1614     {
1615         if( p_input->p->input.p_access )
1616             i_ret = access_Control( p_input->p->input.p_access,
1617                                      ACCESS_SET_PAUSE_STATE, false );
1618         else
1619             i_ret = demux_Control( p_input->p->input.p_demux,
1620                                     DEMUX_SET_PAUSE_STATE, false );
1621         if( i_ret )
1622         {
1623             /* FIXME What to do ? */
1624             msg_Warn( p_input, "cannot unset pause -> EOF" );
1625             input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
1626         }
1627     }
1628
1629     /* Switch to play */
1630     input_ChangeState( p_input, PLAYING_S );
1631
1632     /* */
1633     if( !i_ret )
1634         es_out_SetPauseState( p_input->p->p_es_out, false, false, i_control_date );
1635 }
1636
1637 static bool Control( input_thread_t *p_input,
1638                      int i_type, vlc_value_t val )
1639 {
1640     const mtime_t i_control_date = mdate();
1641     /* FIXME b_force_update is abused, it should be carefully checked */
1642     bool b_force_update = false;
1643
1644     if( !p_input )
1645         return b_force_update;
1646
1647     switch( i_type )
1648     {
1649         case INPUT_CONTROL_SET_DIE:
1650             msg_Dbg( p_input, "control: stopping input" );
1651
1652             /* Mark all submodules to die */
1653             ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );
1654             break;
1655
1656         case INPUT_CONTROL_SET_POSITION:
1657         {
1658             double f_pos;
1659
1660             if( p_input->p->b_recording )
1661             {
1662                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) ignored while recording" );
1663                 break;
1664             }
1665             f_pos = val.f_float;
1666             if( i_type != INPUT_CONTROL_SET_POSITION )
1667                 f_pos += var_GetFloat( p_input, "position" );
1668             if( f_pos < 0.0 )
1669                 f_pos = 0.0;
1670             else if( f_pos > 1.0 )
1671                 f_pos = 1.0;
1672             /* Reset the decoders states and clock sync (before calling the demuxer */
1673             es_out_SetTime( p_input->p->p_es_out, -1 );
1674             if( demux_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION,
1675                                 f_pos, !p_input->p->b_fast_seek ) )
1676             {
1677                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1678                          "%2.1f%% failed", f_pos * 100 );
1679             }
1680             else
1681             {
1682                 if( p_input->p->i_slave > 0 )
1683                     SlaveSeek( p_input );
1684                 p_input->p->input.b_eof = false;
1685
1686                 b_force_update = true;
1687             }
1688             break;
1689         }
1690
1691         case INPUT_CONTROL_SET_TIME:
1692         {
1693             int64_t i_time;
1694             int i_ret;
1695
1696             if( p_input->p->b_recording )
1697             {
1698                 msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) ignored while recording" );
1699                 break;
1700             }
1701
1702             i_time = val.i_time;
1703             if( i_type != INPUT_CONTROL_SET_TIME )
1704                 i_time += var_GetTime( p_input, "time" );
1705
1706             if( i_time < 0 )
1707                 i_time = 0;
1708
1709             /* Reset the decoders states and clock sync (before calling the demuxer */
1710             es_out_SetTime( p_input->p->p_es_out, -1 );
1711
1712             i_ret = demux_Control( p_input->p->input.p_demux,
1713                                    DEMUX_SET_TIME, i_time,
1714                                    !p_input->p->b_fast_seek );
1715             if( i_ret )
1716             {
1717                 int64_t i_length;
1718
1719                 /* Emulate it with a SET_POS */
1720                 if( !demux_Control( p_input->p->input.p_demux,
1721                                     DEMUX_GET_LENGTH, &i_length ) && i_length > 0 )
1722                 {
1723                     double f_pos = (double)i_time / (double)i_length;
1724                     i_ret = demux_Control( p_input->p->input.p_demux,
1725                                             DEMUX_SET_POSITION, f_pos,
1726                                             !p_input->p->b_fast_seek );
1727                 }
1728             }
1729             if( i_ret )
1730             {
1731                 msg_Warn( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) %"PRId64
1732                          " failed or not possible", i_time );
1733             }
1734             else
1735             {
1736                 if( p_input->p->i_slave > 0 )
1737                     SlaveSeek( p_input );
1738                 p_input->p->input.b_eof = false;
1739
1740                 b_force_update = true;
1741             }
1742             break;
1743         }
1744
1745         case INPUT_CONTROL_SET_STATE:
1746             if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
1747                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
1748             else if( p_input->p->i_state == PAUSE_S )
1749             {
1750                 ControlUnpause( p_input, i_control_date );
1751
1752                 b_force_update = true;
1753             }
1754             else if( val.i_int == PAUSE_S && p_input->p->i_state == PLAYING_S /* &&
1755                      p_input->p->b_can_pause */ )
1756             {
1757                 ControlPause( p_input, i_control_date );
1758
1759                 b_force_update = true;
1760             }
1761             else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause && 0 )
1762             {
1763                 b_force_update = true;
1764
1765                 /* Correct "state" value */
1766                 input_ChangeState( p_input, p_input->p->i_state );
1767             }
1768             break;
1769
1770         case INPUT_CONTROL_SET_RATE:
1771         {
1772             /* Get rate and direction */
1773             int i_rate = abs( val.i_int );
1774             int i_rate_sign = val.i_int < 0 ? -1 : 1;
1775
1776             /* Check rate bound */
1777             if( i_rate < INPUT_RATE_MIN )
1778             {
1779                 msg_Dbg( p_input, "cannot set rate faster" );
1780                 i_rate = INPUT_RATE_MIN;
1781             }
1782             else if( i_rate > INPUT_RATE_MAX )
1783             {
1784                 msg_Dbg( p_input, "cannot set rate slower" );
1785                 i_rate = INPUT_RATE_MAX;
1786             }
1787
1788             /* Apply direction */
1789             if( i_rate_sign < 0 )
1790             {
1791                 if( p_input->p->input.b_rescale_ts )
1792                 {
1793                     msg_Dbg( p_input, "cannot set negative rate" );
1794                     i_rate = p_input->p->i_rate;
1795                     assert( i_rate > 0 );
1796                 }
1797                 else
1798                 {
1799                     i_rate *= i_rate_sign;
1800                 }
1801             }
1802
1803             if( i_rate != INPUT_RATE_DEFAULT &&
1804                 ( ( !p_input->p->b_can_rate_control && !p_input->p->input.b_rescale_ts ) ||
1805                   ( p_input->p->p_sout && !p_input->p->b_out_pace_control ) ) )
1806             {
1807                 msg_Dbg( p_input, "cannot change rate" );
1808                 i_rate = INPUT_RATE_DEFAULT;
1809             }
1810             if( i_rate != p_input->p->i_rate &&
1811                 !p_input->p->b_can_pace_control && p_input->p->b_can_rate_control )
1812             {
1813                 int i_ret;
1814                 if( p_input->p->input.p_access )
1815                 {
1816                     i_ret = VLC_EGENERIC;
1817                 }
1818                 else
1819                 {
1820                     if( !p_input->p->input.b_rescale_ts )
1821                         es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1822
1823                     i_ret = demux_Control( p_input->p->input.p_demux,
1824                                             DEMUX_SET_RATE, &i_rate );
1825                 }
1826                 if( i_ret )
1827                 {
1828                     msg_Warn( p_input, "ACCESS/DEMUX_SET_RATE failed" );
1829                     i_rate = p_input->p->i_rate;
1830                 }
1831             }
1832
1833             /* */
1834             if( i_rate != p_input->p->i_rate )
1835             {
1836                 p_input->p->i_rate = i_rate;
1837                 input_SendEventRate( p_input, i_rate );
1838
1839                 if( p_input->p->input.b_rescale_ts )
1840                 {
1841                     const int i_rate_source = (p_input->p->b_can_pace_control || p_input->p->b_can_rate_control ) ? i_rate : INPUT_RATE_DEFAULT;
1842                     es_out_SetRate( p_input->p->p_es_out, i_rate_source, i_rate );
1843                 }
1844
1845                 b_force_update = true;
1846             }
1847             break;
1848         }
1849
1850         case INPUT_CONTROL_SET_PROGRAM:
1851             /* No need to force update, es_out does it if needed */
1852             es_out_Control( p_input->p->p_es_out,
1853                             ES_OUT_SET_GROUP, val.i_int );
1854
1855             demux_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, val.i_int,
1856                             NULL );
1857             break;
1858
1859         case INPUT_CONTROL_SET_ES:
1860             /* No need to force update, es_out does it if needed */
1861             es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_BY_ID, val.i_int );
1862             break;
1863
1864         case INPUT_CONTROL_RESTART_ES:
1865             es_out_Control( p_input->p->p_es_out_display, ES_OUT_RESTART_ES_BY_ID, val.i_int );
1866             break;
1867
1868         case INPUT_CONTROL_SET_AUDIO_DELAY:
1869             input_SendEventAudioDelay( p_input, val.i_time );
1870             UpdatePtsDelay( p_input );
1871             break;
1872
1873         case INPUT_CONTROL_SET_SPU_DELAY:
1874             input_SendEventSubtitleDelay( p_input, val.i_time );
1875             UpdatePtsDelay( p_input );
1876             break;
1877
1878         case INPUT_CONTROL_SET_TITLE:
1879         case INPUT_CONTROL_SET_TITLE_NEXT:
1880         case INPUT_CONTROL_SET_TITLE_PREV:
1881             if( p_input->p->b_recording )
1882             {
1883                 msg_Err( p_input, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
1884                 break;
1885             }
1886             if( p_input->p->input.b_title_demux &&
1887                 p_input->p->input.i_title > 0 )
1888             {
1889                 /* TODO */
1890                 /* FIXME handle demux title */
1891                 demux_t *p_demux = p_input->p->input.p_demux;
1892                 int i_title;
1893
1894                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1895                     i_title = p_demux->info.i_title - 1;
1896                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1897                     i_title = p_demux->info.i_title + 1;
1898                 else
1899                     i_title = val.i_int;
1900
1901                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
1902                 {
1903                     es_out_SetTime( p_input->p->p_es_out, -1 );
1904
1905                     demux_Control( p_demux, DEMUX_SET_TITLE, i_title );
1906                     input_SendEventTitle( p_input, i_title );
1907                 }
1908             }
1909             else if( p_input->p->input.i_title > 0 )
1910             {
1911                 access_t *p_access = p_input->p->input.p_access;
1912                 int i_title;
1913
1914                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1915                     i_title = p_access->info.i_title - 1;
1916                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1917                     i_title = p_access->info.i_title + 1;
1918                 else
1919                     i_title = val.i_int;
1920
1921                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
1922                 {
1923                     es_out_SetTime( p_input->p->p_es_out, -1 );
1924
1925                     stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
1926                                     ACCESS_SET_TITLE, i_title );
1927                     input_SendEventTitle( p_input, i_title );
1928                 }
1929             }
1930             break;
1931         case INPUT_CONTROL_SET_SEEKPOINT:
1932         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1933         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1934             if( p_input->p->b_recording )
1935             {
1936                 msg_Err( p_input, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
1937                 break;
1938             }
1939
1940             if( p_input->p->input.b_title_demux &&
1941                 p_input->p->input.i_title > 0 )
1942             {
1943                 demux_t *p_demux = p_input->p->input.p_demux;
1944                 int i_seekpoint;
1945                 int64_t i_input_time;
1946                 int64_t i_seekpoint_time;
1947
1948                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1949                 {
1950                     i_seekpoint = p_demux->info.i_seekpoint;
1951                     i_seekpoint_time = p_input->p->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1952                     i_input_time = var_GetTime( p_input, "time" );
1953                     if( i_seekpoint_time >= 0 && i_input_time >= 0 )
1954                     {
1955                         if( i_input_time < i_seekpoint_time + 3000000 )
1956                             i_seekpoint--;
1957                     }
1958                     else
1959                         i_seekpoint--;
1960                 }
1961                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
1962                     i_seekpoint = p_demux->info.i_seekpoint + 1;
1963                 else
1964                     i_seekpoint = val.i_int;
1965
1966                 if( i_seekpoint >= 0 && i_seekpoint <
1967                     p_input->p->input.title[p_demux->info.i_title]->i_seekpoint )
1968                 {
1969
1970                     es_out_SetTime( p_input->p->p_es_out, -1 );
1971
1972                     demux_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
1973                     input_SendEventSeekpoint( p_input, p_demux->info.i_title, i_seekpoint );
1974                 }
1975             }
1976             else if( p_input->p->input.i_title > 0 )
1977             {
1978                 access_t *p_access = p_input->p->input.p_access;
1979                 int i_seekpoint;
1980                 int64_t i_input_time;
1981                 int64_t i_seekpoint_time;
1982
1983                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1984                 {
1985                     i_seekpoint = p_access->info.i_seekpoint;
1986                     i_seekpoint_time = p_input->p->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1987                     i_input_time = var_GetTime( p_input, "time" );
1988                     if( i_seekpoint_time >= 0 && i_input_time >= 0 )
1989                     {
1990                         if( i_input_time < i_seekpoint_time + 3000000 )
1991                             i_seekpoint--;
1992                     }
1993                     else
1994                         i_seekpoint--;
1995                 }
1996                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
1997                     i_seekpoint = p_access->info.i_seekpoint + 1;
1998                 else
1999                     i_seekpoint = val.i_int;
2000
2001                 if( i_seekpoint >= 0 && i_seekpoint <
2002                     p_input->p->input.title[p_access->info.i_title]->i_seekpoint )
2003                 {
2004                     es_out_SetTime( p_input->p->p_es_out, -1 );
2005
2006                     stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
2007                                     ACCESS_SET_SEEKPOINT, i_seekpoint );
2008                     input_SendEventSeekpoint( p_input, p_access->info.i_title, i_seekpoint );
2009                 }
2010             }
2011             break;
2012
2013         case INPUT_CONTROL_ADD_SUBTITLE:
2014             if( val.psz_string )
2015                 SubtitleAdd( p_input, val.psz_string, true );
2016             break;
2017
2018         case INPUT_CONTROL_ADD_SLAVE:
2019             if( val.psz_string )
2020             {
2021                 input_source_t *slave = InputSourceNew( p_input );
2022
2023                 if( slave && !InputSourceInit( p_input, slave, val.psz_string, NULL ) )
2024                 {
2025                     vlc_meta_t *p_meta;
2026                     int64_t i_time;
2027
2028                     /* Add the slave */
2029                     msg_Dbg( p_input, "adding %s as slave on the fly",
2030                              val.psz_string );
2031
2032                     /* Set position */
2033                     if( demux_Control( p_input->p->input.p_demux,
2034                                         DEMUX_GET_TIME, &i_time ) )
2035                     {
2036                         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2037                         InputSourceClean( slave );
2038                         free( slave );
2039                         break;
2040                     }
2041                     if( demux_Control( slave->p_demux,
2042                                        DEMUX_SET_TIME, i_time, true ) )
2043                     {
2044                         msg_Err( p_input, "seek failed for new slave" );
2045                         InputSourceClean( slave );
2046                         free( slave );
2047                         break;
2048                     }
2049
2050                     /* Get meta (access and demux) */
2051                     p_meta = vlc_meta_New();
2052                     if( p_meta )
2053                     {
2054                         access_Control( slave->p_access, ACCESS_GET_META, p_meta );
2055                         demux_Control( slave->p_demux, DEMUX_GET_META, p_meta );
2056                         InputUpdateMeta( p_input, p_meta );
2057                     }
2058
2059                     TAB_APPEND( p_input->p->i_slave, p_input->p->slave, slave );
2060                 }
2061                 else
2062                 {
2063                     free( slave );
2064                     msg_Warn( p_input, "failed to add %s as slave",
2065                               val.psz_string );
2066                 }
2067             }
2068             break;
2069
2070         case INPUT_CONTROL_SET_RECORD_STATE:
2071             if( !!p_input->p->b_recording != !!val.b_bool )
2072             {
2073                 if( p_input->p->input.b_can_stream_record )
2074                 {
2075                     if( demux_Control( p_input->p->input.p_demux,
2076                                        DEMUX_SET_RECORD_STATE, val.b_bool ) )
2077                         val.b_bool = false;
2078                 }
2079                 else
2080                 {
2081                     if( es_out_SetRecordState( p_input->p->p_es_out_display, val.b_bool ) )
2082                         val.b_bool = false;
2083                 }
2084                 p_input->p->b_recording = val.b_bool;
2085
2086                 input_SendEventRecord( p_input, val.b_bool );
2087
2088                 b_force_update = true;
2089             }
2090             break;
2091
2092         case INPUT_CONTROL_SET_FRAME_NEXT:
2093             if( p_input->p->i_state == PAUSE_S )
2094             {
2095                 es_out_SetFrameNext( p_input->p->p_es_out );
2096             }
2097             else if( p_input->p->i_state == PLAYING_S )
2098             {
2099                 ControlPause( p_input, i_control_date );
2100             }
2101             else
2102             {
2103                 msg_Err( p_input, "invalid state for frame next" );
2104             }
2105             b_force_update = true;
2106             break;
2107
2108         case INPUT_CONTROL_SET_BOOKMARK:
2109         {
2110             seekpoint_t bookmark;
2111
2112             bookmark.i_time_offset = -1;
2113             bookmark.i_byte_offset = -1;
2114
2115             vlc_mutex_lock( &p_input->p->p_item->lock );
2116             if( val.i_int >= 0 && val.i_int < p_input->p->i_bookmark )
2117             {
2118                 const seekpoint_t *p_bookmark = p_input->p->pp_bookmark[val.i_int];
2119                 bookmark.i_time_offset = p_bookmark->i_time_offset;
2120                 bookmark.i_byte_offset = p_bookmark->i_byte_offset;
2121             }
2122             vlc_mutex_unlock( &p_input->p->p_item->lock );
2123
2124             if( bookmark.i_time_offset < 0 && bookmark.i_byte_offset < 0 )
2125             {
2126                 msg_Err( p_input, "invalid bookmark %d", val.i_int );
2127                 break;
2128             }
2129
2130             if( bookmark.i_time_offset >= 0 )
2131             {
2132                 val.i_time = bookmark.i_time_offset;
2133                 b_force_update = Control( p_input, INPUT_CONTROL_SET_TIME, val );
2134             }
2135             else if( bookmark.i_byte_offset >= 0 &&
2136                      p_input->p->input.p_stream )
2137             {
2138                 const uint64_t i_size = stream_Size( p_input->p->input.p_stream );
2139                 if( i_size > 0 && bookmark.i_byte_offset <= i_size )
2140                 {
2141                     val.f_float = (double)bookmark.i_byte_offset / i_size;
2142                     b_force_update = Control( p_input, INPUT_CONTROL_SET_POSITION, val );
2143                 }
2144             }
2145             break;
2146         }
2147
2148         default:
2149             msg_Err( p_input, "not yet implemented" );
2150             break;
2151     }
2152
2153     ControlRelease( i_type, val );
2154     return b_force_update;
2155 }
2156
2157 /*****************************************************************************
2158  * UpdateTitleSeekpoint
2159  *****************************************************************************/
2160 static int UpdateTitleSeekpoint( input_thread_t *p_input,
2161                                  int i_title, int i_seekpoint )
2162 {
2163     int i_title_end = p_input->p->input.i_title_end -
2164                         p_input->p->input.i_title_offset;
2165     int i_seekpoint_end = p_input->p->input.i_seekpoint_end -
2166                             p_input->p->input.i_seekpoint_offset;
2167
2168     if( i_title_end >= 0 && i_seekpoint_end >= 0 )
2169     {
2170         if( i_title > i_title_end ||
2171             ( i_title == i_title_end && i_seekpoint > i_seekpoint_end ) )
2172             return 0;
2173     }
2174     else if( i_seekpoint_end >= 0 )
2175     {
2176         if( i_seekpoint > i_seekpoint_end )
2177             return 0;
2178     }
2179     else if( i_title_end >= 0 )
2180     {
2181         if( i_title > i_title_end )
2182             return 0;
2183     }
2184     return 1;
2185 }
2186 /*****************************************************************************
2187  * Update*FromDemux:
2188  *****************************************************************************/
2189 static int UpdateTitleSeekpointFromDemux( input_thread_t *p_input )
2190 {
2191     demux_t *p_demux = p_input->p->input.p_demux;
2192
2193     /* TODO event-like */
2194     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
2195     {
2196         input_SendEventTitle( p_input, p_demux->info.i_title );
2197
2198         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
2199     }
2200     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
2201     {
2202         input_SendEventSeekpoint( p_input,
2203                                   p_demux->info.i_title, p_demux->info.i_seekpoint );
2204
2205         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
2206     }
2207
2208     /* Hmmm only works with master input */
2209     if( p_input->p->input.p_demux == p_demux )
2210         return UpdateTitleSeekpoint( p_input,
2211                                      p_demux->info.i_title,
2212                                      p_demux->info.i_seekpoint );
2213     return 1;
2214 }
2215
2216 static void UpdateGenericFromDemux( input_thread_t *p_input )
2217 {
2218     demux_t *p_demux = p_input->p->input.p_demux;
2219
2220     if( p_demux->info.i_update & INPUT_UPDATE_META )
2221     {
2222         vlc_meta_t *p_meta = vlc_meta_New();
2223         if( p_meta )
2224         {
2225             demux_Control( p_input->p->input.p_demux, DEMUX_GET_META, p_meta );
2226             InputUpdateMeta( p_input, p_meta );
2227         }
2228         p_demux->info.i_update &= ~INPUT_UPDATE_META;
2229     }
2230
2231     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
2232 }
2233
2234
2235 /*****************************************************************************
2236  * Update*FromAccess:
2237  *****************************************************************************/
2238 static int UpdateTitleSeekpointFromAccess( input_thread_t *p_input )
2239 {
2240     access_t *p_access = p_input->p->input.p_access;
2241
2242     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
2243     {
2244         input_SendEventTitle( p_input, p_access->info.i_title );
2245
2246         stream_Control( p_input->p->input.p_stream, STREAM_UPDATE_SIZE );
2247
2248         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
2249     }
2250     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
2251     {
2252         input_SendEventSeekpoint( p_input,
2253                                   p_access->info.i_title, p_access->info.i_seekpoint );
2254
2255         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
2256     }
2257     /* Hmmm only works with master input */
2258     if( p_input->p->input.p_access == p_access )
2259         return UpdateTitleSeekpoint( p_input,
2260                                      p_access->info.i_title,
2261                                      p_access->info.i_seekpoint );
2262     return 1;
2263 }
2264 static void UpdateGenericFromAccess( input_thread_t *p_input )
2265 {
2266     access_t *p_access = p_input->p->input.p_access;
2267
2268     if( p_access->info.i_update & INPUT_UPDATE_META )
2269     {
2270         /* TODO maybe multi - access ? */
2271         vlc_meta_t *p_meta = vlc_meta_New();
2272         if( p_meta )
2273         {
2274             access_Control( p_input->p->input.p_access, ACCESS_GET_META, p_meta );
2275             InputUpdateMeta( p_input, p_meta );
2276         }
2277         p_access->info.i_update &= ~INPUT_UPDATE_META;
2278     }
2279     if( p_access->info.i_update & INPUT_UPDATE_SIGNAL )
2280     {
2281         double f_quality;
2282         double f_strength;
2283
2284         if( access_Control( p_access, ACCESS_GET_SIGNAL, &f_quality, &f_strength ) )
2285             f_quality = f_strength = -1;
2286
2287         input_SendEventSignal( p_input, f_quality, f_strength );
2288
2289         p_access->info.i_update &= ~INPUT_UPDATE_SIGNAL;
2290     }
2291
2292     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
2293 }
2294
2295 /*****************************************************************************
2296  * InputSourceNew:
2297  *****************************************************************************/
2298 static input_source_t *InputSourceNew( input_thread_t *p_input )
2299 {
2300     VLC_UNUSED(p_input);
2301
2302     return calloc( 1,  sizeof( input_source_t ) );
2303 }
2304
2305 /*****************************************************************************
2306  * InputSourceInit:
2307  *****************************************************************************/
2308 static int InputSourceInit( input_thread_t *p_input,
2309                             input_source_t *in, const char *psz_mrl,
2310                             const char *psz_forced_demux )
2311 {
2312     const char *psz_access;
2313     const char *psz_demux;
2314     char *psz_path;
2315     char *psz_var_demux = NULL;
2316     double f_fps;
2317
2318     assert( psz_mrl );
2319     char *psz_dup = strdup( psz_mrl );
2320
2321     if( psz_dup == NULL )
2322         goto error;
2323
2324     /* Split uri */
2325     input_SplitMRL( &psz_access, &psz_demux, &psz_path, psz_dup );
2326
2327     msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
2328              psz_mrl, psz_access, psz_demux, psz_path );
2329     if( !p_input->b_preparsing )
2330     {
2331         /* Hack to allow udp://@:port syntax */
2332         if( !psz_access ||
2333             (strncmp( psz_access, "udp", 3 ) &&
2334              strncmp( psz_access, "rtp", 3 )) )
2335         {
2336             /* Find optional titles and seekpoints */
2337             MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
2338                      &in->i_seekpoint_start, &in->i_seekpoint_end );
2339         }
2340
2341         if( psz_forced_demux && *psz_forced_demux )
2342         {
2343             psz_demux = psz_forced_demux;
2344         }
2345         else if( *psz_demux == '\0' )
2346         {
2347             /* special hack for forcing a demuxer with --demux=module
2348              * (and do nothing with a list) */
2349             psz_var_demux = var_GetNonEmptyString( p_input, "demux" );
2350
2351             if( psz_var_demux != NULL &&
2352                 !strchr(psz_var_demux, ',' ) &&
2353                 !strchr(psz_var_demux, ':' ) )
2354             {
2355                 psz_demux = psz_var_demux;
2356
2357                 msg_Dbg( p_input, "enforced demux ` %s'", psz_demux );
2358             }
2359         }
2360
2361         /* Try access_demux first */
2362         in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux, psz_path,
2363                                   NULL, p_input->p->p_es_out, false );
2364     }
2365     else
2366     {
2367         /* Preparsing is only for file:// */
2368         if( *psz_demux )
2369             goto error;
2370         if( !*psz_access ) /* path without scheme:// */
2371             psz_access = "file";
2372         if( strcmp( psz_access, "file" ) )
2373             goto error;
2374         msg_Dbg( p_input, "trying to pre-parse %s",  psz_path );
2375     }
2376
2377     if( in->p_demux )
2378     {
2379         /* Get infos from access_demux */
2380         int i_ret = demux_Control( in->p_demux,
2381                                    DEMUX_GET_PTS_DELAY, &in->i_pts_delay );
2382         assert( !i_ret );
2383         in->i_pts_delay = __MAX( 0, __MIN( in->i_pts_delay, INPUT_PTS_DELAY_MAX ) );
2384
2385
2386         in->b_title_demux = true;
2387         if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2388                             &in->title, &in->i_title,
2389                             &in->i_title_offset, &in->i_seekpoint_offset ) )
2390         {
2391             TAB_INIT( in->i_title, in->title );
2392         }
2393         if( demux_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
2394                             &in->b_can_pace_control ) )
2395             in->b_can_pace_control = false;
2396
2397         assert( in->p_demux->pf_demux != NULL || !in->b_can_pace_control );
2398
2399         if( !in->b_can_pace_control )
2400         {
2401             if( demux_Control( in->p_demux, DEMUX_CAN_CONTROL_RATE,
2402                                 &in->b_can_rate_control, &in->b_rescale_ts ) )
2403             {
2404                 in->b_can_rate_control = false;
2405                 in->b_rescale_ts = true; /* not used */
2406             }
2407         }
2408         else
2409         {
2410             in->b_can_rate_control = true;
2411             in->b_rescale_ts = true;
2412         }
2413         if( demux_Control( in->p_demux, DEMUX_CAN_PAUSE,
2414                             &in->b_can_pause ) )
2415             in->b_can_pause = false;
2416         var_SetBool( p_input, "can-pause", in->b_can_pause || !in->b_can_pace_control ); /* XXX temporary because of es_out_timeshift*/
2417         var_SetBool( p_input, "can-rate", !in->b_can_pace_control || in->b_can_rate_control ); /* XXX temporary because of es_out_timeshift*/
2418         var_SetBool( p_input, "can-rewind", !in->b_rescale_ts && !in->b_can_pace_control && in->b_can_rate_control );
2419
2420         bool b_can_seek;
2421         if( demux_Control( in->p_demux, DEMUX_CAN_SEEK, &b_can_seek ) )
2422             b_can_seek = false;
2423         var_SetBool( p_input, "can-seek", b_can_seek );
2424     }
2425     else
2426     {
2427         /* Now try a real access */
2428         in->p_access = access_New( p_input, p_input, psz_access, psz_demux, psz_path );
2429         if( in->p_access == NULL )
2430         {
2431             if( vlc_object_alive( p_input ) )
2432             {
2433                 msg_Err( p_input, "open of `%s' failed: %s", psz_mrl,
2434                                                              msg_StackMsg() );
2435                 dialog_Fatal( p_input, _("Your input can't be opened"),
2436                               _("VLC is unable to open the MRL '%s'."
2437                                 " Check the log for details."), psz_mrl );
2438             }
2439             goto error;
2440         }
2441
2442         /* Get infos from access */
2443         if( !p_input->b_preparsing )
2444         {
2445             bool b_can_seek;
2446             access_Control( in->p_access,
2447                              ACCESS_GET_PTS_DELAY, &in->i_pts_delay );
2448             in->i_pts_delay = __MAX( 0, __MIN( in->i_pts_delay, INPUT_PTS_DELAY_MAX ) );
2449
2450             in->b_title_demux = false;
2451             if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO,
2452                                  &in->title, &in->i_title,
2453                                 &in->i_title_offset, &in->i_seekpoint_offset ) )
2454
2455             {
2456                 TAB_INIT( in->i_title, in->title );
2457             }
2458             access_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
2459                              &in->b_can_pace_control );
2460             in->b_can_rate_control = in->b_can_pace_control;
2461             in->b_rescale_ts = true;
2462
2463             access_Control( in->p_access, ACCESS_CAN_PAUSE, &in->b_can_pause );
2464             var_SetBool( p_input, "can-pause", in->b_can_pause || !in->b_can_pace_control ); /* XXX temporary because of es_out_timeshift*/
2465             var_SetBool( p_input, "can-rate", !in->b_can_pace_control || in->b_can_rate_control ); /* XXX temporary because of es_out_timeshift*/
2466             var_SetBool( p_input, "can-rewind", !in->b_rescale_ts && !in->b_can_pace_control );
2467
2468             access_Control( in->p_access, ACCESS_CAN_SEEK, &b_can_seek );
2469             var_SetBool( p_input, "can-seek", b_can_seek );
2470         }
2471
2472         /* */
2473         int  i_input_list;
2474         char **ppsz_input_list;
2475
2476         TAB_INIT( i_input_list, ppsz_input_list );
2477
2478         /* On master stream only, use input-list */
2479         if( &p_input->p->input == in )
2480         {
2481             char *psz_list;
2482             char *psz_parser;
2483
2484             psz_list =
2485             psz_parser = var_CreateGetNonEmptyString( p_input, "input-list" );
2486
2487             while( psz_parser && *psz_parser )
2488             {
2489                 char *p = strchr( psz_parser, ',' );
2490                 if( p )
2491                     *p++ = '\0';
2492
2493                 if( *psz_parser )
2494                 {
2495                     char *psz_name = strdup( psz_parser );
2496                     if( psz_name )
2497                         TAB_APPEND( i_input_list, ppsz_input_list, psz_name );
2498                 }
2499
2500                 psz_parser = p;
2501             }
2502             free( psz_list );
2503         }
2504         /* Autodetect extra files if none specified */
2505         if( i_input_list <= 0 )
2506         {
2507             InputGetExtraFiles( p_input, &i_input_list, &ppsz_input_list,
2508                                 psz_access, psz_path );
2509         }
2510         if( i_input_list > 0 )
2511             TAB_APPEND( i_input_list, ppsz_input_list, NULL );
2512
2513         /* Create the stream_t */
2514         in->p_stream = stream_AccessNew( in->p_access, ppsz_input_list );
2515         if( ppsz_input_list )
2516         {
2517             for( int i = 0; ppsz_input_list[i] != NULL; i++ )
2518                 free( ppsz_input_list[i] );
2519             TAB_CLEAN( i_input_list, ppsz_input_list );
2520         }
2521
2522         if( in->p_stream == NULL )
2523         {
2524             msg_Warn( p_input, "cannot create a stream_t from access" );
2525             goto error;
2526         }
2527
2528         /* Add stream filters */
2529         char *psz_stream_filter = var_GetNonEmptyString( p_input,
2530                                                          "stream-filter" );
2531         in->p_stream = stream_FilterChainNew( in->p_stream,
2532                                               psz_stream_filter,
2533                                               var_GetBool( p_input, "input-record-native" ) );
2534         free( psz_stream_filter );
2535
2536         /* Open a demuxer */
2537         if( *psz_demux == '\0' && *in->p_access->psz_demux )
2538         {
2539             psz_demux = in->p_access->psz_demux;
2540         }
2541
2542         in->p_demux = demux_New( p_input, p_input, psz_access, psz_demux,
2543                    /* Take access/stream redirections into account: */
2544                    in->p_stream->psz_path ? in->p_stream->psz_path : psz_path,
2545                                  in->p_stream, p_input->p->p_es_out,
2546                                  p_input->b_preparsing );
2547
2548         if( in->p_demux == NULL )
2549         {
2550             if( vlc_object_alive( p_input ) )
2551             {
2552                 msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
2553                          psz_access, psz_demux, psz_path );
2554                 dialog_Fatal( VLC_OBJECT( p_input ),
2555                               _("VLC can't recognize the input's format"),
2556                               _("The format of '%s' cannot be detected. "
2557                                 "Have a look at the log for details."), psz_mrl );
2558             }
2559             goto error;
2560         }
2561         assert( in->p_demux->pf_demux != NULL );
2562
2563         /* Get title from demux */
2564         if( !p_input->b_preparsing && in->i_title <= 0 )
2565         {
2566             if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2567                                 &in->title, &in->i_title,
2568                                 &in->i_title_offset, &in->i_seekpoint_offset ))
2569             {
2570                 TAB_INIT( in->i_title, in->title );
2571             }
2572             else
2573             {
2574                 in->b_title_demux = true;
2575             }
2576         }
2577     }
2578
2579     free( psz_var_demux );
2580     free( psz_dup );
2581
2582     /* Set record capabilities */
2583     if( demux_Control( in->p_demux, DEMUX_CAN_RECORD, &in->b_can_stream_record ) )
2584         in->b_can_stream_record = false;
2585 #ifdef ENABLE_SOUT
2586     if( !var_GetBool( p_input, "input-record-native" ) )
2587         in->b_can_stream_record = false;
2588     var_SetBool( p_input, "can-record", true );
2589 #else
2590     var_SetBool( p_input, "can-record", in->b_can_stream_record );
2591 #endif
2592
2593     /* get attachment
2594      * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2595     if( 1 || !p_input->b_preparsing )
2596     {
2597         int i_attachment;
2598         input_attachment_t **attachment;
2599         if( !demux_Control( in->p_demux, DEMUX_GET_ATTACHMENTS,
2600                              &attachment, &i_attachment ) )
2601         {
2602             vlc_mutex_lock( &p_input->p->p_item->lock );
2603             AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment,
2604                               i_attachment, attachment );
2605             vlc_mutex_unlock( &p_input->p->p_item->lock );
2606         }
2607     }
2608     if( !demux_Control( in->p_demux, DEMUX_GET_FPS, &f_fps ) && f_fps > 0.0 )
2609     {
2610         vlc_mutex_lock( &p_input->p->p_item->lock );
2611         p_input->p->f_fps = f_fps;
2612         vlc_mutex_unlock( &p_input->p->p_item->lock );
2613     }
2614
2615     if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
2616         in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
2617
2618     return VLC_SUCCESS;
2619
2620 error:
2621     if( in->p_demux )
2622         demux_Delete( in->p_demux );
2623
2624     if( in->p_stream )
2625         stream_Delete( in->p_stream );
2626
2627     if( in->p_access )
2628         access_Delete( in->p_access );
2629
2630     free( psz_var_demux );
2631     free( psz_dup );
2632
2633     return VLC_EGENERIC;
2634 }
2635
2636 /*****************************************************************************
2637  * InputSourceClean:
2638  *****************************************************************************/
2639 static void InputSourceClean( input_source_t *in )
2640 {
2641     int i;
2642
2643     if( in->p_demux )
2644         demux_Delete( in->p_demux );
2645
2646     if( in->p_stream )
2647         stream_Delete( in->p_stream );
2648
2649     if( in->p_access )
2650         access_Delete( in->p_access );
2651
2652     if( in->i_title > 0 )
2653     {
2654         for( i = 0; i < in->i_title; i++ )
2655             vlc_input_title_Delete( in->title[i] );
2656         TAB_CLEAN( in->i_title, in->title );
2657     }
2658 }
2659
2660 /*****************************************************************************
2661  * InputSourceMeta:
2662  *****************************************************************************/
2663 static void InputSourceMeta( input_thread_t *p_input,
2664                              input_source_t *p_source, vlc_meta_t *p_meta )
2665 {
2666     access_t *p_access = p_source->p_access;
2667     demux_t *p_demux = p_source->p_demux;
2668
2669     /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
2670      * is a bad idea */
2671
2672     bool has_meta;
2673
2674     /* Read access meta */
2675     has_meta = p_access && !access_Control( p_access, ACCESS_GET_META, p_meta );
2676
2677     /* Read demux meta */
2678     has_meta |= !demux_Control( p_demux, DEMUX_GET_META, p_meta );
2679
2680     bool has_unsupported;
2681     if( demux_Control( p_demux, DEMUX_HAS_UNSUPPORTED_META, &has_unsupported ) )
2682         has_unsupported = true;
2683
2684     /* If the demux report unsupported meta data, or if we don't have meta data
2685      * try an external "meta reader" */
2686     if( has_meta && !has_unsupported )
2687         return;
2688
2689     demux_meta_t *p_demux_meta =
2690         vlc_custom_create( p_demux, sizeof( *p_demux_meta ),
2691                            VLC_OBJECT_GENERIC, "demux meta" );
2692     if( !p_demux_meta )
2693         return;
2694     vlc_object_attach( p_demux_meta, p_demux );
2695     p_demux_meta->p_demux = p_demux;
2696     p_demux_meta->p_item = p_input->p->p_item;
2697
2698     module_t *p_id3 = module_need( p_demux_meta, "meta reader", NULL, false );
2699     if( p_id3 )
2700     {
2701         if( p_demux_meta->p_meta )
2702         {
2703             vlc_meta_Merge( p_meta, p_demux_meta->p_meta );
2704             vlc_meta_Delete( p_demux_meta->p_meta );
2705         }
2706
2707         if( p_demux_meta->i_attachments > 0 )
2708         {
2709             vlc_mutex_lock( &p_input->p->p_item->lock );
2710             AppendAttachment( &p_input->p->i_attachment, &p_input->p->attachment,
2711                               p_demux_meta->i_attachments, p_demux_meta->attachments );
2712             vlc_mutex_unlock( &p_input->p->p_item->lock );
2713         }
2714         module_unneed( p_demux, p_id3 );
2715     }
2716     vlc_object_release( p_demux_meta );
2717 }
2718
2719
2720 static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled )
2721 {
2722     int64_t i_time;
2723     int i;
2724
2725     *pb_demux_polled = false;
2726     if( demux_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2727     {
2728         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2729         return;
2730     }
2731
2732     for( i = 0; i < p_input->p->i_slave; i++ )
2733     {
2734         input_source_t *in = p_input->p->slave[i];
2735         int i_ret;
2736
2737         if( in->b_eof )
2738             continue;
2739
2740         const bool b_demux_polled = in->p_demux->pf_demux != NULL;
2741         if( !b_demux_polled )
2742             continue;
2743
2744         *pb_demux_polled = true;
2745
2746         /* Call demux_Demux until we have read enough data */
2747         if( demux_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
2748         {
2749             for( ;; )
2750             {
2751                 int64_t i_stime;
2752                 if( demux_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
2753                 {
2754                     msg_Err( p_input, "slave[%d] doesn't like "
2755                              "DEMUX_GET_TIME -> EOF", i );
2756                     i_ret = 0;
2757                     break;
2758                 }
2759
2760                 if( i_stime >= i_time )
2761                 {
2762                     i_ret = 1;
2763                     break;
2764                 }
2765
2766                 if( ( i_ret = demux_Demux( in->p_demux ) ) <= 0 )
2767                     break;
2768             }
2769         }
2770         else
2771         {
2772             i_ret = demux_Demux( in->p_demux );
2773         }
2774
2775         if( i_ret <= 0 )
2776         {
2777             msg_Dbg( p_input, "slave %d EOF", i );
2778             in->b_eof = true;
2779         }
2780     }
2781 }
2782
2783 static void SlaveSeek( input_thread_t *p_input )
2784 {
2785     int64_t i_time;
2786     int i;
2787
2788     if( demux_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2789     {
2790         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2791         return;
2792     }
2793
2794     for( i = 0; i < p_input->p->i_slave; i++ )
2795     {
2796         input_source_t *in = p_input->p->slave[i];
2797
2798         if( demux_Control( in->p_demux, DEMUX_SET_TIME, i_time, true ) )
2799         {
2800             if( !in->b_eof )
2801                 msg_Err( p_input, "seek failed for slave %d -> EOF", i );
2802             in->b_eof = true;
2803         }
2804         else
2805         {
2806             in->b_eof = false;
2807         }
2808     }
2809 }
2810
2811 /*****************************************************************************
2812  * InputMetaUser:
2813  *****************************************************************************/
2814 static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta )
2815 {
2816     static const struct { int i_meta; const char *psz_name; } p_list[] = {
2817         { vlc_meta_Title,       "meta-title" },
2818         { vlc_meta_Artist,      "meta-artist" },
2819         { vlc_meta_Genre,       "meta-genre" },
2820         { vlc_meta_Copyright,   "meta-copyright" },
2821         { vlc_meta_Description, "meta-description" },
2822         { vlc_meta_Date,        "meta-date" },
2823         { vlc_meta_URL,         "meta-url" },
2824         { 0, NULL }
2825     };
2826
2827     /* Get meta information from user */
2828     for( int i = 0; p_list[i].psz_name; i++ )
2829     {
2830         char *psz_string = var_GetNonEmptyString( p_input, p_list[i].psz_name );
2831         if( !psz_string )
2832             continue;
2833
2834         EnsureUTF8( psz_string );
2835         vlc_meta_Set( p_meta, p_list[i].i_meta, psz_string );
2836         free( psz_string );
2837     }
2838 }
2839
2840 /*****************************************************************************
2841  * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2842  * arturl and locking issue.
2843  *****************************************************************************/
2844 static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta )
2845 {
2846     es_out_ControlSetMeta( p_input->p->p_es_out, p_meta );
2847     vlc_meta_Delete( p_meta );
2848 }
2849
2850 static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
2851                               int i_new, input_attachment_t **pp_new )
2852 {
2853     int i_attachment = *pi_attachment;
2854     input_attachment_t **attachment = *ppp_attachment;
2855     int i;
2856
2857     attachment = xrealloc( attachment,
2858                     sizeof(input_attachment_t**) * ( i_attachment + i_new ) );
2859     for( i = 0; i < i_new; i++ )
2860         attachment[i_attachment++] = pp_new[i];
2861     free( pp_new );
2862
2863     /* */
2864     *pi_attachment = i_attachment;
2865     *ppp_attachment = attachment;
2866 }
2867 /*****************************************************************************
2868  * InputGetExtraFiles
2869  *  Autodetect extra input list
2870  *****************************************************************************/
2871 static void InputGetExtraFilesPattern( input_thread_t *p_input,
2872                                        int *pi_list, char ***pppsz_list,
2873                                        const char *psz_path,
2874                                        const char *psz_match,
2875                                        const char *psz_format,
2876                                        int i_start, int i_stop )
2877 {
2878     int i_list;
2879     char **ppsz_list;
2880
2881     TAB_INIT( i_list, ppsz_list );
2882
2883     char *psz_base = strdup( psz_path );
2884     if( !psz_base )
2885         goto exit;
2886
2887     /* Remove the extension */
2888     char *psz_end = &psz_base[strlen(psz_base)-strlen(psz_match)];
2889     assert( psz_end >= psz_base);
2890     *psz_end = '\0';
2891
2892     /* Try to list files */
2893     for( int i = i_start; i <= i_stop; i++ )
2894     {
2895         struct stat st;
2896         char *psz_file;
2897
2898         if( asprintf( &psz_file, psz_format, psz_base, i ) < 0 )
2899             break;
2900
2901         if( vlc_stat( psz_file, &st ) || !S_ISREG( st.st_mode ) || !st.st_size )
2902         {
2903             free( psz_file );
2904             break;
2905         }
2906
2907         msg_Dbg( p_input, "Detected extra file `%s'", psz_file );
2908         TAB_APPEND( i_list, ppsz_list, psz_file );
2909     }
2910     free( psz_base );
2911 exit:
2912     *pi_list = i_list;
2913     *pppsz_list = ppsz_list;
2914 }
2915
2916 static void InputGetExtraFiles( input_thread_t *p_input,
2917                                 int *pi_list, char ***pppsz_list,
2918                                 const char *psz_access, const char *psz_path )
2919 {
2920     static const struct
2921     {
2922         const char *psz_match;
2923         const char *psz_format;
2924         int i_start;
2925         int i_stop;
2926     } p_pattern[] = {
2927         /* XXX the order is important */
2928         { ".001",         "%s.%.3d",        2, 999 },
2929         { ".part1.rar",   "%s.part%.1d.rar",2, 9 },
2930         { ".part01.rar",  "%s.part%.2d.rar",2, 99, },
2931         { ".part001.rar", "%s.part%.3d.rar",2, 999 },
2932         { ".rar",         "%s.r%.2d",       0, 99 },
2933         { NULL, NULL, 0, 0 }
2934     };
2935
2936     TAB_INIT( *pi_list, *pppsz_list );
2937
2938     if( ( psz_access && *psz_access && strcmp( psz_access, "file" ) ) || !psz_path )
2939         return;
2940
2941     const size_t i_path = strlen(psz_path);
2942
2943     for( int i = 0; p_pattern[i].psz_match != NULL; i++ )
2944     {
2945         const size_t i_ext = strlen(p_pattern[i].psz_match );
2946
2947         if( i_path < i_ext )
2948             continue;
2949         if( !strcmp( &psz_path[i_path-i_ext], p_pattern[i].psz_match ) )
2950         {
2951             InputGetExtraFilesPattern( p_input, pi_list, pppsz_list,
2952                                        psz_path,
2953                                        p_pattern[i].psz_match, p_pattern[i].psz_format,
2954                                        p_pattern[i].i_start, p_pattern[i].i_stop );
2955             return;
2956         }
2957     }
2958 }
2959
2960 /* */
2961 static void input_ChangeState( input_thread_t *p_input, int i_state )
2962 {
2963     const bool b_changed = p_input->p->i_state != i_state;
2964
2965     p_input->p->i_state = i_state;
2966     if( i_state == ERROR_S )
2967         p_input->b_error = true;
2968     else if( i_state == END_S )
2969         p_input->b_eof = true;
2970
2971     if( b_changed )
2972     {
2973         input_item_SetErrorWhenReading( p_input->p->p_item, p_input->b_error );
2974         input_SendEventState( p_input, i_state );
2975     }
2976 }
2977
2978
2979 /*****************************************************************************
2980  * MRLSplit: parse the access, demux and url part of the
2981  *           Media Resource Locator.
2982  *****************************************************************************/
2983 void input_SplitMRL( const char **ppsz_access, const char **ppsz_demux,
2984                      char **ppsz_path, char *psz_dup )
2985 {
2986     const char *psz_access;
2987     const char *psz_demux = "";
2988     char *psz_path;
2989
2990     /* Either there is an access/demux specification before ://
2991      * or we have a plain local file path. */
2992     psz_path = strstr( psz_dup, "://" );
2993     if( psz_path != NULL )
2994     {
2995         *psz_path = '\0';
2996         psz_path += 3; /* skips "://" */
2997
2998         psz_access = psz_dup;
2999         /* We really don't want module name substitution here! */
3000         if( psz_access[0] == '$' )
3001             psz_access++;
3002
3003         /* Separate access from demux (<access>/<demux>://<path>) */
3004         char *p = strchr( psz_access, '/' );
3005         if( p )
3006         {
3007             *p = '\0';
3008             psz_demux = p + 1;
3009             if( psz_demux[0] == '$' )
3010                 psz_demux++;
3011         }
3012
3013         /* Remove HTML anchor if present (not supported).
3014          * The hash symbol itself should be URI-encoded. */
3015         p = strchr( psz_path, '#' );
3016         if( p )
3017             *p = '\0';
3018     }
3019     else
3020     {
3021 #ifndef NDEBUG
3022         fprintf( stderr, "%s(\"%s\"): not a valid URI!\n", __func__,
3023                  psz_dup );
3024 #endif
3025         psz_path = psz_dup;
3026         psz_access = "";
3027     }
3028
3029     *ppsz_access = psz_access;
3030     *ppsz_demux = psz_demux;
3031     *ppsz_path = psz_path;
3032 }
3033
3034 static inline bool next(char ** src)
3035 {
3036     char *end;
3037     errno = 0;
3038     long result = strtol( *src, &end, 0 );
3039     if( errno != 0 || result >= LONG_MAX || result <= LONG_MIN ||
3040         end == *src )
3041     {
3042         return false;
3043     }
3044     *src = end;
3045     return true;
3046 }
3047
3048 /*****************************************************************************
3049  * MRLSections: parse title and seekpoint info from the Media Resource Locator.
3050  *
3051  * Syntax:
3052  * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
3053  *****************************************************************************/
3054 static void MRLSections( input_thread_t *p_input, char *psz_source,
3055                          int *pi_title_start, int *pi_title_end,
3056                          int *pi_chapter_start, int *pi_chapter_end )
3057 {
3058     char *psz, *psz_end, *psz_next, *psz_check;
3059
3060     *pi_title_start = *pi_title_end = -1;
3061     *pi_chapter_start = *pi_chapter_end = -1;
3062
3063     /* Start by parsing titles and chapters */
3064     if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
3065
3066
3067     /* Check we are really dealing with a title/chapter section */
3068     psz_check = psz + 1;
3069     if( !*psz_check ) return;
3070     if( isdigit(*psz_check) )
3071         if(!next(&psz_check)) return;
3072     if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
3073     if( *psz_check == ':' && ++psz_check )
3074     {
3075         if( isdigit(*psz_check) )
3076             if(!next(&psz_check)) return;
3077     }
3078     if( *psz_check != '-' && *psz_check ) return;
3079     if( *psz_check == '-' && ++psz_check )
3080     {
3081         if( isdigit(*psz_check) )
3082             if(!next(&psz_check)) return;
3083     }
3084     if( *psz_check != ':' && *psz_check ) return;
3085     if( *psz_check == ':' && ++psz_check )
3086     {
3087         if( isdigit(*psz_check) )
3088             if(!next(&psz_check)) return;
3089     }
3090     if( *psz_check ) return;
3091
3092     /* Separate start and end */
3093     *psz++ = 0;
3094     if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
3095
3096     /* Look for the start title */
3097     *pi_title_start = strtol( psz, &psz_next, 0 );
3098     if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
3099     *pi_title_end = *pi_title_start;
3100     psz = psz_next;
3101
3102     /* Look for the start chapter */
3103     if( *psz ) psz++;
3104     *pi_chapter_start = strtol( psz, &psz_next, 0 );
3105     if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
3106     *pi_chapter_end = *pi_chapter_start;
3107
3108     if( psz_end )
3109     {
3110         /* Look for the end title */
3111         *pi_title_end = strtol( psz_end, &psz_next, 0 );
3112         if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
3113         psz_end = psz_next;
3114
3115         /* Look for the end chapter */
3116         if( *psz_end ) psz_end++;
3117         *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
3118         if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
3119     }
3120
3121     msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
3122              psz_source, *pi_title_start, *pi_chapter_start,
3123              *pi_title_end, *pi_chapter_end );
3124 }
3125
3126 /*****************************************************************************
3127  * input_AddSubtitles: add a subtitles file and enable it
3128  *****************************************************************************/
3129 static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_forced )
3130 {
3131     input_source_t *sub;
3132     vlc_value_t count;
3133     vlc_value_t list;
3134     char *psz_path, *psz_extension;
3135
3136     /* if we are provided a subtitle.sub file,
3137      * see if we don't have a subtitle.idx and use it instead */
3138     psz_path = strdup( psz_subtitle );
3139     if( psz_path )
3140     {
3141         psz_extension = strrchr( psz_path, '.');
3142         if( psz_extension && strcmp( psz_extension, ".sub" ) == 0 )
3143         {
3144             struct stat st;
3145
3146             strcpy( psz_extension, ".idx" );
3147
3148             if( !vlc_stat( psz_path, &st ) && S_ISREG( st.st_mode ) )
3149             {
3150                 msg_Dbg( p_input, "using %s subtitles file instead of %s",
3151                          psz_path, psz_subtitle );
3152                 strcpy( psz_subtitle, psz_path );
3153             }
3154         }
3155         free( psz_path );
3156     }
3157
3158     char *url = make_URI( psz_subtitle );
3159
3160     var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
3161
3162     sub = InputSourceNew( p_input );
3163     if( !sub || !url
3164      || InputSourceInit( p_input, sub, url, "subtitle" ) )
3165     {
3166         free( sub );
3167         free( url );
3168         return;
3169     }
3170     free( url );
3171     TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub );
3172
3173     /* Select the ES */
3174     if( b_forced && !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) )
3175     {
3176         if( count.i_int == 0 )
3177             count.i_int++;
3178         /* if it was first one, there is disable too */
3179
3180         if( count.i_int < list.p_list->i_count )
3181         {
3182             const int i_id = list.p_list->p_values[count.i_int].i_int;
3183
3184             es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_DEFAULT_BY_ID, i_id );
3185             es_out_Control( p_input->p->p_es_out_display, ES_OUT_SET_ES_BY_ID, i_id );
3186         }
3187         var_FreeList( &list, NULL );
3188     }
3189 }
3190
3191 /*****************************************************************************
3192  * Statistics
3193  *****************************************************************************/
3194 void input_UpdateStatistic( input_thread_t *p_input,
3195                             input_statistic_t i_type, int i_delta )
3196 {
3197     assert( p_input->p->i_state != INIT_S );
3198
3199     vlc_mutex_lock( &p_input->p->counters.counters_lock);
3200     switch( i_type )
3201     {
3202 #define I(c) stats_UpdateInteger( p_input, p_input->p->counters.c, i_delta, NULL )
3203     case INPUT_STATISTIC_DECODED_VIDEO:
3204         I(p_decoded_video);
3205         break;
3206     case INPUT_STATISTIC_DECODED_AUDIO:
3207         I(p_decoded_audio);
3208         break;
3209     case INPUT_STATISTIC_DECODED_SUBTITLE:
3210         I(p_decoded_sub);
3211         break;
3212     case INPUT_STATISTIC_SENT_PACKET:
3213         I(p_sout_sent_packets);
3214         break;
3215 #undef I
3216     case INPUT_STATISTIC_SENT_BYTE:
3217     {
3218         int i_bytes; /* That's pretty stupid to define it as an integer, it will overflow
3219                         really fast ... */
3220         if( !stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_bytes, i_delta, &i_bytes ) )
3221             stats_UpdateFloat( p_input, p_input->p->counters.p_sout_send_bitrate, i_bytes, NULL );
3222         break;
3223     }
3224     default:
3225         msg_Err( p_input, "Invalid statistic type %d (internal error)", i_type );
3226         break;
3227     }
3228     vlc_mutex_unlock( &p_input->p->counters.counters_lock);
3229 }
3230
3231 /**/
3232 /* TODO FIXME nearly the same logic that snapshot code */
3233 char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const char *psz_prefix, const char *psz_extension )
3234 {
3235     char *psz_file;
3236     DIR *path;
3237
3238     path = vlc_opendir( psz_path );
3239     if( path )
3240     {
3241         closedir( path );
3242
3243         char *psz_tmp = str_format( p_obj, psz_prefix );
3244         if( !psz_tmp )
3245             return NULL;
3246
3247         filename_sanitize( psz_tmp );
3248
3249         if( asprintf( &psz_file, "%s"DIR_SEP"%s%s%s",
3250                       psz_path, psz_tmp,
3251                       psz_extension ? "." : "",
3252                       psz_extension ? psz_extension : "" ) < 0 )
3253             psz_file = NULL;
3254         free( psz_tmp );
3255         return psz_file;
3256     }
3257     else
3258     {
3259         psz_file = str_format( p_obj, psz_path );
3260         path_sanitize( psz_file );
3261         return psz_file;
3262     }
3263 }
3264