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