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