]> git.sesse.net Git - vlc/blob - src/input/input.c
Add ability to prepend headers to messages (object-specific) and use it for VLM media...
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  *****************************************************************************
4  * Copyright (C) 1998-2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>
29 #include <ctype.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33 #include <vlc/decoder.h>
34 #include <vlc/vout.h>
35
36 #include "input_internal.h"
37
38 #include "stream_output.h"
39 #include "vlc_playlist.h"
40 #include "vlc_interface.h"
41 #include "vlc_interaction.h"
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 static  int Run  ( input_thread_t *p_input );
47 static  int RunAndClean  ( input_thread_t *p_input );
48
49 static input_thread_t * Create  ( vlc_object_t *, input_item_t *, char *,
50                                   vlc_bool_t );
51 static  int             Init    ( input_thread_t *p_input, vlc_bool_t b_quick );
52 static void             Error   ( input_thread_t *p_input );
53 static void             End     ( input_thread_t *p_input );
54 static void             MainLoop( input_thread_t *p_input );
55
56 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
57 static void       ControlReduce( input_thread_t * );
58 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
59
60
61 static int  UpdateFromAccess( input_thread_t * );
62 static int  UpdateFromDemux( input_thread_t * );
63 static int  UpdateMeta( input_thread_t *, vlc_bool_t );
64
65 static void UpdateItemLength( input_thread_t *, int64_t i_length, vlc_bool_t );
66
67 static void ParseOption( input_thread_t *p_input, const char *psz_option );
68
69 static void DecodeUrl( char * );
70 static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
71
72 static input_source_t *InputSourceNew( input_thread_t *);
73 static int  InputSourceInit( input_thread_t *, input_source_t *,
74                              char *, char *psz_forced_demux,
75                              vlc_bool_t b_quick );
76 static void InputSourceClean( input_thread_t *, input_source_t * );
77
78 static void SlaveDemux( input_thread_t *p_input );
79 static void SlaveSeek( input_thread_t *p_input );
80
81 static vlc_meta_t *InputMetaUser( input_thread_t *p_input );
82
83 /*****************************************************************************
84  * This function creates a new input, and returns a pointer
85  * to its description. On error, it returns NULL.
86  *
87  * Variables for _public_ use:
88  * * Get and Set:
89  *  - state
90  *  - rate,rate-slower, rate-faster
91  *  - position, position-offset
92  *  - time, time-offset
93  *  - title,title-next,title-prev
94  *  - chapter,chapter-next, chapter-prev
95  *  - program, audio-es, video-es, spu-es
96  *  - audio-delay, spu-delay
97  *  - bookmark
98  * * Get only:
99  *  - length
100  *  - bookmarks
101  *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
102  * * For intf callback upon changes
103  *  - intf-change
104  * TODO explain when Callback is called
105  * TODO complete this list (?)
106  *****************************************************************************/
107 static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
108                                char *psz_header, vlc_bool_t b_quick )
109 {
110     input_thread_t *p_input;                        /* thread descriptor */
111     vlc_value_t val;
112     int i;
113
114     /* Allocate descriptor */
115     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
116     if( p_input == NULL )
117     {
118         msg_Err( p_parent, "out of memory" );
119         return NULL;
120     }
121     p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
122
123     /* Init Common fields */
124     p_input->b_eof = VLC_FALSE;
125     p_input->b_can_pace_control = VLC_TRUE;
126     p_input->i_start = 0;
127     p_input->i_time  = 0;
128     p_input->i_stop  = 0;
129     p_input->i_title = 0;
130     p_input->title   = NULL;
131     p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
132     p_input->i_state = INIT_S;
133     p_input->i_rate  = INPUT_RATE_DEFAULT;
134     p_input->i_bookmark = 0;
135     p_input->bookmark = NULL;
136     p_input->p_meta  = NULL;
137     p_input->p_es_out = NULL;
138     p_input->p_sout  = NULL;
139     p_input->b_out_pace_control = VLC_FALSE;
140     p_input->i_pts_delay = 0;
141
142     /* Init Input fields */
143     p_input->input.p_item = p_item;
144     p_input->input.p_access = NULL;
145     p_input->input.p_stream = NULL;
146     p_input->input.p_demux  = NULL;
147     p_input->input.b_title_demux = VLC_FALSE;
148     p_input->input.i_title  = 0;
149     p_input->input.title    = NULL;
150     p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
151     p_input->input.b_can_pace_control = VLC_TRUE;
152     p_input->input.b_eof = VLC_FALSE;
153     p_input->input.i_cr_average = 0;
154
155     stats_ReinitInputStats( p_item->p_stats );
156
157     /* No slave */
158     p_input->i_slave = 0;
159     p_input->slave   = NULL;
160
161     /* Init control buffer */
162     vlc_mutex_init( p_input, &p_input->lock_control );
163     p_input->i_control = 0;
164
165     /* Parse input options */
166     vlc_mutex_lock( &p_item->lock );
167     for( i = 0; i < p_item->i_options; i++ )
168     {
169         ParseOption( p_input, p_item->ppsz_options[i] );
170     }
171     vlc_mutex_unlock( &p_item->lock );
172
173     /* Create Object Variables for private use only */
174     input_ConfigVarInit( p_input );
175
176     /* Create Objects variables for public Get and Set */
177     input_ControlVarInit( p_input );
178     p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
179
180     if( !b_quick )
181     {
182         var_Get( p_input, "bookmarks", &val );
183         if( val.psz_string )
184         {
185             /* FIXME: have a common cfg parsing routine used by sout and others */
186             char *psz_parser, *psz_start, *psz_end;
187             psz_parser = val.psz_string;
188             while( (psz_start = strchr( psz_parser, '{' ) ) )
189             {
190                  seekpoint_t *p_seekpoint = vlc_seekpoint_New();
191                  char backup;
192                  psz_start++;
193                  psz_end = strchr( psz_start, '}' );
194                  if( !psz_end ) break;
195                  psz_parser = psz_end + 1;
196                  backup = *psz_parser;
197                  *psz_parser = 0;
198                  *psz_end = ',';
199                  while( (psz_end = strchr( psz_start, ',' ) ) )
200                  {
201                      *psz_end = 0;
202                      if( !strncmp( psz_start, "name=", 5 ) )
203                      {
204                          p_seekpoint->psz_name = psz_start + 5;
205                      }
206                      else if( !strncmp( psz_start, "bytes=", 6 ) )
207                      {
208                          p_seekpoint->i_byte_offset = atoll(psz_start + 6);
209                      }
210                      else if( !strncmp( psz_start, "time=", 5 ) )
211                      {
212                          p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000;
213                      }
214                      psz_start = psz_end + 1;
215                 }
216                 msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
217                                   p_seekpoint->psz_name, p_seekpoint->i_byte_offset,
218                                   p_seekpoint->i_time_offset );
219                 input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
220                 vlc_seekpoint_Delete( p_seekpoint );
221                 *psz_parser = backup;
222             }
223             free( val.psz_string );
224         }
225     }
226
227     /* Remove 'Now playing' info as it is probably outdated */
228     input_Control( p_input, INPUT_DEL_INFO, _("Meta-information"),
229                     VLC_META_NOW_PLAYING );
230
231     return p_input;
232 }
233
234 /**
235  * Initialize an input thread and run it. You will need to monitor the thread to clean
236  * up after it is done
237  *
238  * \param p_parent a vlc_object
239  * \param p_item an input item
240  * \return a pointer to the spawned input thread
241  */
242 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
243                                       input_item_t *p_item )
244 {
245     __input_CreateThread2( p_parent, p_item, NULL );
246 }
247
248
249 /* Gruik ! */
250 input_thread_t *__input_CreateThread2( vlc_object_t *p_parent,
251                                        input_item_t *p_item,
252                                        char *psz_header )
253 {
254     input_thread_t *p_input;                        /* thread descriptor */
255
256     p_input = Create( p_parent, p_item, psz_header, VLC_FALSE );
257     /* Now we can attach our new input */
258     vlc_object_attach( p_input, p_parent );
259
260     /* Create thread and wait for its readiness. */
261     if( vlc_thread_create( p_input, "input", Run,
262                             VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
263     {
264         msg_Err( p_input, "cannot create input thread" );
265         vlc_object_detach( p_input );
266         vlc_object_destroy( p_input );
267         return NULL;
268     }
269
270     return p_input;
271 }
272
273
274 /**
275  * Initialize an input thread and run it. This thread will clean after himself,
276  * you can forget about it. It can work either in blocking or non-blocking mode
277  *
278  * \param p_parent a vlc_object
279  * \param p_item an input item
280  * \param b_block should we block until read is finished ?
281  * \return the input object id if non blocking, an error code else
282  */
283 int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
284                    vlc_bool_t b_block )
285 {
286     input_thread_t *p_input;                        /* thread descriptor */
287
288     p_input = Create( p_parent, p_item, NULL, VLC_FALSE );
289     /* Now we can attach our new input */
290     vlc_object_attach( p_input, p_parent );
291
292     if( b_block )
293     {
294         RunAndClean( p_input );
295         return VLC_SUCCESS;
296     }
297     else
298     {
299         if( vlc_thread_create( p_input, "input", RunAndClean,
300                                VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
301         {
302             msg_Err( p_input, "cannot create input thread" );
303             vlc_object_detach( p_input );
304             vlc_object_destroy( p_input );
305             return VLC_EGENERIC;
306         }
307     }
308     return p_input->i_object_id;
309 }
310
311 /**
312  * Initialize an input and initialize it to preparse the item
313  * This function is blocking. It will only accept to parse files
314  *
315  * \param p_parent a vlc_object_t
316  * \param p_item an input item
317  * \return VLC_SUCCESS or an error
318  */
319 int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
320 {
321     input_thread_t *p_input;                        /* thread descriptor */
322
323     /* Allocate descriptor */
324     p_input = Create( p_parent, p_item, NULL, VLC_TRUE );
325
326     /* Now we can attach our new input */
327     vlc_object_attach( p_input, p_parent );
328
329     Init( p_input, VLC_TRUE );
330
331     /* Clean up master */
332     InputSourceClean( p_input, &p_input->input );
333
334     /* Kill access and demux */
335     if( p_input->input.p_access ) p_input->input.p_access->b_die = VLC_TRUE;
336     if( p_input->input.p_demux ) p_input->input.p_access->b_die = VLC_TRUE;
337
338     /* Unload all modules */
339     if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
340
341     /* Delete meta */
342     if( p_input->p_meta ) vlc_meta_Delete( p_input->p_meta );
343
344     vlc_object_detach( p_input );
345     vlc_object_destroy( p_input );
346
347     return VLC_SUCCESS;
348 }
349
350 /**
351  * Request a running input thread to stop and die
352  *
353  * \param the input thread to stop
354  */
355 void input_StopThread( input_thread_t *p_input )
356 {
357     vlc_list_t *p_list;
358     int i;
359
360     /* Set die for input */
361     p_input->b_die = VLC_TRUE;
362
363     /* We cannot touch p_input fields directly (we can from another thread),
364      * so use the vlc_object_find way, it's perfectly safe */
365
366     /* Set die for all access */
367     p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
368     for( i = 0; i < p_list->i_count; i++ )
369     {
370         p_list->p_values[i].p_object->b_die = VLC_TRUE;
371     }
372     vlc_list_release( p_list );
373
374     /* Set die for all stream */
375     p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
376     for( i = 0; i < p_list->i_count; i++ )
377     {
378         p_list->p_values[i].p_object->b_die = VLC_TRUE;
379     }
380     vlc_list_release( p_list );
381
382     /* Set die for all demux */
383     p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
384     for( i = 0; i < p_list->i_count; i++ )
385     {
386         p_list->p_values[i].p_object->b_die = VLC_TRUE;
387     }
388     vlc_list_release( p_list );
389
390     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
391 }
392
393 /**
394  * Clean up a dead input thread
395  * This function does not return until the thread is effectively cancelled.
396  *
397  * \param the input thread to kill
398  */
399 void input_DestroyThread( input_thread_t *p_input )
400 {
401     /* Join the thread */
402     vlc_thread_join( p_input );
403
404     /* Delete input lock (only after thread joined) */
405     vlc_mutex_destroy( &p_input->lock_control );
406
407     /* TODO: maybe input_DestroyThread should also delete p_input instead
408      * of the playlist but I'm not sure if it's possible */
409 }
410
411 /*****************************************************************************
412  * Run: main thread loop
413  * This is the "normal" thread that spawns the input processing chain,
414  * reads the stream, cleans up and waits
415  *****************************************************************************/
416 static int Run( input_thread_t *p_input )
417 {
418
419     /* Signal that the thread is launched */
420     vlc_thread_ready( p_input );
421
422     if( Init( p_input, VLC_FALSE ) )
423     {
424         /* If we failed, wait before we are killed, and exit */
425         p_input->b_error = VLC_TRUE;
426
427         Error( p_input );
428
429         /* Tell we're dead */
430         p_input->b_dead = VLC_TRUE;
431
432         return 0;
433     }
434
435     MainLoop( p_input );
436
437     if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
438     {
439         /* We have finish to demux data but not to play them */
440         while( !p_input->b_die )
441         {
442             if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
443                 break;
444
445             msg_Dbg( p_input, "waiting decoder fifos to empty" );
446
447             msleep( INPUT_IDLE_SLEEP );
448         }
449
450         /* We have finished */
451         p_input->b_eof = VLC_TRUE;
452     }
453
454     /* Wait we are asked to die */
455     if( !p_input->b_die )
456     {
457         Error( p_input );
458     }
459
460     /* Clean up */
461     End( p_input );
462
463     return 0;
464 }
465
466 /*****************************************************************************
467  * RunAndClean: main thread loop
468  * This is the "just forget me" thread that spawns the input processing chain,
469  * reads the stream, cleans up and releases memory
470  *****************************************************************************/
471 static int RunAndClean( input_thread_t *p_input )
472 {
473     /* Signal that the thread is launched */
474     vlc_thread_ready( p_input );
475
476     if( Init( p_input, VLC_FALSE ) )
477     {
478         /* If we failed, just exit */
479         return 0;
480     }
481
482     MainLoop( p_input );
483
484     if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
485     {
486         /* We have finish to demux data but not to play them */
487         while( !p_input->b_die )
488         {
489             if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
490                 break;
491
492             msg_Dbg( p_input, "waiting decoder fifos to empty" );
493
494             msleep( INPUT_IDLE_SLEEP );
495         }
496         /* We have finished */
497         p_input->b_eof = VLC_TRUE;
498     }
499
500     /* Clean up */
501     End( p_input );
502
503     /* Release memory */
504     vlc_object_detach( p_input );
505     vlc_object_destroy( p_input );
506
507     return 0;
508 }
509
510
511 /*****************************************************************************
512  * Main loop: Fill buffers from access, and demux
513  *****************************************************************************/
514 static void MainLoop( input_thread_t *p_input )
515 {
516     int64_t i_intf_update = 0;
517     while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
518     {
519         vlc_bool_t b_force_update = VLC_FALSE;
520         int i_ret;
521         int i_type;
522         vlc_value_t val;
523
524         /* Do the read */
525         if( p_input->i_state != PAUSE_S  )
526         {
527             if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
528                 i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
529             else
530                 i_ret = 0;  /* EOF */
531
532             if( i_ret > 0 )
533             {
534                 /* TODO */
535                 if( p_input->input.b_title_demux &&
536                     p_input->input.p_demux->info.i_update )
537                 {
538                     i_ret = UpdateFromDemux( p_input );
539                     b_force_update = VLC_TRUE;
540                 }
541                 else if( !p_input->input.b_title_demux &&
542                           p_input->input.p_access &&
543                           p_input->input.p_access->info.i_update )
544                 {
545                     i_ret = UpdateFromAccess( p_input );
546                     b_force_update = VLC_TRUE;
547                 }
548             }
549
550             if( i_ret == 0 )    /* EOF */
551             {
552                 vlc_value_t repeat;
553
554                 var_Get( p_input, "input-repeat", &repeat );
555                 if( repeat.i_int == 0 )
556                 {
557                     /* End of file - we do not set b_die because only the
558                      * playlist is allowed to do so. */
559                     msg_Dbg( p_input, "EOF reached" );
560                     p_input->input.b_eof = VLC_TRUE;
561                 }
562                 else
563                 {
564                     msg_Dbg( p_input, "repeating the same input (%d)",
565                              repeat.i_int );
566                     if( repeat.i_int > 0 )
567                     {
568                         repeat.i_int--;
569                         var_Set( p_input, "input-repeat", repeat );
570                     }
571
572                     /* Seek to start title/seekpoint */
573                     val.i_int = p_input->input.i_title_start -
574                         p_input->input.i_title_offset;
575                     if( val.i_int < 0 || val.i_int >= p_input->input.i_title )
576                         val.i_int = 0;
577                     input_ControlPush( p_input,
578                                        INPUT_CONTROL_SET_TITLE, &val );
579
580                     val.i_int = p_input->input.i_seekpoint_start -
581                         p_input->input.i_seekpoint_offset;
582                     if( val.i_int > 0 /* TODO: check upper boundary */ )
583                         input_ControlPush( p_input,
584                                            INPUT_CONTROL_SET_SEEKPOINT, &val );
585
586                     /* Seek to start position */
587                     if( p_input->i_start > 0 )
588                     {
589                         val.i_time = p_input->i_start;
590                         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
591                                            &val );
592                     }
593                     else
594                     {
595                         val.f_float = 0.0;
596                         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
597                                            &val );
598                     }
599                 }
600             }
601             else if( i_ret < 0 )
602             {
603                 p_input->b_error = VLC_TRUE;
604             }
605
606             if( i_ret > 0 && p_input->i_slave > 0 )
607             {
608                 SlaveDemux( p_input );
609             }
610         }
611         else
612         {
613             /* Small wait */
614             msleep( 10*1000 );
615         }
616
617         /* Handle control */
618         vlc_mutex_lock( &p_input->lock_control );
619         ControlReduce( p_input );
620         while( !ControlPopNoLock( p_input, &i_type, &val ) )
621         {
622             msg_Dbg( p_input, "control type=%d", i_type );
623             if( Control( p_input, i_type, val ) )
624                 b_force_update = VLC_TRUE;
625         }
626         vlc_mutex_unlock( &p_input->lock_control );
627
628         if( b_force_update || i_intf_update < mdate() )
629         {
630             vlc_value_t val;
631             double f_pos;
632             int64_t i_time, i_length;
633             /* update input status variables */
634             if( !demux2_Control( p_input->input.p_demux,
635                                  DEMUX_GET_POSITION, &f_pos ) )
636             {
637                 val.f_float = (float)f_pos;
638                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
639             }
640             if( !demux2_Control( p_input->input.p_demux,
641                                  DEMUX_GET_TIME, &i_time ) )
642             {
643                 p_input->i_time = i_time;
644                 val.i_time = i_time;
645                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
646             }
647             if( !demux2_Control( p_input->input.p_demux,
648                                  DEMUX_GET_LENGTH, &i_length ) )
649             {
650                 vlc_value_t old_val;
651                 var_Get( p_input, "length", &old_val );
652                 val.i_time = i_length;
653                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
654
655                 if( old_val.i_time != val.i_time )
656                 {
657                     UpdateItemLength( p_input, i_length, VLC_TRUE );
658                 }
659             }
660
661             var_SetBool( p_input, "intf-change", VLC_TRUE );
662             i_intf_update = mdate() + I64C(150000);
663         }
664     }
665 }
666
667
668 static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
669 {
670     char *psz;
671     char *psz_subtitle;
672     vlc_value_t val;
673     double f_fps;
674     vlc_meta_t *p_meta, *p_meta_tmp;
675     int i_es_out_mode;
676     int i, i_delay;
677
678     /* Initialize optional stream output. (before access/demuxer)
679      * XXX: we add a special case if the uri starts by vlc.
680      * else 'vlc in.file --sout "" vlc:quit'  cannot work (the output will
681      * be destroyed in case of a file).
682      * (this will break playing of file starting by 'vlc:' but I don't
683      * want to add more logic, just force file by file:// or code it ;)
684      */
685     if( !b_quick )
686     {
687         counter_t *p_counter;
688         stats_Create( p_input, "read_bytes", VLC_VAR_INTEGER, STATS_COUNTER );
689         stats_Create( p_input, "read_packets", VLC_VAR_INTEGER, STATS_COUNTER );
690         stats_Create( p_input, "demux_read", VLC_VAR_INTEGER, STATS_COUNTER );
691         stats_Create( p_input, "input_bitrate", VLC_VAR_FLOAT,
692                                STATS_DERIVATIVE );
693         stats_Create( p_input, "demux_bitrate", VLC_VAR_FLOAT,
694                                STATS_DERIVATIVE );
695         p_counter = stats_CounterGet( p_input, p_input->i_object_id,
696                                       "input_bitrate" );
697         if( p_counter ) p_counter->update_interval = 1000000;
698         p_counter = stats_CounterGet( p_input, p_input->i_object_id,
699                                       "demux_bitrate" );
700         if( p_counter ) p_counter->update_interval = 1000000;
701
702         psz = var_GetString( p_input, "sout" );
703         if( *psz && strncasecmp( p_input->input.p_item->psz_uri, "vlc:", 4 ) )
704         {
705             p_input->p_sout = sout_NewInstance( p_input, psz );
706             if( p_input->p_sout == NULL )
707             {
708                 msg_Err( p_input, "cannot start stream output instance, " \
709                                   "aborting" );
710                 free( psz );
711                 return VLC_EGENERIC;
712             }
713         }
714         free( psz );
715     }
716
717     /* Create es out */
718     p_input->p_es_out = input_EsOutNew( p_input );
719     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
720     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
721
722     if( InputSourceInit( p_input, &p_input->input,
723                          p_input->input.p_item->psz_uri, NULL, b_quick ) )
724     {
725         goto error;
726     }
727
728     /* Create global title (from master) */
729     if( !b_quick )
730     {
731         p_input->i_title = p_input->input.i_title;
732         p_input->title   = p_input->input.title;
733         p_input->i_title_offset = p_input->input.i_title_offset;
734         p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset;
735         if( p_input->i_title > 0 )
736         {
737             /* Setup variables */
738             input_ControlVarNavigation( p_input );
739             input_ControlVarTitle( p_input, 0 );
740         }
741
742         /* Global flag */
743         p_input->b_can_pace_control = p_input->input.b_can_pace_control;
744         p_input->b_can_pause        = p_input->input.b_can_pause;
745
746         /* Fix pts delay */
747         if( p_input->i_pts_delay < 0 )
748             p_input->i_pts_delay = 0;
749
750         /* If the desynchronisation requested by the user is < 0, we need to
751          * cache more data. */
752         var_Get( p_input, "audio-desync", &val );
753         if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);
754
755         /* Update cr_average depending on the caching */
756         p_input->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
757         p_input->input.i_cr_average /= 10;
758         if( p_input->input.i_cr_average < 10 ) p_input->input.i_cr_average = 10;
759     }
760
761     /* Load master infos */
762     /* Init length */
763     if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH,
764                          &val.i_time ) && val.i_time > 0 )
765     {
766         var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
767         UpdateItemLength( p_input, val.i_time, b_quick );
768         p_input->input.p_item->i_duration = val.i_time;
769     }
770
771     /* Start title/chapter */
772     if( !b_quick )
773     {
774         val.i_int = p_input->input.i_title_start -
775                     p_input->input.i_title_offset;
776         if( val.i_int > 0 && val.i_int < p_input->input.i_title )
777             input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
778         val.i_int = p_input->input.i_seekpoint_start -
779                     p_input->input.i_seekpoint_offset;
780         if( val.i_int > 0 /* TODO: check upper boundary */ )
781             input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
782
783         /* Start time*/
784         /* Set start time */
785         p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
786                            I64C(1000000);
787         p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
788                            I64C(1000000);
789
790         if( p_input->i_start > 0 )
791         {
792             if( p_input->i_start >= val.i_time )
793             {
794                 msg_Warn( p_input, "invalid start-time ignored" );
795             }
796             else
797             {
798                 vlc_value_t s;
799
800                 msg_Dbg( p_input, "starting at time: %ds",
801                                   (int)( p_input->i_start / I64C(1000000) ) );
802
803                 s.i_time = p_input->i_start;
804                 input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
805             }
806         }
807         if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
808         {
809             msg_Warn( p_input, "invalid stop-time ignored" );
810             p_input->i_stop = 0;
811         }
812
813
814         /* Load subtitles */
815         /* Get fps and set it if not already set */
816         if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
817             f_fps > 1.0 )
818         {
819             float f_requested_fps;
820
821             var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
822             var_SetFloat( p_input, "sub-original-fps", f_fps );
823
824             f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
825             if( f_requested_fps != f_fps )
826             {
827                 var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
828                                                 VLC_VAR_DOINHERIT );
829                 var_SetFloat( p_input, "sub-fps", f_requested_fps );
830             }
831         }
832
833         i_delay = var_CreateGetInteger( p_input, "sub-delay" );
834         if( i_delay != 0 )
835         {
836             var_SetTime( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
837         }
838
839
840         /* Look for and add subtitle files */
841         psz_subtitle = var_GetString( p_input, "sub-file" );
842         if( *psz_subtitle )
843         {
844             input_source_t *sub;
845             vlc_value_t count;
846             vlc_value_t list;
847
848             msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
849
850             var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
851
852             /* */
853             sub = InputSourceNew( p_input );
854             if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle",
855                                   VLC_FALSE ) )
856             {
857                 TAB_APPEND( p_input->i_slave, p_input->slave, sub );
858
859                 /* Select the ES */
860                 if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list,
861                                  NULL ) )
862                 {
863                     if( count.i_int == 0 )
864                         count.i_int++;
865                         /* if it was first one, there is disable too */
866
867                     if( count.i_int < list.p_list->i_count )
868                     {
869                         input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
870                                           &list.p_list->p_values[count.i_int] );
871                     }
872                     var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list,
873                                 NULL );
874                 }
875             }
876         }
877
878         var_Get( p_input, "sub-autodetect-file", &val );
879         if( val.b_bool )
880         {
881             char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
882             char **subs = subtitles_Detect( p_input, psz_autopath,
883                                             p_input->input.p_item->psz_uri );
884             input_source_t *sub;
885
886             for( i = 0; subs && subs[i]; i++ )
887             {
888                 if( strcmp( psz_subtitle, subs[i] ) )
889                 {
890                     sub = InputSourceNew( p_input );
891                     if( !InputSourceInit( p_input, sub, subs[i], "subtitle",
892                                           VLC_FALSE ) )
893                     {
894                          TAB_APPEND( p_input->i_slave, p_input->slave, sub );
895                     }
896                 }
897                 free( subs[i] );
898             }
899             if( subs ) free( subs );
900             if( psz_autopath ) free( psz_autopath );
901         }
902         free( psz_subtitle );
903
904         /* Look for slave */
905         psz = var_GetString( p_input, "input-slave" );
906         if( *psz )
907         {
908             char *psz_delim;
909             input_source_t *slave;
910             while( psz && *psz )
911             {
912                 while( *psz == ' ' || *psz == '#' )
913                 {
914                     psz++;
915                 }
916                 if( ( psz_delim = strchr( psz, '#' ) ) )
917                 {
918                     *psz_delim++ = '\0';
919                 }
920                 if( *psz == 0 )
921                 {
922                     break;
923                 }
924
925                 msg_Dbg( p_input, "adding slave input '%s'", psz );
926                 slave = InputSourceNew( p_input );
927                 if( !InputSourceInit( p_input, slave, psz, NULL, VLC_FALSE ) )
928                 {
929                     TAB_APPEND( p_input->i_slave, p_input->slave, slave );
930                 }
931                 psz = psz_delim;
932             }
933         }
934         if( psz ) free( psz );
935     }
936     else
937     {
938         p_input->i_start = 0;
939         p_input->i_start = 0;
940     }
941
942     /* Set up es_out */
943     if( !b_quick )
944     {
945         es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
946         i_es_out_mode = ES_OUT_MODE_AUTO;
947         val.p_list = NULL;
948         if( p_input->p_sout )
949         {
950             var_Get( p_input, "sout-all", &val );
951             if ( val.b_bool )
952             {
953                 i_es_out_mode = ES_OUT_MODE_ALL;
954                 val.p_list = NULL;
955             }
956             else
957             {
958                 var_Get( p_input, "programs", &val );
959                 if ( val.p_list && val.p_list->i_count )
960                 {
961                     i_es_out_mode = ES_OUT_MODE_PARTIAL;
962                     /* Note : we should remove the "program" callback. */
963                 }
964                 else
965                     var_Change( p_input, "programs", VLC_VAR_FREELIST, &val,
966                                 NULL );
967             }
968         }
969         es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
970
971         /* Inform the demuxer about waited group (needed only for DVB) */
972         if( i_es_out_mode == ES_OUT_MODE_ALL )
973         {
974             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1, NULL );
975         }
976         else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
977         {
978             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1,
979                             val.p_list );
980         }
981         else
982         {
983             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP,
984                            (int) var_GetInteger( p_input, "program" ), NULL );
985         }
986
987         if( p_input->p_sout )
988         {
989             if( p_input->p_sout->i_out_pace_nocontrol > 0 )
990             {
991                 p_input->b_out_pace_control = VLC_FALSE;
992             }
993             else
994             {
995                 p_input->b_out_pace_control = VLC_TRUE;
996             }
997
998             if( p_input->b_can_pace_control && p_input->b_out_pace_control )
999             {
1000                 /* We don't want a high input priority here or we'll
1001                  * end-up sucking up all the CPU time */
1002                 vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
1003             }
1004
1005             msg_Dbg( p_input, "starting in %s mode",
1006                      p_input->b_out_pace_control ? "asynch" : "synch" );
1007         }
1008     }
1009
1010     /* Get meta data from users */
1011     p_meta_tmp = InputMetaUser( p_input );
1012
1013     /* Get meta data from master input */
1014     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
1015         p_meta = NULL;
1016
1017     /* Merge them */
1018     if( p_meta == NULL )
1019     {
1020         p_meta = p_meta_tmp;
1021     }
1022     else if( p_meta_tmp )
1023     {
1024         vlc_meta_Merge( p_meta, p_meta_tmp );
1025         vlc_meta_Delete( p_meta_tmp );
1026     }
1027
1028     /* Access_file does not give any meta, and there are no slave */
1029     if( !b_quick )
1030     {
1031         if( !p_input->input.p_access ||
1032             access2_Control( p_input->input.p_access, ACCESS_GET_META,
1033                              &p_meta_tmp))
1034             p_meta_tmp = NULL;
1035
1036         if( p_meta == NULL )
1037         {
1038             p_meta = p_meta_tmp;
1039         }
1040         else if( p_meta_tmp )
1041         {
1042             vlc_meta_Merge( p_meta, p_meta_tmp );
1043             vlc_meta_Delete( p_meta_tmp );
1044         }
1045
1046         /* Get meta data from slave input */
1047         for( i = 0; i < p_input->i_slave; i++ )
1048         {
1049             vlc_meta_t *p_meta_slave;
1050
1051             if( !demux2_Control( p_input->slave[i]->p_demux,
1052                                  DEMUX_GET_META, &p_meta_slave ) )
1053             {
1054                 if( p_meta == NULL )
1055                 {
1056                     p_meta = p_meta_slave;
1057                 }
1058                 else if( p_meta_slave )
1059                 {
1060                     vlc_meta_Merge( p_meta, p_meta_slave );
1061                     vlc_meta_Delete( p_meta_slave );
1062                 }
1063             }
1064
1065             if( p_input->slave[i]->p_access &&
1066                 !access2_Control( p_input->slave[i]->p_access,
1067                                   ACCESS_GET_META, &p_meta_slave ) )
1068             {
1069                 if( p_meta == NULL )
1070                 {
1071                     p_meta = p_meta_slave;
1072                 }
1073                 else if( p_meta_slave )
1074                 {
1075                     vlc_meta_Merge( p_meta, p_meta_slave );
1076                     vlc_meta_Delete( p_meta_slave );
1077                 }
1078             }
1079         }
1080     }
1081
1082     p_input->p_meta = p_meta;
1083     UpdateMeta( p_input, b_quick );
1084
1085     if( !b_quick )
1086     {
1087         msg_Dbg( p_input, "`%s' successfully opened",
1088                  p_input->input.p_item->psz_uri );
1089
1090     }
1091
1092     /* initialization is complete */
1093     p_input->i_state = PLAYING_S;
1094
1095     val.i_int = PLAYING_S;
1096     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1097
1098     return VLC_SUCCESS;
1099
1100 error:
1101     if( p_input->p_es_out )
1102         input_EsOutDelete( p_input->p_es_out );
1103
1104     if( p_input->p_sout )
1105         sout_DeleteInstance( p_input->p_sout );
1106
1107     /* Mark them deleted */
1108     p_input->input.p_demux = NULL;
1109     p_input->input.p_stream = NULL;
1110     p_input->input.p_access = NULL;
1111     p_input->p_es_out = NULL;
1112     p_input->p_sout = NULL;
1113
1114     return VLC_EGENERIC;
1115 }
1116
1117 /*****************************************************************************
1118  * Error: RunThread() error loop
1119  *****************************************************************************
1120  * This function is called when an error occurred during thread main's loop.
1121  *****************************************************************************/
1122 static void Error( input_thread_t *p_input )
1123 {
1124     while( !p_input->b_die )
1125     {
1126         /* Sleep a while */
1127         msleep( INPUT_IDLE_SLEEP );
1128     }
1129 }
1130
1131 /*****************************************************************************
1132  * End: end the input thread
1133  *****************************************************************************/
1134 static void End( input_thread_t * p_input )
1135 {
1136     vlc_value_t val;
1137     int i;
1138
1139     msg_Dbg( p_input, "closing input" );
1140
1141     /* We are at the end */
1142     p_input->i_state = END_S;
1143
1144     val.i_int = END_S;
1145     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1146
1147     /* Clean control variables */
1148     input_ControlVarClean( p_input );
1149
1150     /* Clean up master */
1151     InputSourceClean( p_input, &p_input->input );
1152
1153     /* Delete slave */
1154     for( i = 0; i < p_input->i_slave; i++ )
1155     {
1156         InputSourceClean( p_input, p_input->slave[i] );
1157         free( p_input->slave[i] );
1158     }
1159     if( p_input->slave ) free( p_input->slave );
1160
1161     /* Unload all modules */
1162     if( p_input->p_es_out )
1163         input_EsOutDelete( p_input->p_es_out );
1164
1165     /* Close optional stream output instance */
1166     if( p_input->p_sout )
1167     {
1168         vlc_object_t *p_pl =
1169             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
1170         vlc_value_t keep;
1171
1172         if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
1173         {
1174             /* attach sout to the playlist */
1175             msg_Dbg( p_input, "keeping sout" );
1176             vlc_object_detach( p_input->p_sout );
1177             vlc_object_attach( p_input->p_sout, p_pl );
1178         }
1179         else
1180         {
1181             msg_Dbg( p_input, "destroying sout" );
1182             sout_DeleteInstance( p_input->p_sout );
1183         }
1184         if( p_pl )
1185             vlc_object_release( p_pl );
1186     }
1187
1188     /* Delete meta */
1189     if( p_input->p_meta )
1190         vlc_meta_Delete( p_input->p_meta );
1191
1192     /* Tell we're dead */
1193     p_input->b_dead = VLC_TRUE;
1194 }
1195
1196 /*****************************************************************************
1197  * Control
1198  *****************************************************************************/
1199 static inline int ControlPopNoLock( input_thread_t *p_input,
1200                                     int *pi_type, vlc_value_t *p_val )
1201 {
1202     if( p_input->i_control <= 0 )
1203     {
1204         return VLC_EGENERIC;
1205     }
1206
1207     *pi_type = p_input->control[0].i_type;
1208     *p_val   = p_input->control[0].val;
1209
1210     p_input->i_control--;
1211     if( p_input->i_control > 0 )
1212     {
1213         int i;
1214
1215         for( i = 0; i < p_input->i_control; i++ )
1216         {
1217             p_input->control[i].i_type = p_input->control[i+1].i_type;
1218             p_input->control[i].val    = p_input->control[i+1].val;
1219         }
1220     }
1221
1222     return VLC_SUCCESS;
1223 }
1224
1225 static void ControlReduce( input_thread_t *p_input )
1226 {
1227     int i;
1228     for( i = 1; i < p_input->i_control; i++ )
1229     {
1230         const int i_lt = p_input->control[i-1].i_type;
1231         const int i_ct = p_input->control[i].i_type;
1232
1233         /* XXX We can't merge INPUT_CONTROL_SET_ES */
1234 /*        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
1235                  i_lt, i_ct );
1236 */
1237         if( i_lt == i_ct &&
1238             ( i_ct == INPUT_CONTROL_SET_STATE ||
1239               i_ct == INPUT_CONTROL_SET_RATE ||
1240               i_ct == INPUT_CONTROL_SET_POSITION ||
1241               i_ct == INPUT_CONTROL_SET_TIME ||
1242               i_ct == INPUT_CONTROL_SET_PROGRAM ||
1243               i_ct == INPUT_CONTROL_SET_TITLE ||
1244               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
1245               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
1246         {
1247             int j;
1248 //            msg_Dbg( p_input, "merged at %d", i );
1249             /* Remove the i-1 */
1250             for( j = i; j <  p_input->i_control; j++ )
1251                 p_input->control[j-1] = p_input->control[j];
1252             p_input->i_control--;
1253         }
1254         else
1255         {
1256             /* TODO but that's not that important
1257                 - merge SET_X with SET_X_CMD
1258                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1259                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1260                 - ?
1261                 */
1262         }
1263     }
1264 }
1265
1266 static vlc_bool_t Control( input_thread_t *p_input, int i_type,
1267                            vlc_value_t val )
1268 {
1269     vlc_bool_t b_force_update = VLC_FALSE;
1270
1271     if( !p_input ) return b_force_update;
1272
1273     switch( i_type )
1274     {
1275         case INPUT_CONTROL_SET_DIE:
1276             msg_Dbg( p_input, "control: stopping input" );
1277             /* Mark all submodules to die */
1278             if( p_input->input.p_access )
1279                 p_input->input.p_access->b_die = VLC_TRUE;
1280             if( p_input->input.p_stream )
1281                 p_input->input.p_stream->b_die = VLC_TRUE;
1282             p_input->input.p_demux->b_die = VLC_TRUE;
1283
1284             p_input->b_die = VLC_TRUE;
1285             break;
1286
1287         case INPUT_CONTROL_SET_POSITION:
1288         case INPUT_CONTROL_SET_POSITION_OFFSET:
1289         {
1290             double f_pos;
1291             if( i_type == INPUT_CONTROL_SET_POSITION )
1292             {
1293                 f_pos = val.f_float;
1294             }
1295             else
1296             {
1297                 /* Should not fail */
1298                 demux2_Control( p_input->input.p_demux,
1299                                 DEMUX_GET_POSITION, &f_pos );
1300                 f_pos += val.f_float;
1301             }
1302             if( f_pos < 0.0 ) f_pos = 0.0;
1303             if( f_pos > 1.0 ) f_pos = 1.0;
1304             /* Reset the decoders states and clock synch (before calling the demuxer */
1305             es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1306             input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1307             if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
1308                                 f_pos ) )
1309             {
1310                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1311                          "%2.1f%% failed", f_pos * 100 );
1312             }
1313             else
1314             {
1315                 if( p_input->i_slave > 0 )
1316                     SlaveSeek( p_input );
1317
1318                 b_force_update = VLC_TRUE;
1319             }
1320             break;
1321         }
1322
1323         case INPUT_CONTROL_SET_TIME:
1324         case INPUT_CONTROL_SET_TIME_OFFSET:
1325         {
1326             int64_t i_time;
1327             int i_ret;
1328
1329             if( i_type == INPUT_CONTROL_SET_TIME )
1330             {
1331                 i_time = val.i_time;
1332             }
1333             else
1334             {
1335                 /* Should not fail */
1336                 demux2_Control( p_input->input.p_demux,
1337                                 DEMUX_GET_TIME, &i_time );
1338                 i_time += val.i_time;
1339             }
1340             if( i_time < 0 ) i_time = 0;
1341
1342             /* Reset the decoders states and clock synch (before calling the demuxer */
1343             es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1344             input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1345
1346             i_ret = demux2_Control( p_input->input.p_demux,
1347                                     DEMUX_SET_TIME, i_time );
1348             if( i_ret )
1349             {
1350                 int64_t i_length;
1351
1352                 /* Emulate it with a SET_POS */
1353                 demux2_Control( p_input->input.p_demux,
1354                                 DEMUX_GET_LENGTH, &i_length );
1355                 if( i_length > 0 )
1356                 {
1357                     double f_pos = (double)i_time / (double)i_length;
1358                     i_ret = demux2_Control( p_input->input.p_demux,
1359                                             DEMUX_SET_POSITION, f_pos );
1360                 }
1361             }
1362             if( i_ret )
1363             {
1364                 msg_Warn( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
1365                          " failed or not possible", i_time );
1366             }
1367             else
1368             {
1369                 if( p_input->i_slave > 0 )
1370                     SlaveSeek( p_input );
1371
1372                 b_force_update = VLC_TRUE;
1373             }
1374             break;
1375         }
1376
1377         case INPUT_CONTROL_SET_STATE:
1378             if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
1379                 ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
1380             {
1381                 int i_ret;
1382                 if( p_input->input.p_access )
1383                     i_ret = access2_Control( p_input->input.p_access,
1384                                              ACCESS_SET_PAUSE_STATE, VLC_FALSE );
1385                 else
1386                     i_ret = demux2_Control( p_input->input.p_demux,
1387                                             DEMUX_SET_PAUSE_STATE, VLC_FALSE );
1388
1389                 if( i_ret )
1390                 {
1391                     /* FIXME What to do ? */
1392                     msg_Warn( p_input, "cannot unset pause -> EOF" );
1393                     vlc_mutex_unlock( &p_input->lock_control );
1394                     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
1395                     vlc_mutex_lock( &p_input->lock_control );
1396                 }
1397
1398                 b_force_update = VLC_TRUE;
1399
1400                 /* Switch to play */
1401                 p_input->i_state = PLAYING_S;
1402                 val.i_int = PLAYING_S;
1403                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1404
1405                 /* Reset clock */
1406                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1407                 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1408             }
1409             else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
1410                      p_input->b_can_pause )
1411             {
1412                 int i_ret;
1413                 if( p_input->input.p_access )
1414                     i_ret = access2_Control( p_input->input.p_access,
1415                                              ACCESS_SET_PAUSE_STATE, VLC_TRUE );
1416                 else
1417                     i_ret = demux2_Control( p_input->input.p_demux,
1418                                             DEMUX_SET_PAUSE_STATE, VLC_TRUE );
1419
1420                 b_force_update = VLC_TRUE;
1421
1422                 if( i_ret )
1423                 {
1424                     msg_Warn( p_input, "cannot set pause state" );
1425                     val.i_int = p_input->i_state;
1426                 }
1427                 else
1428                 {
1429                     val.i_int = PAUSE_S;
1430                 }
1431
1432                 /* Switch to new state */
1433                 p_input->i_state = val.i_int;
1434                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1435             }
1436             else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
1437             {
1438                 b_force_update = VLC_TRUE;
1439
1440                 /* Correct "state" value */
1441                 val.i_int = p_input->i_state;
1442                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
1443             }
1444             else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
1445             {
1446                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
1447             }
1448             break;
1449
1450         case INPUT_CONTROL_SET_RATE:
1451         case INPUT_CONTROL_SET_RATE_SLOWER:
1452         case INPUT_CONTROL_SET_RATE_FASTER:
1453         {
1454             int i_rate;
1455
1456             if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
1457                 i_rate = p_input->i_rate * 2;
1458             else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
1459                 i_rate = p_input->i_rate / 2;
1460             else
1461                 i_rate = val.i_int;
1462
1463             if( i_rate < INPUT_RATE_MIN )
1464             {
1465                 msg_Dbg( p_input, "cannot set rate faster" );
1466                 i_rate = INPUT_RATE_MIN;
1467             }
1468             else if( i_rate > INPUT_RATE_MAX )
1469             {
1470                 msg_Dbg( p_input, "cannot set rate slower" );
1471                 i_rate = INPUT_RATE_MAX;
1472             }
1473             if( i_rate != INPUT_RATE_DEFAULT &&
1474                 ( !p_input->b_can_pace_control ||
1475                   ( p_input->p_sout && !p_input->b_out_pace_control ) ) )
1476             {
1477                 msg_Dbg( p_input, "cannot change rate" );
1478                 i_rate = INPUT_RATE_DEFAULT;
1479             }
1480             if( i_rate != p_input->i_rate )
1481             {
1482                 p_input->i_rate  = i_rate;
1483                 val.i_int = i_rate;
1484                 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
1485
1486                 /* We haven't send data to decoder when rate != default */
1487                 if( i_rate == INPUT_RATE_DEFAULT )
1488                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
1489
1490                 /* Reset clock */
1491                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1492
1493                 b_force_update = VLC_TRUE;
1494             }
1495             break;
1496         }
1497
1498         case INPUT_CONTROL_SET_PROGRAM:
1499             /* No need to force update, es_out does it if needed */
1500             es_out_Control( p_input->p_es_out,
1501                             ES_OUT_SET_GROUP, val.i_int );
1502
1503             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, val.i_int,
1504                             NULL );
1505             break;
1506
1507         case INPUT_CONTROL_SET_ES:
1508             /* No need to force update, es_out does it if needed */
1509             es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
1510                             input_EsOutGetFromID( p_input->p_es_out,
1511                                                   val.i_int ) );
1512             break;
1513
1514         case INPUT_CONTROL_SET_AUDIO_DELAY:
1515             input_EsOutSetDelay( p_input->p_es_out,
1516                                  AUDIO_ES, val.i_time );
1517             var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
1518             break;
1519
1520         case INPUT_CONTROL_SET_SPU_DELAY:
1521             input_EsOutSetDelay( p_input->p_es_out,
1522                                  SPU_ES, val.i_time );
1523             var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
1524             break;
1525
1526         case INPUT_CONTROL_SET_TITLE:
1527         case INPUT_CONTROL_SET_TITLE_NEXT:
1528         case INPUT_CONTROL_SET_TITLE_PREV:
1529             if( p_input->input.b_title_demux &&
1530                 p_input->input.i_title > 0 )
1531             {
1532                 /* TODO */
1533                 /* FIXME handle demux title */
1534                 demux_t *p_demux = p_input->input.p_demux;
1535                 int i_title;
1536
1537                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1538                     i_title = p_demux->info.i_title - 1;
1539                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1540                     i_title = p_demux->info.i_title + 1;
1541                 else
1542                     i_title = val.i_int;
1543
1544                 if( i_title >= 0 && i_title < p_input->input.i_title )
1545                 {
1546                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1547                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1548
1549                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
1550                     input_ControlVarTitle( p_input, i_title );
1551                 }
1552             }
1553             else if( p_input->input.i_title > 0 )
1554             {
1555                 access_t *p_access = p_input->input.p_access;
1556                 int i_title;
1557
1558                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
1559                     i_title = p_access->info.i_title - 1;
1560                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
1561                     i_title = p_access->info.i_title + 1;
1562                 else
1563                     i_title = val.i_int;
1564
1565                 if( i_title >= 0 && i_title < p_input->input.i_title )
1566                 {
1567                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1568                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1569                     
1570                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
1571                     stream_AccessReset( p_input->input.p_stream );
1572                 }
1573             }
1574             break;
1575         case INPUT_CONTROL_SET_SEEKPOINT:
1576         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
1577         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
1578             if( p_input->input.b_title_demux &&
1579                 p_input->input.i_title > 0 )
1580             {
1581                 demux_t *p_demux = p_input->input.p_demux;
1582                 int i_seekpoint;
1583                 int64_t i_input_time;
1584                 int64_t i_seekpoint_time;
1585
1586                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1587                 {
1588                     i_seekpoint = p_demux->info.i_seekpoint;
1589                     i_seekpoint_time = p_input->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1590                     if( i_seekpoint_time >= 0 &&
1591                          !demux2_Control( p_demux,
1592                                           DEMUX_GET_TIME, &i_input_time ) )
1593                     {
1594                         if ( i_input_time < i_seekpoint_time + 3000000 )
1595                             i_seekpoint--;
1596                     }
1597                     else
1598                         i_seekpoint--;
1599                 }
1600                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
1601                     i_seekpoint = p_demux->info.i_seekpoint + 1;
1602                 else
1603                     i_seekpoint = val.i_int;
1604
1605                 if( i_seekpoint >= 0 && i_seekpoint <
1606                     p_input->input.title[p_demux->info.i_title]->i_seekpoint )
1607                 {
1608                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1609                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1610                     
1611                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
1612                 }
1613             }
1614             else if( p_input->input.i_title > 0 )
1615             {
1616                 demux_t *p_demux = p_input->input.p_demux;
1617                 access_t *p_access = p_input->input.p_access;
1618                 int i_seekpoint;
1619                 int64_t i_input_time;
1620                 int64_t i_seekpoint_time;
1621
1622                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
1623                 {
1624                     i_seekpoint = p_access->info.i_seekpoint;
1625                     i_seekpoint_time = p_input->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
1626                     if( i_seekpoint_time >= 0 &&
1627                         demux2_Control( p_demux,
1628                                         DEMUX_GET_TIME, &i_input_time ) )
1629                     {
1630                         if ( i_input_time < i_seekpoint_time + 3000000 )
1631                             i_seekpoint--;
1632                     }
1633                     else
1634                         i_seekpoint--;
1635                 }
1636                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) 
1637                     i_seekpoint = p_access->info.i_seekpoint + 1;
1638                 else
1639                     i_seekpoint = val.i_int;
1640
1641                 if( i_seekpoint >= 0 && i_seekpoint <
1642                     p_input->input.title[p_access->info.i_title]->i_seekpoint )
1643                 {
1644                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
1645                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
1646                     
1647                     access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
1648                     stream_AccessReset( p_input->input.p_stream );
1649                 }
1650             }
1651             break;
1652
1653         case INPUT_CONTROL_ADD_SLAVE:
1654             if( val.psz_string )
1655             {
1656                 input_source_t *slave = InputSourceNew( p_input );
1657
1658                 if( !InputSourceInit( p_input, slave, val.psz_string, NULL,
1659                                       VLC_FALSE ) )
1660                 {
1661                     vlc_meta_t *p_meta_new = NULL;
1662                     vlc_meta_t *p_meta;
1663                     int64_t i_time;
1664
1665                     /* Add the slave */
1666                     msg_Dbg( p_input, "adding %s as slave on the fly",
1667                              val.psz_string );
1668
1669                     /* Set position */
1670                     if( demux2_Control( p_input->input.p_demux,
1671                                         DEMUX_GET_TIME, &i_time ) )
1672                     {
1673                         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
1674                         InputSourceClean( p_input, slave );
1675                         free( slave );
1676                         break;
1677                     }
1678                     if( demux2_Control( slave->p_demux,
1679                                         DEMUX_SET_TIME, i_time ) )
1680                     {
1681                         msg_Err( p_input, "seek failed for new slave" );
1682                         InputSourceClean( p_input, slave );
1683                         free( slave );
1684                         break;
1685                     }
1686
1687
1688                     /* Get meta (access and demux) */
1689                     if( access2_Control( slave->p_access,
1690                                           ACCESS_GET_META, &p_meta_new ) )
1691                         p_meta_new = NULL;
1692                     if( !demux2_Control( slave->p_demux,
1693                                          DEMUX_GET_META, &p_meta ) )
1694                     {
1695                         if( p_meta_new )
1696                         {
1697                             vlc_meta_Merge( p_meta_new, p_meta );
1698                             vlc_meta_Delete( p_meta );
1699                         }
1700                         else
1701                         {
1702                             p_meta_new = p_meta;
1703                         }
1704                     }
1705                     /* Update meta */
1706                     if( p_meta_new )
1707                     {
1708                         if( p_input->p_meta )
1709                         {
1710                             vlc_meta_Merge( p_input->p_meta, p_meta_new );
1711                             vlc_meta_Delete( p_meta_new );
1712                         }
1713                         else
1714                         {
1715                             p_input->p_meta = p_meta_new;
1716                         }
1717                         UpdateMeta( p_input, VLC_FALSE );
1718                     }
1719
1720                     TAB_APPEND( p_input->i_slave, p_input->slave, slave );
1721                 }
1722                 else
1723                 {
1724                     msg_Warn( p_input, "failed to add %s as slave",
1725                               val.psz_string );
1726                 }
1727
1728                 free( val.psz_string );
1729             }
1730             break;
1731
1732         case INPUT_CONTROL_SET_BOOKMARK:
1733         default:
1734             msg_Err( p_input, "not yet implemented" );
1735             break;
1736     }
1737
1738     return b_force_update;
1739 }
1740
1741 /*****************************************************************************
1742  * UpdateFromDemux:
1743  *****************************************************************************/
1744 static int UpdateFromDemux( input_thread_t *p_input )
1745 {
1746     demux_t *p_demux = p_input->input.p_demux;
1747     vlc_value_t v;
1748
1749     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
1750     {
1751         v.i_int = p_demux->info.i_title;
1752         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1753
1754         input_ControlVarTitle( p_input, p_demux->info.i_title );
1755
1756         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
1757     }
1758     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
1759     {
1760         v.i_int = p_demux->info.i_seekpoint;
1761         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1762
1763         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1764     }
1765     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
1766
1767     /* Hmmm only works with master input */
1768     if( p_input->input.p_demux == p_demux )
1769     {
1770         int i_title_end = p_input->input.i_title_end -
1771             p_input->input.i_title_offset;
1772         int i_seekpoint_end = p_input->input.i_seekpoint_end -
1773             p_input->input.i_seekpoint_offset;
1774
1775         if( i_title_end >= 0 && i_seekpoint_end >= 0 )
1776         {
1777             if( p_demux->info.i_title > i_title_end ||
1778                 ( p_demux->info.i_title == i_title_end &&
1779                   p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0;
1780         }
1781         else if( i_seekpoint_end >=0 )
1782         {
1783             if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0;
1784         }
1785         else if( i_title_end >= 0 )
1786         {
1787             if( p_demux->info.i_title > i_title_end ) return 0;
1788         }
1789     }
1790
1791     return 1;
1792 }
1793
1794 /*****************************************************************************
1795  * UpdateFromAccess:
1796  *****************************************************************************/
1797 static int UpdateFromAccess( input_thread_t *p_input )
1798 {
1799     access_t *p_access = p_input->input.p_access;
1800     vlc_value_t v;
1801
1802     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
1803     {
1804         v.i_int = p_access->info.i_title;
1805         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
1806
1807         input_ControlVarTitle( p_input, p_access->info.i_title );
1808
1809         stream_AccessUpdate( p_input->input.p_stream );
1810
1811         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
1812     }
1813     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
1814     {
1815         v.i_int = p_access->info.i_seekpoint;
1816         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
1817
1818         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
1819     }
1820     if( p_access->info.i_update & INPUT_UPDATE_META )
1821     {
1822         /* TODO maybe multi - access ? */
1823         vlc_meta_t *p_meta;
1824         if( !access2_Control( p_input->input.p_access,ACCESS_GET_META,&p_meta))
1825         {
1826             if( p_input->p_meta )
1827             {
1828                 vlc_meta_Merge( p_input->p_meta, p_meta );
1829                 vlc_meta_Delete( p_meta );
1830             }
1831             else
1832             {
1833                 p_input->p_meta = p_meta;
1834             }
1835
1836             UpdateMeta( p_input, VLC_FALSE );
1837             var_SetBool( p_input, "item-change", p_input->input.p_item->i_id );
1838         }
1839         p_access->info.i_update &= ~INPUT_UPDATE_META;
1840     }
1841
1842     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
1843
1844     /* Hmmm only works with master input */
1845     if( p_input->input.p_access == p_access )
1846     {
1847         int i_title_end = p_input->input.i_title_end -
1848             p_input->input.i_title_offset;
1849         int i_seekpoint_end = p_input->input.i_seekpoint_end -
1850             p_input->input.i_seekpoint_offset;
1851
1852         if( i_title_end >= 0 && i_seekpoint_end >=0 )
1853         {
1854             if( p_access->info.i_title > i_title_end ||
1855                 ( p_access->info.i_title == i_title_end &&
1856                   p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0;
1857         }
1858         else if( i_seekpoint_end >=0 )
1859         {
1860             if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0;
1861         }
1862         else if( i_title_end >= 0 )
1863         {
1864             if( p_access->info.i_title > i_title_end ) return 0;
1865         }
1866     }
1867
1868     return 1;
1869 }
1870
1871 /*****************************************************************************
1872  * UpdateMeta:
1873  *****************************************************************************/
1874 static int  UpdateMeta( input_thread_t *p_input, vlc_bool_t b_quick )
1875 {
1876     vlc_meta_t *p_meta = p_input->p_meta;
1877     int i;
1878
1879     if( !p_meta || p_meta->i_meta == 0 )
1880         return VLC_SUCCESS;
1881
1882     if( !b_quick ) msg_Dbg( p_input, "meta information:" );
1883     for( i = 0; i < p_meta->i_meta; i++ )
1884     {
1885         if( !b_quick )
1886             msg_Dbg( p_input, "  - '%s' = '%s'",
1887                      _(p_meta->name[i]), p_meta->value[i] );
1888
1889         if( !strcmp(p_meta->name[i], VLC_META_TITLE) && p_meta->value[i] &&
1890             !p_input->input.p_item->b_fixed_name )
1891             input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
1892
1893         if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
1894             input_Control( p_input, INPUT_ADD_INFO, _("General"),
1895                            _("Author"), p_meta->value[i] );
1896
1897         input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
1898                       _(p_meta->name[i]), "%s", p_meta->value[i] );
1899     }
1900
1901     for( i = 0; i < p_meta->i_track; i++ )
1902     {
1903         vlc_meta_t *tk = p_meta->track[i];
1904         int j;
1905
1906         if( tk->i_meta > 0 )
1907         {
1908             char *psz_cat = malloc( strlen(_("Stream")) + 10 );
1909
1910             msg_Dbg( p_input, "  - track[%d]:", i );
1911
1912             sprintf( psz_cat, "%s %d", _("Stream"), i );
1913             for( j = 0; j < tk->i_meta; j++ )
1914             {
1915                 msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
1916                          tk->value[j] );
1917
1918                 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1919                                _(tk->name[j]), "%s", tk->value[j] );
1920             }
1921         }
1922     }
1923
1924     if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
1925     {
1926         p_input->p_sout->p_meta = vlc_meta_Duplicate( p_meta );
1927     }
1928
1929     return VLC_SUCCESS;
1930 }
1931
1932 /*****************************************************************************
1933  * UpdateItemLength:
1934  *****************************************************************************/
1935 static void UpdateItemLength( input_thread_t *p_input, int64_t i_length,
1936                               vlc_bool_t b_quick )
1937 {
1938     playlist_t *p_playlist;
1939     char psz_buffer[MSTRTIME_MAX_SIZE];
1940
1941     vlc_mutex_lock( &p_input->input.p_item->lock );
1942     p_input->input.p_item->i_duration = i_length;
1943     vlc_mutex_unlock( &p_input->input.p_item->lock );
1944
1945         p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1946                                                FIND_PARENT);
1947     if( p_playlist )
1948     {
1949         var_SetInteger( p_playlist, "item-change",
1950                         p_input->input.p_item->i_id );
1951         vlc_object_release( p_playlist );
1952     }
1953
1954     input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
1955                    msecstotimestr( psz_buffer, i_length / 1000 ) );
1956 }
1957
1958 /*****************************************************************************
1959  * InputSourceNew:
1960  *****************************************************************************/
1961 static input_source_t *InputSourceNew( input_thread_t *p_input )
1962 {
1963     input_source_t *in = (input_source_t*) malloc( sizeof( input_source_t ) );
1964    
1965     if( !in )
1966     {
1967         msg_Err( p_input, "out of memory for new input source" );
1968         return NULL;
1969     }
1970
1971     in->p_item   = NULL;
1972     in->p_access = NULL;
1973     in->p_stream = NULL;
1974     in->p_demux  = NULL;
1975     in->b_title_demux = VLC_FALSE;
1976     in->i_title  = 0;
1977     in->title    = NULL;
1978     in->b_can_pace_control = VLC_TRUE;
1979     in->b_eof = VLC_FALSE;
1980     in->i_cr_average = 0;
1981
1982     return in;
1983 }
1984
1985 /*****************************************************************************
1986  * InputSourceInit:
1987  *****************************************************************************/
1988 static int InputSourceInit( input_thread_t *p_input,
1989                             input_source_t *in, char *psz_mrl,
1990                             char *psz_forced_demux, vlc_bool_t b_quick )
1991 {
1992     char *psz_dup = strdup( psz_mrl );
1993     char *psz_access;
1994     char *psz_demux;
1995     char *psz_path;
1996     char *psz_tmp;
1997     char *psz;
1998     vlc_value_t val;
1999
2000     if( !in ) return VLC_EGENERIC;
2001
2002     /* Split uri */
2003     if( !b_quick )
2004     {
2005         MRLSplit( VLC_OBJECT(p_input), psz_dup,
2006                   &psz_access, &psz_demux, &psz_path );
2007
2008         msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
2009                  psz_mrl, psz_access, psz_demux, psz_path );
2010
2011         /* Hack to allow udp://@:port syntax */
2012         if( !psz_access ||
2013             (strncmp( psz_access, "udp", 3 ) &&
2014              strncmp( psz_access, "rtp", 3 )) )
2015
2016         /* Find optional titles and seekpoints */
2017         MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
2018                      &in->i_seekpoint_start, &in->i_seekpoint_end );
2019
2020         if( psz_forced_demux && *psz_forced_demux )
2021         {
2022             psz_demux = psz_forced_demux;
2023         }
2024         else if( !psz_demux || *psz_demux == '\0' )
2025         {
2026             /* special hack for forcing a demuxer with --demux=module
2027              * (and do nothing with a list) */
2028             char *psz_var_demux = var_GetString( p_input, "demux" );
2029
2030             if( *psz_var_demux != '\0' &&
2031                 !strchr(psz_var_demux, ',' ) &&
2032                 !strchr(psz_var_demux, ':' ) )
2033             {
2034                 psz_demux = psz_var_demux;
2035
2036                 msg_Dbg( p_input, "Enforce demux ` %s'", psz_demux );
2037             }
2038             else if( psz_var_demux )
2039             {
2040                 free( psz_var_demux );
2041             }
2042         }
2043
2044         /* Try access_demux if no demux given */
2045         if( *psz_demux == '\0' )
2046         {
2047             in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
2048                                       NULL, p_input->p_es_out, VLC_FALSE );
2049         }
2050     }
2051     else
2052     {
2053         psz_path = psz_mrl;
2054         msg_Dbg( p_input, "trying to preparse %s",  psz_path );
2055         psz_demux = strdup( "" );
2056         psz_access = strdup( "file" );
2057     }
2058
2059     if( in->p_demux )
2060     {
2061         int64_t i_pts_delay;
2062
2063         /* Get infos from access_demux */
2064         demux2_Control( in->p_demux,
2065                         DEMUX_GET_PTS_DELAY, &i_pts_delay );
2066         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
2067
2068         in->b_title_demux = VLC_TRUE;
2069         if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2070                             &in->title, &in->i_title,
2071                             &in->i_title_offset, &in->i_seekpoint_offset ) )
2072         {
2073             in->i_title = 0;
2074             in->title   = NULL;
2075         }
2076         demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
2077                         &in->b_can_pace_control );
2078         demux2_Control( in->p_demux, DEMUX_CAN_PAUSE,
2079                         &in->b_can_pause );
2080
2081         /* FIXME todo
2082         demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
2083                         &val.b_bool );
2084         */
2085     }
2086     else
2087     {
2088         int64_t i_pts_delay;
2089
2090         /* Now try a real access */
2091         in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path,
2092                                     b_quick );
2093
2094         /* Access failed, URL encoded ? */
2095         if( in->p_access == NULL && strchr( psz_path, '%' ) )
2096         {
2097             DecodeUrl( psz_path );
2098
2099             msg_Dbg( p_input, "retrying with access `%s' demux `%s' path `%s'",
2100                      psz_access, psz_demux, psz_path );
2101
2102             in->p_access = access2_New( p_input,
2103                                         psz_access, psz_demux, psz_path,
2104                                         b_quick );
2105         }
2106 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
2107                         * are forbidden in filenames on Win32. */
2108
2109         /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
2110         if( in->p_access == NULL &&
2111             *psz_access == '\0' && ( *psz_demux || *psz_path ) )
2112         {
2113             if( psz_dup ) free( psz_dup );
2114             psz_dup = strdup( psz_mrl );
2115             psz_access = "";
2116             psz_demux = "";
2117             psz_path = psz_dup;
2118
2119             in->p_access = access2_New( p_input,
2120                                         psz_access, psz_demux, psz_path,
2121                                         b_quick );
2122         }
2123 #endif
2124
2125         if( in->p_access == NULL )
2126         {
2127             msg_Err( p_input, "no suitable access module for `%s'", psz_mrl );
2128             intf_UserFatal( VLC_OBJECT( p_input),
2129                             _("Errors"),"Unable to open '%s'", psz_mrl );
2130             goto error;
2131         }
2132
2133         /* */
2134         psz_tmp = psz = var_GetString( p_input, "access-filter" );
2135         while( psz && *psz )
2136         {
2137             access_t *p_access = in->p_access;
2138             char *end = strchr( psz, ':' );
2139
2140             if( end )
2141                 *end++ = '\0';
2142
2143             in->p_access = access2_FilterNew( in->p_access, psz );
2144             if( in->p_access == NULL )
2145             {
2146                 in->p_access = p_access;
2147                 msg_Warn( p_input, "failed to insert access filter %s",
2148                           psz );
2149             }
2150
2151             psz = end;
2152         }
2153         if( psz_tmp ) free( psz_tmp );
2154
2155         /* Get infos from access */
2156         if( !b_quick )
2157         {
2158             access2_Control( in->p_access,
2159                              ACCESS_GET_PTS_DELAY, &i_pts_delay );
2160             p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
2161
2162             in->b_title_demux = VLC_FALSE;
2163             if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO,
2164                                  &in->title, &in->i_title,
2165                                 &in->i_title_offset, &in->i_seekpoint_offset ) )
2166
2167             {
2168                 in->i_title = 0;
2169                 in->title   = NULL;
2170             }
2171             access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
2172                              &in->b_can_pace_control );
2173             access2_Control( in->p_access, ACCESS_CAN_PAUSE,
2174                              &in->b_can_pause );
2175             access2_Control( in->p_access, ACCESS_CAN_SEEK,
2176                              &val.b_bool );
2177             var_Set( p_input, "seekable", val );
2178         }
2179
2180         /* Create the stream_t */
2181         in->p_stream = stream_AccessNew( in->p_access, b_quick );
2182         if( in->p_stream == NULL )
2183         {
2184             msg_Warn( p_input, "cannot create a stream_t from access" );
2185             goto error;
2186         }
2187
2188         /* Open a demuxer */
2189         if( *psz_demux == '\0' && *in->p_access->psz_demux )
2190         {
2191             psz_demux = in->p_access->psz_demux;
2192         }
2193         in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
2194                                   in->p_stream, p_input->p_es_out, b_quick );
2195         if( in->p_demux == NULL )
2196         {
2197             msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
2198                      psz_access, psz_demux, psz_path );
2199             intf_UserFatal( VLC_OBJECT( p_input), _("Errors"),
2200                             "Unrecognized format for '%s'", psz_mrl );
2201             goto error;
2202         }
2203
2204         /* TODO get title from demux */
2205         if( !b_quick && in->i_title <= 0 )
2206         {
2207             if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
2208                                 &in->title, &in->i_title,
2209                                 &in->i_title_offset, &in->i_seekpoint_offset ))
2210             {
2211                 in->i_title = 0;
2212                 in->title   = NULL;
2213             }
2214             else
2215             {
2216                 in->b_title_demux = VLC_TRUE;
2217             }
2218         }
2219     }
2220
2221     if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
2222         in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
2223
2224     if( psz_dup ) free( psz_dup );
2225     return VLC_SUCCESS;
2226
2227 error:
2228     if( in->p_demux )
2229         demux2_Delete( in->p_demux );
2230
2231     if( in->p_stream )
2232         stream_Delete( in->p_stream );
2233
2234     if( in->p_access )
2235         access2_Delete( in->p_access );
2236     if( psz_dup ) free( psz_dup );
2237
2238     return VLC_EGENERIC;
2239 }
2240
2241 /*****************************************************************************
2242  * InputSourceClean:
2243  *****************************************************************************/
2244 static void InputSourceClean( input_thread_t *p_input, input_source_t *in )
2245 {
2246     if( in->p_demux )
2247         demux2_Delete( in->p_demux );
2248
2249     if( in->p_stream )
2250         stream_Delete( in->p_stream );
2251
2252     if( in->p_access )
2253         access2_Delete( in->p_access );
2254
2255     if( in->i_title > 0 )
2256     {
2257         int i;
2258         for( i = 0; i < in->i_title; i++ )
2259         {
2260             vlc_input_title_Delete( in->title[i] );
2261         }
2262         free( in->title );
2263     }
2264 }
2265
2266 static void SlaveDemux( input_thread_t *p_input )
2267 {
2268     int64_t i_time;
2269     int i;
2270     
2271     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2272     {
2273         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2274         return;
2275     }
2276
2277     for( i = 0; i < p_input->i_slave; i++ )
2278     {
2279         input_source_t *in = p_input->slave[i];
2280         int i_ret = 1;
2281
2282         if( in->b_eof )
2283             continue;
2284
2285         if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
2286         {
2287             for( ;; )
2288             {
2289                 int64_t i_stime;
2290                 if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
2291                 {
2292                     msg_Err( p_input, "slave[%d] doesn't like "
2293                              "DEMUX_GET_TIME -> EOF", i );
2294                     i_ret = 0;
2295                     break;
2296                 }
2297
2298                 if( i_stime >= i_time )
2299                     break;
2300
2301                 if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
2302                     break;
2303             }
2304         }
2305         else
2306         {
2307             i_ret = in->p_demux->pf_demux( in->p_demux );
2308         }
2309
2310         if( i_ret <= 0 )
2311         {
2312             msg_Dbg( p_input, "slave %d EOF", i );
2313             in->b_eof = VLC_TRUE;
2314         }
2315     }
2316 }
2317
2318 static void SlaveSeek( input_thread_t *p_input )
2319 {
2320     int64_t i_time;
2321     int i;
2322
2323     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
2324     {
2325         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
2326         return;
2327     }
2328
2329     for( i = 0; i < p_input->i_slave; i++ )
2330     {
2331         input_source_t *in = p_input->slave[i];
2332
2333         if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
2334         {
2335             msg_Err( p_input, "seek failed for slave %d -> EOF", i );
2336             in->b_eof = VLC_TRUE;
2337         }
2338     }
2339 }
2340 /*****************************************************************************
2341  * InputMetaUser:
2342  *****************************************************************************/
2343 static vlc_meta_t *InputMetaUser( input_thread_t *p_input )
2344 {
2345     vlc_meta_t *p_meta;
2346     vlc_value_t val;
2347
2348     if( ( p_meta = vlc_meta_New() ) == NULL )
2349         return NULL;
2350
2351     /* Get meta information from user */
2352 #define GET_META( c, s ) \
2353     var_Get( p_input, (s), &val );  \
2354     if( *val.psz_string )       \
2355         vlc_meta_Add( p_meta, c, val.psz_string ); \
2356     free( val.psz_string )
2357
2358     GET_META( VLC_META_TITLE, "meta-title" );
2359     GET_META( VLC_META_AUTHOR, "meta-author" );
2360     GET_META( VLC_META_ARTIST, "meta-artist" );
2361     GET_META( VLC_META_GENRE, "meta-genre" );
2362     GET_META( VLC_META_COPYRIGHT, "meta-copyright" );
2363     GET_META( VLC_META_DESCRIPTION, "meta-description" );
2364     GET_META( VLC_META_DATE, "meta-date" );
2365     GET_META( VLC_META_URL, "meta-url" );
2366 #undef GET_META
2367
2368     return p_meta;
2369 }
2370
2371 /*****************************************************************************
2372  * DecodeUrl: decode a given encoded url
2373  *****************************************************************************/
2374 static void DecodeUrl( char *psz )
2375 {
2376     char *dup = strdup( psz );
2377     char *p = dup;
2378
2379     while( *p )
2380     {
2381         if( *p == '%' )
2382         {
2383             char val[3];
2384             p++;
2385             if( !*p )
2386             {
2387                 break;
2388             }
2389
2390             val[0] = *p++;
2391             val[1] = *p++;
2392             val[2] = '\0';
2393
2394             *psz++ = strtol( val, NULL, 16 );
2395         }
2396         else if( *p == '+' )
2397         {
2398             *psz++ = ' ';
2399             p++;
2400         }
2401         else
2402         {
2403             *psz++ = *p++;
2404         }
2405     }
2406     if( psz ) *psz++  ='\0';
2407     if( dup ) free( dup );
2408 }
2409
2410 /*****************************************************************************
2411  * ParseOption: parses the options for the input
2412  *****************************************************************************
2413  * This function parses the input (config) options and creates their associated
2414  * object variables.
2415  * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
2416  * bar is the value of the option.
2417  *****************************************************************************/
2418 static void ParseOption( input_thread_t *p_input, const char *psz_option )
2419 {
2420     char *psz_name = (char *)psz_option;
2421     char *psz_value = strchr( psz_option, '=' );
2422     int  i_name_len, i_type;
2423     vlc_bool_t b_isno = VLC_FALSE;
2424     vlc_value_t val;
2425
2426     if( psz_value ) i_name_len = psz_value - psz_option;
2427     else i_name_len = strlen( psz_option );
2428
2429     /* It's too much of an hassle to remove the ':' when we parse
2430      * the cmd line :) */
2431     if( i_name_len && *psz_name == ':' )
2432     {
2433         psz_name++;
2434         i_name_len--;
2435     }
2436
2437     if( i_name_len == 0 ) return;
2438
2439     psz_name = strndup( psz_name, i_name_len );
2440     if( psz_value ) psz_value++;
2441
2442     /* FIXME: :programs should be handled generically */
2443     if( !strcmp( psz_name, "programs" ) )
2444         i_type = VLC_VAR_LIST;
2445     else
2446         i_type = config_GetType( p_input, psz_name );
2447
2448     if( !i_type && !psz_value )
2449     {
2450         /* check for "no-foo" or "nofoo" */
2451         if( !strncmp( psz_name, "no-", 3 ) )
2452         {
2453             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
2454         }
2455         else if( !strncmp( psz_name, "no", 2 ) )
2456         {
2457             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
2458         }
2459         else goto cleanup;           /* Option doesn't exist */
2460
2461         b_isno = VLC_TRUE;
2462         i_type = config_GetType( p_input, psz_name );
2463
2464         if( !i_type ) goto cleanup;  /* Option doesn't exist */
2465     }
2466     else if( !i_type ) goto cleanup; /* Option doesn't exist */
2467
2468     if( ( i_type != VLC_VAR_BOOL ) &&
2469         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
2470
2471     /* Create the variable in the input object.
2472      * Children of the input object will be able to retreive this value
2473      * thanks to the inheritance property of the object variables. */
2474     var_Create( p_input, psz_name, i_type );
2475
2476     switch( i_type )
2477     {
2478     case VLC_VAR_BOOL:
2479         val.b_bool = !b_isno;
2480         break;
2481
2482     case VLC_VAR_INTEGER:
2483         val.i_int = strtol( psz_value, NULL, 0 );
2484         break;
2485
2486     case VLC_VAR_FLOAT:
2487         val.f_float = atof( psz_value );
2488         break;
2489
2490     case VLC_VAR_STRING:
2491     case VLC_VAR_MODULE:
2492     case VLC_VAR_FILE:
2493     case VLC_VAR_DIRECTORY:
2494         val.psz_string = psz_value;
2495         break;
2496
2497     case VLC_VAR_LIST:
2498     {
2499         char *psz_orig, *psz_var;
2500         vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
2501         val.p_list = p_list;
2502         p_list->i_count = 0;
2503
2504         psz_var = psz_orig = strdup(psz_value);
2505         while( psz_var && *psz_var )
2506         {
2507             char *psz_item = psz_var;
2508             vlc_value_t val2;
2509             while( *psz_var && *psz_var != ',' ) psz_var++;
2510             if( *psz_var == ',' )
2511             {
2512                 *psz_var = '\0';
2513                 psz_var++;
2514             }
2515             val2.i_int = strtol( psz_item, NULL, 0 );
2516             INSERT_ELEM( p_list->p_values, p_list->i_count,
2517                          p_list->i_count, val2 );
2518             /* p_list->i_count is incremented twice by INSERT_ELEM */
2519             p_list->i_count--;
2520             INSERT_ELEM( p_list->pi_types, p_list->i_count,
2521                          p_list->i_count, VLC_VAR_INTEGER );
2522         }
2523         if( psz_orig ) free( psz_orig );
2524         break;
2525     }
2526
2527     default:
2528         goto cleanup;
2529         break;
2530     }
2531
2532     var_Set( p_input, psz_name, val );
2533
2534     msg_Dbg( p_input, "set input option: %s to %s", psz_name,
2535              psz_value ? psz_value : ( val.b_bool ? "true" : "false") );
2536
2537   cleanup:
2538     if( psz_name ) free( psz_name );
2539     return;
2540 }
2541
2542 /*****************************************************************************
2543  * MRLSplit: parse the access, demux and url part of the
2544  *           Media Resource Locator.
2545  *****************************************************************************/
2546 void MRLSplit( vlc_object_t *p_input, char *psz_dup,
2547                char **ppsz_access, char **ppsz_demux, char **ppsz_path )
2548 {
2549     char *psz_access = NULL;
2550     char *psz_demux  = NULL;
2551     char *psz_path   = NULL;
2552     char *psz, *psz_check;
2553
2554     psz = strchr( psz_dup, ':' );
2555
2556     /* '@' not allowed in access/demux part */
2557     psz_check = strchr( psz_dup, '@' );
2558     if( psz_check && psz_check < psz ) psz = 0;
2559
2560 #if defined( WIN32 ) || defined( UNDER_CE )
2561     if( psz - psz_dup == 1 )
2562     {
2563         msg_Warn( p_input, "drive letter %c: found in source", *psz_dup );
2564         psz_path = psz_dup;
2565     }
2566     else
2567 #endif
2568
2569     if( psz )
2570     {
2571         *psz++ = '\0';
2572         if( psz[0] == '/' && psz[1] == '/' ) psz += 2;
2573
2574         psz_path = psz;
2575
2576         psz = strchr( psz_dup, '/' );
2577         if( psz )
2578         {
2579             *psz++ = '\0';
2580             psz_demux = psz;
2581         }
2582
2583         psz_access = psz_dup;
2584     }
2585     else
2586     {
2587         psz_path = psz_dup;
2588     }
2589
2590     if( !psz_access ) *ppsz_access = "";
2591     else *ppsz_access = psz_access;
2592
2593     if( !psz_demux ) *ppsz_demux = "";
2594     else *ppsz_demux = psz_demux;
2595
2596     if( !psz_path ) *ppsz_path = "";
2597     else *ppsz_path = psz_path;
2598 }
2599
2600 /*****************************************************************************
2601  * MRLSections: parse title and seekpoint info from the Media Resource Locator.
2602  *
2603  * Syntax:
2604  * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
2605  *****************************************************************************/
2606 static void MRLSections( input_thread_t *p_input, char *psz_source,
2607                          int *pi_title_start, int *pi_title_end,
2608                          int *pi_chapter_start, int *pi_chapter_end )
2609 {
2610     char *psz, *psz_end, *psz_next, *psz_check;
2611
2612     *pi_title_start = *pi_title_end = -1;
2613     *pi_chapter_start = *pi_chapter_end = -1;
2614
2615     /* Start by parsing titles and chapters */
2616     if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
2617
2618     /* Check we are really dealing with a title/chapter section */
2619     psz_check = psz + 1;
2620     if( !*psz_check ) return;
2621     if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2622     if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
2623     if( *psz_check == ':' && ++psz_check )
2624         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2625     if( *psz_check != '-' && *psz_check ) return;
2626     if( *psz_check == '-' && ++psz_check )
2627         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2628     if( *psz_check != ':' && *psz_check ) return;
2629     if( *psz_check == ':' && ++psz_check )
2630         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
2631     if( *psz_check ) return;
2632
2633     /* Separate start and end */
2634     *psz++ = 0;
2635     if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
2636
2637     /* Look for the start title */
2638     *pi_title_start = strtol( psz, &psz_next, 0 );
2639     if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
2640     *pi_title_end = *pi_title_start;
2641     psz = psz_next;
2642
2643     /* Look for the start chapter */
2644     if( *psz ) psz++;
2645     *pi_chapter_start = strtol( psz, &psz_next, 0 );
2646     if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
2647     *pi_chapter_end = *pi_chapter_start;
2648
2649     if( psz_end )
2650     {
2651         /* Look for the end title */
2652         *pi_title_end = strtol( psz_end, &psz_next, 0 );
2653         if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
2654         psz_end = psz_next;
2655
2656         /* Look for the end chapter */
2657         if( *psz_end ) psz_end++;
2658         *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
2659         if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
2660     }
2661
2662     msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
2663              psz_source, *pi_title_start, *pi_chapter_start,
2664              *pi_title_end, *pi_chapter_end );
2665 }
2666
2667
2668 /***********************************************************************
2669  * Info management functions
2670  ***********************************************************************/
2671 /**
2672  * Get a info item from a given category in a given input item.
2673  *
2674  * \param p_i The input item to get info from
2675  * \param psz_cat String representing the category for the info
2676  * \param psz_name String representing the name of the desired info
2677  * \return A pointer to the string with the given info if found, or an
2678  *         empty string otherwise. The caller should free the returned
2679  *         pointer.
2680  */
2681 char *vlc_input_item_GetInfo( input_item_t *p_i,
2682                               const char *psz_cat,
2683                               const char *psz_name )
2684 {
2685     int i,j;
2686
2687     vlc_mutex_lock( &p_i->lock );
2688
2689     for( i = 0 ; i< p_i->i_categories  ; i++ )
2690     {
2691         info_category_t *p_cat = p_i->pp_categories[i];
2692
2693         if( !psz_cat || strcmp( p_cat->psz_name, psz_cat ) )
2694             continue;
2695
2696         for( j = 0; j < p_cat->i_infos ; j++ )
2697         {
2698             if( !strcmp( p_cat->pp_infos[j]->psz_name, psz_name ) )
2699             {
2700                 char *psz_ret = strdup( p_cat->pp_infos[j]->psz_value );
2701                 vlc_mutex_unlock( &p_i->lock );
2702                 return psz_ret;
2703             }
2704         }
2705     }
2706     vlc_mutex_unlock( &p_i->lock );
2707     return strdup( "" );
2708 }
2709
2710 int vlc_input_item_AddInfo( input_item_t *p_i,
2711                             const char *psz_cat,
2712                             const char *psz_name,
2713                             const char *psz_format, ... )
2714 {
2715     va_list args;
2716     int i;
2717     info_t *p_info = NULL;
2718     info_category_t *p_cat = NULL ;
2719
2720     vlc_mutex_lock( &p_i->lock );
2721
2722     for( i = 0 ; i < p_i->i_categories ; i ++ )
2723     {
2724         if( !strcmp( p_i->pp_categories[i]->psz_name, psz_cat ) )
2725         {
2726             p_cat = p_i->pp_categories[i];
2727             break;
2728         }
2729     }
2730     if( !p_cat )
2731     {
2732         if( !(p_cat = (info_category_t *)malloc( sizeof(info_category_t) )) )
2733         {
2734             vlc_mutex_unlock( &p_i->lock );
2735             return VLC_EGENERIC;
2736         }
2737         p_cat->psz_name = strdup( psz_cat );
2738         p_cat->i_infos = 0;
2739         p_cat->pp_infos = 0;
2740         INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
2741                      p_cat );
2742     }
2743
2744     for( i = 0; i< p_cat->i_infos; i++ )
2745     {
2746         if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
2747         {
2748             p_info = p_cat->pp_infos[i];
2749             break;
2750         }
2751     }
2752
2753     if( !p_info )
2754     {
2755         if( ( p_info = (info_t *)malloc( sizeof( info_t ) ) ) == NULL )
2756         {
2757             vlc_mutex_unlock( &p_i->lock );
2758             return VLC_EGENERIC;
2759         }
2760         INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos, p_cat->i_infos, p_info );
2761         p_info->psz_name = strdup( psz_name );
2762     }
2763     else
2764     {
2765         if( p_info->psz_value ) free( p_info->psz_value );
2766     }
2767
2768     va_start( args, psz_format );
2769     vasprintf( &p_info->psz_value, psz_format, args);
2770     va_end( args );
2771
2772     vlc_mutex_unlock( &p_i->lock );
2773
2774     return VLC_SUCCESS;
2775 }
2776