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