]> git.sesse.net Git - vlc/blob - src/input/input.c
Install new required files for skins2 on make install
[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 = atoll(psz_start + 6);
296                 }
297                 else if( !strncmp( psz_start, "time=", 5 ) )
298                 {
299                     seekpoint.i_time_offset = atoll(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     double f_fps;
626     playlist_t *p_playlist;
627     mtime_t i_length;
628
629     /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
630     char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
631     vlc_value_t val;
632     int64_t i_microsecondperframe;
633
634     subtitle_demux_t *p_sub_toselect = NULL;
635     char             *psz_sub_file = NULL;
636
637     /* Skip the plug-in names */
638     while( *psz_parser && *psz_parser != ':' )
639     {
640         psz_parser++;
641     }
642 #if defined( WIN32 ) || defined( UNDER_CE )
643     if( psz_parser - p_input->psz_dupsource == 1 )
644     {
645         msg_Warn( p_input, "drive letter %c: found in source string",
646                            p_input->psz_dupsource[0] ) ;
647         psz_parser = "";
648     }
649 #endif
650
651     if( !*psz_parser )
652     {
653         p_input->psz_access = p_input->psz_demux = "";
654         p_input->psz_name = p_input->psz_source;
655         free( p_input->psz_dupsource );
656         p_input->psz_dupsource = NULL;
657     }
658     else
659     {
660         *psz_parser++ = '\0';
661
662         /* let's skip '//' */
663         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
664         {
665             psz_parser += 2 ;
666         }
667
668         p_input->psz_name = psz_parser ;
669
670         /* Come back to parse the access and demux plug-ins */
671         psz_parser = p_input->psz_dupsource;
672
673         if( !*psz_parser )
674         {
675             /* No access */
676             p_input->psz_access = "";
677         }
678         else if( *psz_parser == '/' )
679         {
680             /* No access */
681             p_input->psz_access = "";
682             psz_parser++;
683         }
684         else
685         {
686             p_input->psz_access = psz_parser;
687
688             while( *psz_parser && *psz_parser != '/' )
689             {
690                 psz_parser++;
691             }
692
693             if( *psz_parser == '/' )
694             {
695                 *psz_parser++ = '\0';
696             }
697         }
698
699         if( !*psz_parser )
700         {
701             /* No demux */
702             p_input->psz_demux = "";
703         }
704         else
705         {
706             p_input->psz_demux = psz_parser;
707         }
708     }
709
710     msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
711              p_input->psz_access, p_input->psz_demux, p_input->psz_name );
712
713     if( input_AccessInit( p_input ) == -1 )
714     {
715         free( p_input->psz_source );
716         if( p_input->psz_dupsource != NULL )
717         {
718             free( p_input->psz_dupsource );
719         }
720
721         return VLC_EGENERIC;
722     }
723
724     /* Initialize optional stream output. (before demuxer)*/
725     var_Get( p_input, "sout", &val );
726     if( val.psz_string != NULL )
727     {
728         if ( *val.psz_string && (p_input->stream.p_sout =
729              sout_NewInstance( p_input, val.psz_string )) == NULL )
730         {
731             msg_Err( p_input, "cannot start stream output instance, aborting" );
732             free( val.psz_string );
733
734             input_AccessEnd( p_input );
735             free( p_input->psz_source );
736             if( p_input->psz_dupsource != NULL )
737             {
738                 free( p_input->psz_dupsource );
739             }
740             return VLC_EGENERIC;
741         }
742         free( val.psz_string );
743     }
744
745     p_input->p_es_out = input_EsOutNew( p_input );
746     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
747     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
748
749     /* Find and open appropriate access module */
750     p_input->p_access = module_Need( p_input, "access",
751                                      p_input->psz_access, VLC_TRUE );
752
753 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
754                     * are forbidden in filenames on Win32. */
755
756     /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
757     if ( p_input->p_access == NULL
758           && (*p_input->psz_demux || *p_input->psz_access) )
759     {
760         p_input->psz_access = p_input->psz_demux = "";
761         p_input->psz_name = p_input->psz_source;
762         free( p_input->psz_dupsource);
763         p_input->psz_dupsource = NULL;
764
765         p_input->p_access = module_Need( p_input, "access",
766                                          p_input->psz_access, VLC_TRUE );
767     }
768 #endif
769
770     if( p_input->p_access == NULL )
771     {
772         msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
773                  p_input->psz_access, p_input->psz_demux, p_input->psz_name );
774         if ( p_input->stream.p_sout != NULL )
775         {
776             sout_DeleteInstance( p_input->stream.p_sout );
777         }
778
779         input_AccessEnd( p_input );
780         free( p_input->psz_source );
781         if( p_input->psz_dupsource != NULL )
782         {
783             free( p_input->psz_dupsource );
784         }
785         input_EsOutDelete( p_input->p_es_out );
786         return VLC_EGENERIC;
787     }
788
789     /* Waiting for stream. */
790     if( p_input->i_mtu )
791     {
792         p_input->i_bufsize = p_input->i_mtu;
793     }
794     else
795     {
796         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
797     }
798
799     /* If the desynchronisation requested by the user is < 0, we need to
800      * cache more data. */
801     var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
802     var_Get( p_input, "audio-desync", &val );
803     if( val.i_int < 0 )
804         p_input->i_pts_delay -= (val.i_int * 1000);
805
806     if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
807     {
808         while( !input_FillBuffer( p_input ) )
809         {
810             if( p_input->b_die || p_input->b_error || p_input->b_eof )
811             {
812                 module_Unneed( p_input, p_input->p_access );
813                 if ( p_input->stream.p_sout != NULL )
814                 {
815                     sout_DeleteInstance( p_input->stream.p_sout );
816                 }
817                 input_AccessEnd( p_input );
818                 free( p_input->psz_source );
819                 if( p_input->psz_dupsource != NULL )
820                 {
821                     free( p_input->psz_dupsource );
822                 }
823                 input_EsOutDelete( p_input->p_es_out );
824                 return VLC_EGENERIC;
825             }
826         }
827     }
828
829     /* Create the stream_t facilities */
830     p_input->s = input_StreamNew( p_input );
831     if( p_input->s == NULL )
832     {
833         /* should never occur yet */
834
835         msg_Err( p_input, "cannot create stream_t" );
836
837         module_Unneed( p_input, p_input->p_access );
838         if ( p_input->stream.p_sout != NULL )
839         {
840             sout_DeleteInstance( p_input->stream.p_sout );
841         }
842         input_AccessEnd( p_input );
843         free( p_input->psz_source );
844         if( p_input->psz_dupsource != NULL )
845         {
846             free( p_input->psz_dupsource );
847         }
848         input_EsOutDelete( p_input->p_es_out );
849         return VLC_EGENERIC;
850     }
851
852     /* Find and open appropriate demux module */
853     p_input->p_demux =
854         module_Need( p_input, "demux",
855                      (p_input->psz_demux && *p_input->psz_demux) ?
856                      p_input->psz_demux : "$demux",
857                      (p_input->psz_demux && *p_input->psz_demux) ?
858                      VLC_TRUE : VLC_FALSE );
859
860     if( p_input->p_demux == NULL )
861     {
862         msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
863                  p_input->psz_access, p_input->psz_demux, p_input->psz_name );
864
865         input_StreamDelete( p_input->s );
866         module_Unneed( p_input, p_input->p_access );
867         if ( p_input->stream.p_sout != NULL )
868         {
869             sout_DeleteInstance( p_input->stream.p_sout );
870         }
871         input_AccessEnd( p_input );
872         free( p_input->psz_source );
873         if( p_input->psz_dupsource != NULL )
874         {
875             free( p_input->psz_dupsource );
876         }
877         input_EsOutDelete( p_input->p_es_out );
878         return VLC_EGENERIC;
879     }
880
881     /* Init input_thread_sys_t */
882     p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
883     p_input->p_sys->i_sub = 0;
884     p_input->p_sys->sub   = NULL;
885
886     p_input->p_sys->i_stop_time = 0;
887
888     /* Get meta information from user */
889     var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
890     var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
891     var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
892     var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
893     var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
894     var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
895     var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
896     var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
897     if( (p_meta_user = vlc_meta_New()) )
898     {
899         vlc_value_t val;
900
901         var_Get( p_input, "meta-title", &val );
902         if( val.psz_string && *val.psz_string )
903             vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
904         if( val.psz_string ) free( val.psz_string );
905         var_Get( p_input, "meta-author", &val );
906         if( val.psz_string && *val.psz_string )
907             vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
908         if( val.psz_string ) free( val.psz_string );
909         var_Get( p_input, "meta-artist", &val );
910         if( val.psz_string && *val.psz_string )
911             vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
912         if( val.psz_string ) free( val.psz_string );
913         var_Get( p_input, "meta-genre", &val );
914         if( val.psz_string && *val.psz_string )
915             vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
916         if( val.psz_string ) free( val.psz_string );
917         var_Get( p_input, "meta-copyright", &val );
918         if( val.psz_string && *val.psz_string )
919             vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
920         if( val.psz_string ) free( val.psz_string );
921         var_Get( p_input, "meta-description", &val );
922         if( val.psz_string && *val.psz_string )
923             vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
924         if( val.psz_string ) free( val.psz_string );
925         var_Get( p_input, "meta-date", &val );
926         if( val.psz_string && *val.psz_string )
927             vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
928         if( val.psz_string ) free( val.psz_string );
929         var_Get( p_input, "meta-url", &val );
930         if( val.psz_string && *val.psz_string )
931             vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
932         if( val.psz_string ) free( val.psz_string );
933     }
934
935     /* Get meta informations from demuxer */
936     if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
937         ( p_meta_user && p_meta_user->i_meta ) )
938     {
939         playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_input,
940                                          VLC_OBJECT_PLAYLIST,  FIND_PARENT);
941         playlist_item_t *p_item = NULL;
942         input_info_category_t *p_cat;
943         int i;
944
945         /* Merge demux and user metadata */
946         if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
947         else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );
948
949         if( p_playlist )
950         {
951             vlc_mutex_lock( &p_playlist->object_lock );
952             p_item = playlist_ItemGetByPos( p_playlist, -1 );
953             if( p_item )
954             {
955                 vlc_mutex_lock( &p_item->lock );
956             }
957             vlc_mutex_unlock( &p_playlist->object_lock );
958         }
959
960         msg_Dbg( p_input, "meta informations:" );
961         if( p_meta->i_meta > 0 )
962         {
963             p_cat = input_InfoCategory( p_input, _("File") );
964             for( i = 0; i < p_meta->i_meta; i++ )
965             {
966                 msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
967                          p_meta->value[i] );
968                 if( !strcmp( p_meta->name[i], VLC_META_TITLE ) )
969                 {
970                     playlist_ItemSetName( p_item, p_meta->value[i] );
971                 }
972                 if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
973                 {
974                     playlist_ItemAddInfo( p_item, _("General"), _("Author"),
975                                           p_meta->value[i] );
976                 }
977                 input_AddInfo( p_cat, _(p_meta->name[i]), "%s",
978                                p_meta->value[i] );
979                 if( p_item )
980                 {
981                     playlist_ItemAddInfo( p_item, _("File"),
982                                           _(p_meta->name[i]), "%s",
983                                           p_meta->value[i] );
984                 }
985             }
986         }
987         for( i = 0; i < p_meta->i_track; i++ )
988         {
989             vlc_meta_t *tk = p_meta->track[i];
990             int j;
991
992             msg_Dbg( p_input, "  - track[%d]:", i );
993             if( tk->i_meta > 0 )
994             {
995                 char *psz_cat = malloc( strlen(_("Stream")) + 10 );
996                 sprintf( psz_cat, "%s %d", _("Stream"), i );
997                 p_cat = input_InfoCategory( p_input, psz_cat );
998
999                 for( j = 0; j < tk->i_meta; j++ )
1000                 {
1001                     msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
1002                              tk->value[j] );
1003                     input_AddInfo( p_cat, _(tk->name[j]), "%s", tk->value[j] );
1004                     if( p_item )
1005                     {
1006                         playlist_ItemAddInfo( p_item, psz_cat, _(tk->name[j]),
1007                                               "%s", tk->value[j] );
1008                     }
1009                 }
1010             }
1011         }
1012
1013         if( p_item )
1014         {
1015             vlc_mutex_unlock( &p_item->lock );
1016         }
1017         if( p_playlist ) vlc_object_release( p_playlist );
1018
1019         if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
1020         {
1021             p_input->stream.p_sout->p_meta = p_meta;
1022         }
1023         else
1024         {
1025             vlc_meta_Delete( p_meta );
1026         }
1027     }
1028     if( p_meta_user ) vlc_meta_Delete( p_meta_user );
1029
1030     /* Get length */
1031     if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
1032         i_length > 0 )
1033     {
1034         input_info_category_t *p_cat =
1035             input_InfoCategory( p_input, _("File") );
1036         p_playlist =
1037             (playlist_t*)vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1038                                           FIND_PARENT );
1039         if( p_playlist )
1040         {
1041             playlist_SetDuration( p_playlist, -1 , i_length );
1042             val.b_bool = p_playlist->i_index;
1043             var_Set( p_playlist, "item-change", val );
1044             vlc_object_release( p_playlist );
1045         }
1046         if( p_cat )
1047         {
1048             char psz_buffer[MSTRTIME_MAX_SIZE];
1049             input_AddInfo( p_cat, _("Duration"),
1050                            msecstotimestr( psz_buffer, i_length / 1000 ) );
1051         }
1052
1053         /* Set start time */
1054         var_Get( p_input, "start-time", &val );
1055         if(  val.i_int > 0 )
1056         {
1057             double f_pos = val.i_int * I64C(1000000) / (double)i_length;
1058
1059             if( f_pos >= 1.0 )
1060             {
1061                 msg_Warn( p_input, "invalid start-time, ignored (start-time "
1062                           ">= media length)" );
1063             }
1064             else
1065             {
1066                 p_input->stream.p_selected_area->i_seek =
1067                     (int64_t)( f_pos * (double)p_input->stream.p_selected_area->i_size );
1068
1069                 msg_Dbg( p_input, "start-time %ds (%2.2f)", val.i_int, f_pos );
1070             }
1071         }
1072     }
1073
1074     /* Set stop-time and check validity */
1075     var_Get( p_input, "stop-time", &val );
1076     if( val.i_int > 0 )
1077     {
1078         vlc_value_t start;
1079
1080         var_Get( p_input, "start-time", &start );
1081         if( start.i_int >= val.i_int )
1082         {
1083             msg_Warn( p_input, "invalid stop-time, ignored (stop-time < "
1084                       "start-time)" );
1085         }
1086         else
1087         {
1088             p_input->p_sys->i_stop_time = (int64_t)val.i_int * I64C(1000000);
1089             msg_Dbg( p_input, "stop-time %ds", val.i_int );
1090         }
1091     }
1092
1093     /* Get fps */
1094     if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
1095     {
1096         i_microsecondperframe = 0;
1097     }
1098     else
1099     {
1100         i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
1101     }
1102
1103     /* Look for and add subtitle files */
1104     var_Get( p_input, "sub-file", &val );
1105     if( val.psz_string && *val.psz_string )
1106     {
1107         subtitle_demux_t *p_sub;
1108
1109         msg_Dbg( p_input, "force subtitle: %s", val.psz_string );
1110         if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string),
1111                                     i_microsecondperframe ) ) )
1112         {
1113             p_sub_toselect = p_sub;
1114             TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
1115         }
1116     }
1117     psz_sub_file = val.psz_string;
1118
1119     var_Get( p_input, "sub-autodetect-file", &val );
1120     if( val.b_bool )
1121     {
1122         subtitle_demux_t *p_sub;
1123         int i;
1124         char **tmp = subtitles_Detect( p_input, "", p_input->psz_name );
1125         char **tmp2 = tmp;
1126         for( i = 0; *tmp2 != NULL; i++ )
1127         {
1128             if( psz_sub_file == NULL || strcmp( psz_sub_file, *tmp2 ) )
1129             {
1130                 if( ( p_sub = subtitle_New( p_input, *tmp2,
1131                                             i_microsecondperframe ) ) )
1132                 {
1133                     TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub,
1134                                 p_sub );
1135                 }
1136             }
1137             free( *tmp2++ );
1138         }
1139         free( tmp );
1140     }
1141     if( psz_sub_file ) free( psz_sub_file );
1142
1143     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
1144     val.b_bool =  VLC_FALSE;
1145     if( p_input->stream.p_sout )
1146     {
1147         var_Get( p_input, "sout-all", &val );
1148     }
1149     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
1150                     val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
1151     if( p_sub_toselect )
1152     {
1153         es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
1154                         p_sub_toselect->p_es, VLC_TRUE );
1155     }
1156
1157     if( p_input->stream.p_sout )
1158     {
1159         if( p_input->stream.p_sout->i_out_pace_nocontrol > 0 )
1160         {
1161             p_input->b_out_pace_control = VLC_FALSE;
1162         }
1163         else
1164         {
1165             p_input->b_out_pace_control = VLC_TRUE;
1166         }
1167         msg_Dbg( p_input, "starting in %s mode",
1168                  p_input->b_out_pace_control ? "asynch" : "synch" );
1169     }
1170
1171     return VLC_SUCCESS;
1172 }
1173
1174 /*****************************************************************************
1175  * ErrorThread: RunThread() error loop
1176  *****************************************************************************
1177  * This function is called when an error occured during thread main's loop.
1178  *****************************************************************************/
1179 static void ErrorThread( input_thread_t *p_input )
1180 {
1181     while( !p_input->b_die )
1182     {
1183         /* Sleep a while */
1184         msleep( INPUT_IDLE_SLEEP );
1185     }
1186 }
1187
1188 /*****************************************************************************
1189  * EndThread: end the input thread
1190  *****************************************************************************/
1191 static void EndThread( input_thread_t * p_input )
1192 {
1193     int i;
1194 #ifdef HAVE_SYS_TIMES_H
1195     /* Display statistics */
1196     struct tms  cpu_usage;
1197     times( &cpu_usage );
1198
1199     msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
1200              p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
1201 #else
1202     msg_Dbg( p_input, "%ld loops", p_input->c_loops );
1203 #endif
1204
1205     input_DumpStream( p_input );
1206
1207     /* Free demultiplexer's data */
1208     if( p_input->p_demux ) module_Unneed( p_input, p_input->p_demux );
1209
1210     /* Free all ES and destroy all decoder threads */
1211     input_EndStream( p_input );
1212
1213     /* Close optional stream output instance */
1214     if( p_input->stream.p_sout )
1215     {
1216         vlc_object_t *p_pl =
1217             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1218         vlc_value_t keep;
1219
1220         if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
1221         {
1222             /* attach sout to the playlist */
1223             msg_Warn( p_input, "keeping sout" );
1224             vlc_object_detach( p_input->stream.p_sout );
1225             vlc_object_attach( p_input->stream.p_sout, p_pl );
1226         }
1227         else
1228         {
1229             msg_Warn( p_input, "destroying sout" );
1230             sout_DeleteInstance( p_input->stream.p_sout );
1231         }
1232         if( p_pl )
1233         {
1234             vlc_object_release( p_pl );
1235         }
1236     }
1237
1238     /* Destroy subtitles demuxers */
1239     if( p_input->p_sys )
1240     {
1241         for( i = 0; i < p_input->p_sys->i_sub; i++ )
1242         {
1243             subtitle_Close( p_input->p_sys->sub[i] );
1244         }
1245         if( p_input->p_sys->i_sub > 0 )
1246         {
1247             free( p_input->p_sys->sub );
1248         }
1249
1250         /* Free input_thread_sys_t */
1251         free( p_input->p_sys );
1252     }
1253
1254     /* Destroy the stream_t facilities */
1255     if( p_input->s ) input_StreamDelete( p_input->s );
1256
1257     /* Destroy es out */
1258     if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
1259
1260     /* Close the access plug-in */
1261     if( p_input->p_access ) module_Unneed( p_input, p_input->p_access );
1262
1263     input_AccessEnd( p_input );
1264
1265     /* Free info structures XXX destroy es before 'cause vorbis */
1266     msg_Dbg( p_input, "freeing info structures...");
1267     input_DelInfo( p_input );
1268
1269     free( p_input->psz_source );
1270     if( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
1271
1272     /* Tell we're dead */
1273     p_input->b_dead = 1;
1274 }
1275
1276 /*****************************************************************************
1277  * ParseOption: parses the options for the input
1278  *****************************************************************************
1279  * This function parses the input (config) options and creates their associated
1280  * object variables.
1281  * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
1282  * bar is the value of the option.
1283  *****************************************************************************/
1284 static void ParseOption( input_thread_t *p_input, const char *psz_option )
1285 {
1286     char *psz_name = (char *)psz_option;
1287     char *psz_value = strchr( psz_option, '=' );
1288     int  i_name_len, i_type;
1289     vlc_bool_t b_isno = VLC_FALSE;
1290     vlc_value_t val;
1291
1292     if( psz_value ) i_name_len = psz_value - psz_option;
1293     else i_name_len = strlen( psz_option );
1294
1295     /* It's too much of an hassle to remove the ':' when we parse
1296      * the cmd line :) */
1297     if( i_name_len && *psz_name == ':' )
1298     {
1299         psz_name++;
1300         i_name_len--;
1301     }
1302
1303     if( i_name_len == 0 ) return;
1304
1305     psz_name = strndup( psz_name, i_name_len );
1306     if( psz_value ) psz_value++;
1307
1308     i_type = config_GetType( p_input, psz_name );
1309
1310     if( !i_type && !psz_value )
1311     {
1312         /* check for "no-foo" or "nofoo" */
1313         if( !strncmp( psz_name, "no-", 3 ) )
1314         {
1315             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1316         }
1317         else if( !strncmp( psz_name, "no", 2 ) )
1318         {
1319             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1320         }
1321         else goto cleanup;           /* Option doesn't exist */
1322
1323         b_isno = VLC_TRUE;
1324         i_type = config_GetType( p_input, psz_name );
1325
1326         if( !i_type ) goto cleanup;  /* Option doesn't exist */
1327     }
1328     else if( !i_type ) goto cleanup; /* Option doesn't exist */
1329
1330     if( ( i_type != VLC_VAR_BOOL ) &&
1331         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1332
1333     /* Create the variable in the input object.
1334      * Children of the input object will be able to retreive this value
1335      * thanks to the inheritance property of the object variables. */
1336     var_Create( p_input, psz_name, i_type );
1337
1338     switch( i_type )
1339     {
1340     case VLC_VAR_BOOL:
1341         val.b_bool = !b_isno;
1342         break;
1343
1344     case VLC_VAR_INTEGER:
1345         val.i_int = atoi( psz_value );
1346         break;
1347
1348     case VLC_VAR_FLOAT:
1349         val.f_float = atof( psz_value );
1350         break;
1351
1352     case VLC_VAR_STRING:
1353     case VLC_VAR_MODULE:
1354     case VLC_VAR_FILE:
1355     case VLC_VAR_DIRECTORY:
1356         val.psz_string = psz_value;
1357         break;
1358
1359     default:
1360         goto cleanup;
1361         break;
1362     }
1363
1364     var_Set( p_input, psz_name, val );
1365
1366     msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );
1367
1368   cleanup:
1369     if( psz_name ) free( psz_name );
1370     return;
1371 }
1372
1373 /*****************************************************************************
1374  * Callbacks  (position, time, state, rate )
1375  *****************************************************************************/
1376 static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
1377                              vlc_value_t oldval, vlc_value_t newval,
1378                              void *p_data )
1379 {
1380     input_thread_t *p_input = (input_thread_t *)p_this;
1381
1382     msg_Dbg( p_input, "cmd=%s old=%f new=%f", psz_cmd,
1383              oldval.f_float, newval.f_float );
1384
1385     if( !strcmp( psz_cmd, "position-offset" ) )
1386     {
1387         vlc_value_t val;
1388         var_Get( p_input, "position", &val );
1389
1390         newval.f_float += val.f_float;
1391     }
1392
1393     vlc_mutex_lock( &p_input->stream.stream_lock );
1394     p_input->stream.p_selected_area->i_seek =
1395         (int64_t)( newval.f_float *
1396                    (double)p_input->stream.p_selected_area->i_size );
1397
1398     if( p_input->stream.p_selected_area->i_seek < 0 )
1399     {
1400         p_input->stream.p_selected_area->i_seek = 0;
1401     }
1402     vlc_mutex_unlock( &p_input->stream.stream_lock );
1403
1404     return VLC_SUCCESS;
1405 }
1406
1407 static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
1408                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1409 {
1410     input_thread_t *p_input = (input_thread_t *)p_this;
1411     vlc_value_t     val;
1412
1413     /* FIXME TODO FIXME */
1414     msg_Dbg( p_input, "cmd=%s old=%lld new=%lld", psz_cmd,
1415              oldval.i_time, newval.i_time );
1416
1417     var_Get( p_input, "length", &val );
1418     if( val.i_time > 0 )
1419     {
1420         val.f_float = (double)newval.i_time / (double)val.i_time;
1421         if( !strcmp( psz_cmd, "time-offset" ) )
1422         {
1423             var_Set( p_input, "position-offset", val );
1424         }
1425         else
1426         {
1427             var_Set( p_input, "position", val );
1428         }
1429     }
1430     else
1431     {
1432         msg_Warn( p_input, "TimeCallback: length <= 0 -> can't seek" );
1433     }
1434     return VLC_SUCCESS;
1435 }
1436
1437 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
1438                           vlc_value_t oldval, vlc_value_t newval,
1439                           void *p_data )
1440 {
1441     input_thread_t *p_input = (input_thread_t *)p_this;
1442
1443     msg_Dbg( p_input, "cmd=%s old=%d new=%d",
1444              psz_cmd, oldval.i_int, newval.i_int );
1445
1446     switch( newval.i_int )
1447     {
1448         case PLAYING_S:
1449             input_SetStatus( p_input, INPUT_STATUS_PLAY );
1450             return VLC_SUCCESS;
1451         case PAUSE_S:
1452             input_SetStatus( p_input, INPUT_STATUS_PAUSE );
1453             return VLC_SUCCESS;
1454         case END_S:
1455             input_SetStatus( p_input, INPUT_STATUS_END );
1456             return VLC_SUCCESS;
1457         default:
1458             msg_Err( p_input, "cannot set new state (invalid)" );
1459             return VLC_EGENERIC;
1460     }
1461 }
1462
1463 static int RateCallback( vlc_object_t *p_this, char const *psz_cmd,
1464                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1465 {
1466     input_thread_t *p_input = (input_thread_t *)p_this;
1467
1468     if( !strcmp( psz_cmd, "rate-slower" ) )
1469     {
1470         input_SetStatus( p_input, INPUT_STATUS_SLOWER );
1471     }
1472     else if( !strcmp( psz_cmd, "rate-faster" ) )
1473     {
1474         input_SetStatus( p_input, INPUT_STATUS_FASTER );
1475     }
1476     else
1477     {
1478         msg_Dbg( p_input, "cmd=%s old=%d new=%d",
1479                  psz_cmd, oldval.i_int, newval.i_int );
1480         input_SetRate( p_input, newval.i_int );
1481     }
1482     return VLC_SUCCESS;
1483 }
1484
1485 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
1486                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1487 {
1488     input_thread_t *p_input = (input_thread_t *)p_this;
1489     return input_Control( p_input, INPUT_SET_BOOKMARK, newval );
1490 }