]> git.sesse.net Git - vlc/blob - src/input/input.c
* all: - added a boolean "seekable" object variable to p_input.
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  *****************************************************************************
4  * Copyright (C) 1998-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/decoder.h>
33 #include <vlc/vout.h>
34
35 #include "input_internal.h"
36
37 #include "stream_output.h"
38
39 #include "vlc_interface.h"
40 #include "vlc_meta.h"
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static  int Run  ( input_thread_t *p_input );
46
47 static  int Init ( input_thread_t *p_input );
48 static void Error( input_thread_t *p_input );
49 static void End  ( input_thread_t *p_input );
50
51 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
52 static void       ControlReduce( input_thread_t * );
53 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
54
55
56 static void UpdateFromAccess( input_thread_t * );
57 static void UpdateFromDemux( input_thread_t * );
58
59 static void ParseOption( input_thread_t *p_input, const char *psz_option );
60
61 static void DecodeUrl  ( char * );
62
63 /*****************************************************************************
64  * input_CreateThread: creates a new input thread
65  *****************************************************************************
66  * This function creates a new input, and returns a pointer
67  * to its description. On error, it returns NULL.
68  *
69  * Variables for _public_ use:
70  * * Get and Set:
71  *  - state
72  *  - rate,rate-slower, rate-faster
73  *  - position, position-offset
74  *  - time, time-offset
75  *  - title,title-next,title-prev
76  *  - chapter,chapter-next, chapter-prev
77  *  - program, audio-es, video-es, spu-es
78  *  - audio-delay, spu-delay
79  *  - bookmark
80  * * Get only:
81  *  - length
82  *  - bookmarks
83  *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
84  * * For intf callback upon changes
85  *  - intf-change
86  * TODO explain when Callback is called
87  * TODO complete this list (?)
88  *****************************************************************************/
89 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
90                                       input_item_t *p_item )
91
92 {
93     input_thread_t *p_input;                        /* thread descriptor */
94     int             i;
95
96     /* Allocate descriptor */
97     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
98     if( p_input == NULL )
99     {
100         msg_Err( p_parent, "out of memory" );
101         return NULL;
102     }
103
104     /* Init Common fields */
105     p_input->b_eof = VLC_FALSE;
106     p_input->b_can_pace_control = VLC_TRUE;
107     p_input->i_start = 0;
108     p_input->i_time  = 0;
109     p_input->i_stop  = 0;
110     p_input->i_title = 0;
111     p_input->title   = NULL;
112     p_input->i_state = INIT_S;
113     p_input->i_rate  = INPUT_RATE_DEFAULT;
114     p_input->i_bookmark = 0;
115     p_input->bookmark = NULL;
116     p_input->p_es_out = NULL;
117     p_input->p_sout  = NULL;
118     p_input->b_out_pace_control = VLC_FALSE;
119     p_input->i_pts_delay = 0;
120
121
122     /* Init Input fields */
123     p_input->input.p_item = p_item;
124     p_input->input.p_access = NULL;
125     p_input->input.p_stream = NULL;
126     p_input->input.p_demux  = NULL;
127     p_input->input.b_title_demux = VLC_FALSE;
128     p_input->input.i_title  = 0;
129     p_input->input.title    = NULL;
130     p_input->input.b_can_pace_control = VLC_TRUE;
131     p_input->input.b_eof = VLC_FALSE;
132     p_input->input.i_cr_average = 0;
133
134     /* Init control buffer */
135     vlc_mutex_init( p_input, &p_input->lock_control );
136     p_input->i_control = 0;
137     p_input->p_sys = NULL;
138
139     /* Parse input options */
140     vlc_mutex_lock( &p_item->lock );
141     for( i = 0; i < p_item->i_options; i++ )
142     {
143         msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
144         ParseOption( p_input, p_item->ppsz_options[i] );
145     }
146     vlc_mutex_unlock( &p_item->lock );
147
148     /* Create Object Variables for private use only */
149     input_ConfigVarInit( p_input );
150
151     /* Create Objects variables for public Get and Set */
152     input_ControlVarInit( p_input );
153     p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
154
155 #if 0
156     /* TODO */
157     var_Get( p_input, "bookmarks", &val );
158     if( val.psz_string )
159     {
160         /* FIXME: have a common cfg parsing routine used by sout and others */
161         char *psz_parser, *psz_start, *psz_end;
162         psz_parser = val.psz_string;
163         while( (psz_start = strchr( psz_parser, '{' ) ) )
164         {
165             seekpoint_t seekpoint;
166             char backup;
167             psz_start++;
168             psz_end = strchr( psz_start, '}' );
169             if( !psz_end ) break;
170             psz_parser = psz_end + 1;
171             backup = *psz_parser;
172             *psz_parser = 0;
173             *psz_end = ',';
174
175             seekpoint.psz_name = 0;
176             seekpoint.i_byte_offset = 0;
177             seekpoint.i_time_offset = 0;
178             while( (psz_end = strchr( psz_start, ',' ) ) )
179             {
180                 *psz_end = 0;
181                 if( !strncmp( psz_start, "name=", 5 ) )
182                 {
183                     seekpoint.psz_name = psz_start + 5;
184                 }
185                 else if( !strncmp( psz_start, "bytes=", 6 ) )
186                 {
187                     seekpoint.i_byte_offset = atoll(psz_start + 6);
188                 }
189                 else if( !strncmp( psz_start, "time=", 5 ) )
190                 {
191                     seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
192                 }
193                 psz_start = psz_end + 1;
194             }
195             msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
196                      seekpoint.psz_name, seekpoint.i_byte_offset,
197                      seekpoint.i_time_offset );
198             input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
199             *psz_parser = backup;
200         }
201         free( val.psz_string );
202     }
203 #endif
204
205     /* Now we can attach our new input */
206     vlc_object_attach( p_input, p_parent );
207
208     /* Create thread and wait for its readiness. */
209     if( vlc_thread_create( p_input, "input", Run,
210                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
211     {
212         msg_Err( p_input, "cannot create input thread" );
213         vlc_object_detach( p_input );
214         vlc_object_destroy( p_input );
215         return NULL;
216     }
217
218     return p_input;
219 }
220
221 /*****************************************************************************
222  * input_StopThread: mark an input thread as zombie
223  *****************************************************************************
224  * This function should not return until the thread is effectively cancelled.
225  *****************************************************************************/
226 void input_StopThread( input_thread_t *p_input )
227 {
228     vlc_list_t *p_list;
229     int i;
230
231     /* Set die for input */
232     p_input->b_die = VLC_TRUE;
233
234     /* We cannot touch p_input fields directly (we can from another thread),
235      * so use the vlc_object_find way, it's perfectly safe */
236
237     /* Set die for all access */
238     p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
239     for( i = 0; i < p_list->i_count; i++ )
240     {
241         p_list->p_values[i].p_object->b_die = VLC_TRUE;
242     }
243     vlc_list_release( p_list );
244
245     /* Set die for all stream */
246     p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
247     for( i = 0; i < p_list->i_count; i++ )
248     {
249         p_list->p_values[i].p_object->b_die = VLC_TRUE;
250     }
251     vlc_list_release( p_list );
252
253     /* Set die for all demux */
254     p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
255     for( i = 0; i < p_list->i_count; i++ )
256     {
257         p_list->p_values[i].p_object->b_die = VLC_TRUE;
258     }
259     vlc_list_release( p_list );
260
261     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
262 }
263
264 /*****************************************************************************
265  * input_DestroyThread: mark an input thread as zombie
266  *****************************************************************************
267  * This function should not return until the thread is effectively cancelled.
268  *****************************************************************************/
269 void input_DestroyThread( input_thread_t *p_input )
270 {
271     /* Join the thread */
272     vlc_thread_join( p_input );
273
274     /* Delete input lock (only after thread joined) */
275     vlc_mutex_destroy( &p_input->lock_control );
276
277     /* TODO: maybe input_DestroyThread should also delete p_input instead
278      * of the playlist but I'm not sure if it's possible */
279 }
280
281 /*****************************************************************************
282  * Run: main thread loop
283  *****************************************************************************
284  * Thread in charge of processing the network packets and demultiplexing.
285  *
286  * TODO:
287  *  read subtitle support (XXX take care of spu-delay in the right way).
288  *  multi-input support (XXX may be done with subs)
289  *****************************************************************************/
290 static int Run( input_thread_t *p_input )
291 {
292     int64_t i_intf_update = 0;
293
294     /* Signal that the thread is launched */
295     vlc_thread_ready( p_input );
296
297     if( Init( p_input ) )
298     {
299         /* If we failed, wait before we are killed, and exit */
300         p_input->b_error = VLC_TRUE;
301
302         Error( p_input );
303
304         /* Tell we're dead */
305         p_input->b_dead = VLC_TRUE;
306
307         return 0;
308     }
309
310     /* Main loop */
311     while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
312     {
313         vlc_bool_t b_force_update = VLC_FALSE;
314         int i_ret;
315         int i_type;
316         vlc_value_t val;
317
318         /* Do the read */
319         if( p_input->i_state != PAUSE_S  )
320         {
321             if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
322                 i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
323             else
324                 i_ret = 0;  /* EOF */
325
326             if( i_ret > 0 )
327             {
328                 /* TODO */
329                 if( p_input->input.b_title_demux &&
330                     p_input->input.p_demux->info.i_update )
331                 {
332                     UpdateFromDemux( p_input );
333                     b_force_update = VLC_TRUE;
334                 }
335                 else if( !p_input->input.b_title_demux &&
336                           p_input->input.p_access &&
337                           p_input->input.p_access->info.i_update )
338                 {
339                     UpdateFromAccess( p_input );
340                     b_force_update = VLC_TRUE;
341                 }
342             }
343             else if( i_ret == 0 )    /* EOF */
344             {
345                 vlc_value_t repeat;
346
347                 var_Get( p_input, "input-repeat", &repeat );
348                 if( repeat.i_int == 0 )
349                 {
350                     /* End of file - we do not set b_die because only the
351                      * playlist is allowed to do so. */
352                     msg_Dbg( p_input, "EOF reached" );
353                     p_input->b_eof = VLC_TRUE;
354                     p_input->input.b_eof = VLC_TRUE;
355                 }
356                 else
357                 {
358                     msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
359                     if( repeat.i_int > 0 )
360                     {
361                         repeat.i_int--;
362                         var_Set( p_input, "input-repeat", repeat );
363                     }
364
365                     /* Seek to title 0 position 0(start) */
366                     val.i_int = 0;
367                     input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
368                     if( p_input->i_start > 0 )
369                     {
370                         val.i_time = p_input->i_start;
371                         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
372                                            &val );
373                     }
374                     else
375                     {
376                         val.f_float = 0.0;
377                         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
378                                            &val );
379                     }
380                 }
381             }
382             else if( i_ret < 0 )
383             {
384                 p_input->b_error = VLC_TRUE;
385             }
386         }
387         else
388         {
389             /* Small wait */
390             msleep( 10*1000 );
391         }
392
393         /* Handle control */
394         vlc_mutex_lock( &p_input->lock_control );
395         ControlReduce( p_input );
396         while( !ControlPopNoLock( p_input, &i_type, &val ) )
397         {
398             msg_Dbg( p_input, "control type=%d", i_type );
399             if( Control( p_input, i_type, val ) )
400                 b_force_update = VLC_TRUE;
401         }
402         vlc_mutex_unlock( &p_input->lock_control );
403
404         if( b_force_update ||
405             i_intf_update < mdate() )
406         {
407             vlc_value_t val;
408             double f_pos;
409             int64_t i_time, i_length;
410             /* update input status variables */
411             if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos ) )
412             {
413                 val.f_float = (float)f_pos;
414                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
415             }
416             if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
417             {
418                 p_input->i_time = i_time;
419                 val.i_time = i_time;
420                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
421             }
422             if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &i_length ) )
423             {
424                 vlc_value_t old_val;
425                 var_Get( p_input, "length", &old_val );
426                 val.i_time = i_length;
427                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
428
429                 if( old_val.i_time != val.i_time )
430                 {
431                     /* TODO */
432 #if 0
433                     char psz_buffer[MSTRTIME_MAX_SIZE];
434
435                     vlc_mutex_lock( &p_input->p_item->lock );
436                     p_input->p_item->i_duration = i_length;
437                     vlc_mutex_unlock( &p_input->p_item->lock );
438
439                     input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
440                        msecstotimestr( psz_buffer, i_length / 1000 ) );
441 #endif
442                 }
443             }
444
445             var_SetBool( p_input, "intf-change", VLC_TRUE );
446             i_intf_update = mdate() + I64C(150000);
447         }
448     }
449
450     /* Wait we are asked to die */
451     if( !p_input->b_die )
452     {
453         Error( p_input );
454     }
455
456     /* Clean up */
457     End( p_input );
458
459     return 0;
460
461 #if 0
462     while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
463     {
464         if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
465         {
466             if( p_input->stream.p_selected_area->i_size > 0 )
467             {
468                 unsigned int i;
469                 mtime_t      i_time;
470                 double f = (double)p_input->stream.p_selected_area->i_seek /
471                            (double)p_input->stream.p_selected_area->i_size;
472
473                 vlc_mutex_unlock( &p_input->stream.stream_lock );
474                 demux_Control( p_input, DEMUX_SET_POSITION, f );
475                 vlc_mutex_lock( &p_input->stream.stream_lock );
476
477                 /* Escape all decoders for the stream discontinuity they
478                  * will encounter. */
479                 input_EscapeDiscontinuity( p_input );
480
481                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
482                 {
483                     pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
484
485                     /* Reinitialize synchro. */
486                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
487                 }
488
489                 vlc_mutex_unlock( &p_input->stream.stream_lock );
490                 if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
491                 {
492                     int i;
493                     vlc_value_t val;
494
495                     /* Help in bar display */
496                     val.i_time = i_time;
497                     var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
498
499                     /* Seek subs */
500                     for( i = 0; i < p_input->p_sys->i_sub; i++ )
501                     {
502                         subtitle_Seek( p_input->p_sys->sub[i], i_time );
503                     }
504                 }
505                 if( !demux_Control( p_input, DEMUX_GET_POSITION, &f ) )
506                 {
507                     val.f_float = (float)f;
508                     var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
509                 }
510                 vlc_mutex_lock( &p_input->stream.stream_lock );
511             }
512             p_input->stream.p_selected_area->i_seek = NO_SEEK;
513         }
514
515         /* Read and demultiplex some data. */
516         i_count = p_input->pf_demux( p_input );
517
518         XXXXX
519
520         if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
521         {
522             int i;
523             mtime_t i_time;
524             mtime_t i_length;
525             double  d_pos;
526
527             /* update input status variables */
528             if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
529             {
530                 val.f_float = (float)d_pos;
531                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
532             }
533             if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
534             {
535                 val.i_time = i_time;
536                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
537             }
538             if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
539             {
540                 vlc_value_t old_val;
541                 var_Get( p_input, "length", &old_val );
542                 val.i_time = i_length;
543                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
544                 if( old_val.i_time != val.i_time )
545                 {
546                     char psz_buffer[MSTRTIME_MAX_SIZE];
547
548                     vlc_mutex_lock( &p_input->p_item->lock );
549                     p_input->p_item->i_duration = i_length;
550                     vlc_mutex_unlock( &p_input->p_item->lock );
551
552                     input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
553                        msecstotimestr( psz_buffer, i_length / 1000 ) );
554                 }
555             }
556
557             /* Check stop-time */
558             if( p_input->p_sys->i_stop_time > 0 && p_input->p_sys->i_stop_time < i_time )
559             {
560                 msg_Warn( p_input, "EOF reached because of stop-time" );
561                 p_input->b_eof = 1;
562             }
563
564             /* update subs */
565             for( i = 0; i < p_input->p_sys->i_sub; i++ )
566             {
567                 subtitle_Demux( p_input->p_sys->sub[i], i_time );
568             }
569
570             i_update_next = mdate() + I64C(150000);
571         }
572     }
573
574     if( p_input->b_error || p_input->b_eof )
575     {
576         ErrorThread( p_input );
577     }
578
579     EndThread( p_input );
580
581     return 0;
582 #endif
583 }
584
585 /*****************************************************************************
586  * Init: init the input Thread
587  *****************************************************************************/
588 static int Init( input_thread_t * p_input )
589 {
590     char *psz_dup = strdup( p_input->input.p_item->psz_uri );
591     char *psz_access = NULL;
592     char *psz_demux  = NULL;
593     char *psz_path   = NULL;
594     char *psz;
595     vlc_value_t val;
596
597     /* Open access/stream/demux */
598     psz = strchr( psz_dup, ':' );
599 #if defined( WIN32 ) || defined( UNDER_CE )
600     if( psz - psz_dup == 1 )
601     {
602         msg_Warn( p_input, "drive letter %c: found in source string", psz_dup[0] );
603         psz_path = psz_dup;
604     }
605     else
606 #endif
607     if( psz )
608     {
609         *psz++ = '\0';
610         if( psz[0] == '/' && psz[1] == '/' )
611             psz += 2;
612
613         psz_path = psz;
614
615         psz = strchr( psz_dup, '/' );
616         if( psz )
617         {
618             *psz++ = '\0';
619             psz_demux = psz;
620         }
621
622         psz_access = psz_dup;
623     }
624     else
625     {
626         psz_path = psz_dup;
627     }
628
629     if( psz_access == NULL ) psz_access = "";
630     if( psz_demux == NULL )  psz_demux = "";
631     if( psz_path == NULL )   psz_path = "";
632
633     msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
634             p_input->input.p_item->psz_uri,
635              psz_access, psz_demux, psz_path );
636
637     /* Initialize optional stream output. (before access/demuxer) */
638     psz = var_GetString( p_input, "sout" );
639     if( *psz )
640     {
641         p_input->p_sout = sout_NewInstance( p_input, psz );
642         if( p_input->p_sout == NULL )
643         {
644             msg_Err( p_input, "cannot start stream output instance, aborting" );
645             free( psz );
646             free( psz_dup );
647
648             return VLC_EGENERIC;
649         }
650     }
651     free( psz );
652
653     /* Create es out */
654     p_input->p_es_out = input_EsOutNew( p_input );
655     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
656     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
657
658     /* Try access_demux if no demux given */
659     if( *psz_access && *psz_demux == '\0' )
660     {
661         p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
662                                              NULL, p_input->p_es_out );
663     }
664
665     if( p_input->input.p_demux )
666     {
667         /* Get infos from access_demux */
668         demux2_Control( p_input->input.p_demux,
669                         DEMUX_GET_PTS_DELAY, &p_input->i_pts_delay );
670         p_input->input.b_title_demux = VLC_TRUE;
671         if( demux2_Control( p_input->input.p_demux,
672                             DEMUX_GET_TITLE_INFO,
673                             &p_input->input.title, &p_input->input.i_title ) )
674         {
675             p_input->input.i_title = 0;
676             p_input->input.title   = NULL;
677         }
678         demux2_Control( p_input->input.p_demux, DEMUX_CAN_CONTROL_PACE,
679                         &p_input->input.b_can_pace_control );
680         demux2_Control( p_input->input.p_demux, DEMUX_CAN_PAUSE,
681                         &p_input->input.b_can_pause );
682
683         /* FIXME todo
684         demux2_Control( p_input->input.p_demux, DEMUX_CAN_SEEK,
685                         &val.b_bool );
686         */
687     }
688     else
689     {
690         /* Now try a real access */
691         p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
692
693         /* Access failed, URL encoded ? */
694         if( p_input->input.p_access == NULL && strchr( psz_path, '%' ) )
695         {
696             DecodeUrl( psz_path );
697
698             msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
699                      psz_access, psz_demux, psz_path );
700
701             p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
702         }
703 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
704                         * are forbidden in filenames on Win32. */
705
706         /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
707         if( p_input->input.p_access == NULL &&
708             *psz_access == '\0' && ( *psz_demux || *psz_path ) )
709         {
710             free( psz_dup );
711             psz_dup = strdup( p_input->input.p_item->psz_uri );
712             psz_access = "";
713             psz_demux = "";
714             psz_path = psz_dup;
715
716             p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
717         }
718 #endif
719
720         if( p_input->input.p_access == NULL )
721         {
722             msg_Err( p_input, "no suitable access module for `%s'",
723                      p_input->input.p_item->psz_uri );
724             goto error;
725         }
726
727         /* Get infos from access */
728         access2_Control( p_input->input.p_access,
729                          ACCESS_GET_PTS_DELAY, &p_input->i_pts_delay );
730         p_input->input.b_title_demux = VLC_FALSE;
731         if( access2_Control( p_input->input.p_access,
732                              ACCESS_GET_TITLE_INFO,
733                              &p_input->input.title, &p_input->input.i_title ) )
734         {
735             p_input->input.i_title = 0;
736             p_input->input.title   = NULL;
737         }
738         access2_Control( p_input->input.p_access, ACCESS_CAN_CONTROL_PACE,
739                          &p_input->input.b_can_pace_control );
740         access2_Control( p_input->input.p_access, ACCESS_CAN_PAUSE,
741                          &p_input->input.b_can_pace_control );
742         access2_Control( p_input->input.p_access, ACCESS_CAN_SEEK,
743                          &val.b_bool );
744         var_Set( p_input, "seekable", val );
745
746         /* Create the stream_t */
747         p_input->input.p_stream = stream_AccessNew( p_input->input.p_access );
748         if( p_input->input.p_stream == NULL )
749         {
750             msg_Warn( p_input, "cannot create a stream_t from access" );
751             goto error;
752         }
753
754         /* Open a demuxer */
755         if( *psz_demux == '\0' && *p_input->input.p_access->psz_demux )
756         {
757             psz_demux = p_input->input.p_access->psz_demux;
758         }
759         p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
760                                              p_input->input.p_stream,
761                                              p_input->p_es_out );
762         if( p_input->input.p_demux == NULL )
763         {
764             msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
765                      psz_access, psz_demux, psz_path );
766             goto error;
767         }
768
769         /* TODO get title from demux */
770         if( p_input->input.i_title <= 0 )
771         {
772             if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TITLE_INFO,
773                                 &p_input->input.title, &p_input->input.i_title ) )
774             {
775                 p_input->input.i_title = 0;
776                 p_input->input.title   = NULL;
777             }
778             else
779             {
780                 p_input->input.b_title_demux = VLC_TRUE;
781             }
782         }
783     }
784     /* Create global title (for now, just a copy) */
785     p_input->i_title = p_input->input.i_title;
786     if( p_input->i_title > 0 )
787     {
788         int i;
789         p_input->title = malloc( sizeof( input_title_t *) * p_input->i_title );
790         for( i = 0; i < p_input->i_title; i++ )
791         {
792             p_input->title[i] = vlc_input_title_Duplicate( p_input->input.title[i] );
793         }
794
795         /* Setup variables */
796         input_ControlVarNavigation( p_input );
797         input_ControlVarTitle( p_input, 0 );
798     }
799     /* Global flag */
800     p_input->b_can_pace_control = p_input->input.b_can_pace_control;
801     p_input->b_can_pause        = p_input->input.b_can_pause;
802
803     /* Fix pts delay */
804     if( p_input->i_pts_delay <= 0 )
805         p_input->i_pts_delay = DEFAULT_PTS_DELAY;
806
807     /* If the desynchronisation requested by the user is < 0, we need to
808      * cache more data. */
809     var_Get( p_input, "audio-desync", &val );
810     if( val.i_int < 0 )
811         p_input->i_pts_delay -= (val.i_int * 1000);
812
813     /* Init input_thread_sys_t */
814     p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
815     p_input->p_sys->i_sub = 0;
816     p_input->p_sys->sub   = NULL;
817
818     /* TODO: check meta data from users */
819
820     /* TODO: get meta data from demuxer */
821
822     /* Init length */
823     if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &val.i_time ) && val.i_time > 0 )
824     {
825         var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
826         /* TODO update playlist meta data */
827     }
828     /* Start time*/
829     /* Set start time */
830     p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
831                        I64C(1000000);
832     p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
833                        I64C(1000000);
834
835     if( p_input->i_start > 0 )
836     {
837         if( p_input->i_start >= val.i_time )
838         {
839             msg_Warn( p_input, "invalid start-time ignored" );
840         }
841         else
842         {
843             vlc_value_t s;
844
845             msg_Dbg( p_input, "start-time: %ds",
846                      (int)( p_input->i_start / I64C(1000000) ) );
847
848             s.i_time = p_input->i_start;
849             input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
850         }
851     }
852     if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
853     {
854         msg_Warn( p_input, "invalid stop-time ignored" );
855         p_input->i_stop = 0;
856     }
857
858
859     /* TODO: do subtitle loading */
860
861
862     /* Set up es_out */
863     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
864     val.b_bool =  VLC_FALSE;
865     if( p_input->p_sout )
866     {
867         var_Get( p_input, "sout-all", &val );
868     }
869     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
870                     val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
871
872     /* TODO select forced subs */
873 #if 0
874     if( p_sub_toselect )
875     {
876         es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
877                         p_sub_toselect->p_es, VLC_TRUE );
878     }
879 #endif
880
881     if( p_input->p_sout )
882     {
883         if( p_input->p_sout->i_out_pace_nocontrol > 0 )
884         {
885             p_input->b_out_pace_control = VLC_FALSE;
886         }
887         else
888         {
889             p_input->b_out_pace_control = VLC_TRUE;
890         }
891         msg_Dbg( p_input, "starting in %s mode",
892                  p_input->b_out_pace_control ? "asynch" : "synch" );
893     }
894
895     msg_Dbg( p_input, "`%s' sucessfully opened",
896              p_input->input.p_item->psz_uri );
897
898     /* initialization is complete */
899     p_input->i_state = PLAYING_S;
900
901     val.i_int = PLAYING_S;
902     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
903
904     return VLC_SUCCESS;
905
906 error:
907     if( p_input->input.p_demux )
908         demux2_Delete( p_input->input.p_demux );
909
910     if( p_input->input.p_stream )
911         stream_AccessDelete( p_input->input.p_stream );
912
913     if( p_input->input.p_access )
914         access2_Delete( p_input->input.p_access );
915
916     if( p_input->p_es_out )
917         input_EsOutDelete( p_input->p_es_out );
918
919     if( p_input->p_sout )
920         sout_DeleteInstance( p_input->p_sout );
921
922     /* Mark them deleted */
923     p_input->input.p_demux = NULL;
924     p_input->input.p_stream = NULL;
925     p_input->input.p_access = NULL;
926     p_input->p_es_out = NULL;
927     p_input->p_sout = NULL;
928
929     return VLC_EGENERIC;
930
931 #if 0
932     vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
933 //    float f_fps;
934     double f_fps;
935     mtime_t i_length;
936
937     FIXME
938     p_input->input.i_cr_average = config_GetInt( p_input, "cr-average" );
939     p_input->stream.control.i_status = INIT_S;
940     p_input->stream.control.i_rate = DEFAULT_RATE;
941
942
943     /* Init input_thread_sys_t */
944     p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
945     p_input->p_sys->i_sub = 0;
946     p_input->p_sys->sub   = NULL;
947
948     /* Get meta information from user */
949     var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
950     var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
951     var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
952     var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
953     var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
954     var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
955     var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
956     var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
957     if( (p_meta_user = vlc_meta_New()) )
958     {
959         vlc_value_t val;
960
961         var_Get( p_input, "meta-title", &val );
962         if( *val.psz_string )
963             vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
964         free( val.psz_string );
965         var_Get( p_input, "meta-author", &val );
966         if( *val.psz_string )
967             vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
968         free( val.psz_string );
969         var_Get( p_input, "meta-artist", &val );
970         if( *val.psz_string )
971             vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
972         free( val.psz_string );
973         var_Get( p_input, "meta-genre", &val );
974         if( *val.psz_string )
975             vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
976         free( val.psz_string );
977         var_Get( p_input, "meta-copyright", &val );
978         if( *val.psz_string )
979             vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
980         free( val.psz_string );
981         var_Get( p_input, "meta-description", &val );
982         if( *val.psz_string )
983             vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
984         free( val.psz_string );
985         var_Get( p_input, "meta-date", &val );
986         if( *val.psz_string )
987             vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
988         free( val.psz_string );
989         var_Get( p_input, "meta-url", &val );
990         if( *val.psz_string )
991             vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
992         free( val.psz_string );
993     }
994
995     /* Get meta informations from demuxer */
996     if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
997         ( p_meta_user && p_meta_user->i_meta ) )
998     {
999         int i;
1000
1001         /* Merge demux and user metadata */
1002         if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
1003         else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );
1004
1005         msg_Dbg( p_input, "meta informations:" );
1006         if( p_meta->i_meta > 0 )
1007         {
1008             for( i = 0; i < p_meta->i_meta; i++ )
1009             {
1010                 msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
1011                          p_meta->value[i] );
1012                 if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
1013                     p_meta->value[i] )
1014                     input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
1015
1016                 if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
1017                     input_Control( p_input, INPUT_ADD_INFO, _("General"),
1018                                    _("Author"), p_meta->value[i] );
1019
1020                 input_Control( p_input, INPUT_ADD_INFO, _("File"),
1021                               _(p_meta->name[i]), "%s", p_meta->value[i] );
1022             }
1023         }
1024         for( i = 0; i < p_meta->i_track; i++ )
1025         {
1026             vlc_meta_t *tk = p_meta->track[i];
1027             int j;
1028
1029             msg_Dbg( p_input, "  - track[%d]:", i );
1030             if( tk->i_meta > 0 )
1031             {
1032                 char *psz_cat = malloc( strlen(_("Stream")) + 10 );
1033                 sprintf( psz_cat, "%s %d", _("Stream"), i );
1034
1035                 for( j = 0; j < tk->i_meta; j++ )
1036                 {
1037                     msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
1038                              tk->value[j] );
1039
1040                     input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1041                                    _(tk->name[j]), "%s", tk->value[j] );
1042                 }
1043             }
1044         }
1045
1046         if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
1047         {
1048             p_input->stream.p_sout->p_meta = p_meta;
1049         }
1050         else
1051         {
1052             vlc_meta_Delete( p_meta );
1053         }
1054     }
1055     if( p_meta_user ) vlc_meta_Delete( p_meta_user );
1056
1057     /* Get length */
1058     if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
1059         i_length > 0 )
1060     {
1061         char psz_buffer[MSTRTIME_MAX_SIZE];
1062
1063         vlc_mutex_lock( &p_input->p_item->lock );
1064         p_input->p_item->i_duration = i_length;
1065         vlc_mutex_unlock( &p_input->p_item->lock );
1066
1067         input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
1068                        msecstotimestr( psz_buffer, i_length / 1000 ) );
1069
1070         /* Set start time */
1071         var_Get( p_input, "start-time", &val );
1072         if(  val.i_int > 0 )
1073         {
1074             double f_pos = val.i_int * I64C(1000000) / (double)i_length;
1075
1076             if( f_pos >= 1.0 )
1077             {
1078                 msg_Warn( p_input, "invalid start-time, ignored (start-time "
1079                           ">= media length)" );
1080             }
1081             else
1082             {
1083                 p_input->stream.p_selected_area->i_seek =
1084                     (int64_t)( f_pos * (double)p_input->stream.p_selected_area->i_size );
1085
1086                 msg_Dbg( p_input, "start-time %ds (%2.2f)", val.i_int, f_pos );
1087             }
1088         }
1089     }
1090
1091     /* Get fps */
1092     if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
1093     {
1094         i_microsecondperframe = 0;
1095     }
1096     else
1097     {
1098         i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
1099     }
1100
1101     /* Look for and add subtitle files */
1102     var_Get( p_input, "sub-file", &val );
1103     if( val.psz_string && *val.psz_string )
1104     {
1105         subtitle_demux_t *p_sub;
1106
1107         msg_Dbg( p_input, "force subtitle: %s", val.psz_string );
1108         if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string),
1109                                     i_microsecondperframe ) ) )
1110         {
1111             p_sub_toselect = p_sub;
1112             TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
1113         }
1114     }
1115     psz_sub_file = val.psz_string;
1116
1117     var_Get( p_input, "sub-autodetect-file", &val );
1118     var_Get( p_input, "sub-autodetect-path", &val1 );
1119     if( val.b_bool )
1120     {
1121         subtitle_demux_t *p_sub;
1122         int i;
1123         char **tmp = subtitles_Detect( p_input, val1.psz_string, p_input->psz_name );
1124         char **tmp2 = tmp;
1125         for( i = 0; *tmp2 != NULL; i++ )
1126         {
1127             if( psz_sub_file == NULL || strcmp( psz_sub_file, *tmp2 ) )
1128             {
1129                 if( ( p_sub = subtitle_New( p_input, *tmp2,
1130                                             i_microsecondperframe ) ) )
1131                 {
1132                     TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub,
1133                                 p_sub );
1134                 }
1135             }
1136             free( *tmp2++ );
1137         }
1138         free( tmp );
1139         free( val1.psz_string );
1140     }
1141     if( psz_sub_file ) free( psz_sub_file );
1142
1143     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
1144     val.b_bool =  VLC_FALSE;
1145     if( p_input->stream.p_sout )
1146     {
1147         var_Get( p_input, "sout-all", &val );
1148     }
1149     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
1150                     val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
1151     if( p_sub_toselect )
1152     {
1153         es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
1154                         p_sub_toselect->p_es, VLC_TRUE );
1155     }
1156 #endif
1157 }
1158
1159 /*****************************************************************************
1160  * Error: RunThread() error loop
1161  *****************************************************************************
1162  * This function is called when an error occured during thread main's loop.
1163  *****************************************************************************/
1164 static void Error( input_thread_t *p_input )
1165 {
1166     while( !p_input->b_die )
1167     {
1168         /* Sleep a while */
1169         msleep( INPUT_IDLE_SLEEP );
1170     }
1171 }
1172
1173 /*****************************************************************************
1174  * End: end the input thread
1175  *****************************************************************************/
1176 static void End( input_thread_t * p_input )
1177 {
1178     vlc_value_t val;
1179
1180     msg_Dbg( p_input, "closing `%s'",
1181              p_input->input.p_item->psz_uri );
1182
1183     /* We are at the end */
1184     p_input->i_state = END_S;
1185
1186     val.i_int = END_S;
1187     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1188
1189     /* Clean control variables */
1190     input_ControlVarClean( p_input );
1191
1192     /* Unload all modules */
1193     if( p_input->input.p_demux )
1194         demux2_Delete( p_input->input.p_demux );
1195
1196     if( p_input->input.p_stream )
1197         stream_AccessDelete( p_input->input.p_stream );
1198
1199     if( p_input->input.p_access )
1200         access2_Delete( p_input->input.p_access );
1201
1202     if( p_input->p_es_out )
1203         input_EsOutDelete( p_input->p_es_out );
1204
1205     /* Close optional stream output instance */
1206     if( p_input->p_sout )
1207     {
1208         vlc_object_t *p_pl =
1209             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1210         vlc_value_t keep;
1211
1212         if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
1213         {
1214             /* attach sout to the playlist */
1215             msg_Warn( p_input, "keeping sout" );
1216             vlc_object_detach( p_input->p_sout );
1217             vlc_object_attach( p_input->p_sout, p_pl );
1218         }
1219         else
1220         {
1221             msg_Warn( p_input, "destroying sout" );
1222             sout_DeleteInstance( p_input->p_sout );
1223         }
1224         if( p_pl )
1225             vlc_object_release( p_pl );
1226     }
1227
1228     /* TODO subs */
1229 #if 0
1230     /* Destroy subtitles demuxers */
1231     if( p_input->p_sys )
1232     {
1233         for( i = 0; i < p_input->p_sys->i_sub; i++ )
1234         {
1235             subtitle_Close( p_input->p_sys->sub[i] );
1236         }
1237         if( p_input->p_sys->i_sub > 0 )
1238         {
1239             free( p_input->p_sys->sub );
1240         }
1241
1242     }
1243 #endif
1244
1245     /* Free input_thread_sys_t */
1246     free( p_input->p_sys );
1247
1248     /* Tell we're dead */
1249     p_input->b_dead = VLC_TRUE;
1250 }
1251
1252 /*****************************************************************************
1253  * Control
1254  *****************************************************************************/
1255 static inline int ControlPopNoLock( input_thread_t *p_input,
1256                                     int *pi_type, vlc_value_t *p_val )
1257 {
1258     if( p_input->i_control <= 0 )
1259     {
1260         return VLC_EGENERIC;
1261     }
1262
1263     *pi_type = p_input->control[0].i_type;
1264     *p_val   = p_input->control[0].val;
1265
1266     p_input->i_control--;
1267     if( p_input->i_control > 0 )
1268     {
1269         int i;
1270
1271         for( i = 0; i < p_input->i_control; i++ )
1272         {
1273             p_input->control[i].i_type = p_input->control[i+1].i_type;
1274             p_input->control[i].val    = p_input->control[i+1].val;
1275         }
1276     }
1277
1278     return VLC_SUCCESS;
1279 }
1280
1281 static void ControlReduce( input_thread_t *p_input )
1282 {
1283     int i;
1284     for( i = 1; i < p_input->i_control; i++ )
1285     {
1286         const int i_lt = p_input->control[i-1].i_type;
1287         const int i_ct = p_input->control[i].i_type;
1288
1289         /* XXX We can't merge INPUT_CONTROL_SET_ES */
1290         msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control, i_lt, i_ct );
1291         if( i_lt == i_ct &&
1292             ( i_ct == INPUT_CONTROL_SET_STATE ||
1293               i_ct == INPUT_CONTROL_SET_RATE ||
1294               i_ct == INPUT_CONTROL_SET_POSITION ||
1295               i_ct == INPUT_CONTROL_SET_TIME ||
1296               i_ct == INPUT_CONTROL_SET_PROGRAM ||
1297               i_ct == INPUT_CONTROL_SET_TITLE ||
1298               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
1299               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
1300         {
1301             int j;
1302             msg_Dbg( p_input, "merged at %d", i );
1303             /* Remove the i-1 */
1304             for( j = i; j <  p_input->i_control; j++ )
1305                 p_input->control[j-1] = p_input->control[j];
1306             p_input->i_control--;
1307         }
1308         else
1309         {
1310             /* TODO but that's not that important
1311                 - merge SET_X with SET_X_CMD
1312                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1313                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1314                 - ?
1315                 */
1316         }
1317     }
1318 }
1319
1320 static vlc_bool_t Control( input_thread_t *p_input, int i_type, vlc_value_t val )
1321 {
1322     vlc_bool_t b_force_update = VLC_FALSE;
1323
1324     switch( i_type )
1325     {
1326         case INPUT_CONTROL_SET_DIE:
1327             msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
1328             /* Mark all submodules to die */
1329             if( p_input->input.p_access )
1330                 p_input->input.p_access->b_die = VLC_TRUE;
1331             if( p_input->input.p_stream )
1332                 p_input->input.p_stream->b_die = VLC_TRUE;
1333             p_input->input.p_demux->b_die = VLC_TRUE;
1334
1335             p_input->b_die = VLC_TRUE;
1336             break;
1337
1338         case INPUT_CONTROL_SET_POSITION:
1339         case INPUT_CONTROL_SET_POSITION_OFFSET:
1340         {
1341             double f_pos;
1342             if( i_type == INPUT_CONTROL_SET_POSITION )
1343             {
1344                 f_pos = val.f_float;
1345             }
1346             else
1347             {
1348                 /* Should not fail */
1349                 demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos );
1350                 f_pos += val.f_float;
1351             }
1352             if( f_pos < 0.0 ) f_pos = 0.0;
1353             if( f_pos > 1.0 ) f_pos = 1.0;
1354             if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION, f_pos ) )
1355             {
1356                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) %2.1f%% failed",
1357                          f_pos * 100 );
1358             }
1359             else
1360             {
1361                 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1362                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1363                 b_force_update = VLC_TRUE;
1364             }
1365             break;
1366         }
1367
1368         case INPUT_CONTROL_SET_TIME:
1369         case INPUT_CONTROL_SET_TIME_OFFSET:
1370         {
1371             int64_t i_time;
1372             int i_ret;
1373
1374             if( i_type == INPUT_CONTROL_SET_TIME )
1375             {
1376                 i_time = val.i_time;
1377             }
1378             else
1379             {
1380                 /* Should not fail */
1381                 demux2_Control( p_input->input.p_demux,
1382                                 DEMUX_GET_TIME, &i_time );
1383                 i_time += val.i_time;
1384             }
1385             if( i_time < 0 ) i_time = 0;
1386             i_ret = demux2_Control( p_input->input.p_demux,
1387                                     DEMUX_SET_TIME, i_time );
1388             if( i_ret )
1389             {
1390                 int64_t i_length;
1391                 /* Emulate it with a SET_POS */
1392
1393                 demux2_Control( p_input->input.p_demux,
1394                                 DEMUX_GET_LENGTH, &i_length );
1395                 if( i_length > 0 )
1396                 {
1397                     double f_pos = (double)i_time / (double)i_length;
1398                     i_ret = demux2_Control( p_input->input.p_demux,
1399                                             DEMUX_SET_POSITION, f_pos );
1400                 }
1401             }
1402             if( i_ret )
1403             {
1404                 msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) %lld failed",
1405                          i_time );
1406             }
1407             else
1408             {
1409                 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1410
1411                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1412                 b_force_update = VLC_TRUE;
1413             }
1414             break;
1415         }
1416
1417         case INPUT_CONTROL_SET_STATE:
1418             if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
1419                 ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
1420             {
1421                 int i_ret;
1422                 if( p_input->input.p_access )
1423                     i_ret = access2_Control( p_input->input.p_access,
1424                                              ACCESS_SET_PAUSE_STATE, VLC_FALSE );
1425                 else
1426                     i_ret = demux2_Control( p_input->input.p_demux,
1427                                             DEMUX_SET_PAUSE_STATE, VLC_FALSE );
1428
1429                 if( i_ret )
1430                 {
1431                     /* FIXME What to do ? */
1432                     msg_Warn( p_input, "cannot unset pause -> EOF" );
1433                     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
1434                 }
1435
1436                 b_force_update = VLC_TRUE;
1437
1438                 /* Switch to play */
1439                 p_input->i_state = PLAYING_S;
1440                 val.i_int = PLAYING_S;
1441                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1442
1443                 /* Reset clock */
1444                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1445             }
1446             else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S && p_input->b_can_pause )
1447             {
1448                 int i_ret;
1449                 if( p_input->input.p_access )
1450                     i_ret = access2_Control( p_input->input.p_access,
1451                                              ACCESS_SET_PAUSE_STATE, VLC_TRUE );
1452                 else
1453                     i_ret = demux2_Control( p_input->input.p_demux,
1454                                             DEMUX_SET_PAUSE_STATE, VLC_TRUE );
1455
1456                 b_force_update = VLC_TRUE;
1457
1458                 if( i_ret )
1459                 {
1460                     msg_Warn( p_input, "cannot set pause state" );
1461                     val.i_int = p_input->i_state;
1462                 }
1463                 else
1464                 {
1465                     val.i_int = PAUSE_S;
1466                 }
1467
1468                 /* Switch to new state */
1469                 p_input->i_state = val.i_int;
1470                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1471             }
1472             else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
1473             {
1474                 b_force_update = VLC_TRUE;
1475
1476                 /* Correct "state" value */
1477                 val.i_int = p_input->i_state;
1478                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1479             }
1480             else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
1481             {
1482                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
1483             }
1484             break;
1485
1486         case INPUT_CONTROL_SET_RATE:
1487         case INPUT_CONTROL_SET_RATE_SLOWER:
1488         case INPUT_CONTROL_SET_RATE_FASTER:
1489         {
1490             int i_rate;
1491
1492             if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
1493                 i_rate = p_input->i_rate * 2;
1494             else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
1495                 i_rate = p_input->i_rate / 2;
1496             else
1497                 i_rate = val.i_int;
1498
1499             if( i_rate < INPUT_RATE_MIN )
1500             {
1501                 msg_Dbg( p_input, "cannot set rate faster" );
1502                 i_rate = INPUT_RATE_MIN;
1503             }
1504             else if( i_rate > INPUT_RATE_MAX )
1505             {
1506                 msg_Dbg( p_input, "cannot set rate slower" );
1507                 i_rate = INPUT_RATE_MAX;
1508             }
1509             if( i_rate != INPUT_RATE_DEFAULT &&
1510                 ( !p_input->b_can_pace_control || !p_input->b_out_pace_control ) )
1511             {
1512                 msg_Dbg( p_input, "cannot change rate" );
1513                 i_rate = INPUT_RATE_DEFAULT;
1514             }
1515             if( i_rate != p_input->i_rate )
1516             {
1517                 p_input->i_rate  = i_rate;
1518                 val.i_int = i_rate;
1519                 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
1520
1521                 /* We haven't send data to decoder when rate != default */
1522                 if( i_rate == INPUT_RATE_DEFAULT )
1523                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
1524
1525                 /* Reset clock */
1526                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1527
1528                 b_force_update = VLC_TRUE;
1529             }
1530             break;
1531         }
1532
1533         case INPUT_CONTROL_SET_PROGRAM:
1534             /* No need to force update, es_out does it if needed */
1535             es_out_Control( p_input->p_es_out,
1536                             ES_OUT_SET_GROUP, val.i_int );
1537             break;
1538
1539         case INPUT_CONTROL_SET_ES:
1540             /* No need to force update, es_out does it if needed */
1541             es_out_Control( p_input->p_es_out,
1542                             ES_OUT_SET_ES, input_EsOutGetFromID( p_input->p_es_out, val.i_int ) );
1543             break;
1544
1545         case INPUT_CONTROL_SET_AUDIO_DELAY:
1546             input_EsOutSetDelay( p_input->p_es_out,
1547                                  AUDIO_ES, val.i_time );
1548             var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
1549             break;
1550
1551         case INPUT_CONTROL_SET_SPU_DELAY:
1552             input_EsOutSetDelay( p_input->p_es_out,
1553                                  SPU_ES, val.i_time );
1554             var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
1555             break;
1556
1557         case INPUT_CONTROL_SET_TITLE:
1558         case INPUT_CONTROL_SET_TITLE_NEXT:
1559         case INPUT_CONTROL_SET_TITLE_PREV:
1560             if( p_input->input.b_title_demux &&
1561                 p_input->input.i_title > 0 )
1562             {
1563                 /* TODO */
1564                 /* FIXME handle demux title */
1565                 demux_t *p_demux = p_input->input.p_demux;
1566                 int i_title;
1567
1568                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1569                     i_title = p_demux->info.i_title - 1;
1570                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1571                     i_title = p_demux->info.i_title + 1;
1572                 else
1573                     i_title = val.i_int;
1574
1575                 if( i_title >= 0 && i_title < p_input->input.i_title )
1576                 {
1577                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
1578
1579                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1580                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1581
1582                     input_ControlVarTitle( p_input, i_title );
1583                 }
1584             }
1585             else if( p_input->input.i_title > 0 )
1586             {
1587                 access_t *p_access = p_input->input.p_access;
1588                 int i_title;
1589
1590                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1591                     i_title = p_access->info.i_title - 1;
1592                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1593                     i_title = p_access->info.i_title + 1;
1594                 else
1595                     i_title = val.i_int;
1596
1597                 if( i_title >= 0 && i_title < p_input->input.i_title )
1598                 {
1599                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
1600                     stream_AccessReset( p_input->input.p_stream );
1601
1602                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1603                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1604                 }
1605             }
1606             break;
1607         case INPUT_CONTROL_SET_SEEKPOINT:
1608         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1609         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1610             if( p_input->input.b_title_demux &&
1611                 p_input->input.i_title > 0 )
1612             {
1613                 demux_t *p_demux = p_input->input.p_demux;
1614                 int i_seekpoint;
1615
1616                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1617                     i_seekpoint = p_demux->info.i_seekpoint - 1;
1618                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1619                     i_seekpoint = p_demux->info.i_seekpoint + 1;
1620                 else
1621                     i_seekpoint = val.i_int;
1622
1623                 if( i_seekpoint >= 0 &&
1624                     i_seekpoint < p_input->input.title[p_demux->info.i_title]->i_seekpoint )
1625                 {
1626                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
1627
1628                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1629                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1630                 }
1631             }
1632             else if( p_input->input.i_title > 0 )
1633             {
1634                 access_t *p_access = p_input->input.p_access;
1635                 int i_seekpoint;
1636
1637                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1638                     i_seekpoint = p_access->info.i_seekpoint - 1;
1639                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1640                     i_seekpoint = p_access->info.i_seekpoint + 1;
1641                 else
1642                     i_seekpoint = val.i_int;
1643
1644                 if( i_seekpoint >= 0 &&
1645                     i_seekpoint < p_input->input.title[p_access->info.i_title]->i_seekpoint )
1646                 {
1647                     access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
1648                     stream_AccessReset( p_input->input.p_stream );
1649
1650                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1651                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1652                 }
1653             }
1654             break;
1655
1656         case INPUT_CONTROL_SET_BOOKMARK:
1657         default:
1658             msg_Err( p_input, "not yet implemented" );
1659             break;
1660     }
1661
1662     return b_force_update;
1663 }
1664
1665 /*****************************************************************************
1666  * UpdateFromDemux:
1667  *****************************************************************************/
1668 static void UpdateFromDemux( input_thread_t *p_input )
1669 {
1670     demux_t *p_demux = p_input->input.p_demux;
1671     vlc_value_t v;
1672
1673     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
1674     {
1675         v.i_int = p_demux->info.i_title;
1676         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1677
1678         input_ControlVarTitle( p_input, p_demux->info.i_title );
1679
1680         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
1681     }
1682     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
1683     {
1684         v.i_int = p_demux->info.i_seekpoint;
1685         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1686
1687         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1688     }
1689     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
1690 }
1691
1692 /*****************************************************************************
1693  * UpdateFromAccess:
1694  *****************************************************************************/
1695 static void UpdateFromAccess( input_thread_t *p_input )
1696 {
1697     access_t *p_access = p_input->input.p_access;
1698     vlc_value_t v;
1699
1700     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
1701     {
1702         v.i_int = p_access->info.i_title;
1703         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1704
1705         input_ControlVarTitle( p_input, p_access->info.i_title );
1706
1707         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
1708     }
1709     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
1710     {
1711         v.i_int = p_access->info.i_seekpoint;
1712         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1713
1714         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1715     }
1716     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
1717 }
1718
1719 /*****************************************************************************
1720  * DecodeUrl: decode a given encoded url
1721  *****************************************************************************/
1722 static void DecodeUrl( char *psz )
1723 {
1724     char *dup = strdup( psz );
1725     char *p = dup;
1726
1727     while( *p )
1728     {
1729         if( *p == '%' )
1730         {
1731             char val[3];
1732             p++;
1733             if( !*p )
1734             {
1735                 break;
1736             }
1737
1738             val[0] = *p++;
1739             val[1] = *p++;
1740             val[2] = '\0';
1741
1742             *psz++ = strtol( val, NULL, 16 );
1743         }
1744         else if( *p == '+' )
1745         {
1746             *psz++ = ' ';
1747             p++;
1748         }
1749         else
1750         {
1751             *psz++ = *p++;
1752         }
1753     }
1754     *psz++  ='\0';
1755     free( dup );
1756 }
1757
1758 /*****************************************************************************
1759  * ParseOption: parses the options for the input
1760  *****************************************************************************
1761  * This function parses the input (config) options and creates their associated
1762  * object variables.
1763  * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
1764  * bar is the value of the option.
1765  *****************************************************************************/
1766 static void ParseOption( input_thread_t *p_input, const char *psz_option )
1767 {
1768     char *psz_name = (char *)psz_option;
1769     char *psz_value = strchr( psz_option, '=' );
1770     int  i_name_len, i_type;
1771     vlc_bool_t b_isno = VLC_FALSE;
1772     vlc_value_t val;
1773
1774     if( psz_value ) i_name_len = psz_value - psz_option;
1775     else i_name_len = strlen( psz_option );
1776
1777     /* It's too much of an hassle to remove the ':' when we parse
1778      * the cmd line :) */
1779     if( i_name_len && *psz_name == ':' )
1780     {
1781         psz_name++;
1782         i_name_len--;
1783     }
1784
1785     if( i_name_len == 0 ) return;
1786
1787     psz_name = strndup( psz_name, i_name_len );
1788     if( psz_value ) psz_value++;
1789
1790     i_type = config_GetType( p_input, psz_name );
1791
1792     if( !i_type && !psz_value )
1793     {
1794         /* check for "no-foo" or "nofoo" */
1795         if( !strncmp( psz_name, "no-", 3 ) )
1796         {
1797             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
1798         }
1799         else if( !strncmp( psz_name, "no", 2 ) )
1800         {
1801             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
1802         }
1803         else goto cleanup;           /* Option doesn't exist */
1804
1805         b_isno = VLC_TRUE;
1806         i_type = config_GetType( p_input, psz_name );
1807
1808         if( !i_type ) goto cleanup;  /* Option doesn't exist */
1809     }
1810     else if( !i_type ) goto cleanup; /* Option doesn't exist */
1811
1812     if( ( i_type != VLC_VAR_BOOL ) &&
1813         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
1814
1815     /* Create the variable in the input object.
1816      * Children of the input object will be able to retreive this value
1817      * thanks to the inheritance property of the object variables. */
1818     var_Create( p_input, psz_name, i_type );
1819
1820     switch( i_type )
1821     {
1822     case VLC_VAR_BOOL:
1823         val.b_bool = !b_isno;
1824         break;
1825
1826     case VLC_VAR_INTEGER:
1827         val.i_int = atoi( psz_value );
1828         break;
1829
1830     case VLC_VAR_FLOAT:
1831         val.f_float = atof( psz_value );
1832         break;
1833
1834     case VLC_VAR_STRING:
1835     case VLC_VAR_MODULE:
1836     case VLC_VAR_FILE:
1837     case VLC_VAR_DIRECTORY:
1838         val.psz_string = psz_value;
1839         break;
1840
1841     default:
1842         goto cleanup;
1843         break;
1844     }
1845
1846     var_Set( p_input, psz_name, val );
1847
1848     msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );
1849
1850   cleanup:
1851     if( psz_name ) free( psz_name );
1852     return;
1853 }
1854
1855