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