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