]> git.sesse.net Git - vlc/blob - src/input/input.c
d5058bdbbefd841d19af70866634875770ea7b37
[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 #include <stdlib.h>
29 #include <ctype.h>
30
31 #include <vlc/vlc.h>
32
33 #include "input_internal.h"
34
35 #include <vlc_sout.h>
36 #include "../stream_output/stream_output.h"
37
38 #include <vlc_playlist.h>
39 #include <vlc_interface.h>
40 #include <vlc_url.h>
41 #include <vlc_demux.h>
42 #include <vlc_charset.h>
43
44 #ifdef HAVE_SYS_STAT_H
45 #   include <sys/stat.h>
46 #endif
47
48 /*****************************************************************************
49  * Local prototypes
50  *****************************************************************************/
51 static  int Run  ( input_thread_t *p_input );
52 static  int RunAndDestroy  ( input_thread_t *p_input );
53
54 static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
55                                   const char *, vlc_bool_t, sout_instance_t * );
56 static  int             Init    ( input_thread_t *p_input );
57 static void             Error   ( input_thread_t *p_input );
58 static void             End     ( input_thread_t *p_input );
59 static void             MainLoop( input_thread_t *p_input );
60 static void             Destroy( input_thread_t *p_input, sout_instance_t **pp_sout );
61
62 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
63 static void       ControlReduce( input_thread_t * );
64 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
65
66 static int  UpdateFromAccess( input_thread_t * );
67 static int  UpdateFromDemux( input_thread_t * );
68
69 static void UpdateItemLength( input_thread_t *, int64_t i_length );
70
71 static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
72
73 static input_source_t *InputSourceNew( input_thread_t *);
74 static int  InputSourceInit( input_thread_t *, input_source_t *,
75                              const char *, const char *psz_forced_demux );
76 static void InputSourceClean( input_source_t * );
77 /* TODO */
78 //static void InputGetAttachments( input_thread_t *, input_source_t * );
79
80 static void SlaveDemux( input_thread_t *p_input );
81 static void SlaveSeek( input_thread_t *p_input );
82
83 static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
84 static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta );
85
86 static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, vlc_bool_t * );
87 static void SoutKeep( sout_instance_t * );
88
89 /*****************************************************************************
90  * This function creates a new input, and returns a pointer
91  * to its description. On error, it returns NULL.
92  *
93  * Variables for _public_ use:
94  * * Get and Set:
95  *  - state
96  *  - rate,rate-slower, rate-faster
97  *  - position, position-offset
98  *  - time, time-offset
99  *  - title,title-next,title-prev
100  *  - chapter,chapter-next, chapter-prev
101  *  - program, audio-es, video-es, spu-es
102  *  - audio-delay, spu-delay
103  *  - bookmark
104  * * Get only:
105  *  - length
106  *  - bookmarks
107  *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
108  * * For intf callback upon changes
109  *  - intf-change
110  * TODO explain when Callback is called
111  * TODO complete this list (?)
112  *****************************************************************************/
113 static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
114                                const char *psz_header, vlc_bool_t b_quick, sout_instance_t *p_sout )
115 {
116     input_thread_t *p_input = NULL;                 /* thread descriptor */
117     vlc_value_t val;
118     int i;
119
120     /* Allocate descriptor */
121     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
122     if( p_input == NULL )
123     {
124         msg_Err( p_parent, "out of memory" );
125         return NULL;
126     }
127     MALLOC_NULL( p_input->p, input_thread_private_t );
128
129     /* One "randomly" selected input thread is responsible for computing
130      * the global stats. Check if there is already someone doing this */
131     if( p_input->p_libvlc->p_playlist->p_stats && !b_quick )
132     {
133         vlc_mutex_lock( &p_input->p_libvlc->p_playlist->p_stats->lock );
134         if( p_input->p_libvlc->p_playlist->p_stats_computer == NULL )
135         {
136             p_input->p_libvlc->p_playlist->p_stats_computer = p_input;
137         }
138         vlc_mutex_unlock( &p_input->p_libvlc->p_playlist->p_stats->lock );
139     }
140
141     p_input->b_preparsing = b_quick;
142     p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
143
144     /* Init Common fields */
145     p_input->b_eof = VLC_FALSE;
146     p_input->b_can_pace_control = VLC_TRUE;
147     p_input->p->i_start = 0;
148     p_input->i_time  = 0;
149     p_input->p->i_stop  = 0;
150     p_input->p->i_title = 0;
151     p_input->p->title   = NULL;
152     p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
153     p_input->i_state = INIT_S;
154     p_input->p->i_rate  = INPUT_RATE_DEFAULT;
155     TAB_INIT( p_input->p->i_bookmark, p_input->p->bookmark );
156     TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
157     p_input->p->p_es_out = NULL;
158     p_input->p->p_sout  = NULL;
159     p_input->p->b_sout_keep  = VLC_FALSE;
160     p_input->p->b_out_pace_control = VLC_FALSE;
161     p_input->i_pts_delay = 0;
162
163     /* Init Input fields */
164     p_input->p->input.p_item = p_item;
165     p_input->p->input.p_access = NULL;
166     p_input->p->input.p_stream = NULL;
167     p_input->p->input.p_demux  = NULL;
168     p_input->p->input.b_title_demux = VLC_FALSE;
169     p_input->p->input.i_title  = 0;
170     p_input->p->input.title    = NULL;
171     p_input->p->input.i_title_offset = p_input->p->input.i_seekpoint_offset = 0;
172     p_input->p->input.b_can_pace_control = VLC_TRUE;
173     p_input->p->input.b_eof = VLC_FALSE;
174     p_input->p->input.i_cr_average = 0;
175
176     vlc_mutex_lock( &p_item->lock );
177     if( !p_input->p->input.p_item->p_meta )
178         p_input->p->input.p_item->p_meta = vlc_meta_New();
179
180     if( !p_item->p_stats )
181         p_item->p_stats = stats_NewInputStats( p_input );
182     vlc_mutex_unlock( &p_item->lock );
183
184     /* No slave */
185     p_input->p->i_slave = 0;
186     p_input->p->slave   = NULL;
187
188     /* Init control buffer */
189     vlc_mutex_init( p_input, &p_input->p->lock_control );
190     p_input->p->i_control = 0;
191
192     /* Parse input options */
193     vlc_mutex_lock( &p_item->lock );
194     for( i = 0; i < p_item->i_options; i++ )
195         var_OptionParse( p_input, p_item->ppsz_options[i] );
196     vlc_mutex_unlock( &p_item->lock );
197
198     /* Create Object Variables for private use only */
199     input_ConfigVarInit( p_input );
200
201     /* Create Objects variables for public Get and Set */
202     input_ControlVarInit( p_input );
203
204     p_input->p->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
205
206     if( !p_input->b_preparsing )
207     {
208         var_Get( p_input, "bookmarks", &val );
209         if( val.psz_string )
210         {
211             /* FIXME: have a common cfg parsing routine used by sout and others */
212             char *psz_parser, *psz_start, *psz_end;
213             psz_parser = val.psz_string;
214             while( (psz_start = strchr( psz_parser, '{' ) ) )
215             {
216                  seekpoint_t *p_seekpoint = vlc_seekpoint_New();
217                  char backup;
218                  psz_start++;
219                  psz_end = strchr( psz_start, '}' );
220                  if( !psz_end ) break;
221                  psz_parser = psz_end + 1;
222                  backup = *psz_parser;
223                  *psz_parser = 0;
224                  *psz_end = ',';
225                  while( (psz_end = strchr( psz_start, ',' ) ) )
226                  {
227                      *psz_end = 0;
228                      if( !strncmp( psz_start, "name=", 5 ) )
229                      {
230                          p_seekpoint->psz_name = psz_start + 5;
231                      }
232                      else if( !strncmp( psz_start, "bytes=", 6 ) )
233                      {
234                          p_seekpoint->i_byte_offset = atoll(psz_start + 6);
235                      }
236                      else if( !strncmp( psz_start, "time=", 5 ) )
237                      {
238                          p_seekpoint->i_time_offset = atoll(psz_start + 5) *
239                                                         1000000;
240                      }
241                      psz_start = psz_end + 1;
242                 }
243                 msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
244                                   p_seekpoint->psz_name, p_seekpoint->i_byte_offset,
245                                   p_seekpoint->i_time_offset );
246                 input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
247                 vlc_seekpoint_Delete( p_seekpoint );
248                 *psz_parser = backup;
249             }
250             free( val.psz_string );
251         }
252     }
253
254     /* Remove 'Now playing' info as it is probably outdated */
255     input_Control( p_input, INPUT_DEL_INFO, _(VLC_META_INFO_CAT), VLC_META_NOW_PLAYING );
256     vlc_mutex_lock( &p_item->lock );
257     vlc_meta_SetNowPlaying( p_item->p_meta, NULL );
258     vlc_mutex_unlock( &p_item->lock );
259
260     /* */
261     if( p_input->b_preparsing )
262         p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
263
264     /* */
265     if( p_sout )
266         p_input->p->p_sout = p_sout;
267
268     /* Attach only once we are ready */
269     vlc_object_attach( p_input, p_parent );
270
271     return p_input;
272 }
273
274 static void Destroy( input_thread_t *p_input, sout_instance_t **pp_sout )
275 {
276     vlc_object_detach( p_input );
277
278     if( pp_sout )
279         *pp_sout = NULL;
280     if( p_input->p->p_sout )
281     {
282         if( pp_sout )
283             *pp_sout = p_input->p->p_sout;
284         else if( p_input->p->b_sout_keep )
285             SoutKeep( p_input->p->p_sout );
286         else
287             sout_DeleteInstance( p_input->p->p_sout );
288     }
289
290     vlc_mutex_destroy( &p_input->p->lock_control );
291     free( p_input->p );
292
293     vlc_object_destroy( p_input );
294 }
295
296 /**
297  * Initialize an input thread and run it. You will need to monitor the
298  * thread to clean up after it is done
299  *
300  * \param p_parent a vlc_object
301  * \param p_item an input item
302  * \return a pointer to the spawned input thread
303  */
304 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
305                                       input_item_t *p_item )
306 {
307     vlc_bool_t b_sout_keep;
308     sout_instance_t *p_sout = SoutFind( p_parent, p_item, &b_sout_keep );
309     input_thread_t *p_input =  __input_CreateThreadExtended( p_parent, p_item, NULL, p_sout );
310
311     if( !p_input && p_sout )
312         SoutKeep( p_sout );
313
314     p_input->p->b_sout_keep = b_sout_keep;
315     return p_input;
316 }
317
318 /* */
319 input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
320                                               input_item_t *p_item,
321                                               const char *psz_log, sout_instance_t *p_sout )
322 {
323     input_thread_t *p_input;
324
325     p_input = Create( p_parent, p_item, psz_log, VLC_FALSE, p_sout );
326     if( !p_input )
327         return NULL;
328
329     /* Create thread and wait for its readiness. */
330     if( vlc_thread_create( p_input, "input", Run,
331                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
332     {
333         input_ChangeState( p_input, ERROR_S );
334         msg_Err( p_input, "cannot create input thread" );
335         Destroy( p_input, &p_sout );
336         return NULL;
337     }
338
339     return p_input;
340 }
341
342 /**
343  * Initialize an input thread and run it. This thread will clean after himself,
344  * you can forget about it. It can work either in blocking or non-blocking mode
345  *
346  * \param p_parent a vlc_object
347  * \param p_item an input item
348  * \param b_block should we block until read is finished ?
349  * \return the input object id if non blocking, an error code else
350  */
351 int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
352                    vlc_bool_t b_block )
353 {
354     vlc_bool_t b_sout_keep;
355     sout_instance_t *p_sout = SoutFind( p_parent, p_item, &b_sout_keep );
356     input_thread_t *p_input;
357
358     p_input = Create( p_parent, p_item, NULL, VLC_FALSE, p_sout );
359     if( !p_input && p_sout )
360     {
361         SoutKeep( p_sout );
362         return VLC_EGENERIC;
363     }
364     p_input->p->b_sout_keep = b_sout_keep;
365
366     if( b_block )
367     {
368         RunAndDestroy( p_input );
369         return VLC_SUCCESS;
370     }
371     else
372     {
373         if( vlc_thread_create( p_input, "input", RunAndDestroy,
374                                VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
375         {
376             input_ChangeState( p_input, ERROR_S );
377             msg_Err( p_input, "cannot create input thread" );
378             Destroy( p_input, NULL );
379             return VLC_EGENERIC;
380         }
381     }
382     return p_input->i_object_id;
383 }
384
385 /**
386  * Initialize an input and initialize it to preparse the item
387  * This function is blocking. It will only accept to parse files
388  *
389  * \param p_parent a vlc_object_t
390  * \param p_item an input item
391  * \return VLC_SUCCESS or an error
392  */
393 int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
394 {
395     input_thread_t *p_input;
396
397     /* Allocate descriptor */
398     p_input = Create( p_parent, p_item, NULL, VLC_TRUE, NULL );
399     if( !p_input )
400         return VLC_EGENERIC;
401
402     if( !Init( p_input ) )
403         End( p_input );
404
405     Destroy( p_input, NULL );
406
407     return VLC_SUCCESS;
408 }
409
410 /**
411  * Request a running input thread to stop and die
412  *
413  * \param the input thread to stop
414  */
415 void input_StopThread( input_thread_t *p_input )
416 {
417     vlc_list_t *p_list;
418     int i;
419
420     /* Set die for input */
421     vlc_object_kill( p_input );
422     /* FIXME: seems to be duplicated in ControlPush(INPUT_CONTROL_SET_DIE) */
423
424     /* We cannot touch p_input fields directly (we come from another thread),
425      * so use the vlc_object_find way, it's perfectly safe */
426
427     /* Set die for all access */
428     p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
429     for( i = 0; i < p_list->i_count; i++ )
430     {
431         vlc_object_kill( p_list->p_values[i].p_object );
432     }
433     vlc_list_release( p_list );
434
435     /* Set die for all stream */
436     p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
437     for( i = 0; i < p_list->i_count; i++ )
438     {
439         vlc_object_kill( p_list->p_values[i].p_object );
440     }
441     vlc_list_release( p_list );
442
443     /* Set die for all demux */
444     p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
445     for( i = 0; i < p_list->i_count; i++ )
446     {
447         vlc_object_kill( p_list->p_values[i].p_object );
448     }
449     vlc_list_release( p_list );
450
451     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
452 }
453
454 /**
455  * Clean up a dead input thread
456  * This function does not return until the thread is effectively cancelled.
457  *
458  * \param the input thread to kill
459  */
460 void input_DestroyThread( input_thread_t *p_input )
461 {
462     input_DestroyThreadExtended( p_input, NULL );
463 }
464
465 void input_DestroyThreadExtended( input_thread_t *p_input, sout_instance_t **pp_sout )
466 {
467     /* Join the thread */
468     vlc_thread_join( p_input );
469
470     /* */
471     Destroy( p_input, pp_sout );
472 }
473
474 /*****************************************************************************
475  * Run: main thread loop
476  * This is the "normal" thread that spawns the input processing chain,
477  * reads the stream, cleans up and waits
478  *****************************************************************************/
479 static int Run( input_thread_t *p_input )
480 {
481     /* Signal that the thread is launched */
482     vlc_thread_ready( p_input );
483
484     if( Init( p_input ) )
485     {
486         /* If we failed, wait before we are killed, and exit */
487         p_input->b_error = VLC_TRUE;
488         playlist_Signal( pl_Get( p_input ) );
489
490         Error( p_input );
491
492         /* Tell we're dead */
493         p_input->b_dead = VLC_TRUE;
494
495         return 0;
496     }
497
498     MainLoop( p_input );
499
500     if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
501     {
502         /* We have finish to demux data but not to play them */
503         while( !p_input->b_die )
504         {
505             if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
506                 break;
507
508             msg_Dbg( p_input, "waiting decoder fifos to empty" );
509
510             msleep( INPUT_IDLE_SLEEP );
511         }
512
513         /* We have finished */
514         p_input->b_eof = VLC_TRUE;
515         playlist_Signal( pl_Get( p_input ) );
516     }
517
518     /* Wait until we are asked to die */
519     if( !p_input->b_die )
520     {
521         Error( p_input );
522     }
523
524     /* Clean up */
525     End( p_input );
526
527     return 0;
528 }
529
530 /*****************************************************************************
531  * RunAndDestroy: main thread loop
532  * This is the "just forget me" thread that spawns the input processing chain,
533  * reads the stream, cleans up and releases memory
534  *****************************************************************************/
535 static int RunAndDestroy( input_thread_t *p_input )
536 {
537     /* Signal that the thread is launched */
538     vlc_thread_ready( p_input );
539
540     if( Init( p_input ) )
541         goto exit;
542
543     MainLoop( p_input );
544
545     if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
546     {
547         /* We have finished demuxing data but not playing it */
548         while( !p_input->b_die )
549         {
550             if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
551                 break;
552
553             msg_Dbg( p_input, "waiting decoder fifos to empty" );
554
555             msleep( INPUT_IDLE_SLEEP );
556         }
557
558         /* We have finished */
559         p_input->b_eof = VLC_TRUE;
560     }
561
562     /* Clean up */
563     End( p_input );
564
565 exit:
566     /* Release memory */
567     Destroy( p_input, NULL );
568     return 0;
569 }
570
571 /*****************************************************************************
572  * Main loop: Fill buffers from access, and demux
573  *****************************************************************************/
574 static void MainLoop( input_thread_t *p_input )
575 {
576     int64_t i_intf_update = 0;
577     int i_updates = 0;
578
579     while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof )
580     {
581         vlc_bool_t b_force_update = VLC_FALSE;
582         int i_ret;
583         int i_type;
584         vlc_value_t val;
585
586         /* Do the read */
587         if( p_input->i_state != PAUSE_S  )
588         {
589             if( p_input->p->i_stop <= 0 || p_input->i_time < p_input->p->i_stop )
590                 i_ret=p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux);
591             else
592                 i_ret = 0;  /* EOF */
593
594             if( i_ret > 0 )
595             {
596                 /* TODO */
597                 if( p_input->p->input.b_title_demux &&
598                     p_input->p->input.p_demux->info.i_update )
599                 {
600                     i_ret = UpdateFromDemux( p_input );
601                     b_force_update = VLC_TRUE;
602                 }
603                 else if( !p_input->p->input.b_title_demux &&
604                           p_input->p->input.p_access &&
605                           p_input->p->input.p_access->info.i_update )
606                 {
607                     i_ret = UpdateFromAccess( p_input );
608                     b_force_update = VLC_TRUE;
609                 }
610             }
611
612             if( i_ret == 0 )    /* EOF */
613             {
614                 vlc_value_t repeat;
615
616                 var_Get( p_input, "input-repeat", &repeat );
617                 if( repeat.i_int == 0 )
618                 {
619                     /* End of file - we do not set b_die because only the
620                      * playlist is allowed to do so. */
621                     input_ChangeState( p_input, END_S );
622                     msg_Dbg( p_input, "EOF reached" );
623                     p_input->p->input.b_eof = VLC_TRUE;
624                 }
625                 else
626                 {
627                     msg_Dbg( p_input, "repeating the same input (%d)",
628                              repeat.i_int );
629                     if( repeat.i_int > 0 )
630                     {
631                         repeat.i_int--;
632                         var_Set( p_input, "input-repeat", repeat );
633                     }
634
635                     /* Seek to start title/seekpoint */
636                     val.i_int = p_input->p->input.i_title_start -
637                         p_input->p->input.i_title_offset;
638                     if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title )
639                         val.i_int = 0;
640                     input_ControlPush( p_input,
641                                        INPUT_CONTROL_SET_TITLE, &val );
642
643                     val.i_int = p_input->p->input.i_seekpoint_start -
644                         p_input->p->input.i_seekpoint_offset;
645                     if( val.i_int > 0 /* TODO: check upper boundary */ )
646                         input_ControlPush( p_input,
647                                            INPUT_CONTROL_SET_SEEKPOINT, &val );
648
649                     /* Seek to start position */
650                     if( p_input->p->i_start > 0 )
651                     {
652                         val.i_time = p_input->p->i_start;
653                         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
654                                            &val );
655                     }
656                     else
657                     {
658                         val.f_float = 0.0;
659                         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
660                                            &val );
661                     }
662                 }
663             }
664             else if( i_ret < 0 )
665             {
666                 p_input->b_error = VLC_TRUE;
667             }
668
669             if( i_ret > 0 && p_input->p->i_slave > 0 )
670             {
671                 SlaveDemux( p_input );
672             }
673         }
674         else
675         {
676             /* Small wait */
677             msleep( 10*1000 );
678         }
679
680         /* Handle control */
681         vlc_mutex_lock( &p_input->p->lock_control );
682         ControlReduce( p_input );
683         while( !ControlPopNoLock( p_input, &i_type, &val ) )
684         {
685             msg_Dbg( p_input, "control type=%d", i_type );
686             if( Control( p_input, i_type, val ) )
687                 b_force_update = VLC_TRUE;
688         }
689         vlc_mutex_unlock( &p_input->p->lock_control );
690
691         if( b_force_update || i_intf_update < mdate() )
692         {
693             vlc_value_t val;
694             double f_pos;
695             int64_t i_time, i_length;
696             /* update input status variables */
697             if( !demux2_Control( p_input->p->input.p_demux,
698                                  DEMUX_GET_POSITION, &f_pos ) )
699             {
700                 val.f_float = (float)f_pos;
701                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
702             }
703             if( !demux2_Control( p_input->p->input.p_demux,
704                                  DEMUX_GET_TIME, &i_time ) )
705             {
706                 p_input->i_time = i_time;
707                 val.i_time = i_time;
708                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
709             }
710             if( !demux2_Control( p_input->p->input.p_demux,
711                                  DEMUX_GET_LENGTH, &i_length ) )
712             {
713                 vlc_value_t old_val;
714                 var_Get( p_input, "length", &old_val );
715                 val.i_time = i_length;
716                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
717
718                 if( old_val.i_time != val.i_time )
719                 {
720                     UpdateItemLength( p_input, i_length );
721                 }
722             }
723
724             var_SetBool( p_input, "intf-change", VLC_TRUE );
725             i_intf_update = mdate() + I64C(150000);
726         }
727         /* 150ms * 8 = ~ 1 second */
728         if( ++i_updates % 8 == 0 )
729         {
730             stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
731             /* Are we the thread responsible for computing global stats ? */
732             if( p_input->p_libvlc->p_playlist->p_stats_computer == p_input )
733             {
734                 stats_ComputeGlobalStats( p_input->p_libvlc->p_playlist,
735                                      p_input->p_libvlc->p_playlist->p_stats );
736             }
737         }
738     }
739 }
740
741 static int Init( input_thread_t * p_input )
742 {
743     char *psz;
744     char *psz_subtitle;
745     vlc_value_t val;
746     double f_fps;
747     vlc_meta_t *p_meta;
748     int i_es_out_mode;
749     int i, i_delay;
750
751     /* Initialize optional stream output. (before access/demuxer)
752      * XXX: we add a special case if the uri starts by vlc.
753      * else 'vlc in.file --sout "" vlc:quit'  cannot work (the output will
754      * be destroyed in case of a file).
755      * (this will break playing of file starting by 'vlc:' but I don't
756      * want to add more logic, just force file by file:// or code it ;)
757      */
758     memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
759     vlc_mutex_init( p_input, &p_input->p->counters.counters_lock );
760
761     if( !p_input->b_preparsing )
762     {
763         /* Prepare statistics */
764 #define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
765      stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
766         if( p_input->p_libvlc->b_stats )
767         {
768             INIT_COUNTER( read_bytes, INTEGER, COUNTER );
769             INIT_COUNTER( read_packets, INTEGER, COUNTER );
770             INIT_COUNTER( demux_read, INTEGER, COUNTER );
771             INIT_COUNTER( input_bitrate, FLOAT, DERIVATIVE );
772             INIT_COUNTER( demux_bitrate, FLOAT, DERIVATIVE );
773             INIT_COUNTER( played_abuffers, INTEGER, COUNTER );
774             INIT_COUNTER( lost_abuffers, INTEGER, COUNTER );
775             INIT_COUNTER( displayed_pictures, INTEGER, COUNTER );
776             INIT_COUNTER( lost_pictures, INTEGER, COUNTER );
777             INIT_COUNTER( decoded_audio, INTEGER, COUNTER );
778             INIT_COUNTER( decoded_video, INTEGER, COUNTER );
779             INIT_COUNTER( decoded_sub, INTEGER, COUNTER );
780             p_input->p->counters.p_sout_send_bitrate = NULL;
781             p_input->p->counters.p_sout_sent_packets = NULL;
782             p_input->p->counters.p_sout_sent_bytes = NULL;
783             if( p_input->p->counters.p_demux_bitrate )
784                 p_input->p->counters.p_demux_bitrate->update_interval = 1000000;
785             if( p_input->p->counters.p_input_bitrate )
786                 p_input->p->counters.p_input_bitrate->update_interval = 1000000;
787         }
788
789         /* Find a usable sout and attach it to p_input */
790         psz = var_GetString( p_input, "sout" );
791         if( *psz && strncasecmp( p_input->p->input.p_item->psz_uri, "vlc:", 4 ) )
792         {
793             /* Check the validity of the provided sout */
794             if( p_input->p->p_sout )
795             {
796                 if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
797                 {
798                     msg_Dbg( p_input, "destroying unusable sout" );
799
800                     sout_DeleteInstance( p_input->p->p_sout );
801                     p_input->p->p_sout = NULL;
802                 }
803             }
804
805             if( p_input->p->p_sout )
806             {
807                 /* Reuse it */
808                 msg_Dbg( p_input, "sout keep: reusing sout" );
809                 msg_Dbg( p_input, "sout keep: you probably want to use "
810                                   "gather stream_out" );
811                 vlc_object_attach( p_input->p->p_sout, p_input );
812             }
813             else
814             {
815                 /* Create a new one */
816                 p_input->p->p_sout = sout_NewInstance( p_input, psz );
817
818                 if( !p_input->p->p_sout )
819                 {
820                     input_ChangeState( p_input, ERROR_S );
821                     msg_Err( p_input, "cannot start stream output instance, " \
822                                       "aborting" );
823                     free( psz );
824                     return VLC_EGENERIC;
825                 }
826             }
827
828             if( p_input->p_libvlc->b_stats )
829             {
830                 INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
831                 INIT_COUNTER (sout_sent_bytes, INTEGER, COUNTER );
832                 INIT_COUNTER( sout_send_bitrate, FLOAT, DERIVATIVE );
833                 if( p_input->p->counters.p_sout_send_bitrate )
834                      p_input->p->counters.p_sout_send_bitrate->update_interval =
835                              1000000;
836             }
837         }
838         else if( p_input->p->p_sout )
839         {
840             msg_Dbg( p_input, "destroying useless sout" );
841
842             sout_DeleteInstance( p_input->p->p_sout );
843             p_input->p->p_sout = NULL;
844         }
845         free( psz );
846     }
847
848     /* Create es out */
849     p_input->p->p_es_out = input_EsOutNew( p_input );
850     es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
851     es_out_Control( p_input->p->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
852
853     var_Create( p_input, "bit-rate", VLC_VAR_INTEGER );
854     var_Create( p_input, "sample-rate", VLC_VAR_INTEGER );
855
856     if( InputSourceInit( p_input, &p_input->p->input,
857                          p_input->p->input.p_item->psz_uri, NULL ) )
858     {
859         goto error;
860     }
861
862     /* Create global title (from master) */
863     if( !p_input->b_preparsing )
864     {
865         p_input->p->i_title = p_input->p->input.i_title;
866         p_input->p->title   = p_input->p->input.title;
867         p_input->p->i_title_offset = p_input->p->input.i_title_offset;
868         p_input->p->i_seekpoint_offset = p_input->p->input.i_seekpoint_offset;
869         if( p_input->p->i_title > 0 )
870         {
871             /* Setup variables */
872             input_ControlVarNavigation( p_input );
873             input_ControlVarTitle( p_input, 0 );
874         }
875
876         /* Global flag */
877         p_input->b_can_pace_control = p_input->p->input.b_can_pace_control;
878         p_input->p->b_can_pause        = p_input->p->input.b_can_pause;
879
880         /* Fix pts delay */
881         if( p_input->i_pts_delay < 0 )
882             p_input->i_pts_delay = 0;
883
884         /* If the desynchronisation requested by the user is < 0, we need to
885          * cache more data. */
886         var_Get( p_input, "audio-desync", &val );
887         if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);
888
889         /* Update cr_average depending on the caching */
890         p_input->p->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
891         p_input->p->input.i_cr_average /= 10;
892         if( p_input->p->input.i_cr_average < 10 ) p_input->p->input.i_cr_average = 10;
893     }
894
895     /* Load master infos */
896     /* Init length */
897     if( !demux2_Control( p_input->p->input.p_demux, DEMUX_GET_LENGTH,
898                          &val.i_time ) && val.i_time > 0 )
899     {
900         var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
901         UpdateItemLength( p_input, val.i_time );
902     }
903
904     /* Start title/chapter */
905     if( !p_input->b_preparsing )
906     {
907         val.i_int = p_input->p->input.i_title_start -
908                     p_input->p->input.i_title_offset;
909         if( val.i_int > 0 && val.i_int < p_input->p->input.i_title )
910             input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
911         val.i_int = p_input->p->input.i_seekpoint_start -
912                     p_input->p->input.i_seekpoint_offset;
913         if( val.i_int > 0 /* TODO: check upper boundary */ )
914             input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
915
916         /* Start time*/
917         /* Set start time */
918         p_input->p->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
919                            I64C(1000000);
920         p_input->p->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
921                            I64C(1000000);
922
923         if( p_input->p->i_start > 0 )
924         {
925             if( p_input->p->i_start >= val.i_time )
926             {
927                 msg_Warn( p_input, "invalid start-time ignored" );
928             }
929             else
930             {
931                 vlc_value_t s;
932
933                 msg_Dbg( p_input, "starting at time: %ds",
934                                   (int)( p_input->p->i_start / I64C(1000000) ) );
935
936                 s.i_time = p_input->p->i_start;
937                 input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
938             }
939         }
940         if( p_input->p->i_stop > 0 && p_input->p->i_stop <= p_input->p->i_start )
941         {
942             msg_Warn( p_input, "invalid stop-time ignored" );
943             p_input->p->i_stop = 0;
944         }
945
946         /* Load subtitles */
947         /* Get fps and set it if not already set */
948         if( !demux2_Control( p_input->p->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
949             f_fps > 1.0 )
950         {
951             float f_requested_fps;
952
953             var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
954             var_SetFloat( p_input, "sub-original-fps", f_fps );
955
956             f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
957             if( f_requested_fps != f_fps )
958             {
959                 var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
960                                                 VLC_VAR_DOINHERIT );
961                 var_SetFloat( p_input, "sub-fps", f_requested_fps );
962             }
963         }
964
965         i_delay = var_CreateGetInteger( p_input, "sub-delay" );
966         if( i_delay != 0 )
967         {
968             var_SetTime( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
969         }
970
971         /* Look for and add subtitle files */
972         psz_subtitle = var_GetString( p_input, "sub-file" );
973         if( *psz_subtitle )
974         {
975             msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
976             input_AddSubtitles( p_input, psz_subtitle, VLC_FALSE );
977         }
978
979         var_Get( p_input, "sub-autodetect-file", &val );
980         if( val.b_bool )
981         {
982             char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
983             char **subs = subtitles_Detect( p_input, psz_autopath,
984                                             p_input->p->input.p_item->psz_uri );
985             input_source_t *sub;
986             i = 0;
987
988             /* Try to autoselect the first autodetected subtitles file
989              * if no subtitles file was specified */
990             if( *psz_subtitle == 0 && subs && subs[0] )
991             {
992                 input_AddSubtitles( p_input, subs[0], VLC_FALSE );
993                 free( subs[0] );
994                 i = 1;
995             }
996
997             /* Then, just add the following subtitles files */
998             for( ; subs && subs[i]; i++ )
999             {
1000                 if( strcmp( psz_subtitle, subs[i] ) )
1001                 {
1002                     sub = InputSourceNew( p_input );
1003                     if( !InputSourceInit( p_input, sub, subs[i], "subtitle" ) )
1004                     {
1005                         TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub );
1006                     }
1007                     else free( sub );
1008                 }
1009                 free( subs[i] );
1010             }
1011             if( subs ) free( subs );
1012             if( psz_autopath ) free( psz_autopath );
1013         }
1014         free( psz_subtitle );
1015
1016         /* Look for slave */
1017         psz = var_GetString( p_input, "input-slave" );
1018         if( *psz )
1019         {
1020             char *psz_delim;
1021             input_source_t *slave;
1022             while( psz && *psz )
1023             {
1024                 while( *psz == ' ' || *psz == '#' )
1025                 {
1026                     psz++;
1027                 }
1028                 if( ( psz_delim = strchr( psz, '#' ) ) )
1029                 {
1030                     *psz_delim++ = '\0';
1031                 }
1032                 if( *psz == 0 )
1033                 {
1034                     break;
1035                 }
1036
1037                 msg_Dbg( p_input, "adding slave input '%s'", psz );
1038                 slave = InputSourceNew( p_input );
1039                 if( !InputSourceInit( p_input, slave, psz, NULL ) )
1040                 {
1041                     TAB_APPEND( p_input->p->i_slave, p_input->p->slave, slave );
1042                 }
1043                 else free( slave );
1044                 psz = psz_delim;
1045             }
1046         }
1047         if( psz ) free( psz );
1048     }
1049     else
1050     {
1051         p_input->p->i_start = 0;
1052         p_input->p->i_start = 0;
1053     }
1054
1055     /* Set up es_out */
1056     if( !p_input->b_preparsing )
1057     {
1058         es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
1059         i_es_out_mode = ES_OUT_MODE_AUTO;
1060         val.p_list = NULL;
1061         if( p_input->p->p_sout )
1062         {
1063             var_Get( p_input, "sout-all", &val );
1064             if ( val.b_bool )
1065             {
1066                 i_es_out_mode = ES_OUT_MODE_ALL;
1067                 val.p_list = NULL;
1068             }
1069             else
1070             {
1071                 var_Get( p_input, "programs", &val );
1072                 if ( val.p_list && val.p_list->i_count )
1073                 {
1074                     i_es_out_mode = ES_OUT_MODE_PARTIAL;
1075                     /* Note : we should remove the "program" callback. */
1076                 }
1077                 else
1078                     var_Change( p_input, "programs", VLC_VAR_FREELIST, &val,
1079                                 NULL );
1080             }
1081         }
1082         es_out_Control( p_input->p->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
1083
1084         /* Inform the demuxer about waited group (needed only for DVB) */
1085         if( i_es_out_mode == ES_OUT_MODE_ALL )
1086         {
1087             demux2_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, -1, NULL );
1088         }
1089         else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
1090         {
1091             demux2_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, -1,
1092                             val.p_list );
1093         }
1094         else
1095         {
1096             demux2_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP,
1097                            (int) var_GetInteger( p_input, "program" ), NULL );
1098         }
1099
1100         if( p_input->p->p_sout )
1101         {
1102             if( p_input->p->p_sout->i_out_pace_nocontrol > 0 )
1103             {
1104                 p_input->p->b_out_pace_control = VLC_FALSE;
1105             }
1106             else
1107             {
1108                 p_input->p->b_out_pace_control = VLC_TRUE;
1109             }
1110
1111             if( p_input->b_can_pace_control && p_input->p->b_out_pace_control )
1112             {
1113                 /* We don't want a high input priority here or we'll
1114                  * end-up sucking up all the CPU time */
1115                 vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
1116             }
1117
1118             msg_Dbg( p_input, "starting in %s mode",
1119                      p_input->p->b_out_pace_control ? "async" : "sync" );
1120         }
1121     }
1122
1123     p_meta = vlc_meta_New();
1124     /* Get meta data from users */
1125     InputMetaUser( p_input, p_meta );
1126
1127     /* Get meta data from master input */
1128     demux2_Control( p_input->p->input.p_demux, DEMUX_GET_META, p_meta );
1129
1130     /* Access_file does not give any meta, and there are no slave */
1131     if( !p_input->b_preparsing )
1132     {
1133         if( p_input->p->input.p_access )
1134             access2_Control( p_input->p->input.p_access, ACCESS_GET_META,
1135                              p_meta );
1136
1137         /* Get meta data from slave input */
1138         for( i = 0; i < p_input->p->i_slave; i++ )
1139         {
1140             demux2_Control( p_input->p->slave[i]->p_demux,
1141                             DEMUX_GET_META, p_meta );
1142             if( p_input->p->slave[i]->p_access )
1143             {
1144                 access2_Control( p_input->p->slave[i]->p_access,
1145                                  ACCESS_GET_META, p_meta );
1146             }
1147         }
1148     }
1149
1150     InputUpdateMeta( p_input, p_meta );
1151
1152     if( !p_input->b_preparsing )
1153     {
1154         msg_Dbg( p_input, "`%s' successfully opened",
1155                  p_input->p->input.p_item->psz_uri );
1156
1157     }
1158
1159     /* initialization is complete */
1160     input_ChangeState( p_input, PLAYING_S );
1161
1162     return VLC_SUCCESS;
1163
1164 error:
1165     input_ChangeState( p_input, ERROR_S );
1166
1167     if( p_input->p->p_es_out )
1168         input_EsOutDelete( p_input->p->p_es_out );
1169
1170     if( p_input->p->p_sout )
1171     {
1172         vlc_object_detach( p_input->p->p_sout );
1173         sout_DeleteInstance( p_input->p->p_sout );
1174     }
1175
1176
1177     if( !p_input->b_preparsing && p_input->p_libvlc->b_stats )
1178     {
1179 #define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
1180                                    stats_CounterClean( p_input->p->counters.p_##c );\
1181                                p_input->p->counters.p_##c = NULL; } while(0)
1182         EXIT_COUNTER( read_bytes );
1183         EXIT_COUNTER( read_packets );
1184         EXIT_COUNTER( demux_read );
1185         EXIT_COUNTER( input_bitrate );
1186         EXIT_COUNTER( demux_bitrate );
1187         EXIT_COUNTER( played_abuffers );
1188         EXIT_COUNTER( lost_abuffers );
1189         EXIT_COUNTER( displayed_pictures );
1190         EXIT_COUNTER( lost_pictures );
1191         EXIT_COUNTER( decoded_audio );
1192         EXIT_COUNTER( decoded_video );
1193         EXIT_COUNTER( decoded_sub );
1194
1195         if( p_input->p->p_sout )
1196         {
1197             EXIT_COUNTER( sout_sent_packets );
1198             EXIT_COUNTER (sout_sent_bytes );
1199             EXIT_COUNTER( sout_send_bitrate );
1200         }
1201 #undef EXIT_COUNTER
1202     }
1203
1204     /* Mark them deleted */
1205     p_input->p->input.p_demux = NULL;
1206     p_input->p->input.p_stream = NULL;
1207     p_input->p->input.p_access = NULL;
1208     p_input->p->p_es_out = NULL;
1209     p_input->p->p_sout = NULL;
1210
1211     return VLC_EGENERIC;
1212 }
1213
1214 /*****************************************************************************
1215  * Error: RunThread() error loop
1216  *****************************************************************************
1217  * This function is called when an error occurred during thread main's loop.
1218  *****************************************************************************/
1219 static void Error( input_thread_t *p_input )
1220 {
1221     while( !p_input->b_die )
1222     {
1223         /* Sleep a while */
1224         input_ChangeState( p_input, ERROR_S );
1225         msleep( INPUT_IDLE_SLEEP );
1226     }
1227 }
1228
1229 /*****************************************************************************
1230  * End: end the input thread
1231  *****************************************************************************/
1232 static void End( input_thread_t * p_input )
1233 {
1234     int i;
1235
1236     /* We are at the end */
1237     input_ChangeState( p_input, END_S );
1238
1239     /* Clean control variables */
1240     input_ControlVarClean( p_input );
1241
1242     /* Clean up master */
1243     InputSourceClean( &p_input->p->input );
1244
1245     /* Delete slave */
1246     for( i = 0; i < p_input->p->i_slave; i++ )
1247     {
1248         InputSourceClean( p_input->p->slave[i] );
1249         free( p_input->p->slave[i] );
1250     }
1251     if( p_input->p->slave ) free( p_input->p->slave );
1252
1253     /* Unload all modules */
1254     if( p_input->p->p_es_out )
1255         input_EsOutDelete( p_input->p->p_es_out );
1256
1257     if( !p_input->b_preparsing )
1258     {
1259 #define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
1260         if( p_input->p_libvlc->b_stats )
1261         {
1262             /* make sure we are up to date */
1263             stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
1264             if( p_input->p_libvlc->p_playlist->p_stats_computer == p_input )
1265             {
1266                 stats_ComputeGlobalStats( p_input->p_libvlc->p_playlist,
1267                                           p_input->p_libvlc->p_playlist->p_stats );
1268                 p_input->p_libvlc->p_playlist->p_stats_computer = NULL;
1269             }
1270             CL_CO( read_bytes );
1271             CL_CO( read_packets );
1272             CL_CO( demux_read );
1273             CL_CO( input_bitrate );
1274             CL_CO( demux_bitrate );
1275             CL_CO( played_abuffers );
1276             CL_CO( lost_abuffers );
1277             CL_CO( displayed_pictures );
1278             CL_CO( lost_pictures );
1279             CL_CO( decoded_audio) ;
1280             CL_CO( decoded_video );
1281             CL_CO( decoded_sub) ;
1282         }
1283
1284         /* Close optional stream output instance */
1285         if( p_input->p->p_sout )
1286         {
1287             CL_CO( sout_sent_packets );
1288             CL_CO( sout_sent_bytes );
1289             CL_CO( sout_send_bitrate );
1290
1291             vlc_object_detach( p_input->p->p_sout );
1292         }
1293 #undef CL_CO
1294     }
1295
1296     if( p_input->p->i_attachment > 0 )
1297     {
1298         for( i = 0; i < p_input->p->i_attachment; i++ )
1299             vlc_input_attachment_Delete( p_input->p->attachment[i] );
1300         TAB_CLEAN( p_input->p->i_attachment, p_input->p->attachment );
1301     }
1302
1303     vlc_mutex_destroy( &p_input->p->counters.counters_lock );
1304
1305     /* Tell we're dead */
1306     p_input->b_dead = VLC_TRUE;
1307 }
1308
1309 static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, vlc_bool_t *pb_sout_keep )
1310 {
1311     vlc_bool_t b_keep_sout = var_CreateGetBool( p_parent, "sout-keep" );
1312     sout_instance_t *p_sout = NULL;
1313     int i;
1314
1315     /* Search sout-keep options
1316      * XXX it has to be done here, but it is duplicated work :( */
1317     vlc_mutex_lock( &p_item->lock );
1318     for( i = 0; i < p_item->i_options; i++ )
1319     {
1320         const char *psz_option = p_item->ppsz_options[i];
1321         if( !psz_option )
1322             continue;
1323         if( *psz_option == ':' )
1324             psz_option++;
1325
1326         if( !strcmp( psz_option, "sout-keep" ) )
1327             b_keep_sout = VLC_TRUE;
1328         else if( !strcmp( psz_option, "no-sout-keep" ) || !strcmp( psz_option, "nosout-keep" ) )
1329             b_keep_sout = VLC_FALSE;
1330     }
1331     vlc_mutex_unlock( &p_item->lock );
1332
1333     /* Find a potential sout to reuse
1334      * XXX it might be unusable but this will be checked later */
1335     if( b_keep_sout )
1336     {
1337         /* Remove the sout from the playlist garbage collector */
1338         playlist_t *p_playlist = pl_Yield( p_parent );
1339
1340         vlc_mutex_lock( &p_playlist->gc_lock );
1341         p_sout = vlc_object_find( p_playlist, VLC_OBJECT_SOUT, FIND_CHILD );
1342         if( p_sout )
1343         {
1344             if( p_sout->p_parent != VLC_OBJECT(p_playlist) )
1345             {
1346                 vlc_object_release( p_sout );
1347                 p_sout = NULL;
1348             }
1349             else
1350             {
1351                 vlc_object_detach( p_sout );    /* Remove it from the GC */
1352
1353                 vlc_object_release( p_sout );
1354             }
1355         }
1356         vlc_mutex_unlock( &p_playlist->gc_lock );
1357
1358         pl_Release( p_parent );
1359     }
1360
1361     if( pb_sout_keep )
1362         *pb_sout_keep = b_keep_sout;
1363
1364     return p_sout;
1365 }
1366 static void SoutKeep( sout_instance_t *p_sout )
1367 {
1368     /* attach sout to the playlist */
1369     playlist_t  *p_playlist = pl_Yield( p_sout );
1370
1371     msg_Dbg( p_sout, "sout has been kept" );
1372     vlc_object_attach( p_sout, p_playlist );
1373
1374     pl_Release( p_sout );
1375 }
1376
1377 /*****************************************************************************
1378  * Control
1379  *****************************************************************************/
1380 static inline int ControlPopNoLock( input_thread_t *p_input,
1381                                     int *pi_type, vlc_value_t *p_val )
1382 {
1383     if( p_input->p->i_control <= 0 )
1384     {
1385         return VLC_EGENERIC;
1386     }
1387
1388     *pi_type = p_input->p->control[0].i_type;
1389     *p_val   = p_input->p->control[0].val;
1390
1391     p_input->p->i_control--;
1392     if( p_input->p->i_control > 0 )
1393     {
1394         int i;
1395
1396         for( i = 0; i < p_input->p->i_control; i++ )
1397         {
1398             p_input->p->control[i].i_type = p_input->p->control[i+1].i_type;
1399             p_input->p->control[i].val    = p_input->p->control[i+1].val;
1400         }
1401     }
1402
1403     return VLC_SUCCESS;
1404 }
1405
1406 static void ControlReduce( input_thread_t *p_input )
1407 {
1408     int i;
1409
1410     if( !p_input )
1411         return;
1412
1413     for( i = 1; i < p_input->p->i_control; i++ )
1414     {
1415         const int i_lt = p_input->p->control[i-1].i_type;
1416         const int i_ct = p_input->p->control[i].i_type;
1417
1418         /* XXX We can't merge INPUT_CONTROL_SET_ES */
1419 /*        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->p->i_control,
1420                  i_lt, i_ct );
1421 */
1422         if( i_lt == i_ct &&
1423             ( i_ct == INPUT_CONTROL_SET_STATE ||
1424               i_ct == INPUT_CONTROL_SET_RATE ||
1425               i_ct == INPUT_CONTROL_SET_POSITION ||
1426               i_ct == INPUT_CONTROL_SET_TIME ||
1427               i_ct == INPUT_CONTROL_SET_PROGRAM ||
1428               i_ct == INPUT_CONTROL_SET_TITLE ||
1429               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
1430               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
1431         {
1432             int j;
1433 //            msg_Dbg( p_input, "merged at %d", i );
1434             /* Remove the i-1 */
1435             for( j = i; j <  p_input->p->i_control; j++ )
1436                 p_input->p->control[j-1] = p_input->p->control[j];
1437             p_input->p->i_control--;
1438         }
1439         else
1440         {
1441             /* TODO but that's not that important
1442                 - merge SET_X with SET_X_CMD
1443                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1444                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1445                 - ?
1446                 */
1447         }
1448     }
1449 }
1450
1451 static vlc_bool_t Control( input_thread_t *p_input, int i_type,
1452                            vlc_value_t val )
1453 {
1454     vlc_bool_t b_force_update = VLC_FALSE;
1455
1456     if( !p_input ) return b_force_update;
1457
1458     switch( i_type )
1459     {
1460         case INPUT_CONTROL_SET_DIE:
1461             msg_Dbg( p_input, "control: stopping input" );
1462             /* Mark all submodules to die */
1463             if( p_input->p->input.p_access )
1464                 vlc_object_kill( p_input->p->input.p_access );
1465             if( p_input->p->input.p_stream )
1466                 vlc_object_kill( p_input->p->input.p_stream );
1467             vlc_object_kill( p_input->p->input.p_demux );
1468
1469             vlc_object_kill( p_input );
1470             break;
1471
1472         case INPUT_CONTROL_SET_POSITION:
1473         case INPUT_CONTROL_SET_POSITION_OFFSET:
1474         {
1475             double f_pos;
1476             if( i_type == INPUT_CONTROL_SET_POSITION )
1477             {
1478                 f_pos = val.f_float;
1479             }
1480             else
1481             {
1482                 /* Should not fail */
1483                 demux2_Control( p_input->p->input.p_demux,
1484                                 DEMUX_GET_POSITION, &f_pos );
1485                 f_pos += val.f_float;
1486             }
1487             if( f_pos < 0.0 ) f_pos = 0.0;
1488             if( f_pos > 1.0 ) f_pos = 1.0;
1489             /* Reset the decoders states and clock sync (before calling the demuxer */
1490             es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1491             input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1492             if( demux2_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION,
1493                                 f_pos ) )
1494             {
1495                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1496                          "%2.1f%% failed", f_pos * 100 );
1497             }
1498             else
1499             {
1500                 if( p_input->p->i_slave > 0 )
1501                     SlaveSeek( p_input );
1502
1503                 b_force_update = VLC_TRUE;
1504             }
1505             break;
1506         }
1507
1508         case INPUT_CONTROL_SET_TIME:
1509         case INPUT_CONTROL_SET_TIME_OFFSET:
1510         {
1511             int64_t i_time;
1512             int i_ret;
1513
1514             if( i_type == INPUT_CONTROL_SET_TIME )
1515             {
1516                 i_time = val.i_time;
1517             }
1518             else
1519             {
1520                 /* Should not fail */
1521                 demux2_Control( p_input->p->input.p_demux,
1522                                 DEMUX_GET_TIME, &i_time );
1523                 i_time += val.i_time;
1524             }
1525             if( i_time < 0 ) i_time = 0;
1526
1527             /* Reset the decoders states and clock sync (before calling the demuxer */
1528             es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1529             input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1530
1531             i_ret = demux2_Control( p_input->p->input.p_demux,
1532                                     DEMUX_SET_TIME, i_time );
1533             if( i_ret )
1534             {
1535                 int64_t i_length;
1536
1537                 /* Emulate it with a SET_POS */
1538                 demux2_Control( p_input->p->input.p_demux,
1539                                 DEMUX_GET_LENGTH, &i_length );
1540                 if( i_length > 0 )
1541                 {
1542                     double f_pos = (double)i_time / (double)i_length;
1543                     i_ret = demux2_Control( p_input->p->input.p_demux,
1544                                             DEMUX_SET_POSITION, f_pos );
1545                 }
1546             }
1547             if( i_ret )
1548             {
1549                 msg_Warn( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
1550                          " failed or not possible", i_time );
1551             }
1552             else
1553             {
1554                 if( p_input->p->i_slave > 0 )
1555                     SlaveSeek( p_input );
1556
1557                 b_force_update = VLC_TRUE;
1558             }
1559             break;
1560         }
1561
1562         case INPUT_CONTROL_SET_STATE:
1563             if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
1564                 ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
1565             {
1566                 int i_ret;
1567                 if( p_input->p->input.p_access )
1568                     i_ret = access2_Control( p_input->p->input.p_access,
1569                                              ACCESS_SET_PAUSE_STATE, VLC_FALSE );
1570                 else
1571                     i_ret = demux2_Control( p_input->p->input.p_demux,
1572                                             DEMUX_SET_PAUSE_STATE, VLC_FALSE );
1573
1574                 if( i_ret )
1575                 {
1576                     /* FIXME What to do ? */
1577                     msg_Warn( p_input, "cannot unset pause -> EOF" );
1578                     vlc_mutex_unlock( &p_input->p->lock_control );
1579                     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
1580                     vlc_mutex_lock( &p_input->p->lock_control );
1581                 }
1582
1583                 b_force_update = VLC_TRUE;
1584
1585                 /* Switch to play */
1586                 p_input->i_state = PLAYING_S;
1587                 val.i_int = PLAYING_S;
1588                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1589
1590                 /* Reset clock */
1591                 es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1592             }
1593             else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
1594                      p_input->p->b_can_pause )
1595             {
1596                 int i_ret;
1597                 if( p_input->p->input.p_access )
1598                     i_ret = access2_Control( p_input->p->input.p_access,
1599                                              ACCESS_SET_PAUSE_STATE, VLC_TRUE );
1600                 else
1601                     i_ret = demux2_Control( p_input->p->input.p_demux,
1602                                             DEMUX_SET_PAUSE_STATE, VLC_TRUE );
1603
1604                 b_force_update = VLC_TRUE;
1605
1606                 if( i_ret )
1607                 {
1608                     msg_Warn( p_input, "cannot set pause state" );
1609                     val.i_int = p_input->i_state;
1610                 }
1611                 else
1612                 {
1613                     val.i_int = PAUSE_S;
1614                 }
1615
1616                 /* Switch to new state */
1617                 p_input->i_state = val.i_int;
1618                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1619
1620                 /* Send discontinuity to decoders (it will allow them to flush
1621                  * if implemented */
1622                 input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_FALSE, VLC_FALSE );
1623             }
1624             else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause )
1625             {
1626                 b_force_update = VLC_TRUE;
1627
1628                 /* Correct "state" value */
1629                 val.i_int = p_input->i_state;
1630                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1631             }
1632             else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
1633             {
1634                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
1635             }
1636             break;
1637
1638         case INPUT_CONTROL_SET_RATE:
1639         case INPUT_CONTROL_SET_RATE_SLOWER:
1640         case INPUT_CONTROL_SET_RATE_FASTER:
1641         {
1642             int i_rate;
1643
1644             if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
1645                 i_rate = p_input->p->i_rate * 2;
1646             else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
1647                 i_rate = p_input->p->i_rate / 2;
1648             else
1649                 i_rate = val.i_int;
1650
1651             if( i_rate < INPUT_RATE_MIN )
1652             {
1653                 msg_Dbg( p_input, "cannot set rate faster" );
1654                 i_rate = INPUT_RATE_MIN;
1655             }
1656             else if( i_rate > INPUT_RATE_MAX )
1657             {
1658                 msg_Dbg( p_input, "cannot set rate slower" );
1659                 i_rate = INPUT_RATE_MAX;
1660             }
1661             if( i_rate != INPUT_RATE_DEFAULT &&
1662                 ( !p_input->b_can_pace_control ||
1663                   ( p_input->p->p_sout && !p_input->p->b_out_pace_control ) ) )
1664             {
1665                 msg_Dbg( p_input, "cannot change rate" );
1666                 i_rate = INPUT_RATE_DEFAULT;
1667             }
1668             if( i_rate != p_input->p->i_rate )
1669             {
1670                 val.i_int = i_rate;
1671                 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
1672
1673                 input_EsOutDiscontinuity( p_input->p->p_es_out,
1674                                           VLC_FALSE, VLC_FALSE );
1675
1676                 p_input->p->i_rate  = i_rate;
1677
1678                 input_EsOutSetRate( p_input->p->p_es_out );
1679
1680                 b_force_update = VLC_TRUE;
1681             }
1682             break;
1683         }
1684
1685         case INPUT_CONTROL_SET_PROGRAM:
1686             /* No need to force update, es_out does it if needed */
1687             es_out_Control( p_input->p->p_es_out,
1688                             ES_OUT_SET_GROUP, val.i_int );
1689
1690             demux2_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, val.i_int,
1691                             NULL );
1692             break;
1693
1694         case INPUT_CONTROL_SET_ES:
1695             /* No need to force update, es_out does it if needed */
1696             es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ES,
1697                             input_EsOutGetFromID( p_input->p->p_es_out,
1698                                                   val.i_int ) );
1699             break;
1700
1701         case INPUT_CONTROL_SET_AUDIO_DELAY:
1702             input_EsOutSetDelay( p_input->p->p_es_out,
1703                                  AUDIO_ES, val.i_time );
1704             var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
1705             break;
1706
1707         case INPUT_CONTROL_SET_SPU_DELAY:
1708             input_EsOutSetDelay( p_input->p->p_es_out,
1709                                  SPU_ES, val.i_time );
1710             var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
1711             break;
1712
1713         case INPUT_CONTROL_SET_TITLE:
1714         case INPUT_CONTROL_SET_TITLE_NEXT:
1715         case INPUT_CONTROL_SET_TITLE_PREV:
1716             if( p_input->p->input.b_title_demux &&
1717                 p_input->p->input.i_title > 0 )
1718             {
1719                 /* TODO */
1720                 /* FIXME handle demux title */
1721                 demux_t *p_demux = p_input->p->input.p_demux;
1722                 int i_title;
1723
1724                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1725                     i_title = p_demux->info.i_title - 1;
1726                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1727                     i_title = p_demux->info.i_title + 1;
1728                 else
1729                     i_title = val.i_int;
1730
1731                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
1732                 {
1733                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1734                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1735
1736                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
1737                     input_ControlVarTitle( p_input, i_title );
1738                 }
1739             }
1740             else if( p_input->p->input.i_title > 0 )
1741             {
1742                 access_t *p_access = p_input->p->input.p_access;
1743                 int i_title;
1744
1745                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1746                     i_title = p_access->info.i_title - 1;
1747                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1748                     i_title = p_access->info.i_title + 1;
1749                 else
1750                     i_title = val.i_int;
1751
1752                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
1753                 {
1754                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1755                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1756
1757                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
1758                     stream_AccessReset( p_input->p->input.p_stream );
1759                 }
1760             }
1761             break;
1762         case INPUT_CONTROL_SET_SEEKPOINT:
1763         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1764         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1765             if( p_input->p->input.b_title_demux &&
1766                 p_input->p->input.i_title > 0 )
1767             {
1768                 demux_t *p_demux = p_input->p->input.p_demux;
1769                 int i_seekpoint;
1770                 int64_t i_input_time;
1771                 int64_t i_seekpoint_time;
1772
1773                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1774                 {
1775                     i_seekpoint = p_demux->info.i_seekpoint;
1776                     i_seekpoint_time = p_input->p->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1777                     if( i_seekpoint_time >= 0 &&
1778                          !demux2_Control( p_demux,
1779                                           DEMUX_GET_TIME, &i_input_time ) )
1780                     {
1781                         if ( i_input_time < i_seekpoint_time + 3000000 )
1782                             i_seekpoint--;
1783                     }
1784                     else
1785                         i_seekpoint--;
1786                 }
1787                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
1788                     i_seekpoint = p_demux->info.i_seekpoint + 1;
1789                 else
1790                     i_seekpoint = val.i_int;
1791
1792                 if( i_seekpoint >= 0 && i_seekpoint <
1793                     p_input->p->input.title[p_demux->info.i_title]->i_seekpoint )
1794                 {
1795                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1796                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1797
1798                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
1799                 }
1800             }
1801             else if( p_input->p->input.i_title > 0 )
1802             {
1803                 demux_t *p_demux = p_input->p->input.p_demux;
1804                 access_t *p_access = p_input->p->input.p_access;
1805                 int i_seekpoint;
1806                 int64_t i_input_time;
1807                 int64_t i_seekpoint_time;
1808
1809                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1810                 {
1811                     i_seekpoint = p_access->info.i_seekpoint;
1812                     i_seekpoint_time = p_input->p->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1813                     if( i_seekpoint_time >= 0 &&
1814                         demux2_Control( p_demux,
1815                                         DEMUX_GET_TIME, &i_input_time ) )
1816                     {
1817                         if ( i_input_time < i_seekpoint_time + 3000000 )
1818                             i_seekpoint--;
1819                     }
1820                     else
1821                         i_seekpoint--;
1822                 }
1823                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) 
1824                     i_seekpoint = p_access->info.i_seekpoint + 1;
1825                 else
1826                     i_seekpoint = val.i_int;
1827
1828                 if( i_seekpoint >= 0 && i_seekpoint <
1829                     p_input->p->input.title[p_access->info.i_title]->i_seekpoint )
1830                 {
1831                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1832                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1833
1834                     access2_Control( p_access, ACCESS_SET_SEEKPOINT,
1835                                     i_seekpoint );
1836                     stream_AccessReset( p_input->p->input.p_stream );
1837                 }
1838             }
1839             break;
1840
1841         case INPUT_CONTROL_ADD_SLAVE:
1842             if( val.psz_string )
1843             {
1844                 input_source_t *slave = InputSourceNew( p_input );
1845
1846                 if( !InputSourceInit( p_input, slave, val.psz_string, NULL ) )
1847                 {
1848                     vlc_meta_t *p_meta;
1849                     int64_t i_time;
1850
1851                     /* Add the slave */
1852                     msg_Dbg( p_input, "adding %s as slave on the fly",
1853                              val.psz_string );
1854
1855                     /* Set position */
1856                     if( demux2_Control( p_input->p->input.p_demux,
1857                                         DEMUX_GET_TIME, &i_time ) )
1858                     {
1859                         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
1860                         InputSourceClean( slave );
1861                         free( slave );
1862                         break;
1863                     }
1864                     if( demux2_Control( slave->p_demux,
1865                                         DEMUX_SET_TIME, i_time ) )
1866                     {
1867                         msg_Err( p_input, "seek failed for new slave" );
1868                         InputSourceClean( slave );
1869                         free( slave );
1870                         break;
1871                     }
1872
1873                     /* Get meta (access and demux) */
1874                     p_meta = vlc_meta_New();
1875                     access2_Control( slave->p_access, ACCESS_GET_META,
1876                                      p_meta );
1877                     demux2_Control( slave->p_demux, DEMUX_GET_META, p_meta );
1878                     InputUpdateMeta( p_input, p_meta );
1879
1880                     TAB_APPEND( p_input->p->i_slave, p_input->p->slave, slave );
1881                 }
1882                 else
1883                 {
1884                     free( slave );
1885                     msg_Warn( p_input, "failed to add %s as slave",
1886                               val.psz_string );
1887                 }
1888
1889                 free( val.psz_string );
1890             }
1891             break;
1892
1893         case INPUT_CONTROL_SET_BOOKMARK:
1894         default:
1895             msg_Err( p_input, "not yet implemented" );
1896             break;
1897     }
1898
1899     return b_force_update;
1900 }
1901
1902 /*****************************************************************************
1903  * UpdateFromDemux:
1904  *****************************************************************************/
1905 static int UpdateFromDemux( input_thread_t *p_input )
1906 {
1907     demux_t *p_demux = p_input->p->input.p_demux;
1908     vlc_value_t v;
1909
1910     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
1911     {
1912         v.i_int = p_demux->info.i_title;
1913         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1914
1915         input_ControlVarTitle( p_input, p_demux->info.i_title );
1916
1917         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
1918     }
1919     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
1920     {
1921         v.i_int = p_demux->info.i_seekpoint;
1922         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1923
1924         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1925     }
1926     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
1927
1928     /* Hmmm only works with master input */
1929     if( p_input->p->input.p_demux == p_demux )
1930     {
1931         int i_title_end = p_input->p->input.i_title_end -
1932             p_input->p->input.i_title_offset;
1933         int i_seekpoint_end = p_input->p->input.i_seekpoint_end -
1934             p_input->p->input.i_seekpoint_offset;
1935
1936         if( i_title_end >= 0 && i_seekpoint_end >= 0 )
1937         {
1938             if( p_demux->info.i_title > i_title_end ||
1939                 ( p_demux->info.i_title == i_title_end &&
1940                   p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0;
1941         }
1942         else if( i_seekpoint_end >=0 )
1943         {
1944             if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0;
1945         }
1946         else if( i_title_end >= 0 )
1947         {
1948             if( p_demux->info.i_title > i_title_end ) return 0;
1949         }
1950     }
1951
1952     return 1;
1953 }
1954
1955 /*****************************************************************************
1956  * UpdateFromAccess:
1957  *****************************************************************************/
1958 static int UpdateFromAccess( input_thread_t *p_input )
1959 {
1960     access_t *p_access = p_input->p->input.p_access;
1961     vlc_value_t v;
1962
1963     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
1964     {
1965         v.i_int = p_access->info.i_title;
1966         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1967
1968         input_ControlVarTitle( p_input, p_access->info.i_title );
1969
1970         stream_AccessUpdate( p_input->p->input.p_stream );
1971
1972         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
1973     }
1974     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
1975     {
1976         v.i_int = p_access->info.i_seekpoint;
1977         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1978         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1979     }
1980     if( p_access->info.i_update & INPUT_UPDATE_META )
1981     {
1982         /* TODO maybe multi - access ? */
1983         vlc_meta_t *p_meta = vlc_meta_New();
1984         access2_Control( p_input->p->input.p_access,ACCESS_GET_META, p_meta );
1985         InputUpdateMeta( p_input, p_meta );
1986         var_SetBool( p_input, "item-change", p_input->p->input.p_item->i_id );
1987         p_access->info.i_update &= ~INPUT_UPDATE_META;
1988     }
1989
1990     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
1991
1992     /* Hmmm only works with master input */
1993     if( p_input->p->input.p_access == p_access )
1994     {
1995         int i_title_end = p_input->p->input.i_title_end -
1996             p_input->p->input.i_title_offset;
1997         int i_seekpoint_end = p_input->p->input.i_seekpoint_end -
1998             p_input->p->input.i_seekpoint_offset;
1999
2000         if( i_title_end >= 0 && i_seekpoint_end >=0 )
2001         {
2002             if( p_access->info.i_title > i_title_end ||
2003                 ( p_access->info.i_title == i_title_end &&
2004                   p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0;
2005         }
2006         else if( i_seekpoint_end >=0 )
2007         {
2008             if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0;
2009         }
2010         else if( i_title_end >= 0 )
2011         {
2012             if( p_access->info.i_title > i_title_end ) return 0;
2013         }
2014     }
2015
2016     return 1;
2017 }
2018
2019 /*****************************************************************************
2020  * UpdateItemLength:
2021  *****************************************************************************/
2022 static void UpdateItemLength( input_thread_t *p_input, int64_t i_length )
2023 {
2024     vlc_mutex_lock( &p_input->p->input.p_item->lock );
2025     p_input->p->input.p_item->i_duration = i_length;
2026     vlc_mutex_unlock( &p_input->p->input.p_item->lock );
2027
2028     if( !p_input->b_preparsing )
2029     {
2030         pl_Yield( p_input );
2031         var_SetInteger( pl_Get( p_input ), "item-change",
2032                         p_input->p->input.p_item->i_id );
2033         pl_Release( p_input )
2034     }
2035 }
2036
2037 /*****************************************************************************
2038  * InputSourceNew:
2039  *****************************************************************************/
2040 static input_source_t *InputSourceNew( input_thread_t *p_input )
2041 {
2042     input_source_t *in = (input_source_t*) malloc( sizeof( input_source_t ) );
2043
2044     if( !in )
2045     {
2046         msg_Err( p_input, "out of memory for new input source" );
2047         return NULL;
2048     }
2049
2050     in->p_item   = NULL;
2051     in->p_access = NULL;
2052     in->p_stream = NULL;
2053     in->p_demux  = NULL;
2054     in->b_title_demux = VLC_FALSE;
2055     TAB_INIT( in->i_title, in->title );
2056     in->b_can_pace_control = VLC_TRUE;
2057     in->b_eof = VLC_FALSE;
2058     in->i_cr_average = 0;
2059
2060     return in;
2061 }
2062
2063 /*****************************************************************************
2064  * InputSourceInit:
2065  *****************************************************************************/
2066 static int InputSourceInit( input_thread_t *p_input,
2067                             input_source_t *in, const char *psz_mrl,
2068                             const char *psz_forced_demux )
2069 {
2070     char psz_dup[strlen (psz_mrl) + 1];
2071     const char *psz_access;
2072     const char *psz_demux;
2073     char *psz_path;
2074     char *psz_tmp;
2075     char *psz;
2076     vlc_value_t val;
2077
2078     strcpy( psz_dup, psz_mrl );
2079
2080     if( !in ) return VLC_EGENERIC;
2081     if( !p_input ) return VLC_EGENERIC;
2082
2083     /* Split uri */
2084     if( !p_input->b_preparsing )
2085     {
2086         MRLSplit( VLC_OBJECT(p_input), psz_dup,
2087                   &psz_access, &psz_demux, &psz_path );
2088
2089         msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
2090                  psz_mrl, psz_access, psz_demux, psz_path );
2091
2092         /* Hack to allow udp://@:port syntax */
2093         if( !psz_access ||
2094             (strncmp( psz_access, "udp", 3 ) &&
2095              strncmp( psz_access, "rtp", 3 )) )
2096
2097         /* Find optional titles and seekpoints */
2098         MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
2099                      &in->i_seekpoint_start, &in->i_seekpoint_end );
2100
2101         if( psz_forced_demux && *psz_forced_demux )
2102         {
2103             psz_demux = psz_forced_demux;
2104         }
2105         else if( !psz_demux || *psz_demux == '\0' )
2106         {
2107             /* special hack for forcing a demuxer with --demux=module
2108              * (and do nothing with a list) */
2109             char *psz_var_demux = var_GetString( p_input, "demux" );
2110
2111             if( *psz_var_demux != '\0' &&
2112                 !strchr(psz_var_demux, ',' ) &&
2113                 !strchr(psz_var_demux, ':' ) )
2114             {
2115                 psz_demux = psz_var_demux;
2116
2117                 msg_Dbg( p_input, "enforced demux ` %s'", psz_demux );
2118             }
2119             else if( psz_var_demux )
2120             {
2121                 free( psz_var_demux );
2122             }
2123         }
2124
2125         /* Try access_demux if no demux given */
2126         if( *psz_demux == '\0' )
2127         {
2128             in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
2129                                       NULL, p_input->p->p_es_out, VLC_FALSE );
2130         }
2131     }
2132     else
2133     {
2134         psz_path = psz_dup;
2135         if( !strncmp( psz_path, "file://", 7 ) )
2136             psz_path += 7;
2137         msg_Dbg( p_input, "trying to pre-parse %s",  psz_path );
2138         psz_demux = "";
2139         psz_access = "file";
2140     }
2141
2142     if( in->p_demux )
2143     {
2144         int64_t i_pts_delay;
2145
2146         /* Get infos from access_demux */
2147         demux2_Control( in->p_demux,
2148                         DEMUX_GET_PTS_DELAY, &i_pts_delay );
2149         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
2150
2151         in->b_title_demux = VLC_TRUE;
2152         if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2153                             &in->title, &in->i_title,
2154                             &in->i_title_offset, &in->i_seekpoint_offset ) )
2155         {
2156             in->i_title = 0;
2157             in->title   = NULL;
2158         }
2159         demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
2160                         &in->b_can_pace_control );
2161         demux2_Control( in->p_demux, DEMUX_CAN_PAUSE,
2162                         &in->b_can_pause );
2163
2164         /* FIXME todo
2165         demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
2166                         &val.b_bool );
2167         */
2168     }
2169     else
2170     {
2171         int64_t i_pts_delay;
2172
2173         input_ChangeState( p_input, OPENING_S );
2174
2175         /* Now try a real access */
2176         in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path,
2177                                     p_input->b_preparsing );
2178
2179         /* Access failed, URL encoded ? */
2180         if( in->p_access == NULL && strchr( psz_path, '%' ) )
2181         {
2182             decode_URI( psz_path );
2183
2184             msg_Dbg( p_input, "retrying with access `%s' demux `%s' path `%s'",
2185                      psz_access, psz_demux, psz_path );
2186
2187             in->p_access = access2_New( p_input,
2188                                         psz_access, psz_demux, psz_path,
2189                                         p_input->b_preparsing );
2190         }
2191
2192         if( in->p_access == NULL )
2193         {
2194             msg_Err( p_input, "open of `%s' failed: %s", psz_mrl,
2195                                                          msg_StackMsg() );
2196             intf_UserFatal( VLC_OBJECT( p_input), VLC_FALSE,
2197                             _("Your input can't be opened"),
2198                             _("VLC is unable to open the MRL '%s'."
2199                             " Check the log for details."), psz_mrl );
2200             goto error;
2201         }
2202
2203         /* */
2204         psz_tmp = psz = var_GetString( p_input, "access-filter" );
2205         while( psz && *psz )
2206         {
2207             access_t *p_access = in->p_access;
2208             char *end = strchr( psz, ':' );
2209
2210             if( end )
2211                 *end++ = '\0';
2212
2213             in->p_access = access2_FilterNew( in->p_access, psz );
2214             if( in->p_access == NULL )
2215             {
2216                 in->p_access = p_access;
2217                 msg_Warn( p_input, "failed to insert access filter %s",
2218                           psz );
2219             }
2220
2221             psz = end;
2222         }
2223         if( psz_tmp ) free( psz_tmp );
2224
2225         /* Get infos from access */
2226         if( !p_input->b_preparsing )
2227         {
2228             access2_Control( in->p_access,
2229                              ACCESS_GET_PTS_DELAY, &i_pts_delay );
2230             p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
2231
2232             in->b_title_demux = VLC_FALSE;
2233             if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO,
2234                                  &in->title, &in->i_title,
2235                                 &in->i_title_offset, &in->i_seekpoint_offset ) )
2236
2237             {
2238                 in->i_title = 0;
2239                 in->title   = NULL;
2240             }
2241             access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
2242                              &in->b_can_pace_control );
2243             access2_Control( in->p_access, ACCESS_CAN_PAUSE,
2244                              &in->b_can_pause );
2245             access2_Control( in->p_access, ACCESS_CAN_SEEK,
2246                              &val.b_bool );
2247             var_Set( p_input, "seekable", val );
2248         }
2249
2250         input_ChangeState( p_input, BUFFERING_S );
2251
2252         /* Create the stream_t */
2253         in->p_stream = stream_AccessNew( in->p_access, p_input->b_preparsing );
2254         if( in->p_stream == NULL )
2255         {
2256             msg_Warn( p_input, "cannot create a stream_t from access" );
2257             goto error;
2258         }
2259
2260         /* Open a demuxer */
2261         if( *psz_demux == '\0' && *in->p_access->psz_demux )
2262         {
2263             psz_demux = in->p_access->psz_demux;
2264         }
2265
2266         {
2267             /* Take access redirections into account */
2268             char *psz_real_path;
2269             char *psz_buf = NULL;
2270             if( in->p_access->psz_path )
2271             {
2272                 const char *psz_a, *psz_d;
2273                 psz_buf = strdup( in->p_access->psz_path );
2274                 MRLSplit( VLC_OBJECT(p_input), psz_buf,
2275                           &psz_a, &psz_d, &psz_real_path );
2276             }
2277             else
2278             {
2279                 psz_real_path = psz_path;
2280             }
2281             in->p_demux = demux2_New( p_input, psz_access, psz_demux,
2282                                       psz_real_path,
2283                                       in->p_stream, p_input->p->p_es_out,
2284                                       p_input->b_preparsing );
2285             free( psz_buf );
2286         }
2287
2288         if( in->p_demux == NULL )
2289         {
2290             msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
2291                      psz_access, psz_demux, psz_path );
2292             intf_UserFatal( VLC_OBJECT( p_input ), VLC_FALSE,
2293                             _("Can't recognize the input's format"),
2294                             _("The format of '%s' can't be detected. "
2295                             "Have a look the log for details."), psz_mrl );
2296             goto error;
2297         }
2298
2299         /* Get title from demux */
2300         if( !p_input->b_preparsing && in->i_title <= 0 )
2301         {
2302             if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2303                                 &in->title, &in->i_title,
2304                                 &in->i_title_offset, &in->i_seekpoint_offset ))
2305             {
2306                 TAB_INIT( in->i_title, in->title );
2307             }
2308             else
2309             {
2310                 in->b_title_demux = VLC_TRUE;
2311             }
2312         }
2313         /* get attachment
2314          * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2315         if( 1 || !p_input->b_preparsing )
2316         {
2317             int i_attachment;
2318             input_attachment_t **attachment;
2319             if( !demux2_Control( in->p_demux, DEMUX_GET_ATTACHMENTS,
2320                                  &attachment, &i_attachment ) )
2321             {
2322                 int i;
2323                 vlc_mutex_lock( &p_input->p->input.p_item->lock );
2324                 p_input->p->attachment = realloc( p_input->p->attachment,
2325                         sizeof(input_attachment_t**) * ( p_input->p->i_attachment + i_attachment ) );
2326                 for( i = 0; i < i_attachment; i++ )
2327                     p_input->p->attachment[p_input->p->i_attachment++] = attachment[i];
2328                 if( attachment )
2329                     free( attachment );
2330                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
2331             }
2332         }
2333     }
2334
2335     if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
2336         in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
2337
2338     return VLC_SUCCESS;
2339
2340 error:
2341     input_ChangeState( p_input, ERROR_S );
2342
2343     if( in->p_demux )
2344         demux2_Delete( in->p_demux );
2345
2346     if( in->p_stream )
2347         stream_Delete( in->p_stream );
2348
2349     if( in->p_access )
2350         access2_Delete( in->p_access );
2351
2352     return VLC_EGENERIC;
2353 }
2354
2355 /*****************************************************************************
2356  * InputSourceClean:
2357  *****************************************************************************/
2358 static void InputSourceClean( input_source_t *in )
2359 {
2360     int i;
2361
2362     if( in->p_demux )
2363         demux2_Delete( in->p_demux );
2364
2365     if( in->p_stream )
2366         stream_Delete( in->p_stream );
2367
2368     if( in->p_access )
2369         access2_Delete( in->p_access );
2370
2371     if( in->i_title > 0 )
2372     {
2373         for( i = 0; i < in->i_title; i++ )
2374             vlc_input_title_Delete( in->title[i] );
2375         TAB_CLEAN( in->i_title, in->title );
2376     }
2377 }
2378
2379 static void SlaveDemux( input_thread_t *p_input )
2380 {
2381     int64_t i_time;
2382     int i;
2383
2384     if( demux2_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2385     {
2386         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2387         return;
2388     }
2389
2390     for( i = 0; i < p_input->p->i_slave; i++ )
2391     {
2392         input_source_t *in = p_input->p->slave[i];
2393         int i_ret = 1;
2394
2395         if( in->b_eof )
2396             continue;
2397
2398         if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
2399         {
2400             for( ;; )
2401             {
2402                 int64_t i_stime;
2403                 if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
2404                 {
2405                     msg_Err( p_input, "slave[%d] doesn't like "
2406                              "DEMUX_GET_TIME -> EOF", i );
2407                     i_ret = 0;
2408                     break;
2409                 }
2410
2411                 if( i_stime >= i_time )
2412                     break;
2413
2414                 if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
2415                     break;
2416             }
2417         }
2418         else
2419         {
2420             i_ret = in->p_demux->pf_demux( in->p_demux );
2421         }
2422
2423         if( i_ret <= 0 )
2424         {
2425             msg_Dbg( p_input, "slave %d EOF", i );
2426             in->b_eof = VLC_TRUE;
2427         }
2428     }
2429 }
2430
2431 static void SlaveSeek( input_thread_t *p_input )
2432 {
2433     int64_t i_time;
2434     int i;
2435
2436     if( !p_input ) return;
2437
2438     if( demux2_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2439     {
2440         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2441         return;
2442     }
2443
2444     for( i = 0; i < p_input->p->i_slave; i++ )
2445     {
2446         input_source_t *in = p_input->p->slave[i];
2447
2448         if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
2449         {
2450             msg_Err( p_input, "seek failed for slave %d -> EOF", i );
2451             in->b_eof = VLC_TRUE;
2452         }
2453     }
2454 }
2455
2456 /*****************************************************************************
2457  * InputMetaUser:
2458  *****************************************************************************/
2459 static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta )
2460 {
2461     vlc_value_t val;
2462
2463     if( !p_meta ) return;
2464
2465     /* Get meta information from user */
2466 #define GET_META( field, s ) \
2467     var_Get( p_input, (s), &val );  \
2468     if( *val.psz_string ) { \
2469         if( p_meta->psz_ ## field ) free ( p_meta->psz_ ## field ); \
2470         p_meta->psz_ ## field = strdup( val.psz_string ); \
2471     } \
2472     free( val.psz_string )
2473
2474     GET_META( title, "meta-title" );
2475     GET_META( artist, "meta-artist" );
2476     GET_META( genre, "meta-genre" );
2477     GET_META( copyright, "meta-copyright" );
2478     GET_META( description, "meta-description" );
2479     GET_META( date, "meta-date" );
2480     GET_META( url, "meta-url" );
2481 #undef GET_META
2482 }
2483
2484 /*****************************************************************************
2485  * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2486  * arturl and locking issue.
2487  *****************************************************************************/
2488 static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta )
2489 {
2490     input_item_t *p_item = p_input->p->input.p_item;
2491     char *psz_title = NULL;
2492
2493     if( !p_meta )
2494         return;
2495
2496     vlc_mutex_lock( &p_item->lock );
2497     if( p_meta->psz_title && !p_item->b_fixed_name )
2498         psz_title = strdup( p_meta->psz_title );
2499
2500     if( p_item->p_meta )
2501     {
2502         char *psz_arturl = p_item->p_meta->psz_arturl;
2503         p_item->p_meta->psz_arturl = NULL;
2504
2505         vlc_meta_Merge( p_item->p_meta, p_meta );
2506
2507         if( psz_arturl && *psz_arturl )
2508             vlc_meta_SetArtURL( p_item->p_meta, psz_arturl );
2509
2510         vlc_meta_Delete( p_meta );
2511     }
2512     else
2513     {
2514         p_item->p_meta = p_meta;
2515     }
2516     if( p_item->p_meta->psz_arturl && !strncmp( p_item->p_meta->psz_arturl, "attachment://", strlen("attachment") ) )
2517     {
2518         /* Don't look for art cover if sout
2519          * XXX It can change when sout has meta data support */
2520         if( p_input->p->p_sout && !p_input->b_preparsing )
2521             vlc_meta_SetArtURL( p_item->p_meta, "" );
2522         else
2523             input_ExtractAttachmentAndCacheArt( p_input );
2524     }
2525
2526     p_item->p_meta->i_status |= ITEM_PREPARSED;
2527     vlc_mutex_unlock( &p_item->lock );
2528
2529     if( psz_title )
2530     {
2531         input_Control( p_input, INPUT_SET_NAME, psz_title );
2532         free( psz_title );
2533     }
2534
2535     /** \todo handle sout meta */
2536 }
2537
2538
2539 static inline vlc_bool_t IsValidAccess( const char *psz )
2540 {
2541     char c;
2542
2543     while( ( c = *psz ) != '\0' )
2544     {
2545         if( c == ':' )
2546             return VLC_TRUE;
2547
2548         if( ( !isascii( c ) || !isalnum( c ) ) && ( c != '/' ) )
2549             return VLC_FALSE;
2550         psz++;
2551     }
2552     /* should not happen though */
2553     return VLC_FALSE;
2554 }
2555
2556
2557 /*****************************************************************************
2558  * MRLSplit: parse the access, demux and url part of the
2559  *           Media Resource Locator.
2560  *****************************************************************************/
2561 void MRLSplit( vlc_object_t *p_input, char *psz_dup,
2562                const char **ppsz_access, const char **ppsz_demux,
2563                char **ppsz_path )
2564 {
2565     const char *psz_access = "";
2566     const char *psz_demux  = "";
2567     char *psz_path;
2568     char *psz;
2569
2570     psz = strchr( psz_dup, ':' );
2571
2572     if( psz != NULL )
2573     {
2574         /* Guess whether ':' is part of a local filename, or separates
2575          * access/demux from path */
2576         if( !IsValidAccess( psz_dup ) )
2577             psz = NULL;
2578 #if defined( WIN32 ) || defined( UNDER_CE )
2579         else if( ( psz - psz_dup == 1 ) && isalpha( psz_dup[0] ) )
2580         {
2581             msg_Dbg( p_input, "drive letter %c: found in source", *psz_dup );
2582             psz = NULL;
2583         }
2584 #endif
2585     }
2586
2587     if( psz != NULL )
2588     {
2589         *psz++ = '\0';
2590         if( psz[0] == '/' && psz[1] == '/' ) psz += 2;
2591
2592         psz_path = psz;
2593
2594         psz = strchr( psz_dup, '/' );
2595         if( psz )
2596         {
2597             *psz++ = '\0';
2598             psz_demux = psz;
2599         }
2600
2601         psz_access = psz_dup;
2602     }
2603     else
2604     {
2605         psz_path = psz_dup;
2606     }
2607
2608     *ppsz_access = psz_access;
2609     *ppsz_demux = psz_demux;
2610     *ppsz_path = psz_path;
2611 }
2612
2613 /*****************************************************************************
2614  * MRLSections: parse title and seekpoint info from the Media Resource Locator.
2615  *
2616  * Syntax:
2617  * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
2618  *****************************************************************************/
2619 static void MRLSections( input_thread_t *p_input, char *psz_source,
2620                          int *pi_title_start, int *pi_title_end,
2621                          int *pi_chapter_start, int *pi_chapter_end )
2622 {
2623     char *psz, *psz_end, *psz_next, *psz_check;
2624
2625     *pi_title_start = *pi_title_end = -1;
2626     *pi_chapter_start = *pi_chapter_end = -1;
2627
2628     /* Start by parsing titles and chapters */
2629     if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
2630
2631     /* Check we are really dealing with a title/chapter section */
2632     psz_check = psz + 1;
2633     if( !*psz_check ) return;
2634     if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2635     if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
2636     if( *psz_check == ':' && ++psz_check )
2637         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2638     if( *psz_check != '-' && *psz_check ) return;
2639     if( *psz_check == '-' && ++psz_check )
2640         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2641     if( *psz_check != ':' && *psz_check ) return;
2642     if( *psz_check == ':' && ++psz_check )
2643         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2644     if( *psz_check ) return;
2645
2646     /* Separate start and end */
2647     *psz++ = 0;
2648     if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
2649
2650     /* Look for the start title */
2651     *pi_title_start = strtol( psz, &psz_next, 0 );
2652     if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
2653     *pi_title_end = *pi_title_start;
2654     psz = psz_next;
2655
2656     /* Look for the start chapter */
2657     if( *psz ) psz++;
2658     *pi_chapter_start = strtol( psz, &psz_next, 0 );
2659     if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
2660     *pi_chapter_end = *pi_chapter_start;
2661
2662     if( psz_end )
2663     {
2664         /* Look for the end title */
2665         *pi_title_end = strtol( psz_end, &psz_next, 0 );
2666         if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
2667         psz_end = psz_next;
2668
2669         /* Look for the end chapter */
2670         if( *psz_end ) psz_end++;
2671         *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
2672         if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
2673     }
2674
2675     msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
2676              psz_source, *pi_title_start, *pi_chapter_start,
2677              *pi_title_end, *pi_chapter_end );
2678 }
2679
2680 /*****************************************************************************
2681  * input_AddSubtitles: add a subtitles file and enable it
2682  *****************************************************************************/
2683 vlc_bool_t input_AddSubtitles( input_thread_t *p_input, char *psz_subtitle,
2684                                vlc_bool_t b_check_extension )
2685 {
2686     input_source_t *sub;
2687     vlc_value_t count;
2688     vlc_value_t list;
2689     char *psz_path, *psz_extension;
2690
2691     if( b_check_extension && !subtitles_Filter( psz_subtitle ) )
2692     {
2693         return VLC_FALSE;
2694     }
2695
2696     /* if we are provided a subtitle.sub file,
2697      * see if we don't have a subtitle.idx and use it instead */
2698     psz_path = strdup( psz_subtitle );
2699     if( psz_path )
2700     {
2701         psz_extension = strrchr( psz_path, '.');
2702         if( psz_extension && strcmp( psz_extension, ".sub" ) == 0 )
2703         {
2704             FILE *f;
2705
2706             strcpy( psz_extension, ".idx" );
2707             /* FIXME: a portable wrapper for stat() or access() would be more suited */
2708             if( ( f = utf8_fopen( psz_path, "rt" ) ) )
2709             {
2710                 fclose( f );
2711                 msg_Dbg( p_input, "using %s subtitles file instead of %s",
2712                          psz_path, psz_subtitle );
2713                 strcpy( psz_subtitle, psz_path );
2714             }
2715         }
2716         free( psz_path );
2717     }
2718
2719     var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
2720
2721     sub = InputSourceNew( p_input );
2722     if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
2723     {
2724         TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub );
2725
2726         /* Select the ES */
2727         if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) )
2728         {
2729             if( count.i_int == 0 )
2730                 count.i_int++;
2731             /* if it was first one, there is disable too */
2732
2733             if( count.i_int < list.p_list->i_count )
2734             {
2735                 input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
2736                                    &list.p_list->p_values[count.i_int] );
2737             }
2738             var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list, NULL );
2739         }
2740     }
2741     else free( sub );
2742
2743     return VLC_TRUE;
2744 }