]> git.sesse.net Git - vlc/blob - src/input/input.c
* src/input/*: update position on title change.
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  *****************************************************************************
4  * Copyright (C) 1998-2004 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/decoder.h>
33 #include <vlc/vout.h>
34
35 #include "input_internal.h"
36
37 #include "stream_output.h"
38
39 #include "vlc_interface.h"
40 #include "vlc_meta.h"
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static  int Run  ( input_thread_t *p_input );
46
47 static  int Init ( input_thread_t *p_input );
48 static void Error( input_thread_t *p_input );
49 static void End  ( input_thread_t *p_input );
50
51 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
52 static void       ControlReduce( input_thread_t * );
53 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
54
55
56 static void UpdateFromAccess( input_thread_t * );
57 static void UpdateFromDemux( input_thread_t * );
58
59 static void UpdateItemLength( input_thread_t *, int64_t i_length );
60
61 static void ParseOption( input_thread_t *p_input, const char *psz_option );
62
63 static void DecodeUrl  ( char * );
64 static void MRLSplit( input_thread_t *, char *, char **, char **, char ** );
65
66 static input_source_t *InputSourceNew( input_thread_t *);
67 static int  InputSourceInit( input_thread_t *, input_source_t *,
68                              char *, char *psz_forced_demux );
69 static void InputSourceClean( input_thread_t *, input_source_t * );
70
71 static void SlaveDemux( input_thread_t *p_input );
72 static void SlaveSeek( input_thread_t *p_input );
73
74 static vlc_meta_t *InputMetaUser( input_thread_t *p_input );
75
76 /*****************************************************************************
77  * input_CreateThread: creates a new input thread
78  *****************************************************************************
79  * This function creates a new input, and returns a pointer
80  * to its description. On error, it returns NULL.
81  *
82  * Variables for _public_ use:
83  * * Get and Set:
84  *  - state
85  *  - rate,rate-slower, rate-faster
86  *  - position, position-offset
87  *  - time, time-offset
88  *  - title,title-next,title-prev
89  *  - chapter,chapter-next, chapter-prev
90  *  - program, audio-es, video-es, spu-es
91  *  - audio-delay, spu-delay
92  *  - bookmark
93  * * Get only:
94  *  - length
95  *  - bookmarks
96  *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
97  * * For intf callback upon changes
98  *  - intf-change
99  * TODO explain when Callback is called
100  * TODO complete this list (?)
101  *****************************************************************************/
102 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
103                                       input_item_t *p_item )
104
105 {
106     input_thread_t *p_input;                        /* thread descriptor */
107     vlc_value_t val;
108     int i;
109
110     /* Allocate descriptor */
111     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
112     if( p_input == NULL )
113     {
114         msg_Err( p_parent, "out of memory" );
115         return NULL;
116     }
117
118     /* Init Common fields */
119     p_input->b_eof = VLC_FALSE;
120     p_input->b_can_pace_control = VLC_TRUE;
121     p_input->i_start = 0;
122     p_input->i_time  = 0;
123     p_input->i_stop  = 0;
124     p_input->i_title = 0;
125     p_input->title   = NULL;
126     p_input->i_state = INIT_S;
127     p_input->i_rate  = INPUT_RATE_DEFAULT;
128     p_input->i_bookmark = 0;
129     p_input->bookmark = NULL;
130     p_input->p_es_out = NULL;
131     p_input->p_sout  = NULL;
132     p_input->b_out_pace_control = VLC_FALSE;
133     p_input->i_pts_delay = 0;
134
135
136     /* Init Input fields */
137     p_input->input.p_item = p_item;
138     p_input->input.p_access = NULL;
139     p_input->input.p_stream = NULL;
140     p_input->input.p_demux  = NULL;
141     p_input->input.b_title_demux = VLC_FALSE;
142     p_input->input.i_title  = 0;
143     p_input->input.title    = NULL;
144     p_input->input.b_can_pace_control = VLC_TRUE;
145     p_input->input.b_eof = VLC_FALSE;
146     p_input->input.i_cr_average = 0;
147
148     /* No slave */
149     p_input->i_slave = 0;
150     p_input->slave   = NULL;
151
152     /* Init control buffer */
153     vlc_mutex_init( p_input, &p_input->lock_control );
154     p_input->i_control = 0;
155
156     /* Parse input options */
157     vlc_mutex_lock( &p_item->lock );
158     for( i = 0; i < p_item->i_options; i++ )
159     {
160         msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
161         ParseOption( p_input, p_item->ppsz_options[i] );
162     }
163     vlc_mutex_unlock( &p_item->lock );
164
165     /* Create Object Variables for private use only */
166     input_ConfigVarInit( p_input );
167
168     /* Create Objects variables for public Get and Set */
169     input_ControlVarInit( p_input );
170     p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
171
172     /* TODO */
173     var_Get( p_input, "bookmarks", &val );
174     if( val.psz_string )
175     {
176         /* FIXME: have a common cfg parsing routine used by sout and others */
177         char *psz_parser, *psz_start, *psz_end;
178         psz_parser = val.psz_string;
179         while( (psz_start = strchr( psz_parser, '{' ) ) )
180         {
181             seekpoint_t seekpoint;
182             char backup;
183             psz_start++;
184             psz_end = strchr( psz_start, '}' );
185             if( !psz_end ) break;
186             psz_parser = psz_end + 1;
187             backup = *psz_parser;
188             *psz_parser = 0;
189             *psz_end = ',';
190
191             seekpoint.psz_name = 0;
192             seekpoint.i_byte_offset = 0;
193             seekpoint.i_time_offset = 0;
194             while( (psz_end = strchr( psz_start, ',' ) ) )
195             {
196                 *psz_end = 0;
197                 if( !strncmp( psz_start, "name=", 5 ) )
198                 {
199                     seekpoint.psz_name = psz_start + 5;
200                 }
201                 else if( !strncmp( psz_start, "bytes=", 6 ) )
202                 {
203                     seekpoint.i_byte_offset = atoll(psz_start + 6);
204                 }
205                 else if( !strncmp( psz_start, "time=", 5 ) )
206                 {
207                     seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
208                 }
209                 psz_start = psz_end + 1;
210             }
211             msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
212                      seekpoint.psz_name, seekpoint.i_byte_offset,
213                      seekpoint.i_time_offset );
214             input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
215             *psz_parser = backup;
216         }
217         free( val.psz_string );
218     }
219
220     /* Now we can attach our new input */
221     vlc_object_attach( p_input, p_parent );
222
223     /* Create thread and wait for its readiness. */
224     if( vlc_thread_create( p_input, "input", Run,
225                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
226     {
227         msg_Err( p_input, "cannot create input thread" );
228         vlc_object_detach( p_input );
229         vlc_object_destroy( p_input );
230         return NULL;
231     }
232
233     return p_input;
234 }
235
236 /*****************************************************************************
237  * input_StopThread: mark an input thread as zombie
238  *****************************************************************************
239  * This function should not return until the thread is effectively cancelled.
240  *****************************************************************************/
241 void input_StopThread( input_thread_t *p_input )
242 {
243     vlc_list_t *p_list;
244     int i;
245
246     /* Set die for input */
247     p_input->b_die = VLC_TRUE;
248
249     /* We cannot touch p_input fields directly (we can from another thread),
250      * so use the vlc_object_find way, it's perfectly safe */
251
252     /* Set die for all access */
253     p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
254     for( i = 0; i < p_list->i_count; i++ )
255     {
256         p_list->p_values[i].p_object->b_die = VLC_TRUE;
257     }
258     vlc_list_release( p_list );
259
260     /* Set die for all stream */
261     p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
262     for( i = 0; i < p_list->i_count; i++ )
263     {
264         p_list->p_values[i].p_object->b_die = VLC_TRUE;
265     }
266     vlc_list_release( p_list );
267
268     /* Set die for all demux */
269     p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
270     for( i = 0; i < p_list->i_count; i++ )
271     {
272         p_list->p_values[i].p_object->b_die = VLC_TRUE;
273     }
274     vlc_list_release( p_list );
275
276     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
277 }
278
279 /*****************************************************************************
280  * input_DestroyThread: mark an input thread as zombie
281  *****************************************************************************
282  * This function should not return until the thread is effectively cancelled.
283  *****************************************************************************/
284 void input_DestroyThread( input_thread_t *p_input )
285 {
286     /* Join the thread */
287     vlc_thread_join( p_input );
288
289     /* Delete input lock (only after thread joined) */
290     vlc_mutex_destroy( &p_input->lock_control );
291
292     /* TODO: maybe input_DestroyThread should also delete p_input instead
293      * of the playlist but I'm not sure if it's possible */
294 }
295
296 /*****************************************************************************
297  * Run: main thread loop
298  *****************************************************************************
299  * Thread in charge of processing the network packets and demultiplexing.
300  *
301  * TODO:
302  *  read subtitle support (XXX take care of spu-delay in the right way).
303  *  multi-input support (XXX may be done with subs)
304  *****************************************************************************/
305 static int Run( input_thread_t *p_input )
306 {
307     int64_t i_intf_update = 0;
308
309     /* Signal that the thread is launched */
310     vlc_thread_ready( p_input );
311
312     if( Init( p_input ) )
313     {
314         /* If we failed, wait before we are killed, and exit */
315         p_input->b_error = VLC_TRUE;
316
317         Error( p_input );
318
319         /* Tell we're dead */
320         p_input->b_dead = VLC_TRUE;
321
322         return 0;
323     }
324
325     /* Main loop */
326     while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
327     {
328         vlc_bool_t b_force_update = VLC_FALSE;
329         int i_ret;
330         int i_type;
331         vlc_value_t val;
332
333         /* Do the read */
334         if( p_input->i_state != PAUSE_S  )
335         {
336             if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
337                 i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
338             else
339                 i_ret = 0;  /* EOF */
340
341             if( i_ret > 0 )
342             {
343                 /* TODO */
344                 if( p_input->input.b_title_demux &&
345                     p_input->input.p_demux->info.i_update )
346                 {
347                     UpdateFromDemux( p_input );
348                     b_force_update = VLC_TRUE;
349                 }
350                 else if( !p_input->input.b_title_demux &&
351                           p_input->input.p_access &&
352                           p_input->input.p_access->info.i_update )
353                 {
354                     UpdateFromAccess( p_input );
355                     b_force_update = VLC_TRUE;
356                 }
357             }
358             else if( i_ret == 0 )    /* EOF */
359             {
360                 vlc_value_t repeat;
361
362                 var_Get( p_input, "input-repeat", &repeat );
363                 if( repeat.i_int == 0 )
364                 {
365                     /* End of file - we do not set b_die because only the
366                      * playlist is allowed to do so. */
367                     msg_Dbg( p_input, "EOF reached" );
368                     p_input->input.b_eof = VLC_TRUE;
369                 }
370                 else
371                 {
372                     msg_Dbg( p_input, "repeating the same input (%d)",
373                              repeat.i_int );
374                     if( repeat.i_int > 0 )
375                     {
376                         repeat.i_int--;
377                         var_Set( p_input, "input-repeat", repeat );
378                     }
379
380                     /* Seek to title 0 position 0(start) */
381                     val.i_int = 0;
382                     input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
383                     if( p_input->i_start > 0 )
384                     {
385                         val.i_time = p_input->i_start;
386                         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
387                                            &val );
388                     }
389                     else
390                     {
391                         val.f_float = 0.0;
392                         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
393                                            &val );
394                     }
395                 }
396             }
397             else if( i_ret < 0 )
398             {
399                 p_input->b_error = VLC_TRUE;
400             }
401
402             if( i_ret > 0 && p_input->i_slave > 0 )
403             {
404                 SlaveDemux( p_input );
405             }
406         }
407         else
408         {
409             /* Small wait */
410             msleep( 10*1000 );
411         }
412
413         /* Handle control */
414         vlc_mutex_lock( &p_input->lock_control );
415         ControlReduce( p_input );
416         while( !ControlPopNoLock( p_input, &i_type, &val ) )
417         {
418             msg_Dbg( p_input, "control type=%d", i_type );
419             if( Control( p_input, i_type, val ) )
420                 b_force_update = VLC_TRUE;
421         }
422         vlc_mutex_unlock( &p_input->lock_control );
423
424         if( b_force_update ||
425             i_intf_update < mdate() )
426         {
427             vlc_value_t val;
428             double f_pos;
429             int64_t i_time, i_length;
430             /* update input status variables */
431             if( !demux2_Control( p_input->input.p_demux,
432                                  DEMUX_GET_POSITION, &f_pos ) )
433             {
434                 val.f_float = (float)f_pos;
435                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
436             }
437             if( !demux2_Control( p_input->input.p_demux,
438                                  DEMUX_GET_TIME, &i_time ) )
439             {
440                 p_input->i_time = i_time;
441                 val.i_time = i_time;
442                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
443             }
444             if( !demux2_Control( p_input->input.p_demux,
445                                  DEMUX_GET_LENGTH, &i_length ) )
446             {
447                 vlc_value_t old_val;
448                 var_Get( p_input, "length", &old_val );
449                 val.i_time = i_length;
450                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
451
452                 if( old_val.i_time != val.i_time )
453                 {
454                     UpdateItemLength( p_input, i_length );
455                 }
456             }
457
458             var_SetBool( p_input, "intf-change", VLC_TRUE );
459             i_intf_update = mdate() + I64C(150000);
460         }
461     }
462
463     if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
464     {
465         /* We have finish to demux data but not to play them */
466         while( !p_input->b_die )
467         {
468             if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
469                 break;
470
471             msg_Dbg( p_input, "waiting decoder fifos to empty" );
472
473             msleep( INPUT_IDLE_SLEEP );
474         }
475
476         /* We have finished */
477         p_input->b_eof = VLC_TRUE;
478     }
479
480     /* Wait we are asked to die */
481     if( !p_input->b_die )
482     {
483         Error( p_input );
484     }
485
486     /* Clean up */
487     End( p_input );
488
489     return 0;
490 }
491
492 /*****************************************************************************
493  * Init: init the input Thread
494  *****************************************************************************/
495 static int Init( input_thread_t * p_input )
496 {
497     char *psz;
498     char *psz_subtitle;
499     vlc_value_t val;
500     double f_fps;
501     vlc_meta_t *p_meta, *p_meta_user;
502     int i;
503
504     /* Initialize optional stream output. (before access/demuxer) */
505     psz = var_GetString( p_input, "sout" );
506     if( *psz )
507     {
508         p_input->p_sout = sout_NewInstance( p_input, psz );
509         if( p_input->p_sout == NULL )
510         {
511             msg_Err( p_input, "cannot start stream output instance, aborting" );
512             free( psz );
513             return VLC_EGENERIC;
514         }
515     }
516     free( psz );
517
518     /* Create es out */
519     p_input->p_es_out = input_EsOutNew( p_input );
520     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
521     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
522
523     if( InputSourceInit( p_input, &p_input->input,
524                          p_input->input.p_item->psz_uri, NULL ) )
525     {
526         goto error;
527     }
528
529     /* Create global title (from master) */
530     p_input->i_title = p_input->input.i_title;
531     p_input->title   = p_input->input.title;
532     if( p_input->i_title > 0 )
533     {
534         /* Setup variables */
535         input_ControlVarNavigation( p_input );
536         input_ControlVarTitle( p_input, 0 );
537     }
538
539     /* Global flag */
540     p_input->b_can_pace_control = p_input->input.b_can_pace_control;
541     p_input->b_can_pause        = p_input->input.b_can_pause;
542
543     /* Fix pts delay */
544     if( p_input->i_pts_delay <= 0 )
545         p_input->i_pts_delay = DEFAULT_PTS_DELAY;
546
547     /* If the desynchronisation requested by the user is < 0, we need to
548      * cache more data. */
549     var_Get( p_input, "audio-desync", &val );
550     if( val.i_int < 0 )
551         p_input->i_pts_delay -= (val.i_int * 1000);
552
553     /* Load master infos */
554     /* Init length */
555     if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH,
556                          &val.i_time ) && val.i_time > 0 )
557     {
558         var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
559
560         UpdateItemLength( p_input, val.i_time );
561     }
562     /* Start time*/
563     /* Set start time */
564     p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
565                        I64C(1000000);
566     p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
567                        I64C(1000000);
568
569     if( p_input->i_start > 0 )
570     {
571         if( p_input->i_start >= val.i_time )
572         {
573             msg_Warn( p_input, "invalid start-time ignored" );
574         }
575         else
576         {
577             vlc_value_t s;
578
579             msg_Dbg( p_input, "start-time: %ds",
580                      (int)( p_input->i_start / I64C(1000000) ) );
581
582             s.i_time = p_input->i_start;
583             input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
584         }
585     }
586     if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
587     {
588         msg_Warn( p_input, "invalid stop-time ignored" );
589         p_input->i_stop = 0;
590     }
591
592
593     /* Load subtitles */
594     /* Get fps and set it if not already set */
595     if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
596         f_fps > 1.0 )
597     {
598         vlc_value_t fps;
599
600         if( var_Get( p_input, "sub-fps", &fps ) )
601         {
602             var_Create( p_input, "sub-fps", VLC_VAR_FLOAT| VLC_VAR_DOINHERIT );
603             var_SetFloat( p_input, "sub-fps", f_fps );
604         }
605     }
606
607     /* Look for and add subtitle files */
608     psz_subtitle = var_GetString( p_input, "sub-file" );
609     if( *psz_subtitle )
610     {
611         input_source_t *sub;
612         vlc_value_t count;
613         vlc_value_t list;
614
615         msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
616
617         var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
618
619         /* */
620         sub = InputSourceNew( p_input );
621         if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
622         {
623             TAB_APPEND( p_input->i_slave, p_input->slave, sub );
624
625             /* Select the ES */
626             if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) )
627             {
628                 if( count.i_int == 0 )
629                     count.i_int++;  /* if it was first one, there is disable too */
630
631                 if( count.i_int < list.p_list->i_count )
632                 {
633                     input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
634                                        &list.p_list->p_values[count.i_int] );
635                 }
636                 var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list, NULL );
637             }
638         }
639     }
640
641     var_Get( p_input, "sub-autodetect-file", &val );
642     if( val.b_bool )
643     {
644         char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
645         char **subs = subtitles_Detect( p_input, psz_autopath,
646                                         p_input->input.p_item->psz_uri );
647         input_source_t *sub;
648
649         for( i = 0; subs[i] != NULL; i++ )
650         {
651             if( strcmp( psz_subtitle, subs[i] ) )
652             {
653                 sub = InputSourceNew( p_input );
654                 if( !InputSourceInit( p_input, sub, subs[i], "subtitle" ) )
655                 {
656                     TAB_APPEND( p_input->i_slave, p_input->slave, sub );
657                 }
658             }
659             free( subs[i] );
660         }
661         free( subs );
662         free( psz_autopath );
663     }
664     free( psz_subtitle );
665
666     /* Look for slave */
667     psz = var_GetString( p_input, "input-slave" );
668     if( *psz )
669     {
670         char *psz_delim = strchr( psz, '#' );
671
672         for( ;; )
673         {
674             input_source_t *slave;
675
676             if( psz_delim )
677             {
678                 *psz_delim++ = '\0';
679             }
680
681             if( *psz == '\0' )
682             {
683                 if( psz_delim )
684                     continue;
685                 else
686                     break;
687             }
688
689             msg_Dbg( p_input, "adding slave '%s'", psz );
690             slave = InputSourceNew( p_input );
691             if( !InputSourceInit( p_input, slave, psz, NULL ) )
692             {
693                 TAB_APPEND( p_input->i_slave, p_input->slave, slave );
694             }
695             if( !psz_delim )
696                 break;
697         }
698     }
699     free( psz );
700
701     /* Set up es_out */
702     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
703     val.b_bool =  VLC_FALSE;
704     if( p_input->p_sout )
705     {
706         var_Get( p_input, "sout-all", &val );
707     }
708     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
709                     val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
710
711     if( p_input->p_sout )
712     {
713         if( p_input->p_sout->i_out_pace_nocontrol > 0 )
714         {
715             p_input->b_out_pace_control = VLC_FALSE;
716         }
717         else
718         {
719             p_input->b_out_pace_control = VLC_TRUE;
720         }
721         msg_Dbg( p_input, "starting in %s mode",
722                  p_input->b_out_pace_control ? "asynch" : "synch" );
723     }
724
725     /* Get meta data from users */
726     p_meta_user = InputMetaUser( p_input );
727
728     /* Get meta data from master input */
729     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
730         p_meta = NULL;
731
732     /* Merge them */
733     if( p_meta == NULL )
734     {
735         p_meta = p_meta_user;
736     }
737     else if( p_meta_user )
738     {
739         vlc_meta_Merge( p_meta, p_meta_user );
740         vlc_meta_Delete( p_meta_user );
741     }
742
743     /* Get meta data from slave input */
744     for( i = 0; i < p_input->i_slave; i++ )
745     {
746         vlc_meta_t *p_meta_slave;
747
748         if( !demux2_Control( p_input->slave[i]->p_demux, DEMUX_GET_META, &p_meta_slave ) )
749         {
750             if( p_meta == NULL )
751             {
752                 p_meta = p_meta_slave;
753             }
754             else if( p_meta_slave )
755             {
756                 vlc_meta_Merge( p_meta, p_meta_slave );
757                 vlc_meta_Delete( p_meta_slave );
758             }
759         }
760     }
761
762     if( p_meta && p_meta->i_meta > 0 )
763     {
764         msg_Dbg( p_input, "meta information:" );
765         for( i = 0; i < p_meta->i_meta; i++ )
766         {
767             msg_Dbg( p_input, "  - '%s' = '%s'",
768                     _(p_meta->name[i]), p_meta->value[i] );
769
770             if( !strcmp(p_meta->name[i], VLC_META_TITLE) && p_meta->value[i] )
771                 input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
772
773             if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
774                 input_Control( p_input, INPUT_ADD_INFO, _("General"),
775                                _("Author"), p_meta->value[i] );
776
777             input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
778                           _(p_meta->name[i]), "%s", p_meta->value[i] );
779         }
780
781         for( i = 0; i < p_meta->i_track; i++ )
782         {
783             vlc_meta_t *tk = p_meta->track[i];
784             int j;
785
786             if( tk->i_meta > 0 )
787             {
788                 char *psz_cat = malloc( strlen(_("Stream")) + 10 );
789
790                 msg_Dbg( p_input, "  - track[%d]:", i );
791
792                 sprintf( psz_cat, "%s %d", _("Stream"), i );
793                 for( j = 0; j < tk->i_meta; j++ )
794                 {
795                     msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
796                              tk->value[j] );
797
798                     input_Control( p_input, INPUT_ADD_INFO, psz_cat,
799                                    _(tk->name[j]), "%s", tk->value[j] );
800                 }
801             }
802         }
803
804         if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
805         {
806             p_input->p_sout->p_meta = p_meta;
807         }
808         else
809         {
810             vlc_meta_Delete( p_meta );
811         }
812     }
813
814     msg_Dbg( p_input, "`%s' sucessfully opened",
815              p_input->input.p_item->psz_uri );
816
817     /* initialization is complete */
818     p_input->i_state = PLAYING_S;
819
820     val.i_int = PLAYING_S;
821     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
822
823     return VLC_SUCCESS;
824
825 error:
826     if( p_input->p_es_out )
827         input_EsOutDelete( p_input->p_es_out );
828
829     if( p_input->p_sout )
830         sout_DeleteInstance( p_input->p_sout );
831
832     /* Mark them deleted */
833     p_input->input.p_demux = NULL;
834     p_input->input.p_stream = NULL;
835     p_input->input.p_access = NULL;
836     p_input->p_es_out = NULL;
837     p_input->p_sout = NULL;
838
839     return VLC_EGENERIC;
840 }
841
842 /*****************************************************************************
843  * Error: RunThread() error loop
844  *****************************************************************************
845  * This function is called when an error occured during thread main's loop.
846  *****************************************************************************/
847 static void Error( input_thread_t *p_input )
848 {
849     while( !p_input->b_die )
850     {
851         /* Sleep a while */
852         msleep( INPUT_IDLE_SLEEP );
853     }
854 }
855
856 /*****************************************************************************
857  * End: end the input thread
858  *****************************************************************************/
859 static void End( input_thread_t * p_input )
860 {
861     vlc_value_t val;
862     int i;
863
864     msg_Dbg( p_input, "closing `%s'",
865              p_input->input.p_item->psz_uri );
866
867     /* We are at the end */
868     p_input->i_state = END_S;
869
870     val.i_int = END_S;
871     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
872
873     /* Clean control variables */
874     input_ControlVarClean( p_input );
875
876     /* Clean up master */
877     InputSourceClean( p_input, &p_input->input );
878
879     /* Delete slave */
880     for( i = 0; i < p_input->i_slave; i++ )
881     {
882         InputSourceClean( p_input, p_input->slave[i] );
883         free( p_input->slave[i] );
884     }
885     if( p_input->slave ) free( p_input->slave );
886
887     /* Unload all modules */
888     if( p_input->p_es_out )
889         input_EsOutDelete( p_input->p_es_out );
890
891     /* Close optional stream output instance */
892     if( p_input->p_sout )
893     {
894         vlc_object_t *p_pl =
895             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
896         vlc_value_t keep;
897
898         if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
899         {
900             /* attach sout to the playlist */
901             msg_Warn( p_input, "keeping sout" );
902             vlc_object_detach( p_input->p_sout );
903             vlc_object_attach( p_input->p_sout, p_pl );
904         }
905         else
906         {
907             msg_Warn( p_input, "destroying sout" );
908             sout_DeleteInstance( p_input->p_sout );
909         }
910         if( p_pl )
911             vlc_object_release( p_pl );
912     }
913
914     /* Tell we're dead */
915     p_input->b_dead = VLC_TRUE;
916 }
917
918 /*****************************************************************************
919  * Control
920  *****************************************************************************/
921 static inline int ControlPopNoLock( input_thread_t *p_input,
922                                     int *pi_type, vlc_value_t *p_val )
923 {
924     if( p_input->i_control <= 0 )
925     {
926         return VLC_EGENERIC;
927     }
928
929     *pi_type = p_input->control[0].i_type;
930     *p_val   = p_input->control[0].val;
931
932     p_input->i_control--;
933     if( p_input->i_control > 0 )
934     {
935         int i;
936
937         for( i = 0; i < p_input->i_control; i++ )
938         {
939             p_input->control[i].i_type = p_input->control[i+1].i_type;
940             p_input->control[i].val    = p_input->control[i+1].val;
941         }
942     }
943
944     return VLC_SUCCESS;
945 }
946
947 static void ControlReduce( input_thread_t *p_input )
948 {
949     int i;
950     for( i = 1; i < p_input->i_control; i++ )
951     {
952         const int i_lt = p_input->control[i-1].i_type;
953         const int i_ct = p_input->control[i].i_type;
954
955         /* XXX We can't merge INPUT_CONTROL_SET_ES */
956         msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
957                  i_lt, i_ct );
958         if( i_lt == i_ct &&
959             ( i_ct == INPUT_CONTROL_SET_STATE ||
960               i_ct == INPUT_CONTROL_SET_RATE ||
961               i_ct == INPUT_CONTROL_SET_POSITION ||
962               i_ct == INPUT_CONTROL_SET_TIME ||
963               i_ct == INPUT_CONTROL_SET_PROGRAM ||
964               i_ct == INPUT_CONTROL_SET_TITLE ||
965               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
966               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
967         {
968             int j;
969             msg_Dbg( p_input, "merged at %d", i );
970             /* Remove the i-1 */
971             for( j = i; j <  p_input->i_control; j++ )
972                 p_input->control[j-1] = p_input->control[j];
973             p_input->i_control--;
974         }
975         else
976         {
977             /* TODO but that's not that important
978                 - merge SET_X with SET_X_CMD
979                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
980                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
981                 - ?
982                 */
983         }
984     }
985 }
986
987 static vlc_bool_t Control( input_thread_t *p_input, int i_type,
988                            vlc_value_t val )
989 {
990     vlc_bool_t b_force_update = VLC_FALSE;
991
992     switch( i_type )
993     {
994         case INPUT_CONTROL_SET_DIE:
995             msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
996             /* Mark all submodules to die */
997             if( p_input->input.p_access )
998                 p_input->input.p_access->b_die = VLC_TRUE;
999             if( p_input->input.p_stream )
1000                 p_input->input.p_stream->b_die = VLC_TRUE;
1001             p_input->input.p_demux->b_die = VLC_TRUE;
1002
1003             p_input->b_die = VLC_TRUE;
1004             break;
1005
1006         case INPUT_CONTROL_SET_POSITION:
1007         case INPUT_CONTROL_SET_POSITION_OFFSET:
1008         {
1009             double f_pos;
1010             if( i_type == INPUT_CONTROL_SET_POSITION )
1011             {
1012                 f_pos = val.f_float;
1013             }
1014             else
1015             {
1016                 /* Should not fail */
1017                 demux2_Control( p_input->input.p_demux,
1018                                 DEMUX_GET_POSITION, &f_pos );
1019                 f_pos += val.f_float;
1020             }
1021             if( f_pos < 0.0 ) f_pos = 0.0;
1022             if( f_pos > 1.0 ) f_pos = 1.0;
1023             if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
1024                                 f_pos ) )
1025             {
1026                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1027                          "%2.1f%% failed", f_pos * 100 );
1028             }
1029             else
1030             {
1031                 if( p_input->i_slave > 0 )
1032                     SlaveSeek( p_input );
1033
1034                 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1035                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1036                 b_force_update = VLC_TRUE;
1037             }
1038             break;
1039         }
1040
1041         case INPUT_CONTROL_SET_TIME:
1042         case INPUT_CONTROL_SET_TIME_OFFSET:
1043         {
1044             int64_t i_time;
1045             int i_ret;
1046
1047             if( i_type == INPUT_CONTROL_SET_TIME )
1048             {
1049                 i_time = val.i_time;
1050             }
1051             else
1052             {
1053                 /* Should not fail */
1054                 demux2_Control( p_input->input.p_demux,
1055                                 DEMUX_GET_TIME, &i_time );
1056                 i_time += val.i_time;
1057             }
1058             if( i_time < 0 ) i_time = 0;
1059             i_ret = demux2_Control( p_input->input.p_demux,
1060                                     DEMUX_SET_TIME, i_time );
1061             if( i_ret )
1062             {
1063                 int64_t i_length;
1064                 /* Emulate it with a SET_POS */
1065
1066                 demux2_Control( p_input->input.p_demux,
1067                                 DEMUX_GET_LENGTH, &i_length );
1068                 if( i_length > 0 )
1069                 {
1070                     double f_pos = (double)i_time / (double)i_length;
1071                     i_ret = demux2_Control( p_input->input.p_demux,
1072                                             DEMUX_SET_POSITION, f_pos );
1073                 }
1074             }
1075             if( i_ret )
1076             {
1077                 msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
1078                          " failed", i_time );
1079             }
1080             else
1081             {
1082                 if( p_input->i_slave > 0 )
1083                     SlaveSeek( p_input );
1084
1085                 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1086
1087                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1088                 b_force_update = VLC_TRUE;
1089             }
1090             break;
1091         }
1092
1093         case INPUT_CONTROL_SET_STATE:
1094             if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
1095                 ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
1096             {
1097                 int i_ret;
1098                 if( p_input->input.p_access )
1099                     i_ret = access2_Control( p_input->input.p_access,
1100                                              ACCESS_SET_PAUSE_STATE, VLC_FALSE );
1101                 else
1102                     i_ret = demux2_Control( p_input->input.p_demux,
1103                                             DEMUX_SET_PAUSE_STATE, VLC_FALSE );
1104
1105                 if( i_ret )
1106                 {
1107                     /* FIXME What to do ? */
1108                     msg_Warn( p_input, "cannot unset pause -> EOF" );
1109                     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
1110                 }
1111
1112                 b_force_update = VLC_TRUE;
1113
1114                 /* Switch to play */
1115                 p_input->i_state = PLAYING_S;
1116                 val.i_int = PLAYING_S;
1117                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1118
1119                 /* Reset clock */
1120                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1121             }
1122             else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
1123                      p_input->b_can_pause )
1124             {
1125                 int i_ret;
1126                 if( p_input->input.p_access )
1127                     i_ret = access2_Control( p_input->input.p_access,
1128                                              ACCESS_SET_PAUSE_STATE, VLC_TRUE );
1129                 else
1130                     i_ret = demux2_Control( p_input->input.p_demux,
1131                                             DEMUX_SET_PAUSE_STATE, VLC_TRUE );
1132
1133                 b_force_update = VLC_TRUE;
1134
1135                 if( i_ret )
1136                 {
1137                     msg_Warn( p_input, "cannot set pause state" );
1138                     val.i_int = p_input->i_state;
1139                 }
1140                 else
1141                 {
1142                     val.i_int = PAUSE_S;
1143                 }
1144
1145                 /* Switch to new state */
1146                 p_input->i_state = val.i_int;
1147                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1148             }
1149             else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
1150             {
1151                 b_force_update = VLC_TRUE;
1152
1153                 /* Correct "state" value */
1154                 val.i_int = p_input->i_state;
1155                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1156             }
1157             else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
1158             {
1159                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
1160             }
1161             break;
1162
1163         case INPUT_CONTROL_SET_RATE:
1164         case INPUT_CONTROL_SET_RATE_SLOWER:
1165         case INPUT_CONTROL_SET_RATE_FASTER:
1166         {
1167             int i_rate;
1168
1169             if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
1170                 i_rate = p_input->i_rate * 2;
1171             else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
1172                 i_rate = p_input->i_rate / 2;
1173             else
1174                 i_rate = val.i_int;
1175
1176             if( i_rate < INPUT_RATE_MIN )
1177             {
1178                 msg_Dbg( p_input, "cannot set rate faster" );
1179                 i_rate = INPUT_RATE_MIN;
1180             }
1181             else if( i_rate > INPUT_RATE_MAX )
1182             {
1183                 msg_Dbg( p_input, "cannot set rate slower" );
1184                 i_rate = INPUT_RATE_MAX;
1185             }
1186             if( i_rate != INPUT_RATE_DEFAULT &&
1187                 ( !p_input->b_can_pace_control ||
1188                   ( p_input->p_sout && !p_input->b_out_pace_control ) ) )
1189             {
1190                 msg_Dbg( p_input, "cannot change rate" );
1191                 i_rate = INPUT_RATE_DEFAULT;
1192             }
1193             if( i_rate != p_input->i_rate )
1194             {
1195                 p_input->i_rate  = i_rate;
1196                 val.i_int = i_rate;
1197                 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
1198
1199                 /* We haven't send data to decoder when rate != default */
1200                 if( i_rate == INPUT_RATE_DEFAULT )
1201                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
1202
1203                 /* Reset clock */
1204                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1205
1206                 b_force_update = VLC_TRUE;
1207             }
1208             break;
1209         }
1210
1211         case INPUT_CONTROL_SET_PROGRAM:
1212             /* No need to force update, es_out does it if needed */
1213             es_out_Control( p_input->p_es_out,
1214                             ES_OUT_SET_GROUP, val.i_int );
1215             break;
1216
1217         case INPUT_CONTROL_SET_ES:
1218             /* No need to force update, es_out does it if needed */
1219             es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
1220                             input_EsOutGetFromID( p_input->p_es_out,
1221                                                   val.i_int ) );
1222             break;
1223
1224         case INPUT_CONTROL_SET_AUDIO_DELAY:
1225             input_EsOutSetDelay( p_input->p_es_out,
1226                                  AUDIO_ES, val.i_time );
1227             var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
1228             break;
1229
1230         case INPUT_CONTROL_SET_SPU_DELAY:
1231             input_EsOutSetDelay( p_input->p_es_out,
1232                                  SPU_ES, val.i_time );
1233             var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
1234             break;
1235
1236         case INPUT_CONTROL_SET_TITLE:
1237         case INPUT_CONTROL_SET_TITLE_NEXT:
1238         case INPUT_CONTROL_SET_TITLE_PREV:
1239             if( p_input->input.b_title_demux &&
1240                 p_input->input.i_title > 0 )
1241             {
1242                 /* TODO */
1243                 /* FIXME handle demux title */
1244                 demux_t *p_demux = p_input->input.p_demux;
1245                 int i_title;
1246
1247                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1248                     i_title = p_demux->info.i_title - 1;
1249                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1250                     i_title = p_demux->info.i_title + 1;
1251                 else
1252                     i_title = val.i_int;
1253
1254                 if( i_title >= 0 && i_title < p_input->input.i_title )
1255                 {
1256                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
1257
1258                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1259                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1260
1261                     input_ControlVarTitle( p_input, i_title );
1262                 }
1263             }
1264             else if( p_input->input.i_title > 0 )
1265             {
1266                 access_t *p_access = p_input->input.p_access;
1267                 int i_title;
1268
1269                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1270                     i_title = p_access->info.i_title - 1;
1271                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1272                     i_title = p_access->info.i_title + 1;
1273                 else
1274                     i_title = val.i_int;
1275
1276                 if( i_title >= 0 && i_title < p_input->input.i_title )
1277                 {
1278                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
1279                     stream_AccessReset( p_input->input.p_stream );
1280
1281                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1282                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1283                 }
1284             }
1285             break;
1286         case INPUT_CONTROL_SET_SEEKPOINT:
1287         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1288         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1289             if( p_input->input.b_title_demux &&
1290                 p_input->input.i_title > 0 )
1291             {
1292                 demux_t *p_demux = p_input->input.p_demux;
1293                 int i_seekpoint;
1294
1295                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1296                     i_seekpoint = p_demux->info.i_seekpoint - 1;
1297                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
1298                     i_seekpoint = p_demux->info.i_seekpoint + 1;
1299                 else
1300                     i_seekpoint = val.i_int;
1301
1302                 if( i_seekpoint >= 0 && i_seekpoint <
1303                     p_input->input.title[p_demux->info.i_title]->i_seekpoint )
1304                 {
1305                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
1306
1307                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1308                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1309                 }
1310             }
1311             else if( p_input->input.i_title > 0 )
1312             {
1313                 access_t *p_access = p_input->input.p_access;
1314                 int i_seekpoint;
1315
1316                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1317                     i_seekpoint = p_access->info.i_seekpoint - 1;
1318                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1319                     i_seekpoint = p_access->info.i_seekpoint + 1;
1320                 else
1321                     i_seekpoint = val.i_int;
1322
1323                 if( i_seekpoint >= 0 && i_seekpoint <
1324                     p_input->input.title[p_access->info.i_title]->i_seekpoint )
1325                 {
1326                     access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
1327                     stream_AccessReset( p_input->input.p_stream );
1328
1329                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1330                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1331                 }
1332             }
1333             break;
1334
1335         case INPUT_CONTROL_SET_BOOKMARK:
1336         default:
1337             msg_Err( p_input, "not yet implemented" );
1338             break;
1339     }
1340
1341     return b_force_update;
1342 }
1343
1344 /*****************************************************************************
1345  * UpdateFromDemux:
1346  *****************************************************************************/
1347 static void UpdateFromDemux( input_thread_t *p_input )
1348 {
1349     demux_t *p_demux = p_input->input.p_demux;
1350     vlc_value_t v;
1351
1352     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
1353     {
1354         v.i_int = p_demux->info.i_title;
1355         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1356
1357         input_ControlVarTitle( p_input, p_demux->info.i_title );
1358
1359         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
1360     }
1361     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
1362     {
1363         v.i_int = p_demux->info.i_seekpoint;
1364         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1365
1366         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1367     }
1368     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
1369 }
1370
1371 /*****************************************************************************
1372  * UpdateFromAccess:
1373  *****************************************************************************/
1374 static void UpdateFromAccess( input_thread_t *p_input )
1375 {
1376     access_t *p_access = p_input->input.p_access;
1377     vlc_value_t v;
1378
1379     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
1380     {
1381         v.i_int = p_access->info.i_title;
1382         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1383
1384         input_ControlVarTitle( p_input, p_access->info.i_title );
1385
1386         stream_AccessUpdate( p_input->input.p_stream );
1387
1388         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
1389     }
1390     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
1391     {
1392         v.i_int = p_access->info.i_seekpoint;
1393         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1394
1395         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1396     }
1397     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
1398 }
1399
1400 /*****************************************************************************
1401  * UpdateItemLength:
1402  *****************************************************************************/
1403 static void UpdateItemLength( input_thread_t *p_input, int64_t i_length )
1404 {
1405     char psz_buffer[MSTRTIME_MAX_SIZE];
1406
1407     vlc_mutex_lock( &p_input->input.p_item->lock );
1408     p_input->input.p_item->i_duration = i_length;
1409     vlc_mutex_unlock( &p_input->input.p_item->lock );
1410
1411     input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
1412                    msecstotimestr( psz_buffer, i_length / 1000 ) );
1413 }
1414
1415 /*****************************************************************************
1416  * InputSourceNew:
1417  *****************************************************************************/
1418 static input_source_t *InputSourceNew( input_thread_t *p_input )
1419 {
1420     input_source_t *in = malloc( sizeof( input_source_t ) );
1421
1422     in->p_item   = NULL;
1423     in->p_access = NULL;
1424     in->p_stream = NULL;
1425     in->p_demux  = NULL;
1426     in->b_title_demux = VLC_FALSE;
1427     in->i_title  = 0;
1428     in->title    = NULL;
1429     in->b_can_pace_control = VLC_TRUE;
1430     in->b_eof = VLC_FALSE;
1431     in->i_cr_average = 0;
1432
1433     return in;
1434 }
1435
1436 /*****************************************************************************
1437  * InputSourceInit:
1438  *****************************************************************************/
1439 static int InputSourceInit( input_thread_t *p_input,
1440                             input_source_t *in, char *psz_mrl,
1441                             char *psz_forced_demux )
1442 {
1443     char *psz_dup = strdup( psz_mrl );
1444     char *psz_access;
1445     char *psz_demux;
1446     char *psz_path;
1447     vlc_value_t val;
1448
1449     /* Split uri */
1450     MRLSplit( p_input, psz_dup, &psz_access, &psz_demux, &psz_path );
1451
1452     msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
1453              psz_mrl, psz_access, psz_demux, psz_path );
1454
1455     if( psz_forced_demux && *psz_forced_demux )
1456         psz_demux = psz_forced_demux;
1457
1458     /* Try access_demux if no demux given */
1459     if( *psz_demux == '\0' )
1460     {
1461         in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
1462                                   NULL, p_input->p_es_out );
1463     }
1464
1465     if( in->p_demux )
1466     {
1467         int64_t i_pts_delay;
1468
1469         /* Get infos from access_demux */
1470         demux2_Control( in->p_demux,
1471                         DEMUX_GET_PTS_DELAY, &i_pts_delay );
1472         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
1473
1474         in->b_title_demux = VLC_TRUE;
1475         if( demux2_Control( in->p_demux,
1476                             DEMUX_GET_TITLE_INFO,
1477                             &in->title, &in->i_title ) )
1478         {
1479             in->i_title = 0;
1480             in->title   = NULL;
1481         }
1482         demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
1483                         &in->b_can_pace_control );
1484         demux2_Control( in->p_demux, DEMUX_CAN_PAUSE,
1485                         &in->b_can_pause );
1486
1487         /* FIXME todo
1488         demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
1489                         &val.b_bool );
1490         */
1491     }
1492     else
1493     {
1494         int64_t i_pts_delay;
1495
1496         /* Now try a real access */
1497         in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
1498
1499         /* Access failed, URL encoded ? */
1500         if( in->p_access == NULL && strchr( psz_path, '%' ) )
1501         {
1502             DecodeUrl( psz_path );
1503
1504             msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
1505                      psz_access, psz_demux, psz_path );
1506
1507             in->p_access = access2_New( p_input,
1508                                         psz_access, psz_demux, psz_path );
1509         }
1510 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
1511                         * are forbidden in filenames on Win32. */
1512
1513         /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
1514         if( in->p_access == NULL &&
1515             *psz_access == '\0' && ( *psz_demux || *psz_path ) )
1516         {
1517             free( psz_dup );
1518             psz_dup = strdup( psz_mrl );
1519             psz_access = "";
1520             psz_demux = "";
1521             psz_path = psz_dup;
1522
1523             in->p_access = access2_New( p_input,
1524                                         psz_access, psz_demux, psz_path );
1525         }
1526 #endif
1527
1528         if( in->p_access == NULL )
1529         {
1530             msg_Err( p_input, "no suitable access module for `%s'", psz_mrl );
1531             goto error;
1532         }
1533
1534         /* Get infos from access */
1535         access2_Control( in->p_access,
1536                          ACCESS_GET_PTS_DELAY, &i_pts_delay );
1537         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
1538
1539         in->b_title_demux = VLC_FALSE;
1540         if( access2_Control( in->p_access,
1541                              ACCESS_GET_TITLE_INFO,
1542                              &in->title, &in->i_title ) )
1543         {
1544             in->i_title = 0;
1545             in->title   = NULL;
1546         }
1547         access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
1548                          &in->b_can_pace_control );
1549         access2_Control( in->p_access, ACCESS_CAN_PAUSE,
1550                          &in->b_can_pause );
1551         access2_Control( in->p_access, ACCESS_CAN_SEEK,
1552                          &val.b_bool );
1553         var_Set( p_input, "seekable", val );
1554
1555         /* Create the stream_t */
1556         in->p_stream = stream_AccessNew( in->p_access );
1557         if( in->p_stream == NULL )
1558         {
1559             msg_Warn( p_input, "cannot create a stream_t from access" );
1560             goto error;
1561         }
1562
1563         /* Open a demuxer */
1564         if( *psz_demux == '\0' && *in->p_access->psz_demux )
1565         {
1566             psz_demux = in->p_access->psz_demux;
1567         }
1568         in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
1569                                   in->p_stream, p_input->p_es_out );
1570         if( in->p_demux == NULL )
1571         {
1572             msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
1573                      psz_access, psz_demux, psz_path );
1574             goto error;
1575         }
1576
1577         /* TODO get title from demux */
1578         if( in->i_title <= 0 )
1579         {
1580             if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
1581                                 &in->title, &in->i_title ) )
1582             {
1583                 in->i_title = 0;
1584                 in->title   = NULL;
1585             }
1586             else
1587             {
1588                 in->b_title_demux = VLC_TRUE;
1589             }
1590         }
1591     }
1592     free( psz_dup );
1593     return VLC_SUCCESS;
1594
1595 error:
1596     if( in->p_demux )
1597         demux2_Delete( in->p_demux );
1598
1599     if( in->p_stream )
1600         stream_AccessDelete( in->p_stream );
1601
1602     if( in->p_access )
1603         access2_Delete( in->p_access );
1604     free( psz_dup );
1605
1606     return VLC_EGENERIC;
1607 }
1608
1609 /*****************************************************************************
1610  * InputSourceClean:
1611  *****************************************************************************/
1612 static void InputSourceClean( input_thread_t *p_input, input_source_t *in )
1613 {
1614     if( in->p_demux )
1615         demux2_Delete( in->p_demux );
1616
1617     if( in->p_stream )
1618         stream_AccessDelete( in->p_stream );
1619
1620     if( in->p_access )
1621         access2_Delete( in->p_access );
1622
1623     if( in->i_title > 0 )
1624     {
1625         int i;
1626         for( i = 0; i < in->i_title; i++ )
1627         {
1628             vlc_input_title_Delete( in->title[i] );
1629         }
1630         free( in->title );
1631     }
1632 }
1633
1634 static void SlaveDemux( input_thread_t *p_input )
1635 {
1636     int64_t i_time;
1637     int i;
1638     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
1639     {
1640         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
1641         return;
1642     }
1643
1644     for( i = 0; i < p_input->i_slave; i++ )
1645     {
1646         input_source_t *in = p_input->slave[i];
1647         int i_ret = 1;
1648
1649         if( in->b_eof )
1650             continue;
1651
1652         if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
1653         {
1654             for( ;; )
1655             {
1656                 int64_t i_stime;
1657                 if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
1658                 {
1659                     msg_Err( p_input, "slave[%d] doesn't like "
1660                              "DEMUX_GET_TIME -> EOF", i );
1661                     i_ret = 0;
1662                     break;
1663                 }
1664
1665                 if( i_stime >= i_time )
1666                     break;
1667
1668                 if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
1669                     break;
1670             }
1671         }
1672         else
1673         {
1674             i_ret = in->p_demux->pf_demux( in->p_demux );
1675         }
1676
1677         if( i_ret <= 0 )
1678         {
1679             msg_Dbg( p_input, "slave %d EOF", i );
1680             in->b_eof = VLC_TRUE;
1681         }
1682     }
1683 }
1684
1685 static void SlaveSeek( input_thread_t *p_input )
1686 {
1687     int64_t i_time;
1688     int i;
1689
1690     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
1691     {
1692         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
1693         return;
1694     }
1695
1696     for( i = 0; i < p_input->i_slave; i++ )
1697     {
1698         input_source_t *in = p_input->slave[i];
1699
1700         if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
1701         {
1702             msg_Err( p_input, "seek failed for slave %d -> EOF", i );
1703             in->b_eof = VLC_TRUE;
1704         }
1705     }
1706 }
1707 /*****************************************************************************
1708  * InputMetaUser:
1709  *****************************************************************************/
1710 static vlc_meta_t *InputMetaUser( input_thread_t *p_input )
1711 {
1712     vlc_meta_t *p_meta;
1713     vlc_value_t val;
1714
1715     if( ( p_meta = vlc_meta_New() ) == NULL )
1716         return NULL;
1717
1718     /* Get meta information from user */
1719 #define GET_META( c, s ) \
1720     var_Get( p_input, (s), &val );  \
1721     if( *val.psz_string )       \
1722         vlc_meta_Add( p_meta, c, val.psz_string ); \
1723     free( val.psz_string )
1724
1725     GET_META( VLC_META_TITLE, "meta-title" );
1726     GET_META( VLC_META_AUTHOR, "meta-author" );
1727     GET_META( VLC_META_ARTIST, "meta-artist" );
1728     GET_META( VLC_META_GENRE, "meta-genre" );
1729     GET_META( VLC_META_COPYRIGHT, "meta-copyright" );
1730     GET_META( VLC_META_DESCRIPTION, "meta-description" );
1731     GET_META( VLC_META_DATE, "meta-date" );
1732     GET_META( VLC_META_URL, "meta-url" );
1733 #undef GET_META
1734
1735     return p_meta;
1736 }
1737
1738 /*****************************************************************************
1739  * DecodeUrl: decode a given encoded url
1740  *****************************************************************************/
1741 static void DecodeUrl( char *psz )
1742 {
1743     char *dup = strdup( psz );
1744     char *p = dup;
1745
1746     while( *p )
1747     {
1748         if( *p == '%' )
1749         {
1750             char val[3];
1751             p++;
1752             if( !*p )
1753             {
1754                 break;
1755             }
1756
1757             val[0] = *p++;
1758             val[1] = *p++;
1759             val[2] = '\0';
1760
1761             *psz++ = strtol( val, NULL, 16 );
1762         }
1763         else if( *p == '+' )
1764         {
1765             *psz++ = ' ';
1766             p++;
1767         }
1768         else
1769         {
1770             *psz++ = *p++;
1771         }
1772     }
1773     *psz++  ='\0';
1774     free( dup );
1775 }
1776
1777 /*****************************************************************************
1778  * ParseOption: parses the options for the input
1779  *****************************************************************************
1780  * This function parses the input (config) options and creates their associated
1781  * object variables.
1782  * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
1783  * bar is the value of the option.
1784  *****************************************************************************/
1785 static void ParseOption( input_thread_t *p_input, const char *psz_option )
1786 {
1787     char *psz_name = (char *)psz_option;
1788     char *psz_value = strchr( psz_option, '=' );
1789     int  i_name_len, i_type;
1790     vlc_bool_t b_isno = VLC_FALSE;
1791     vlc_value_t val;
1792
1793     if( psz_value ) i_name_len = psz_value - psz_option;
1794     else i_name_len = strlen( psz_option );
1795
1796     /* It's too much of an hassle to remove the ':' when we parse
1797      * the cmd line :) */
1798     if( i_name_len && *psz_name == ':' )
1799     {
1800         psz_name++;
1801         i_name_len--;
1802     }
1803
1804     if( i_name_len == 0 ) return;
1805
1806     psz_name = strndup( psz_name, i_name_len );
1807     if( psz_value ) psz_value++;
1808
1809     i_type = config_GetType( p_input, psz_name );
1810
1811     if( !i_type && !psz_value )
1812     {
1813         /* check for "no-foo" or "nofoo" */
1814         if( !strncmp( psz_name, "no-", 3 ) )
1815         {
1816             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1817         }
1818         else if( !strncmp( psz_name, "no", 2 ) )
1819         {
1820             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1821         }
1822         else goto cleanup;           /* Option doesn't exist */
1823
1824         b_isno = VLC_TRUE;
1825         i_type = config_GetType( p_input, psz_name );
1826
1827         if( !i_type ) goto cleanup;  /* Option doesn't exist */
1828     }
1829     else if( !i_type ) goto cleanup; /* Option doesn't exist */
1830
1831     if( ( i_type != VLC_VAR_BOOL ) &&
1832         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1833
1834     /* Create the variable in the input object.
1835      * Children of the input object will be able to retreive this value
1836      * thanks to the inheritance property of the object variables. */
1837     var_Create( p_input, psz_name, i_type );
1838
1839     switch( i_type )
1840     {
1841     case VLC_VAR_BOOL:
1842         val.b_bool = !b_isno;
1843         break;
1844
1845     case VLC_VAR_INTEGER:
1846         val.i_int = atoi( psz_value );
1847         break;
1848
1849     case VLC_VAR_FLOAT:
1850         val.f_float = atof( psz_value );
1851         break;
1852
1853     case VLC_VAR_STRING:
1854     case VLC_VAR_MODULE:
1855     case VLC_VAR_FILE:
1856     case VLC_VAR_DIRECTORY:
1857         val.psz_string = psz_value;
1858         break;
1859
1860     default:
1861         goto cleanup;
1862         break;
1863     }
1864
1865     var_Set( p_input, psz_name, val );
1866
1867     msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );
1868
1869   cleanup:
1870     if( psz_name ) free( psz_name );
1871     return;
1872 }
1873
1874 static void MRLSplit( input_thread_t *p_input, char *psz_dup,
1875                       char **ppsz_access, char **ppsz_demux, char **ppsz_path )
1876 {
1877     char *psz_access = NULL;
1878     char *psz_demux  = NULL;
1879     char *psz_path   = NULL;
1880     char *psz;
1881
1882     psz = strchr( psz_dup, ':' );
1883
1884 #if defined( WIN32 ) || defined( UNDER_CE )
1885     if( psz - psz_dup == 1 )
1886     {
1887         msg_Warn( p_input, "drive letter %c: found in source string",
1888                   psz_dup[0] );
1889         psz_path = psz_dup;
1890     }
1891     else
1892 #endif
1893
1894     if( psz )
1895     {
1896         *psz++ = '\0';
1897         if( psz[0] == '/' && psz[1] == '/' )
1898             psz += 2;
1899
1900         psz_path = psz;
1901
1902         psz = strchr( psz_dup, '/' );
1903         if( psz )
1904         {
1905             *psz++ = '\0';
1906             psz_demux = psz;
1907         }
1908
1909         psz_access = psz_dup;
1910     }
1911     else
1912     {
1913         psz_path = psz_dup;
1914     }
1915
1916     if( psz_access == NULL )
1917         *ppsz_access = "";
1918     else
1919         *ppsz_access = psz_access;
1920
1921     if( psz_demux == NULL )
1922         *ppsz_demux = "";
1923     else
1924         *ppsz_demux = psz_demux;
1925
1926     if( psz_path == NULL )
1927         *ppsz_path = "";
1928     else
1929         *ppsz_path = psz_path;
1930 }