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