]> git.sesse.net Git - vlc/blob - src/input/input.c
* input: if we failed to open the file, and the name has a '%', we
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  * Read a stream, demultiplex and parse it before sending it to
4  * decoders.
5  *****************************************************************************
6  * Copyright (C) 1998-2004 VideoLAN
7  * $Id$
8  *
9  * Authors: Christophe Massiot <massiot@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/decoder.h>
34 #include <vlc/vout.h>
35
36 #ifdef HAVE_SYS_TIMES_H
37 #   include <sys/times.h>
38 #endif
39
40 #include "stream_output.h"
41
42 #include "vlc_interface.h"
43 #include "codecs.h"
44 #include "vlc_meta.h"
45 #include "../../modules/demux/util/sub.h"
46
47 /*****************************************************************************
48  * Local prototypes
49  *****************************************************************************/
50 struct input_thread_sys_t
51 {
52     /* subtitles */
53     int              i_sub;
54     subtitle_demux_t **sub;
55
56     int64_t          i_stop_time;
57 };
58
59 static  int RunThread  ( input_thread_t *p_input );
60 static  int InitThread ( input_thread_t *p_input );
61 static void ErrorThread( input_thread_t *p_input );
62 static void EndThread  ( input_thread_t *p_input );
63
64 static void ParseOption( input_thread_t *p_input, const char *psz_option );
65
66 static void DecodeUrl  ( char * );
67
68 /*****************************************************************************
69  * Callbacks
70  *****************************************************************************/
71 static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
72                              vlc_value_t oldval, vlc_value_t newval, void *p_data );
73 static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
74                              vlc_value_t oldval, vlc_value_t newval, void *p_data );
75 static int StateCallback   ( vlc_object_t *p_this, char const *psz_cmd,
76                              vlc_value_t oldval, vlc_value_t newval, void *p_data );
77 static int RateCallback    ( vlc_object_t *p_this, char const *psz_cmd,
78                              vlc_value_t oldval, vlc_value_t newval, void *p_data );
79 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
80                              vlc_value_t oldval, vlc_value_t newval, void *p_data );
81
82 /*****************************************************************************
83  * input_CreateThread: creates a new input thread
84  *****************************************************************************
85  * This function creates a new input, and returns a pointer
86  * to its description. On error, it returns NULL.
87  *****************************************************************************/
88 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
89                                       input_item_t *p_item )
90
91 {
92     input_thread_t *p_input;                        /* thread descriptor */
93     vlc_value_t     val;
94     int             i;
95
96     /* Allocate descriptor */
97     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
98     if( p_input == NULL )
99     {
100         msg_Err( p_parent, "out of memory" );
101         return NULL;
102     }
103
104     /* Store pointer to input item descriptor */
105     p_input->p_item = p_item;
106
107     /* Parse input options */
108     vlc_mutex_lock( &p_item->lock );
109     for( i = 0; i < p_item->i_options; i++ )
110     {
111         msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
112         ParseOption( p_input, p_item->ppsz_options[i] );
113     }
114     vlc_mutex_unlock( &p_item->lock );
115
116     /* Create a few object variables we'll need later on */
117     var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
118     var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
119     var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
120     var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
121     var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
122     var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
123                 VLC_VAR_DOINHERIT );
124     var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
125                 VLC_VAR_DOINHERIT );
126
127     var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
128     var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
129     var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
130     var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
131     var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
132
133     /* repeat variable */
134     var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
135
136     /* start/stop time */
137     var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
138     var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
139
140     /* decoders */
141     var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
142
143     /* play status */
144
145     /* position variable */
146     var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
147     var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
148     val.f_float = 0.0;
149     var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
150     var_AddCallback( p_input, "position", PositionCallback, NULL );
151     var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
152
153     /* time variable */
154     var_Create( p_input, "time",  VLC_VAR_TIME );
155     var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
156     val.i_time = 0;
157     var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
158     var_AddCallback( p_input, "time", TimeCallback, NULL );
159     var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
160
161     /* length variable */
162     var_Create( p_input, "length",  VLC_VAR_TIME );
163     val.i_time = 0;
164     var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
165
166     /* rate variable */
167     var_Create( p_input, "rate", VLC_VAR_INTEGER );
168     var_Create( p_input, "rate-slower", VLC_VAR_VOID );
169     var_Create( p_input, "rate-faster", VLC_VAR_VOID );
170     val.i_int = DEFAULT_RATE;
171     var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
172     var_AddCallback( p_input, "rate", RateCallback, NULL );
173     var_AddCallback( p_input, "rate-slower", RateCallback, NULL );
174     var_AddCallback( p_input, "rate-faster", RateCallback, NULL );
175
176     /* state variable */
177     var_Create( p_input, "state", VLC_VAR_INTEGER );
178     val.i_int = INIT_S;
179     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
180     var_AddCallback( p_input, "state", StateCallback, NULL );
181
182     /* state variable */
183     var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
184     val.b_bool = VLC_FALSE;
185     var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
186
187     /* Initialize thread properties */
188     p_input->b_eof      = 0;
189     p_input->b_out_pace_control = VLC_FALSE;
190     p_input->p_sys      = NULL;
191
192     /* Set target */
193     vlc_mutex_lock( &p_item->lock );
194     p_input->psz_source = strdup( p_item->psz_uri );
195     vlc_mutex_unlock( &p_item->lock );
196
197     /* Stream */
198     p_input->s = NULL;
199
200     /* es out */
201     p_input->p_es_out = NULL;
202
203     /* Demux */
204     p_input->p_demux   = NULL;
205     p_input->pf_demux  = NULL;
206     p_input->pf_rewind = NULL;
207     p_input->pf_demux_control = demux_vaControlDefault;
208     p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
209
210     /* Access */
211     p_input->p_access = NULL;
212
213     p_input->i_bufsize = 0;
214     p_input->i_mtu = 0;
215     p_input->i_pts_delay = DEFAULT_PTS_DELAY;
216
217     /* Initialize statistics */
218     p_input->c_loops                    = 0;
219     p_input->stream.c_packets_read      = 0;
220     p_input->stream.c_packets_trashed   = 0;
221
222     /* Set locks. */
223     vlc_mutex_init( p_input, &p_input->stream.stream_lock );
224     vlc_cond_init( p_input, &p_input->stream.stream_wait );
225     vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
226
227     /* Initialize stream description */
228     p_input->stream.b_changed = 0;
229     p_input->stream.i_es_number = 0;
230     p_input->stream.i_selected_es_number = 0;
231     p_input->stream.i_pgrm_number = 0;
232     p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
233     p_input->stream.b_new_mute = MUTE_NO_CHANGE;
234     p_input->stream.i_mux_rate = 0;
235     p_input->stream.b_seekable = 0;
236     p_input->stream.p_sout = NULL;
237
238     /* no stream, no program, no area, no es */
239     p_input->stream.p_new_program = NULL;
240
241     p_input->stream.i_area_nb = 0;
242     p_input->stream.pp_areas = NULL;
243     p_input->stream.p_selected_area = NULL;
244     p_input->stream.p_new_area = NULL;
245
246     p_input->stream.pp_selected_es = NULL;
247     p_input->stream.p_removed_es = NULL;
248     p_input->stream.p_newly_selected_es = NULL;
249
250     /* By default there is one area in a stream */
251     input_AddArea( p_input, 0, 1 );
252     p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
253
254     /* Initialize stream control properties. */
255     p_input->stream.control.i_status = INIT_S;
256     p_input->stream.control.i_rate = DEFAULT_RATE;
257     p_input->stream.control.b_mute = 0;
258     p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
259
260     msg_Info( p_input, "playlist item `%s'", p_input->psz_source );
261
262     /* Bookmarks */
263     var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
264     var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
265                 VLC_VAR_ISCOMMAND );
266     val.psz_string = _("Bookmark");
267     var_Change( p_input, "bookmark", VLC_VAR_SETTEXT, &val, NULL );
268     var_AddCallback( p_input, "bookmark", BookmarkCallback, NULL );
269
270     p_input->i_bookmarks = 0;
271     p_input->pp_bookmarks = NULL;
272
273     var_Get( p_input, "bookmarks", &val );
274     if( val.psz_string )
275     {
276         /* FIXME: have a common cfg parsing routine used by sout and others */
277         char *psz_parser, *psz_start, *psz_end;
278         psz_parser = val.psz_string;
279         while( (psz_start = strchr( psz_parser, '{' ) ) )
280         {
281             seekpoint_t seekpoint;
282             char backup;
283             psz_start++;
284             psz_end = strchr( psz_start, '}' );
285             if( !psz_end ) break;
286             psz_parser = psz_end + 1;
287             backup = *psz_parser;
288             *psz_parser = 0;
289             *psz_end = ',';
290
291             seekpoint.psz_name = 0;
292             seekpoint.i_byte_offset = 0;
293             seekpoint.i_time_offset = 0;
294             while( (psz_end = strchr( psz_start, ',' ) ) )
295             {
296                 *psz_end = 0;
297                 if( !strncmp( psz_start, "name=", 5 ) )
298                 {
299                     seekpoint.psz_name = psz_start + 5;
300                 }
301                 else if( !strncmp( psz_start, "bytes=", 6 ) )
302                 {
303                     seekpoint.i_byte_offset = atoll(psz_start + 6);
304                 }
305                 else if( !strncmp( psz_start, "time=", 5 ) )
306                 {
307                     seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
308                 }
309                 psz_start = psz_end + 1;
310             }
311             msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
312                      seekpoint.psz_name, seekpoint.i_byte_offset,
313                      seekpoint.i_time_offset );
314             input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
315             *psz_parser = backup;
316         }
317         free( val.psz_string );
318     }
319
320     vlc_object_attach( p_input, p_parent );
321
322     /* Create thread and wait for its readiness. */
323     if( vlc_thread_create( p_input, "input", RunThread,
324                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
325     {
326         msg_Err( p_input, "cannot create input thread" );
327         free( p_input );
328         return NULL;
329     }
330
331     return p_input;
332 }
333
334 /*****************************************************************************
335  * input_StopThread: mark an input thread as zombie
336  *****************************************************************************
337  * This function should not return until the thread is effectively cancelled.
338  *****************************************************************************/
339 void input_StopThread( input_thread_t *p_input )
340 {
341     /* Make the thread exit from a possible vlc_cond_wait() */
342     vlc_mutex_lock( &p_input->stream.stream_lock );
343     /* Request thread destruction */
344     p_input->b_die = 1;
345
346     vlc_cond_signal( &p_input->stream.stream_wait );
347     vlc_mutex_unlock( &p_input->stream.stream_lock );
348 }
349
350 /*****************************************************************************
351  * input_DestroyThread: mark an input thread as zombie
352  *****************************************************************************
353  * This function should not return until the thread is effectively cancelled.
354  *****************************************************************************/
355 void input_DestroyThread( input_thread_t *p_input )
356 {
357     /* Join the thread */
358     vlc_thread_join( p_input );
359
360     /* Destroy Mutex locks */
361     vlc_mutex_destroy( &p_input->stream.control.control_lock );
362     vlc_cond_destroy( &p_input->stream.stream_wait );
363     vlc_mutex_destroy( &p_input->stream.stream_lock );
364 }
365
366 /*****************************************************************************
367  * RunThread: main thread loop
368  *****************************************************************************
369  * Thread in charge of processing the network packets and demultiplexing.
370  *****************************************************************************/
371 static int RunThread( input_thread_t *p_input )
372 {
373     vlc_value_t  val;
374     mtime_t      i_update_next = -1;
375
376     /* Signal right now, otherwise we'll get stuck in a peek */
377     vlc_thread_ready( p_input );
378
379     if( InitThread( p_input ) )
380     {
381         /* If we failed, wait before we are killed, and exit */
382         p_input->b_error = 1;
383
384         ErrorThread( p_input );
385
386         /* Tell we're dead */
387         p_input->b_dead = 1;
388
389         return 0;
390     }
391
392     /* initialization is complete */
393     vlc_mutex_lock( &p_input->stream.stream_lock );
394     p_input->stream.b_changed        = 1;
395     p_input->stream.control.i_status = PLAYING_S;
396     vlc_mutex_unlock( &p_input->stream.stream_lock );
397
398     val.i_int = PLAYING_S;
399     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
400
401     while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
402     {
403         unsigned int i, i_count;
404
405         p_input->c_loops++;
406
407         vlc_mutex_lock( &p_input->stream.stream_lock );
408
409         if( p_input->stream.p_new_program )
410         {
411             if( p_input->pf_set_program != NULL )
412             {
413
414                 /* Reinitialize buffer manager. */
415                 input_AccessReinit( p_input );
416
417                 p_input->pf_set_program( p_input,
418                                          p_input->stream.p_new_program );
419
420                 /* Escape all decoders for the stream discontinuity they
421                  * will encounter. */
422                 input_EscapeDiscontinuity( p_input );
423
424                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
425                 {
426                     pgrm_descriptor_t * p_pgrm
427                                             = p_input->stream.pp_programs[i];
428
429                     /* Reinitialize synchro. */
430                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
431                 }
432             }
433             p_input->stream.p_new_program = NULL;
434         }
435
436         if( p_input->stream.p_new_area )
437         {
438             if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
439             {
440                 input_AccessReinit( p_input );
441
442                 p_input->pf_set_area( p_input, p_input->stream.p_new_area );
443
444                 /* Escape all decoders for the stream discontinuity they
445                  * will encounter. */
446                 input_EscapeDiscontinuity( p_input );
447
448                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
449                 {
450                     pgrm_descriptor_t * p_pgrm
451                                             = p_input->stream.pp_programs[i];
452
453                     /* Reinitialize synchro. */
454                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
455                 }
456             }
457             p_input->stream.p_new_area = NULL;
458         }
459
460         if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
461         {
462             if( p_input->stream.p_selected_area->i_size > 0 )
463             {
464                 unsigned int i;
465                 mtime_t      i_time;
466                 double f = (double)p_input->stream.p_selected_area->i_seek /
467                            (double)p_input->stream.p_selected_area->i_size;
468
469                 vlc_mutex_unlock( &p_input->stream.stream_lock );
470                 demux_Control( p_input, DEMUX_SET_POSITION, f );
471                 vlc_mutex_lock( &p_input->stream.stream_lock );
472
473                 /* Escape all decoders for the stream discontinuity they
474                  * will encounter. */
475                 input_EscapeDiscontinuity( p_input );
476
477                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
478                 {
479                     pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
480
481                     /* Reinitialize synchro. */
482                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
483                 }
484
485                 vlc_mutex_unlock( &p_input->stream.stream_lock );
486                 if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
487                 {
488                     int i;
489                     vlc_value_t val;
490
491                     /* Help in bar display */
492                     val.i_time = i_time;
493                     var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
494
495                     /* Seek subs */
496                     for( i = 0; i < p_input->p_sys->i_sub; i++ )
497                     {
498                         subtitle_Seek( p_input->p_sys->sub[i], i_time );
499                     }
500                 }
501                 if( !demux_Control( p_input, DEMUX_GET_POSITION, &f ) )
502                 {
503                     val.f_float = (float)f;
504                     var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
505                 }
506                 vlc_mutex_lock( &p_input->stream.stream_lock );
507             }
508             p_input->stream.p_selected_area->i_seek = NO_SEEK;
509         }
510
511         if( p_input->stream.p_removed_es )
512         {
513             input_UnselectES( p_input, p_input->stream.p_removed_es );
514             p_input->stream.p_removed_es = NULL;
515         }
516
517         if( p_input->stream.p_newly_selected_es )
518         {
519             input_SelectES( p_input, p_input->stream.p_newly_selected_es );
520             p_input->stream.p_newly_selected_es = NULL;
521         }
522
523         if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
524         {
525             if( p_input->stream.b_new_mute )
526             {
527                 input_EscapeAudioDiscontinuity( p_input );
528             }
529
530             vlc_mutex_lock( &p_input->stream.control.control_lock );
531             p_input->stream.control.b_mute = p_input->stream.b_new_mute;
532             vlc_mutex_unlock( &p_input->stream.control.control_lock );
533
534             p_input->stream.b_new_mute = MUTE_NO_CHANGE;
535         }
536
537         vlc_mutex_unlock( &p_input->stream.stream_lock );
538
539         /* Read and demultiplex some data. */
540         i_count = p_input->pf_demux( p_input );
541
542         if( i_count == 0 )
543         {
544             vlc_value_t repeat;
545
546             var_Get( p_input, "input-repeat", &repeat );
547             if( repeat.i_int == 0 || p_input->stream.i_area_nb <= 0 )
548             {
549                 /* End of file - we do not set b_die because only the
550                  * playlist is allowed to do so. */
551                 msg_Info( p_input, "EOF reached" );
552                 p_input->b_eof = 1;
553             }
554             else
555             {
556                 msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
557                 if( repeat.i_int > 0 )
558                 {
559                     repeat.i_int--;
560                     var_Set( p_input, "input-repeat", repeat );
561                 }
562
563                 p_input->stream.p_new_area = p_input->stream.pp_areas[0];
564                 p_input->stream.p_new_area->i_seek = 0;
565             }
566         }
567         else if( i_count < 0 )
568         {
569             p_input->b_error = 1;
570         }
571
572         if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
573         {
574             int i;
575             mtime_t i_time;
576             mtime_t i_length;
577             double  d_pos;
578
579             /* update input status variables */
580             if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
581             {
582                 val.f_float = (float)d_pos;
583                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
584             }
585             if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
586             {
587                 val.i_time = i_time;
588                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
589             }
590             if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
591             {
592                 val.i_time = i_length;
593                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
594             }
595
596             /* Check stop-time */
597             if( p_input->p_sys->i_stop_time > 0 && p_input->p_sys->i_stop_time < i_time )
598             {
599                 msg_Warn( p_input, "EOF reached because of stop-time" );
600                 p_input->b_eof = 1;
601             }
602
603             /* update subs */
604             for( i = 0; i < p_input->p_sys->i_sub; i++ )
605             {
606                 subtitle_Demux( p_input->p_sys->sub[i], i_time );
607             }
608
609             i_update_next = mdate() + I64C(150000);
610         }
611     }
612
613     if( p_input->b_error || p_input->b_eof )
614     {
615         ErrorThread( p_input );
616     }
617
618     EndThread( p_input );
619
620     return 0;
621 }
622
623 /*****************************************************************************
624  * InitThread: init the input Thread
625  *****************************************************************************/
626 static int InitThread( input_thread_t * p_input )
627 {
628     vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
629 //    float f_fps;
630     double f_fps;
631     mtime_t i_length;
632
633     /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
634     char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
635     vlc_value_t val;
636     int64_t i_microsecondperframe;
637
638     subtitle_demux_t *p_sub_toselect = NULL;
639     char             *psz_sub_file = NULL;
640
641     /* Skip the plug-in names */
642     while( *psz_parser && *psz_parser != ':' )
643     {
644         psz_parser++;
645     }
646 #if defined( WIN32 ) || defined( UNDER_CE )
647     if( psz_parser - p_input->psz_dupsource == 1 )
648     {
649         msg_Warn( p_input, "drive letter %c: found in source string",
650                            p_input->psz_dupsource[0] ) ;
651         psz_parser = "";
652     }
653 #endif
654
655     if( !*psz_parser )
656     {
657         p_input->psz_access = p_input->psz_demux = "";
658         p_input->psz_name = p_input->psz_source;
659         free( p_input->psz_dupsource );
660         p_input->psz_dupsource = NULL;
661     }
662     else
663     {
664         *psz_parser++ = '\0';
665
666         /* let's skip '//' */
667         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
668         {
669             psz_parser += 2 ;
670         }
671
672         p_input->psz_name = psz_parser ;
673
674         /* Come back to parse the access and demux plug-ins */
675         psz_parser = p_input->psz_dupsource;
676
677         if( !*psz_parser )
678         {
679             /* No access */
680             p_input->psz_access = "";
681         }
682         else if( *psz_parser == '/' )
683         {
684             /* No access */
685             p_input->psz_access = "";
686             psz_parser++;
687         }
688         else
689         {
690             p_input->psz_access = psz_parser;
691
692             while( *psz_parser && *psz_parser != '/' )
693             {
694                 psz_parser++;
695             }
696
697             if( *psz_parser == '/' )
698             {
699                 *psz_parser++ = '\0';
700             }
701         }
702
703         if( !*psz_parser )
704         {
705             /* No demux */
706             p_input->psz_demux = "";
707         }
708         else
709         {
710             p_input->psz_demux = psz_parser;
711         }
712     }
713
714     msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
715              p_input->psz_access, p_input->psz_demux, p_input->psz_name );
716
717     if( input_AccessInit( p_input ) == -1 )
718     {
719         free( p_input->psz_source );
720         if( p_input->psz_dupsource != NULL )
721         {
722             free( p_input->psz_dupsource );
723         }
724
725         return VLC_EGENERIC;
726     }
727
728     /* Initialize optional stream output. (before demuxer)*/
729     var_Get( p_input, "sout", &val );
730     if( val.psz_string != NULL )
731     {
732         if ( *val.psz_string && (p_input->stream.p_sout =
733              sout_NewInstance( p_input, val.psz_string )) == NULL )
734         {
735             msg_Err( p_input, "cannot start stream output instance, aborting" );
736             free( val.psz_string );
737
738             input_AccessEnd( p_input );
739             free( p_input->psz_source );
740             if( p_input->psz_dupsource != NULL )
741             {
742                 free( p_input->psz_dupsource );
743             }
744             return VLC_EGENERIC;
745         }
746         free( val.psz_string );
747     }
748
749     p_input->p_es_out = input_EsOutNew( p_input );
750     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
751     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
752
753     /* Find and open appropriate access module */
754     p_input->p_access = module_Need( p_input, "access",
755                                      p_input->psz_access, VLC_TRUE );
756
757     /* Maybe we had an encoded url */
758     if( !p_input->p_access && strchr( p_input->psz_name, '%' ) )
759     {
760         DecodeUrl( p_input->psz_name );
761
762         msg_Dbg( p_input, "retying with %s", p_input->psz_name );
763         p_input->p_access = module_Need( p_input, "access",
764                                          p_input->psz_access, VLC_TRUE );
765     }
766 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
767                     * are forbidden in filenames on Win32. */
768
769     /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
770     if ( p_input->p_access == NULL
771           && (*p_input->psz_demux || *p_input->psz_access) )
772     {
773         p_input->psz_access = p_input->psz_demux = "";
774         p_input->psz_name = p_input->psz_source;
775         free( p_input->psz_dupsource);
776         p_input->psz_dupsource = NULL;
777
778         p_input->p_access = module_Need( p_input, "access",
779                                          p_input->psz_access, VLC_TRUE );
780     }
781 #endif
782     if( p_input->p_access == NULL )
783     {
784         msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
785                  p_input->psz_access, p_input->psz_demux, p_input->psz_name );
786         if ( p_input->stream.p_sout != NULL )
787         {
788             sout_DeleteInstance( p_input->stream.p_sout );
789         }
790
791         input_AccessEnd( p_input );
792         free( p_input->psz_source );
793         if( p_input->psz_dupsource != NULL )
794         {
795             free( p_input->psz_dupsource );
796         }
797         input_EsOutDelete( p_input->p_es_out );
798         return VLC_EGENERIC;
799     }
800
801     /* Waiting for stream. */
802     if( p_input->i_mtu )
803     {
804         p_input->i_bufsize = p_input->i_mtu;
805     }
806     else
807     {
808         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
809     }
810
811     /* If the desynchronisation requested by the user is < 0, we need to
812      * cache more data. */
813     var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
814     var_Get( p_input, "audio-desync", &val );
815     if( val.i_int < 0 )
816         p_input->i_pts_delay -= (val.i_int * 1000);
817
818     if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
819     {
820         while( !input_FillBuffer( p_input ) )
821         {
822             if( p_input->b_die || p_input->b_error || p_input->b_eof )
823             {
824                 module_Unneed( p_input, p_input->p_access );
825                 if ( p_input->stream.p_sout != NULL )
826                 {
827                     sout_DeleteInstance( p_input->stream.p_sout );
828                 }
829                 input_AccessEnd( p_input );
830                 free( p_input->psz_source );
831                 if( p_input->psz_dupsource != NULL )
832                 {
833                     free( p_input->psz_dupsource );
834                 }
835                 input_EsOutDelete( p_input->p_es_out );
836                 return VLC_EGENERIC;
837             }
838         }
839     }
840
841     /* Create the stream_t facilities */
842     p_input->s = input_StreamNew( p_input );
843     if( p_input->s == NULL )
844     {
845         /* should never occur yet */
846
847         msg_Err( p_input, "cannot create stream_t" );
848
849         module_Unneed( p_input, p_input->p_access );
850         if ( p_input->stream.p_sout != NULL )
851         {
852             sout_DeleteInstance( p_input->stream.p_sout );
853         }
854         input_AccessEnd( p_input );
855         free( p_input->psz_source );
856         if( p_input->psz_dupsource != NULL )
857         {
858             free( p_input->psz_dupsource );
859         }
860         input_EsOutDelete( p_input->p_es_out );
861         return VLC_EGENERIC;
862     }
863
864     /* Find and open appropriate demux module */
865     p_input->p_demux =
866         module_Need( p_input, "demux",
867                      (p_input->psz_demux && *p_input->psz_demux) ?
868                      p_input->psz_demux : "$demux",
869                      (p_input->psz_demux && *p_input->psz_demux) ?
870                      VLC_TRUE : VLC_FALSE );
871
872     if( p_input->p_demux == NULL )
873     {
874         msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
875                  p_input->psz_access, p_input->psz_demux, p_input->psz_name );
876
877         input_StreamDelete( p_input->s );
878         module_Unneed( p_input, p_input->p_access );
879         if ( p_input->stream.p_sout != NULL )
880         {
881             sout_DeleteInstance( p_input->stream.p_sout );
882         }
883         input_AccessEnd( p_input );
884         free( p_input->psz_source );
885         if( p_input->psz_dupsource != NULL )
886         {
887             free( p_input->psz_dupsource );
888         }
889         input_EsOutDelete( p_input->p_es_out );
890         return VLC_EGENERIC;
891     }
892
893     /* Init input_thread_sys_t */
894     p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
895     p_input->p_sys->i_sub = 0;
896     p_input->p_sys->sub   = NULL;
897
898     p_input->p_sys->i_stop_time = 0;
899
900     /* Get meta information from user */
901     var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
902     var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
903     var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
904     var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
905     var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
906     var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
907     var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
908     var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
909     if( (p_meta_user = vlc_meta_New()) )
910     {
911         vlc_value_t val;
912
913         var_Get( p_input, "meta-title", &val );
914         if( val.psz_string && *val.psz_string )
915             vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
916         if( val.psz_string ) free( val.psz_string );
917         var_Get( p_input, "meta-author", &val );
918         if( val.psz_string && *val.psz_string )
919             vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
920         if( val.psz_string ) free( val.psz_string );
921         var_Get( p_input, "meta-artist", &val );
922         if( val.psz_string && *val.psz_string )
923             vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
924         if( val.psz_string ) free( val.psz_string );
925         var_Get( p_input, "meta-genre", &val );
926         if( val.psz_string && *val.psz_string )
927             vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
928         if( val.psz_string ) free( val.psz_string );
929         var_Get( p_input, "meta-copyright", &val );
930         if( val.psz_string && *val.psz_string )
931             vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
932         if( val.psz_string ) free( val.psz_string );
933         var_Get( p_input, "meta-description", &val );
934         if( val.psz_string && *val.psz_string )
935             vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
936         if( val.psz_string ) free( val.psz_string );
937         var_Get( p_input, "meta-date", &val );
938         if( val.psz_string && *val.psz_string )
939             vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
940         if( val.psz_string ) free( val.psz_string );
941         var_Get( p_input, "meta-url", &val );
942         if( val.psz_string && *val.psz_string )
943             vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
944         if( val.psz_string ) free( val.psz_string );
945     }
946
947     /* Get meta informations from demuxer */
948     if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
949         ( p_meta_user && p_meta_user->i_meta ) )
950     {
951         int i;
952
953         /* Merge demux and user metadata */
954         if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
955         else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );
956
957         msg_Dbg( p_input, "meta informations:" );
958         if( p_meta->i_meta > 0 )
959         {
960             for( i = 0; i < p_meta->i_meta; i++ )
961             {
962                 msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
963                          p_meta->value[i] );
964                 if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
965                     p_meta->value[i] )
966                     input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
967
968                 if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
969                     input_Control( p_input, INPUT_ADD_INFO, _("General"),
970                                    _("Author"), p_meta->value[i] );
971
972                 input_Control( p_input, INPUT_ADD_INFO, _("File"),
973                               _(p_meta->name[i]), "%s", p_meta->value[i] );
974             }
975         }
976         for( i = 0; i < p_meta->i_track; i++ )
977         {
978             vlc_meta_t *tk = p_meta->track[i];
979             int j;
980
981             msg_Dbg( p_input, "  - track[%d]:", i );
982             if( tk->i_meta > 0 )
983             {
984                 char *psz_cat = malloc( strlen(_("Stream")) + 10 );
985                 sprintf( psz_cat, "%s %d", _("Stream"), i );
986
987                 for( j = 0; j < tk->i_meta; j++ )
988                 {
989                     msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
990                              tk->value[j] );
991
992                     input_Control( p_input, INPUT_ADD_INFO, psz_cat,
993                                    _(tk->name[j]), "%s", tk->value[j] );
994                 }
995             }
996         }
997
998         if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
999         {
1000             p_input->stream.p_sout->p_meta = p_meta;
1001         }
1002         else
1003         {
1004             vlc_meta_Delete( p_meta );
1005         }
1006     }
1007     if( p_meta_user ) vlc_meta_Delete( p_meta_user );
1008
1009     /* Get length */
1010     if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
1011         i_length > 0 )
1012     {
1013         char psz_buffer[MSTRTIME_MAX_SIZE];
1014
1015         vlc_mutex_lock( &p_input->p_item->lock );
1016         p_input->p_item->i_duration = i_length;
1017         vlc_mutex_unlock( &p_input->p_item->lock );
1018
1019         input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
1020                        msecstotimestr( psz_buffer, i_length / 1000 ) );
1021
1022         /* Set start time */
1023         var_Get( p_input, "start-time", &val );
1024         if(  val.i_int > 0 )
1025         {
1026             double f_pos = val.i_int * I64C(1000000) / (double)i_length;
1027
1028             if( f_pos >= 1.0 )
1029             {
1030                 msg_Warn( p_input, "invalid start-time, ignored (start-time "
1031                           ">= media length)" );
1032             }
1033             else
1034             {
1035                 p_input->stream.p_selected_area->i_seek =
1036                     (int64_t)( f_pos * (double)p_input->stream.p_selected_area->i_size );
1037
1038                 msg_Dbg( p_input, "start-time %ds (%2.2f)", val.i_int, f_pos );
1039             }
1040         }
1041     }
1042
1043     /* Set stop-time and check validity */
1044     var_Get( p_input, "stop-time", &val );
1045     if( val.i_int > 0 )
1046     {
1047         vlc_value_t start;
1048
1049         var_Get( p_input, "start-time", &start );
1050         if( start.i_int >= val.i_int )
1051         {
1052             msg_Warn( p_input, "invalid stop-time, ignored (stop-time < "
1053                       "start-time)" );
1054         }
1055         else
1056         {
1057             p_input->p_sys->i_stop_time = (int64_t)val.i_int * I64C(1000000);
1058             msg_Dbg( p_input, "stop-time %ds", val.i_int );
1059         }
1060     }
1061
1062     /* Get fps */
1063     if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
1064     {
1065         i_microsecondperframe = 0;
1066     }
1067     else
1068     {
1069         i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
1070     }
1071
1072     /* Look for and add subtitle files */
1073     var_Get( p_input, "sub-file", &val );
1074     if( val.psz_string && *val.psz_string )
1075     {
1076         subtitle_demux_t *p_sub;
1077
1078         msg_Dbg( p_input, "force subtitle: %s", val.psz_string );
1079         if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string),
1080                                     i_microsecondperframe ) ) )
1081         {
1082             p_sub_toselect = p_sub;
1083             TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
1084         }
1085     }
1086     psz_sub_file = val.psz_string;
1087
1088     var_Get( p_input, "sub-autodetect-file", &val );
1089     if( val.b_bool )
1090     {
1091         subtitle_demux_t *p_sub;
1092         int i;
1093         char **tmp = subtitles_Detect( p_input, "", p_input->psz_name );
1094         char **tmp2 = tmp;
1095         for( i = 0; *tmp2 != NULL; i++ )
1096         {
1097             if( psz_sub_file == NULL || strcmp( psz_sub_file, *tmp2 ) )
1098             {
1099                 if( ( p_sub = subtitle_New( p_input, *tmp2,
1100                                             i_microsecondperframe ) ) )
1101                 {
1102                     TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub,
1103                                 p_sub );
1104                 }
1105             }
1106             free( *tmp2++ );
1107         }
1108         free( tmp );
1109     }
1110     if( psz_sub_file ) free( psz_sub_file );
1111
1112     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
1113     val.b_bool =  VLC_FALSE;
1114     if( p_input->stream.p_sout )
1115     {
1116         var_Get( p_input, "sout-all", &val );
1117     }
1118     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
1119                     val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
1120     if( p_sub_toselect )
1121     {
1122         es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
1123                         p_sub_toselect->p_es, VLC_TRUE );
1124     }
1125
1126     if( p_input->stream.p_sout )
1127     {
1128         if( p_input->stream.p_sout->i_out_pace_nocontrol > 0 )
1129         {
1130             p_input->b_out_pace_control = VLC_FALSE;
1131         }
1132         else
1133         {
1134             p_input->b_out_pace_control = VLC_TRUE;
1135         }
1136         msg_Dbg( p_input, "starting in %s mode",
1137                  p_input->b_out_pace_control ? "asynch" : "synch" );
1138     }
1139
1140     return VLC_SUCCESS;
1141 }
1142
1143 /*****************************************************************************
1144  * ErrorThread: RunThread() error loop
1145  *****************************************************************************
1146  * This function is called when an error occured during thread main's loop.
1147  *****************************************************************************/
1148 static void ErrorThread( input_thread_t *p_input )
1149 {
1150     while( !p_input->b_die )
1151     {
1152         /* Sleep a while */
1153         msleep( INPUT_IDLE_SLEEP );
1154     }
1155 }
1156
1157 /*****************************************************************************
1158  * EndThread: end the input thread
1159  *****************************************************************************/
1160 static void EndThread( input_thread_t * p_input )
1161 {
1162     int i;
1163 #ifdef HAVE_SYS_TIMES_H
1164     /* Display statistics */
1165     struct tms  cpu_usage;
1166     times( &cpu_usage );
1167
1168     msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
1169              p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
1170 #else
1171     msg_Dbg( p_input, "%ld loops", p_input->c_loops );
1172 #endif
1173
1174     input_DumpStream( p_input );
1175
1176     /* Free demultiplexer's data */
1177     if( p_input->p_demux ) module_Unneed( p_input, p_input->p_demux );
1178
1179     /* Free all ES and destroy all decoder threads */
1180     input_EndStream( p_input );
1181
1182     /* Close optional stream output instance */
1183     if( p_input->stream.p_sout )
1184     {
1185         vlc_object_t *p_pl =
1186             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1187         vlc_value_t keep;
1188
1189         if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
1190         {
1191             /* attach sout to the playlist */
1192             msg_Warn( p_input, "keeping sout" );
1193             vlc_object_detach( p_input->stream.p_sout );
1194             vlc_object_attach( p_input->stream.p_sout, p_pl );
1195         }
1196         else
1197         {
1198             msg_Warn( p_input, "destroying sout" );
1199             sout_DeleteInstance( p_input->stream.p_sout );
1200         }
1201         if( p_pl )
1202         {
1203             vlc_object_release( p_pl );
1204         }
1205     }
1206
1207     /* Destroy subtitles demuxers */
1208     if( p_input->p_sys )
1209     {
1210         for( i = 0; i < p_input->p_sys->i_sub; i++ )
1211         {
1212             subtitle_Close( p_input->p_sys->sub[i] );
1213         }
1214         if( p_input->p_sys->i_sub > 0 )
1215         {
1216             free( p_input->p_sys->sub );
1217         }
1218
1219         /* Free input_thread_sys_t */
1220         free( p_input->p_sys );
1221     }
1222
1223     /* Destroy the stream_t facilities */
1224     if( p_input->s ) input_StreamDelete( p_input->s );
1225
1226     /* Destroy es out */
1227     if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
1228
1229     /* Close the access plug-in */
1230     if( p_input->p_access ) module_Unneed( p_input, p_input->p_access );
1231
1232     input_AccessEnd( p_input );
1233
1234     /* Free info structures XXX destroy es before 'cause vorbis */
1235     msg_Dbg( p_input, "freeing info structures...");
1236
1237     free( p_input->psz_source );
1238     if( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
1239
1240     /* Tell we're dead */
1241     p_input->b_dead = 1;
1242 }
1243 /*****************************************************************************
1244  * DecodeUrl: decode a given encoded url
1245  *****************************************************************************/
1246 static void DecodeUrl( char *psz )
1247 {
1248     char *dup = strdup( psz );
1249     char *p = dup;
1250
1251     while( *p )
1252     {
1253         if( *p == '%' )
1254         {
1255             char val[3];
1256             p++;
1257             if( !*p )
1258             {
1259                 break;
1260             }
1261
1262             val[0] = *p++;
1263             val[1] = *p++;
1264             val[2] = '\0';
1265
1266             *psz++ = strtol( val, NULL, 16 );
1267         }
1268         else if( *p == '+' )
1269         {
1270             *psz++ = ' ';
1271             p++;
1272         }
1273         else
1274         {
1275             *psz++ = *p++;
1276         }
1277     }
1278     *psz++  ='\0';
1279     free( dup );
1280 }
1281
1282 /*****************************************************************************
1283  * ParseOption: parses the options for the input
1284  *****************************************************************************
1285  * This function parses the input (config) options and creates their associated
1286  * object variables.
1287  * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
1288  * bar is the value of the option.
1289  *****************************************************************************/
1290 static void ParseOption( input_thread_t *p_input, const char *psz_option )
1291 {
1292     char *psz_name = (char *)psz_option;
1293     char *psz_value = strchr( psz_option, '=' );
1294     int  i_name_len, i_type;
1295     vlc_bool_t b_isno = VLC_FALSE;
1296     vlc_value_t val;
1297
1298     if( psz_value ) i_name_len = psz_value - psz_option;
1299     else i_name_len = strlen( psz_option );
1300
1301     /* It's too much of an hassle to remove the ':' when we parse
1302      * the cmd line :) */
1303     if( i_name_len && *psz_name == ':' )
1304     {
1305         psz_name++;
1306         i_name_len--;
1307     }
1308
1309     if( i_name_len == 0 ) return;
1310
1311     psz_name = strndup( psz_name, i_name_len );
1312     if( psz_value ) psz_value++;
1313
1314     i_type = config_GetType( p_input, psz_name );
1315
1316     if( !i_type && !psz_value )
1317     {
1318         /* check for "no-foo" or "nofoo" */
1319         if( !strncmp( psz_name, "no-", 3 ) )
1320         {
1321             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1322         }
1323         else if( !strncmp( psz_name, "no", 2 ) )
1324         {
1325             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1326         }
1327         else goto cleanup;           /* Option doesn't exist */
1328
1329         b_isno = VLC_TRUE;
1330         i_type = config_GetType( p_input, psz_name );
1331
1332         if( !i_type ) goto cleanup;  /* Option doesn't exist */
1333     }
1334     else if( !i_type ) goto cleanup; /* Option doesn't exist */
1335
1336     if( ( i_type != VLC_VAR_BOOL ) &&
1337         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1338
1339     /* Create the variable in the input object.
1340      * Children of the input object will be able to retreive this value
1341      * thanks to the inheritance property of the object variables. */
1342     var_Create( p_input, psz_name, i_type );
1343
1344     switch( i_type )
1345     {
1346     case VLC_VAR_BOOL:
1347         val.b_bool = !b_isno;
1348         break;
1349
1350     case VLC_VAR_INTEGER:
1351         val.i_int = atoi( psz_value );
1352         break;
1353
1354     case VLC_VAR_FLOAT:
1355         val.f_float = atof( psz_value );
1356         break;
1357
1358     case VLC_VAR_STRING:
1359     case VLC_VAR_MODULE:
1360     case VLC_VAR_FILE:
1361     case VLC_VAR_DIRECTORY:
1362         val.psz_string = psz_value;
1363         break;
1364
1365     default:
1366         goto cleanup;
1367         break;
1368     }
1369
1370     var_Set( p_input, psz_name, val );
1371
1372     msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );
1373
1374   cleanup:
1375     if( psz_name ) free( psz_name );
1376     return;
1377 }
1378
1379 /*****************************************************************************
1380  * Callbacks  (position, time, state, rate )
1381  *****************************************************************************/
1382 static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
1383                              vlc_value_t oldval, vlc_value_t newval,
1384                              void *p_data )
1385 {
1386     input_thread_t *p_input = (input_thread_t *)p_this;
1387
1388     msg_Dbg( p_input, "cmd=%s old=%f new=%f", psz_cmd,
1389              oldval.f_float, newval.f_float );
1390
1391     if( !strcmp( psz_cmd, "position-offset" ) )
1392     {
1393         vlc_value_t val;
1394         var_Get( p_input, "position", &val );
1395
1396         newval.f_float += val.f_float;
1397     }
1398
1399     vlc_mutex_lock( &p_input->stream.stream_lock );
1400     p_input->stream.p_selected_area->i_seek =
1401         (int64_t)( newval.f_float *
1402                    (double)p_input->stream.p_selected_area->i_size );
1403
1404     if( p_input->stream.p_selected_area->i_seek < 0 )
1405     {
1406         p_input->stream.p_selected_area->i_seek = 0;
1407     }
1408     vlc_mutex_unlock( &p_input->stream.stream_lock );
1409
1410     return VLC_SUCCESS;
1411 }
1412
1413 static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
1414                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1415 {
1416     input_thread_t *p_input = (input_thread_t *)p_this;
1417     vlc_value_t     val;
1418
1419     /* FIXME TODO FIXME */
1420     msg_Dbg( p_input, "cmd=%s old=%lld new=%lld", psz_cmd,
1421              oldval.i_time, newval.i_time );
1422
1423     var_Get( p_input, "length", &val );
1424     if( val.i_time > 0 )
1425     {
1426         val.f_float = (double)newval.i_time / (double)val.i_time;
1427         if( !strcmp( psz_cmd, "time-offset" ) )
1428         {
1429             var_Set( p_input, "position-offset", val );
1430         }
1431         else
1432         {
1433             var_Set( p_input, "position", val );
1434         }
1435     }
1436     else
1437     {
1438         msg_Warn( p_input, "TimeCallback: length <= 0 -> can't seek" );
1439     }
1440     return VLC_SUCCESS;
1441 }
1442
1443 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
1444                           vlc_value_t oldval, vlc_value_t newval,
1445                           void *p_data )
1446 {
1447     input_thread_t *p_input = (input_thread_t *)p_this;
1448
1449     msg_Dbg( p_input, "cmd=%s old=%d new=%d",
1450              psz_cmd, oldval.i_int, newval.i_int );
1451
1452     switch( newval.i_int )
1453     {
1454         case PLAYING_S:
1455             input_SetStatus( p_input, INPUT_STATUS_PLAY );
1456             return VLC_SUCCESS;
1457         case PAUSE_S:
1458             input_SetStatus( p_input, INPUT_STATUS_PAUSE );
1459             return VLC_SUCCESS;
1460         case END_S:
1461             input_SetStatus( p_input, INPUT_STATUS_END );
1462             return VLC_SUCCESS;
1463         default:
1464             msg_Err( p_input, "cannot set new state (invalid)" );
1465             return VLC_EGENERIC;
1466     }
1467 }
1468
1469 static int RateCallback( vlc_object_t *p_this, char const *psz_cmd,
1470                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1471 {
1472     input_thread_t *p_input = (input_thread_t *)p_this;
1473
1474     if( !strcmp( psz_cmd, "rate-slower" ) )
1475     {
1476         input_SetStatus( p_input, INPUT_STATUS_SLOWER );
1477     }
1478     else if( !strcmp( psz_cmd, "rate-faster" ) )
1479     {
1480         input_SetStatus( p_input, INPUT_STATUS_FASTER );
1481     }
1482     else
1483     {
1484         msg_Dbg( p_input, "cmd=%s old=%d new=%d",
1485                  psz_cmd, oldval.i_int, newval.i_int );
1486         input_SetRate( p_input, newval.i_int );
1487     }
1488     return VLC_SUCCESS;
1489 }
1490
1491 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
1492                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1493 {
1494     input_thread_t *p_input = (input_thread_t *)p_this;
1495     return input_Control( p_input, INPUT_SET_BOOKMARK, newval );
1496 }