]> git.sesse.net Git - vlc/blob - src/input/input.c
- Added support for embeded cover. Demuxer just need to fill psz_arturl meta
[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                 /* We will not send audio data if new rate != default */
1674                 if( i_rate != INPUT_RATE_DEFAULT && p_input->p->i_rate == INPUT_RATE_DEFAULT )
1675                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_TRUE );
1676
1677                 p_input->p->i_rate  = i_rate;
1678
1679                 /* Reset clock */
1680                 es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1681
1682                 b_force_update = VLC_TRUE;
1683             }
1684             break;
1685         }
1686
1687         case INPUT_CONTROL_SET_PROGRAM:
1688             /* No need to force update, es_out does it if needed */
1689             es_out_Control( p_input->p->p_es_out,
1690                             ES_OUT_SET_GROUP, val.i_int );
1691
1692             demux2_Control( p_input->p->input.p_demux, DEMUX_SET_GROUP, val.i_int,
1693                             NULL );
1694             break;
1695
1696         case INPUT_CONTROL_SET_ES:
1697             /* No need to force update, es_out does it if needed */
1698             es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ES,
1699                             input_EsOutGetFromID( p_input->p->p_es_out,
1700                                                   val.i_int ) );
1701             break;
1702
1703         case INPUT_CONTROL_SET_AUDIO_DELAY:
1704             input_EsOutSetDelay( p_input->p->p_es_out,
1705                                  AUDIO_ES, val.i_time );
1706             var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
1707             break;
1708
1709         case INPUT_CONTROL_SET_SPU_DELAY:
1710             input_EsOutSetDelay( p_input->p->p_es_out,
1711                                  SPU_ES, val.i_time );
1712             var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
1713             break;
1714
1715         case INPUT_CONTROL_SET_TITLE:
1716         case INPUT_CONTROL_SET_TITLE_NEXT:
1717         case INPUT_CONTROL_SET_TITLE_PREV:
1718             if( p_input->p->input.b_title_demux &&
1719                 p_input->p->input.i_title > 0 )
1720             {
1721                 /* TODO */
1722                 /* FIXME handle demux title */
1723                 demux_t *p_demux = p_input->p->input.p_demux;
1724                 int i_title;
1725
1726                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1727                     i_title = p_demux->info.i_title - 1;
1728                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1729                     i_title = p_demux->info.i_title + 1;
1730                 else
1731                     i_title = val.i_int;
1732
1733                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
1734                 {
1735                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1736                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1737
1738                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
1739                     input_ControlVarTitle( p_input, i_title );
1740                 }
1741             }
1742             else if( p_input->p->input.i_title > 0 )
1743             {
1744                 access_t *p_access = p_input->p->input.p_access;
1745                 int i_title;
1746
1747                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1748                     i_title = p_access->info.i_title - 1;
1749                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1750                     i_title = p_access->info.i_title + 1;
1751                 else
1752                     i_title = val.i_int;
1753
1754                 if( i_title >= 0 && i_title < p_input->p->input.i_title )
1755                 {
1756                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1757                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1758
1759                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
1760                     stream_AccessReset( p_input->p->input.p_stream );
1761                 }
1762             }
1763             break;
1764         case INPUT_CONTROL_SET_SEEKPOINT:
1765         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1766         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1767             if( p_input->p->input.b_title_demux &&
1768                 p_input->p->input.i_title > 0 )
1769             {
1770                 demux_t *p_demux = p_input->p->input.p_demux;
1771                 int i_seekpoint;
1772                 int64_t i_input_time;
1773                 int64_t i_seekpoint_time;
1774
1775                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1776                 {
1777                     i_seekpoint = p_demux->info.i_seekpoint;
1778                     i_seekpoint_time = p_input->p->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1779                     if( i_seekpoint_time >= 0 &&
1780                          !demux2_Control( p_demux,
1781                                           DEMUX_GET_TIME, &i_input_time ) )
1782                     {
1783                         if ( i_input_time < i_seekpoint_time + 3000000 )
1784                             i_seekpoint--;
1785                     }
1786                     else
1787                         i_seekpoint--;
1788                 }
1789                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
1790                     i_seekpoint = p_demux->info.i_seekpoint + 1;
1791                 else
1792                     i_seekpoint = val.i_int;
1793
1794                 if( i_seekpoint >= 0 && i_seekpoint <
1795                     p_input->p->input.title[p_demux->info.i_title]->i_seekpoint )
1796                 {
1797                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1798                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1799
1800                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
1801                 }
1802             }
1803             else if( p_input->p->input.i_title > 0 )
1804             {
1805                 demux_t *p_demux = p_input->p->input.p_demux;
1806                 access_t *p_access = p_input->p->input.p_access;
1807                 int i_seekpoint;
1808                 int64_t i_input_time;
1809                 int64_t i_seekpoint_time;
1810
1811                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1812                 {
1813                     i_seekpoint = p_access->info.i_seekpoint;
1814                     i_seekpoint_time = p_input->p->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1815                     if( i_seekpoint_time >= 0 &&
1816                         demux2_Control( p_demux,
1817                                         DEMUX_GET_TIME, &i_input_time ) )
1818                     {
1819                         if ( i_input_time < i_seekpoint_time + 3000000 )
1820                             i_seekpoint--;
1821                     }
1822                     else
1823                         i_seekpoint--;
1824                 }
1825                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) 
1826                     i_seekpoint = p_access->info.i_seekpoint + 1;
1827                 else
1828                     i_seekpoint = val.i_int;
1829
1830                 if( i_seekpoint >= 0 && i_seekpoint <
1831                     p_input->p->input.title[p_access->info.i_title]->i_seekpoint )
1832                 {
1833                     es_out_Control( p_input->p->p_es_out, ES_OUT_RESET_PCR );
1834                     input_EsOutDiscontinuity( p_input->p->p_es_out, VLC_TRUE, VLC_FALSE );
1835
1836                     access2_Control( p_access, ACCESS_SET_SEEKPOINT,
1837                                     i_seekpoint );
1838                     stream_AccessReset( p_input->p->input.p_stream );
1839                 }
1840             }
1841             break;
1842
1843         case INPUT_CONTROL_ADD_SLAVE:
1844             if( val.psz_string )
1845             {
1846                 input_source_t *slave = InputSourceNew( p_input );
1847
1848                 if( !InputSourceInit( p_input, slave, val.psz_string, NULL ) )
1849                 {
1850                     vlc_meta_t *p_meta;
1851                     int64_t i_time;
1852
1853                     /* Add the slave */
1854                     msg_Dbg( p_input, "adding %s as slave on the fly",
1855                              val.psz_string );
1856
1857                     /* Set position */
1858                     if( demux2_Control( p_input->p->input.p_demux,
1859                                         DEMUX_GET_TIME, &i_time ) )
1860                     {
1861                         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
1862                         InputSourceClean( slave );
1863                         free( slave );
1864                         break;
1865                     }
1866                     if( demux2_Control( slave->p_demux,
1867                                         DEMUX_SET_TIME, i_time ) )
1868                     {
1869                         msg_Err( p_input, "seek failed for new slave" );
1870                         InputSourceClean( slave );
1871                         free( slave );
1872                         break;
1873                     }
1874
1875                     /* Get meta (access and demux) */
1876                     p_meta = vlc_meta_New();
1877                     access2_Control( slave->p_access, ACCESS_GET_META,
1878                                      p_meta );
1879                     demux2_Control( slave->p_demux, DEMUX_GET_META, p_meta );
1880                     InputUpdateMeta( p_input, p_meta );
1881
1882                     TAB_APPEND( p_input->p->i_slave, p_input->p->slave, slave );
1883                 }
1884                 else
1885                 {
1886                     free( slave );
1887                     msg_Warn( p_input, "failed to add %s as slave",
1888                               val.psz_string );
1889                 }
1890
1891                 free( val.psz_string );
1892             }
1893             break;
1894
1895         case INPUT_CONTROL_SET_BOOKMARK:
1896         default:
1897             msg_Err( p_input, "not yet implemented" );
1898             break;
1899     }
1900
1901     return b_force_update;
1902 }
1903
1904 /*****************************************************************************
1905  * UpdateFromDemux:
1906  *****************************************************************************/
1907 static int UpdateFromDemux( input_thread_t *p_input )
1908 {
1909     demux_t *p_demux = p_input->p->input.p_demux;
1910     vlc_value_t v;
1911
1912     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
1913     {
1914         v.i_int = p_demux->info.i_title;
1915         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1916
1917         input_ControlVarTitle( p_input, p_demux->info.i_title );
1918
1919         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
1920     }
1921     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
1922     {
1923         v.i_int = p_demux->info.i_seekpoint;
1924         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1925
1926         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1927     }
1928     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
1929
1930     /* Hmmm only works with master input */
1931     if( p_input->p->input.p_demux == p_demux )
1932     {
1933         int i_title_end = p_input->p->input.i_title_end -
1934             p_input->p->input.i_title_offset;
1935         int i_seekpoint_end = p_input->p->input.i_seekpoint_end -
1936             p_input->p->input.i_seekpoint_offset;
1937
1938         if( i_title_end >= 0 && i_seekpoint_end >= 0 )
1939         {
1940             if( p_demux->info.i_title > i_title_end ||
1941                 ( p_demux->info.i_title == i_title_end &&
1942                   p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0;
1943         }
1944         else if( i_seekpoint_end >=0 )
1945         {
1946             if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0;
1947         }
1948         else if( i_title_end >= 0 )
1949         {
1950             if( p_demux->info.i_title > i_title_end ) return 0;
1951         }
1952     }
1953
1954     return 1;
1955 }
1956
1957 /*****************************************************************************
1958  * UpdateFromAccess:
1959  *****************************************************************************/
1960 static int UpdateFromAccess( input_thread_t *p_input )
1961 {
1962     access_t *p_access = p_input->p->input.p_access;
1963     vlc_value_t v;
1964
1965     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
1966     {
1967         v.i_int = p_access->info.i_title;
1968         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1969
1970         input_ControlVarTitle( p_input, p_access->info.i_title );
1971
1972         stream_AccessUpdate( p_input->p->input.p_stream );
1973
1974         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
1975     }
1976     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
1977     {
1978         v.i_int = p_access->info.i_seekpoint;
1979         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1980         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1981     }
1982     if( p_access->info.i_update & INPUT_UPDATE_META )
1983     {
1984         /* TODO maybe multi - access ? */
1985         vlc_meta_t *p_meta = vlc_meta_New();
1986         access2_Control( p_input->p->input.p_access,ACCESS_GET_META, p_meta );
1987         InputUpdateMeta( p_input, p_meta );
1988         var_SetBool( p_input, "item-change", p_input->p->input.p_item->i_id );
1989         p_access->info.i_update &= ~INPUT_UPDATE_META;
1990     }
1991
1992     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
1993
1994     /* Hmmm only works with master input */
1995     if( p_input->p->input.p_access == p_access )
1996     {
1997         int i_title_end = p_input->p->input.i_title_end -
1998             p_input->p->input.i_title_offset;
1999         int i_seekpoint_end = p_input->p->input.i_seekpoint_end -
2000             p_input->p->input.i_seekpoint_offset;
2001
2002         if( i_title_end >= 0 && i_seekpoint_end >=0 )
2003         {
2004             if( p_access->info.i_title > i_title_end ||
2005                 ( p_access->info.i_title == i_title_end &&
2006                   p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0;
2007         }
2008         else if( i_seekpoint_end >=0 )
2009         {
2010             if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0;
2011         }
2012         else if( i_title_end >= 0 )
2013         {
2014             if( p_access->info.i_title > i_title_end ) return 0;
2015         }
2016     }
2017
2018     return 1;
2019 }
2020
2021 /*****************************************************************************
2022  * UpdateItemLength:
2023  *****************************************************************************/
2024 static void UpdateItemLength( input_thread_t *p_input, int64_t i_length )
2025 {
2026     vlc_mutex_lock( &p_input->p->input.p_item->lock );
2027     p_input->p->input.p_item->i_duration = i_length;
2028     vlc_mutex_unlock( &p_input->p->input.p_item->lock );
2029
2030     if( !p_input->b_preparsing )
2031     {
2032         pl_Yield( p_input );
2033         var_SetInteger( pl_Get( p_input ), "item-change",
2034                         p_input->p->input.p_item->i_id );
2035         pl_Release( p_input )
2036     }
2037 }
2038
2039 /*****************************************************************************
2040  * InputSourceNew:
2041  *****************************************************************************/
2042 static input_source_t *InputSourceNew( input_thread_t *p_input )
2043 {
2044     input_source_t *in = (input_source_t*) malloc( sizeof( input_source_t ) );
2045
2046     if( !in )
2047     {
2048         msg_Err( p_input, "out of memory for new input source" );
2049         return NULL;
2050     }
2051
2052     in->p_item   = NULL;
2053     in->p_access = NULL;
2054     in->p_stream = NULL;
2055     in->p_demux  = NULL;
2056     in->b_title_demux = VLC_FALSE;
2057     TAB_INIT( in->i_title, in->title );
2058     in->b_can_pace_control = VLC_TRUE;
2059     in->b_eof = VLC_FALSE;
2060     in->i_cr_average = 0;
2061
2062     return in;
2063 }
2064
2065 /*****************************************************************************
2066  * InputSourceInit:
2067  *****************************************************************************/
2068 static int InputSourceInit( input_thread_t *p_input,
2069                             input_source_t *in, const char *psz_mrl,
2070                             const char *psz_forced_demux )
2071 {
2072     char psz_dup[strlen (psz_mrl) + 1];
2073     const char *psz_access;
2074     const char *psz_demux;
2075     char *psz_path;
2076     char *psz_tmp;
2077     char *psz;
2078     vlc_value_t val;
2079
2080     strcpy( psz_dup, psz_mrl );
2081
2082     if( !in ) return VLC_EGENERIC;
2083     if( !p_input ) return VLC_EGENERIC;
2084
2085     /* Split uri */
2086     if( !p_input->b_preparsing )
2087     {
2088         MRLSplit( VLC_OBJECT(p_input), psz_dup,
2089                   &psz_access, &psz_demux, &psz_path );
2090
2091         msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
2092                  psz_mrl, psz_access, psz_demux, psz_path );
2093
2094         /* Hack to allow udp://@:port syntax */
2095         if( !psz_access ||
2096             (strncmp( psz_access, "udp", 3 ) &&
2097              strncmp( psz_access, "rtp", 3 )) )
2098
2099         /* Find optional titles and seekpoints */
2100         MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
2101                      &in->i_seekpoint_start, &in->i_seekpoint_end );
2102
2103         if( psz_forced_demux && *psz_forced_demux )
2104         {
2105             psz_demux = psz_forced_demux;
2106         }
2107         else if( !psz_demux || *psz_demux == '\0' )
2108         {
2109             /* special hack for forcing a demuxer with --demux=module
2110              * (and do nothing with a list) */
2111             char *psz_var_demux = var_GetString( p_input, "demux" );
2112
2113             if( *psz_var_demux != '\0' &&
2114                 !strchr(psz_var_demux, ',' ) &&
2115                 !strchr(psz_var_demux, ':' ) )
2116             {
2117                 psz_demux = psz_var_demux;
2118
2119                 msg_Dbg( p_input, "enforced demux ` %s'", psz_demux );
2120             }
2121             else if( psz_var_demux )
2122             {
2123                 free( psz_var_demux );
2124             }
2125         }
2126
2127         /* Try access_demux if no demux given */
2128         if( *psz_demux == '\0' )
2129         {
2130             in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
2131                                       NULL, p_input->p->p_es_out, VLC_FALSE );
2132         }
2133     }
2134     else
2135     {
2136         psz_path = psz_dup;
2137         if( !strncmp( psz_path, "file://", 7 ) )
2138             psz_path += 7;
2139         msg_Dbg( p_input, "trying to pre-parse %s",  psz_path );
2140         psz_demux = "";
2141         psz_access = "file";
2142     }
2143
2144     if( in->p_demux )
2145     {
2146         int64_t i_pts_delay;
2147
2148         /* Get infos from access_demux */
2149         demux2_Control( in->p_demux,
2150                         DEMUX_GET_PTS_DELAY, &i_pts_delay );
2151         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
2152
2153         in->b_title_demux = VLC_TRUE;
2154         if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2155                             &in->title, &in->i_title,
2156                             &in->i_title_offset, &in->i_seekpoint_offset ) )
2157         {
2158             in->i_title = 0;
2159             in->title   = NULL;
2160         }
2161         demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
2162                         &in->b_can_pace_control );
2163         demux2_Control( in->p_demux, DEMUX_CAN_PAUSE,
2164                         &in->b_can_pause );
2165
2166         /* FIXME todo
2167         demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
2168                         &val.b_bool );
2169         */
2170     }
2171     else
2172     {
2173         int64_t i_pts_delay;
2174
2175         input_ChangeState( p_input, OPENING_S );
2176
2177         /* Now try a real access */
2178         in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path,
2179                                     p_input->b_preparsing );
2180
2181         /* Access failed, URL encoded ? */
2182         if( in->p_access == NULL && strchr( psz_path, '%' ) )
2183         {
2184             decode_URI( psz_path );
2185
2186             msg_Dbg( p_input, "retrying with access `%s' demux `%s' path `%s'",
2187                      psz_access, psz_demux, psz_path );
2188
2189             in->p_access = access2_New( p_input,
2190                                         psz_access, psz_demux, psz_path,
2191                                         p_input->b_preparsing );
2192         }
2193
2194         if( in->p_access == NULL )
2195         {
2196             msg_Err( p_input, "open of `%s' failed: %s", psz_mrl,
2197                                                          msg_StackMsg() );
2198             intf_UserFatal( VLC_OBJECT( p_input), VLC_FALSE,
2199                             _("Your input can't be opened"),
2200                             _("VLC is unable to open the MRL '%s'."
2201                             " Check the log for details."), psz_mrl );
2202             goto error;
2203         }
2204
2205         /* */
2206         psz_tmp = psz = var_GetString( p_input, "access-filter" );
2207         while( psz && *psz )
2208         {
2209             access_t *p_access = in->p_access;
2210             char *end = strchr( psz, ':' );
2211
2212             if( end )
2213                 *end++ = '\0';
2214
2215             in->p_access = access2_FilterNew( in->p_access, psz );
2216             if( in->p_access == NULL )
2217             {
2218                 in->p_access = p_access;
2219                 msg_Warn( p_input, "failed to insert access filter %s",
2220                           psz );
2221             }
2222
2223             psz = end;
2224         }
2225         if( psz_tmp ) free( psz_tmp );
2226
2227         /* Get infos from access */
2228         if( !p_input->b_preparsing )
2229         {
2230             access2_Control( in->p_access,
2231                              ACCESS_GET_PTS_DELAY, &i_pts_delay );
2232             p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
2233
2234             in->b_title_demux = VLC_FALSE;
2235             if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO,
2236                                  &in->title, &in->i_title,
2237                                 &in->i_title_offset, &in->i_seekpoint_offset ) )
2238
2239             {
2240                 in->i_title = 0;
2241                 in->title   = NULL;
2242             }
2243             access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
2244                              &in->b_can_pace_control );
2245             access2_Control( in->p_access, ACCESS_CAN_PAUSE,
2246                              &in->b_can_pause );
2247             access2_Control( in->p_access, ACCESS_CAN_SEEK,
2248                              &val.b_bool );
2249             var_Set( p_input, "seekable", val );
2250         }
2251
2252         input_ChangeState( p_input, BUFFERING_S );
2253
2254         /* Create the stream_t */
2255         in->p_stream = stream_AccessNew( in->p_access, p_input->b_preparsing );
2256         if( in->p_stream == NULL )
2257         {
2258             msg_Warn( p_input, "cannot create a stream_t from access" );
2259             goto error;
2260         }
2261
2262         /* Open a demuxer */
2263         if( *psz_demux == '\0' && *in->p_access->psz_demux )
2264         {
2265             psz_demux = in->p_access->psz_demux;
2266         }
2267
2268         {
2269             /* Take access redirections into account */
2270             char *psz_real_path;
2271             char *psz_buf = NULL;
2272             if( in->p_access->psz_path )
2273             {
2274                 const char *psz_a, *psz_d;
2275                 psz_buf = strdup( in->p_access->psz_path );
2276                 MRLSplit( VLC_OBJECT(p_input), psz_buf,
2277                           &psz_a, &psz_d, &psz_real_path );
2278             }
2279             else
2280             {
2281                 psz_real_path = psz_path;
2282             }
2283             in->p_demux = demux2_New( p_input, psz_access, psz_demux,
2284                                       psz_real_path,
2285                                       in->p_stream, p_input->p->p_es_out,
2286                                       p_input->b_preparsing );
2287             free( psz_buf );
2288         }
2289
2290         if( in->p_demux == NULL )
2291         {
2292             msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
2293                      psz_access, psz_demux, psz_path );
2294             intf_UserFatal( VLC_OBJECT( p_input ), VLC_FALSE,
2295                             _("Can't recognize the input's format"),
2296                             _("The format of '%s' can't be detected. "
2297                             "Have a look the log for details."), psz_mrl );
2298             goto error;
2299         }
2300
2301         /* Get title from demux */
2302         if( !p_input->b_preparsing && in->i_title <= 0 )
2303         {
2304             if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2305                                 &in->title, &in->i_title,
2306                                 &in->i_title_offset, &in->i_seekpoint_offset ))
2307             {
2308                 TAB_INIT( in->i_title, in->title );
2309             }
2310             else
2311             {
2312                 in->b_title_demux = VLC_TRUE;
2313             }
2314         }
2315         /* get attachment
2316          * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2317         if( 1 || !p_input->b_preparsing )
2318         {
2319             int i_attachment;
2320             input_attachment_t **attachment;
2321             if( !demux2_Control( in->p_demux, DEMUX_GET_ATTACHMENTS,
2322                                  &attachment, &i_attachment ) )
2323             {
2324                 int i;
2325                 vlc_mutex_lock( &p_input->p->input.p_item->lock );
2326                 p_input->p->attachment = realloc( p_input->p->attachment,
2327                         sizeof(input_attachment_t**) * ( p_input->p->i_attachment + i_attachment ) );
2328                 for( i = 0; i < i_attachment; i++ )
2329                     p_input->p->attachment[p_input->p->i_attachment++] = attachment[i];
2330                 if( attachment )
2331                     free( attachment );
2332                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
2333             }
2334         }
2335     }
2336
2337     if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
2338         in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
2339
2340     return VLC_SUCCESS;
2341
2342 error:
2343     input_ChangeState( p_input, ERROR_S );
2344
2345     if( in->p_demux )
2346         demux2_Delete( in->p_demux );
2347
2348     if( in->p_stream )
2349         stream_Delete( in->p_stream );
2350
2351     if( in->p_access )
2352         access2_Delete( in->p_access );
2353
2354     return VLC_EGENERIC;
2355 }
2356
2357 /*****************************************************************************
2358  * InputSourceClean:
2359  *****************************************************************************/
2360 static void InputSourceClean( input_source_t *in )
2361 {
2362     int i;
2363
2364     if( in->p_demux )
2365         demux2_Delete( in->p_demux );
2366
2367     if( in->p_stream )
2368         stream_Delete( in->p_stream );
2369
2370     if( in->p_access )
2371         access2_Delete( in->p_access );
2372
2373     if( in->i_title > 0 )
2374     {
2375         for( i = 0; i < in->i_title; i++ )
2376             vlc_input_title_Delete( in->title[i] );
2377         TAB_CLEAN( in->i_title, in->title );
2378     }
2379 }
2380
2381 static void SlaveDemux( input_thread_t *p_input )
2382 {
2383     int64_t i_time;
2384     int i;
2385
2386     if( demux2_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2387     {
2388         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2389         return;
2390     }
2391
2392     for( i = 0; i < p_input->p->i_slave; i++ )
2393     {
2394         input_source_t *in = p_input->p->slave[i];
2395         int i_ret = 1;
2396
2397         if( in->b_eof )
2398             continue;
2399
2400         if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
2401         {
2402             for( ;; )
2403             {
2404                 int64_t i_stime;
2405                 if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
2406                 {
2407                     msg_Err( p_input, "slave[%d] doesn't like "
2408                              "DEMUX_GET_TIME -> EOF", i );
2409                     i_ret = 0;
2410                     break;
2411                 }
2412
2413                 if( i_stime >= i_time )
2414                     break;
2415
2416                 if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
2417                     break;
2418             }
2419         }
2420         else
2421         {
2422             i_ret = in->p_demux->pf_demux( in->p_demux );
2423         }
2424
2425         if( i_ret <= 0 )
2426         {
2427             msg_Dbg( p_input, "slave %d EOF", i );
2428             in->b_eof = VLC_TRUE;
2429         }
2430     }
2431 }
2432
2433 static void SlaveSeek( input_thread_t *p_input )
2434 {
2435     int64_t i_time;
2436     int i;
2437
2438     if( !p_input ) return;
2439
2440     if( demux2_Control( p_input->p->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2441     {
2442         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2443         return;
2444     }
2445
2446     for( i = 0; i < p_input->p->i_slave; i++ )
2447     {
2448         input_source_t *in = p_input->p->slave[i];
2449
2450         if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
2451         {
2452             msg_Err( p_input, "seek failed for slave %d -> EOF", i );
2453             in->b_eof = VLC_TRUE;
2454         }
2455     }
2456 }
2457
2458 /*****************************************************************************
2459  * InputMetaUser:
2460  *****************************************************************************/
2461 static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta )
2462 {
2463     vlc_value_t val;
2464
2465     if( !p_meta ) return;
2466
2467     /* Get meta information from user */
2468 #define GET_META( field, s ) \
2469     var_Get( p_input, (s), &val );  \
2470     if( *val.psz_string ) { \
2471         if( p_meta->psz_ ## field ) free ( p_meta->psz_ ## field ); \
2472         p_meta->psz_ ## field = strdup( val.psz_string ); \
2473     } \
2474     free( val.psz_string )
2475
2476     GET_META( title, "meta-title" );
2477     GET_META( artist, "meta-artist" );
2478     GET_META( genre, "meta-genre" );
2479     GET_META( copyright, "meta-copyright" );
2480     GET_META( description, "meta-description" );
2481     GET_META( date, "meta-date" );
2482     GET_META( url, "meta-url" );
2483 #undef GET_META
2484 }
2485
2486 /*****************************************************************************
2487  * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2488  * arturl and locking issue.
2489  *****************************************************************************/
2490 static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta )
2491 {
2492     input_item_t *p_item = p_input->p->input.p_item;
2493     char *psz_title = NULL;
2494
2495     if( !p_meta )
2496         return;
2497
2498     vlc_mutex_lock( &p_item->lock );
2499     if( p_meta->psz_title && !p_item->b_fixed_name )
2500         psz_title = strdup( p_meta->psz_title );
2501
2502     if( p_item->p_meta )
2503     {
2504         char *psz_arturl = p_item->p_meta->psz_arturl;
2505         p_item->p_meta->psz_arturl = NULL;
2506
2507         vlc_meta_Merge( p_item->p_meta, p_meta );
2508
2509         if( psz_arturl && *psz_arturl )
2510             vlc_meta_SetArtURL( p_item->p_meta, psz_arturl );
2511
2512         vlc_meta_Delete( p_meta );
2513     }
2514     else
2515     {
2516         p_item->p_meta = p_meta;
2517     }
2518     if( p_item->p_meta->psz_arturl && !strncmp( p_item->p_meta->psz_arturl, "attachment://", strlen("attachment") ) )
2519     {
2520         /* Don't look for art cover if sout
2521          * XXX It can change when sout has meta data support */
2522         if( p_input->p->p_sout && !p_input->b_preparsing )
2523             vlc_meta_SetArtURL( p_item->p_meta, "" );
2524         else
2525             input_ExtractAttachmentAndCacheArt( p_input );
2526     }
2527
2528     p_item->p_meta->i_status |= ITEM_PREPARSED;
2529     vlc_mutex_unlock( &p_item->lock );
2530
2531     if( psz_title )
2532     {
2533         input_Control( p_input, INPUT_SET_NAME, psz_title );
2534         free( psz_title );
2535     }
2536
2537     /** \todo handle sout meta */
2538 }
2539
2540 /*****************************************************************************
2541  * MRLSplit: parse the access, demux and url part of the
2542  *           Media Resource Locator.
2543  *****************************************************************************/
2544 void MRLSplit( vlc_object_t *p_input, char *psz_dup,
2545                const char **ppsz_access, const char **ppsz_demux,
2546                char **ppsz_path )
2547 {
2548     const char *psz_access = "";
2549     const char *psz_demux  = "";
2550     char *psz_path;
2551     char *psz, *psz_check;
2552
2553     psz = strchr( psz_dup, ':' );
2554
2555     /* '@' not allowed in access/demux part */
2556     psz_check = strchr( psz_dup, '@' );
2557     if( psz_check && psz_check < psz ) psz = 0;
2558
2559 #if defined( WIN32 ) || defined( UNDER_CE )
2560     if( psz - psz_dup == 1 )
2561     {
2562         msg_Dbg( p_input, "drive letter %c: found in source", *psz_dup );
2563         psz_path = psz_dup;
2564     }
2565     else
2566 #endif
2567
2568     if( psz )
2569     {
2570         *psz++ = '\0';
2571         if( psz[0] == '/' && psz[1] == '/' ) psz += 2;
2572
2573         psz_path = psz;
2574
2575         psz = strchr( psz_dup, '/' );
2576         if( psz )
2577         {
2578             *psz++ = '\0';
2579             psz_demux = psz;
2580         }
2581
2582         psz_access = psz_dup;
2583     }
2584     else
2585     {
2586         psz_path = psz_dup;
2587     }
2588
2589     *ppsz_access = psz_access;
2590     *ppsz_demux = psz_demux;
2591     *ppsz_path = psz_path;
2592 }
2593
2594 /*****************************************************************************
2595  * MRLSections: parse title and seekpoint info from the Media Resource Locator.
2596  *
2597  * Syntax:
2598  * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
2599  *****************************************************************************/
2600 static void MRLSections( input_thread_t *p_input, char *psz_source,
2601                          int *pi_title_start, int *pi_title_end,
2602                          int *pi_chapter_start, int *pi_chapter_end )
2603 {
2604     char *psz, *psz_end, *psz_next, *psz_check;
2605
2606     *pi_title_start = *pi_title_end = -1;
2607     *pi_chapter_start = *pi_chapter_end = -1;
2608
2609     /* Start by parsing titles and chapters */
2610     if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
2611
2612     /* Check we are really dealing with a title/chapter section */
2613     psz_check = psz + 1;
2614     if( !*psz_check ) return;
2615     if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2616     if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
2617     if( *psz_check == ':' && ++psz_check )
2618         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2619     if( *psz_check != '-' && *psz_check ) return;
2620     if( *psz_check == '-' && ++psz_check )
2621         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2622     if( *psz_check != ':' && *psz_check ) return;
2623     if( *psz_check == ':' && ++psz_check )
2624         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2625     if( *psz_check ) return;
2626
2627     /* Separate start and end */
2628     *psz++ = 0;
2629     if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
2630
2631     /* Look for the start title */
2632     *pi_title_start = strtol( psz, &psz_next, 0 );
2633     if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
2634     *pi_title_end = *pi_title_start;
2635     psz = psz_next;
2636
2637     /* Look for the start chapter */
2638     if( *psz ) psz++;
2639     *pi_chapter_start = strtol( psz, &psz_next, 0 );
2640     if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
2641     *pi_chapter_end = *pi_chapter_start;
2642
2643     if( psz_end )
2644     {
2645         /* Look for the end title */
2646         *pi_title_end = strtol( psz_end, &psz_next, 0 );
2647         if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
2648         psz_end = psz_next;
2649
2650         /* Look for the end chapter */
2651         if( *psz_end ) psz_end++;
2652         *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
2653         if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
2654     }
2655
2656     msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
2657              psz_source, *pi_title_start, *pi_chapter_start,
2658              *pi_title_end, *pi_chapter_end );
2659 }
2660
2661 /*****************************************************************************
2662  * input_AddSubtitles: add a subtitles file and enable it
2663  *****************************************************************************/
2664 vlc_bool_t input_AddSubtitles( input_thread_t *p_input, char *psz_subtitle,
2665                                vlc_bool_t b_check_extension )
2666 {
2667     input_source_t *sub;
2668     vlc_value_t count;
2669     vlc_value_t list;
2670     char *psz_path, *psz_extension;
2671
2672     if( b_check_extension && !subtitles_Filter( psz_subtitle ) )
2673     {
2674         return VLC_FALSE;
2675     }
2676
2677     /* if we are provided a subtitle.sub file,
2678      * see if we don't have a subtitle.idx and use it instead */
2679     psz_path = strdup( psz_subtitle );
2680     if( psz_path )
2681     {
2682         psz_extension = strrchr( psz_path, '.');
2683         if( psz_extension && strcmp( psz_extension, ".sub" ) == 0 )
2684         {
2685             FILE *f;
2686
2687             strcpy( psz_extension, ".idx" );
2688             /* FIXME: a portable wrapper for stat() or access() would be more suited */
2689             if( ( f = utf8_fopen( psz_path, "rt" ) ) )
2690             {
2691                 fclose( f );
2692                 msg_Dbg( p_input, "using %s subtitles file instead of %s",
2693                          psz_path, psz_subtitle );
2694                 strcpy( psz_subtitle, psz_path );
2695             }
2696         }
2697         free( psz_path );
2698     }
2699
2700     var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
2701
2702     sub = InputSourceNew( p_input );
2703     if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
2704     {
2705         TAB_APPEND( p_input->p->i_slave, p_input->p->slave, sub );
2706
2707         /* Select the ES */
2708         if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) )
2709         {
2710             if( count.i_int == 0 )
2711                 count.i_int++;
2712             /* if it was first one, there is disable too */
2713
2714             if( count.i_int < list.p_list->i_count )
2715             {
2716                 input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
2717                                    &list.p_list->p_values[count.i_int] );
2718             }
2719             var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list, NULL );
2720         }
2721     }
2722     else free( sub );
2723
2724     return VLC_TRUE;
2725 }