]> git.sesse.net Git - vlc/blob - src/stream_output/stream_output.c
Make Zorglub less unhappy
[vlc] / src / stream_output / stream_output.c
1 /*****************************************************************************
2  * stream_output.c : stream output module
3  *****************************************************************************
4  * Copyright (C) 2002-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Eric Petit <titer@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                                /* free() */
30 #include <stdio.h>                                              /* sprintf() */
31 #include <string.h>                                            /* strerror() */
32
33 #include <vlc/vlc.h>
34 #include <vlc/sout.h>
35
36 #include "vlc_meta.h"
37
38 #undef DEBUG_BUFFER
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 static void sout_CfgDestroy( sout_cfg_t * );
43
44 #define sout_stream_url_to_chain( p, s ) \
45     _sout_stream_url_to_chain( VLC_OBJECT(p), s )
46 static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
47
48 /*
49  * Generic MRL parser
50  *
51  */
52
53 typedef struct
54 {
55     char *psz_access;
56     char *psz_way;
57     char *psz_name;
58 } mrl_t;
59
60 /* mrl_Parse: parse psz_mrl and fill p_mrl */
61 static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
62 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
63 static void mrl_Clean( mrl_t *p_mrl );
64
65 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
66
67 /*****************************************************************************
68  * sout_NewInstance: creates a new stream output instance
69  *****************************************************************************/
70 sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
71 {
72     sout_instance_t *p_sout;
73     vlc_value_t keep;
74
75     if( var_Get( p_parent, "sout-keep", &keep ) < 0 )
76     {
77         msg_Warn( p_parent, "cannot get sout-keep value" );
78         keep.b_bool = VLC_FALSE;
79     }
80     else if( keep.b_bool )
81     {
82         msg_Warn( p_parent, "sout-keep true" );
83         if( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
84                                         FIND_ANYWHERE ) ) )
85         {
86             if( !strcmp( p_sout->psz_sout, psz_dest ) )
87             {
88                 msg_Warn( p_parent, "sout keep : reusing sout" );
89                 msg_Warn( p_parent, "sout keep : you probably want to use "
90                           "gather stream_out" );
91                 vlc_object_detach( p_sout );
92                 vlc_object_attach( p_sout, p_parent );
93                 vlc_object_release( p_sout );
94                 return p_sout;
95             }
96             else
97             {
98                 msg_Warn( p_parent, "sout keep : destroying unusable sout" );
99                 sout_DeleteInstance( p_sout );
100             }
101         }
102     }
103     else if( !keep.b_bool )
104     {
105         while( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
106                                            FIND_PARENT ) ) )
107         {
108             msg_Warn( p_parent, "sout keep : destroying old sout" );
109             sout_DeleteInstance( p_sout );
110         }
111     }
112
113     /* *** Allocate descriptor *** */
114     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
115     if( p_sout == NULL )
116     {
117         msg_Err( p_parent, "out of memory" );
118         return NULL;
119     }
120
121     /* *** init descriptor *** */
122     p_sout->psz_sout    = strdup( psz_dest );
123     p_sout->p_meta      = NULL;
124     p_sout->i_out_pace_nocontrol = 0;
125     p_sout->p_sys       = NULL;
126
127     vlc_mutex_init( p_sout, &p_sout->lock );
128     if( psz_dest && psz_dest[0] == '#' )
129     {
130         p_sout->psz_chain = strdup( &psz_dest[1] );
131     }
132     else
133     {
134         p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
135         msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
136     }
137     p_sout->p_stream = NULL;
138
139     /* attach it for inherit */
140     vlc_object_attach( p_sout, p_parent );
141
142     p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
143
144     if( p_sout->p_stream == NULL )
145     {
146         msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain );
147
148         FREE( p_sout->psz_sout );
149         FREE( p_sout->psz_chain );
150
151         vlc_object_detach( p_sout );
152         vlc_object_destroy( p_sout );
153         return NULL;
154     }
155
156     return p_sout;
157 }
158 /*****************************************************************************
159  * sout_DeleteInstance: delete a previously allocated instance
160  *****************************************************************************/
161 void sout_DeleteInstance( sout_instance_t * p_sout )
162 {
163     /* Unlink object */
164     vlc_object_detach( p_sout );
165
166     /* remove the stream out chain */
167     sout_StreamDelete( p_sout->p_stream );
168
169     /* *** free all string *** */
170     FREE( p_sout->psz_sout );
171     FREE( p_sout->psz_chain );
172
173     /* delete meta */
174     if( p_sout->p_meta )
175     {
176         vlc_meta_Delete( p_sout->p_meta );
177     }
178
179     vlc_mutex_destroy( &p_sout->lock );
180
181     /* *** free structure *** */
182     vlc_object_destroy( p_sout );
183 }
184
185 /*****************************************************************************
186  * Packetizer/Input
187  *****************************************************************************/
188 sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
189                                         es_format_t *p_fmt )
190 {
191     sout_packetizer_input_t *p_input;
192
193     msg_Dbg( p_sout, "adding a new input" );
194
195     /* *** create a packetizer input *** */
196     p_input         = malloc( sizeof( sout_packetizer_input_t ) );
197     p_input->p_sout = p_sout;
198     p_input->p_fmt  = p_fmt;
199
200     if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
201     {
202         vlc_object_release( p_sout );
203         return p_input;
204     }
205
206     /* *** add it to the stream chain */
207     vlc_mutex_lock( &p_sout->lock );
208     p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
209     vlc_mutex_unlock( &p_sout->lock );
210
211     if( p_input->id == NULL )
212     {
213         free( p_input );
214         return NULL;
215     }
216
217     return( p_input );
218 }
219
220 /*****************************************************************************
221  *
222  *****************************************************************************/
223 int sout_InputDelete( sout_packetizer_input_t *p_input )
224 {
225     sout_instance_t     *p_sout = p_input->p_sout;
226
227     msg_Dbg( p_sout, "removing an input" );
228
229     if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
230     {
231         vlc_mutex_lock( &p_sout->lock );
232         p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
233         vlc_mutex_unlock( &p_sout->lock );
234     }
235
236     free( p_input );
237
238     return( VLC_SUCCESS);
239 }
240
241 /*****************************************************************************
242  *
243  *****************************************************************************/
244 int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
245                           block_t *p_buffer )
246 {
247     sout_instance_t     *p_sout = p_input->p_sout;
248     int                 i_ret;
249
250     if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
251     {
252         block_Release( p_buffer );
253         return VLC_SUCCESS;
254     }
255     if( p_buffer->i_dts <= 0 )
256     {
257         msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
258         block_Release( p_buffer );
259         return VLC_SUCCESS;
260     }
261
262     vlc_mutex_lock( &p_sout->lock );
263     i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
264                                        p_input->id, p_buffer );
265     vlc_mutex_unlock( &p_sout->lock );
266
267     return i_ret;
268 }
269
270 /*****************************************************************************
271  * sout_AccessOutNew: allocate a new access out
272  *****************************************************************************/
273 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
274                                       char *psz_access, char *psz_name )
275 {
276     sout_access_out_t *p_access;
277     char              *psz_next;
278
279     if( !( p_access = vlc_object_create( p_sout,
280                                          sizeof( sout_access_out_t ) ) ) )
281     {
282         msg_Err( p_sout, "out of memory" );
283         return NULL;
284     }
285
286     psz_next = sout_CfgCreate( &p_access->psz_access, &p_access->p_cfg,
287                                 psz_access );
288     if( psz_next )
289     {
290         free( psz_next );
291     }
292     p_access->psz_name   = strdup( psz_name ? psz_name : "" );
293     p_access->p_sout     = p_sout;
294     p_access->p_sys = NULL;
295     p_access->pf_seek    = NULL;
296     p_access->pf_read    = NULL;
297     p_access->pf_write   = NULL;
298     p_access->p_module   = NULL;
299     vlc_object_attach( p_access, p_sout );
300
301     p_access->p_module   =
302         module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
303
304     if( !p_access->p_module )
305     {
306         free( p_access->psz_access );
307         free( p_access->psz_name );
308         vlc_object_detach( p_access );
309         vlc_object_destroy( p_access );
310         return( NULL );
311     }
312
313     return p_access;
314 }
315 /*****************************************************************************
316  * sout_AccessDelete: delete an access out
317  *****************************************************************************/
318 void sout_AccessOutDelete( sout_access_out_t *p_access )
319 {
320     vlc_object_detach( p_access );
321     if( p_access->p_module )
322     {
323         module_Unneed( p_access, p_access->p_module );
324     }
325     free( p_access->psz_access );
326
327     sout_CfgDestroy( p_access->p_cfg );
328
329     free( p_access->psz_name );
330
331     vlc_object_destroy( p_access );
332 }
333
334 /*****************************************************************************
335  * sout_AccessSeek:
336  *****************************************************************************/
337 int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
338 {
339     return p_access->pf_seek( p_access, i_pos );
340 }
341
342 /*****************************************************************************
343  * sout_AccessRead:
344  *****************************************************************************/
345 int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
346 {
347     return( p_access->pf_read ?
348             p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
349 }
350
351 /*****************************************************************************
352  * sout_AccessWrite:
353  *****************************************************************************/
354 int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
355 {
356     return p_access->pf_write( p_access, p_buffer );
357 }
358
359 /*****************************************************************************
360  * sout_MuxNew: create a new mux
361  *****************************************************************************/
362 sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
363                           sout_access_out_t *p_access )
364 {
365     sout_mux_t *p_mux;
366     char       *psz_next;
367
368     p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
369     if( p_mux == NULL )
370     {
371         msg_Err( p_sout, "out of memory" );
372         return NULL;
373     }
374
375     p_mux->p_sout = p_sout;
376     psz_next = sout_CfgCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
377     if( psz_next ) free( psz_next );
378
379     p_mux->p_access     = p_access;
380     p_mux->pf_control   = NULL;
381     p_mux->pf_addstream = NULL;
382     p_mux->pf_delstream = NULL;
383     p_mux->pf_mux       = NULL;
384     p_mux->i_nb_inputs  = 0;
385     p_mux->pp_inputs    = NULL;
386
387     p_mux->p_sys        = NULL;
388     p_mux->p_module     = NULL;
389
390     p_mux->b_add_stream_any_time = VLC_FALSE;
391     p_mux->b_waiting_stream = VLC_TRUE;
392     p_mux->i_add_stream_start = -1;
393
394     vlc_object_attach( p_mux, p_sout );
395
396     p_mux->p_module =
397         module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
398
399     if( p_mux->p_module == NULL )
400     {
401         FREE( p_mux->psz_mux );
402
403         vlc_object_detach( p_mux );
404         vlc_object_destroy( p_mux );
405         return NULL;
406     }
407
408     /* *** probe mux capacity *** */
409     if( p_mux->pf_control )
410     {
411         int b_answer = VLC_FALSE;
412
413         if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
414                              &b_answer ) )
415         {
416             b_answer = VLC_FALSE;
417         }
418
419         if( b_answer )
420         {
421             msg_Dbg( p_sout, "muxer support adding stream at any time" );
422             p_mux->b_add_stream_any_time = VLC_TRUE;
423             p_mux->b_waiting_stream = VLC_FALSE;
424
425             /* If we control the output pace then it's better to wait before
426              * starting muxing (generates better streams/files). */
427             if( !p_sout->i_out_pace_nocontrol )
428             {
429                 b_answer = VLC_TRUE;
430             }
431             else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
432                                       &b_answer ) )
433             {
434                 b_answer = VLC_FALSE;
435             }
436
437             if( b_answer )
438             {
439                 msg_Dbg( p_sout, "muxer prefers waiting for all ES before "
440                          "starting muxing" );
441                 p_mux->b_waiting_stream = VLC_TRUE;
442             }
443         }
444     }
445
446     return p_mux;
447 }
448
449 /*****************************************************************************
450  * sout_MuxDelete:
451  *****************************************************************************/
452 void sout_MuxDelete( sout_mux_t *p_mux )
453 {
454     vlc_object_detach( p_mux );
455     if( p_mux->p_module )
456     {
457         module_Unneed( p_mux, p_mux->p_module );
458     }
459     free( p_mux->psz_mux );
460
461     sout_CfgDestroy( p_mux->p_cfg );
462
463     vlc_object_destroy( p_mux );
464 }
465
466 /*****************************************************************************
467  * sout_MuxAddStream:
468  *****************************************************************************/
469 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
470 {
471     sout_input_t *p_input;
472
473     if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
474     {
475         msg_Err( p_mux, "cannot add a new stream (unsuported while muxing "
476                         "for this format)" );
477         return NULL;
478     }
479
480     msg_Dbg( p_mux, "adding a new input" );
481
482     /* create a new sout input */
483     p_input = malloc( sizeof( sout_input_t ) );
484     p_input->p_sout = p_mux->p_sout;
485     p_input->p_fmt  = p_fmt;
486     p_input->p_fifo = block_FifoNew( p_mux->p_sout );
487     p_input->p_sys  = NULL;
488
489     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
490     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
491     {
492             msg_Err( p_mux, "cannot add this stream" );
493             TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
494             block_FifoRelease( p_input->p_fifo );
495             free( p_input );
496             return NULL;
497     }
498
499     return p_input;
500 }
501
502 /*****************************************************************************
503  * sout_MuxDeleteStream:
504  *****************************************************************************/
505 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
506 {
507     int i_index;
508
509     if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
510     {
511         /* We stop waiting, and call the muxer for taking care of the data
512          * before we remove this es */
513         p_mux->b_waiting_stream = VLC_FALSE;
514         p_mux->pf_mux( p_mux );
515     }
516
517     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
518     if( i_index >= 0 )
519     {
520         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
521         {
522             msg_Err( p_mux, "cannot del this stream from mux" );
523         }
524
525         /* remove the entry */
526         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
527
528         if( p_mux->i_nb_inputs == 0 )
529         {
530             msg_Warn( p_mux, "no more input stream for this mux" );
531         }
532
533         block_FifoRelease( p_input->p_fifo );
534         free( p_input );
535     }
536 }
537
538 /*****************************************************************************
539  * sout_MuxSendBuffer:
540  *****************************************************************************/
541 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
542                          block_t *p_buffer )
543 {
544     block_FifoPut( p_input->p_fifo, p_buffer );
545
546     if( p_mux->p_sout->i_out_pace_nocontrol )
547     {
548         mtime_t current_date = mdate();
549         if ( current_date > p_buffer->i_dts )
550             msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
551                       current_date - p_buffer->i_dts );
552     }
553
554     if( p_mux->b_waiting_stream )
555     {
556         if( p_mux->i_add_stream_start < 0 )
557         {
558             p_mux->i_add_stream_start = p_buffer->i_dts;
559         }
560
561         if( p_mux->i_add_stream_start >= 0 &&
562             p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
563         {
564             /* Wait until we have more than 1.5 seconds worth of data
565              * before start muxing */
566             p_mux->b_waiting_stream = VLC_FALSE;
567         }
568         else
569         {
570             return;
571         }
572     }
573     p_mux->pf_mux( p_mux );
574 }
575
576 /*****************************************************************************
577  *
578  *****************************************************************************/
579 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
580 {
581     char * psz_dup = strdup( psz_mrl );
582     char * psz_parser = psz_dup;
583     char * psz_access = "";
584     char * psz_way = "";
585     char * psz_name = "";
586
587     /* *** first parse psz_dest */
588     while( *psz_parser && *psz_parser != ':' )
589     {
590         if( *psz_parser == '{' )
591         {
592             while( *psz_parser && *psz_parser != '}' )
593             {
594                 psz_parser++;
595             }
596             if( *psz_parser )
597             {
598                 psz_parser++;
599             }
600         }
601         else
602         {
603             psz_parser++;
604         }
605     }
606 #if defined( WIN32 ) || defined( UNDER_CE )
607     if( psz_parser - psz_dup == 1 )
608     {
609         /* msg_Warn( p_sout, "drive letter %c: found in source string",
610                           *psz_dup ) ; */
611         psz_parser = "";
612     }
613 #endif
614
615     if( !*psz_parser )
616     {
617         psz_access = psz_way = "";
618         psz_name = psz_dup;
619     }
620     else
621     {
622         *psz_parser++ = '\0';
623
624         /* let's skip '//' */
625         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
626         {
627             psz_parser += 2 ;
628         }
629
630         psz_name = psz_parser ;
631
632         /* Come back to parse the access and mux plug-ins */
633         psz_parser = psz_dup;
634
635         if( !*psz_parser )
636         {
637             /* No access */
638             psz_access = "";
639         }
640         else if( *psz_parser == '/' )
641         {
642             /* No access */
643             psz_access = "";
644             psz_parser++;
645         }
646         else
647         {
648             psz_access = psz_parser;
649
650             while( *psz_parser && *psz_parser != '/' )
651             {
652                 if( *psz_parser == '{' )
653                 {
654                     while( *psz_parser && *psz_parser != '}' )
655                     {
656                         psz_parser++;
657                     }
658                     if( *psz_parser )
659                     {
660                         psz_parser++;
661                     }
662                 }
663                 else
664                 {
665                     psz_parser++;
666                 }
667             }
668
669             if( *psz_parser == '/' )
670             {
671                 *psz_parser++ = '\0';
672             }
673         }
674
675         if( !*psz_parser )
676         {
677             /* No mux */
678             psz_way = "";
679         }
680         else
681         {
682             psz_way = psz_parser;
683         }
684     }
685
686     p_mrl->psz_access = strdup( psz_access );
687     p_mrl->psz_way    = strdup( psz_way );
688     p_mrl->psz_name   = strdup( psz_name );
689
690     free( psz_dup );
691     return( VLC_SUCCESS );
692 }
693
694
695 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
696 static void mrl_Clean( mrl_t *p_mrl )
697 {
698     FREE( p_mrl->psz_access );
699     FREE( p_mrl->psz_way );
700     FREE( p_mrl->psz_name );
701 }
702
703
704 /****************************************************************************
705  ****************************************************************************
706  **
707  **
708  **
709  ****************************************************************************
710  ****************************************************************************/
711
712 /* create a complete chain */
713 /* chain format:
714     module{option=*:option=*}[:module{option=*:...}]
715  */
716
717 /*
718  * parse module{options=str, option="str "}:
719  *  return a pointer on the rest
720  *  XXX: psz_chain is modified
721  */
722 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
723 #define SKIPTRAILINGSPACE( p, e ) \
724     { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
725
726 /* go accross " " and { } */
727 static char *_get_chain_end( char *str )
728 {
729     char c, *p = str;
730
731     SKIPSPACE( p );
732
733     for( ;; )
734     {
735         if( !*p || *p == ',' || *p == '}' ) return p;
736
737         if( *p != '{' && *p != '"' && *p != '\'' )
738         {
739             p++;
740             continue;
741         }
742
743         if( *p == '{' ) c = '}';
744         else c = *p;
745         p++;
746
747         for( ;; )
748         {
749             if( !*p ) return p;
750
751             if( *p == c ) return ++p;
752             else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
753             else p++;
754         }
755     }
756 }
757
758 char *sout_CfgCreate( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
759 {
760     sout_cfg_t *p_cfg = NULL;
761     char       *p = psz_chain;
762
763     *ppsz_name = NULL;
764     *pp_cfg    = NULL;
765
766     if( !p ) return NULL;
767
768     SKIPSPACE( p );
769
770     while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
771
772     if( p == psz_chain ) return NULL;
773
774     *ppsz_name = strndup( psz_chain, p - psz_chain );
775
776     SKIPSPACE( p );
777
778     if( *p == '{' )
779     {
780         char *psz_name;
781
782         p++;
783
784         for( ;; )
785         {
786             sout_cfg_t cfg;
787
788             SKIPSPACE( p );
789
790             psz_name = p;
791
792             while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
793                    *p != ' ' && *p != '\t' ) p++;
794
795             /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
796             if( p == psz_name )
797             {
798                 fprintf( stderr, "invalid options (empty)" );
799                 break;
800             }
801
802             cfg.psz_name = strndup( psz_name, p - psz_name );
803
804             SKIPSPACE( p );
805
806             if( *p == '=' || *p == '{' )
807             {
808                 char *end;
809                 vlc_bool_t b_keep_brackets = (*p == '{');
810
811                 if( *p == '=' ) p++;
812
813                 end = _get_chain_end( p );
814                 if( end <= p )
815                 {
816                     cfg.psz_value = NULL;
817                 }
818                 else
819                 {
820                     /* Skip heading and trailing spaces.
821                      * This ain't necessary but will avoid simple
822                      * user mistakes. */
823                     SKIPSPACE( p );
824                 }
825
826                 if( end <= p )
827                 {
828                     cfg.psz_value = NULL;
829                 }
830                 else
831                 {
832                     if( *p == '\'' || *p == '"' ||
833                         ( !b_keep_brackets && *p == '{' ) )
834                     {
835                         p++;
836
837                         if( *(end-1) != '\'' && *(end-1) == '"' )
838                             SKIPTRAILINGSPACE( p, end );
839
840                         if( end - 1 <= p ) cfg.psz_value = NULL;
841                         else cfg.psz_value = strndup( p, end -1 - p );
842                     }
843                     else
844                     {
845                         SKIPTRAILINGSPACE( p, end );
846                         if( end <= p ) cfg.psz_value = NULL;
847                         else cfg.psz_value = strndup( p, end - p );
848                     }
849                 }
850
851                 p = end;
852                 SKIPSPACE( p );
853             }
854             else
855             {
856                 cfg.psz_value = NULL;
857             }
858
859             cfg.p_next = NULL;
860             if( p_cfg )
861             {
862                 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
863                 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
864
865                 p_cfg = p_cfg->p_next;
866             }
867             else
868             {
869                 p_cfg = malloc( sizeof( sout_cfg_t ) );
870                 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
871
872                 *pp_cfg = p_cfg;
873             }
874
875             if( *p == ',' ) p++;
876
877             if( *p == '}' )
878             {
879                 p++;
880                 break;
881             }
882         }
883     }
884
885     if( *p == ':' ) return( strdup( p + 1 ) );
886
887     return NULL;
888 }
889
890 static void sout_CfgDestroy( sout_cfg_t *p_cfg )
891 {
892     while( p_cfg != NULL )
893     {
894         sout_cfg_t *p_next;
895
896         p_next = p_cfg->p_next;
897
898         FREE( p_cfg->psz_name );
899         FREE( p_cfg->psz_value );
900         free( p_cfg );
901
902         p_cfg = p_next;
903     }
904 }
905
906 void __sout_CfgParse( vlc_object_t *p_this, char *psz_prefix,
907                       const char **ppsz_options, sout_cfg_t *cfg )
908 {
909     char *psz_name;
910     int  i_type;
911     int  i;
912
913     /* First, var_Create all variables */
914     for( i = 0; ppsz_options[i] != NULL; i++ )
915     {
916         asprintf( &psz_name, "%s%s", psz_prefix,
917                   *ppsz_options[i] == '*' ? &ppsz_options[i][1] : ppsz_options[i] );
918
919         i_type = config_GetType( p_this, psz_name );
920
921         var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
922         free( psz_name );
923     }
924
925     /* Now parse options and set value */
926     if( psz_prefix == NULL ) psz_prefix = "";
927
928     while( cfg )
929     {
930         vlc_value_t val;
931         vlc_bool_t b_yes = VLC_TRUE;
932         vlc_bool_t b_once = VLC_FALSE;
933
934         if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
935         {
936             cfg = cfg->p_next;
937             continue;
938         }
939         for( i = 0; ppsz_options[i] != NULL; i++ )
940         {
941             if( !strcmp( ppsz_options[i], cfg->psz_name ) )
942             {
943                 break;
944             }
945             if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
946                   !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
947                 ( !strncmp( cfg->psz_name, "no", 2 ) &&
948                   !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
949             {
950                 b_yes = VLC_FALSE;
951                 break;
952             }
953
954             if( *ppsz_options[i] == '*' &&
955                 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
956             {
957                 b_once = VLC_TRUE;
958                 break;
959             }
960
961         }
962         if( ppsz_options[i] == NULL )
963         {
964             msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
965             cfg = cfg->p_next;
966             continue;
967         }
968
969         /* create name */
970         asprintf( &psz_name, "%s%s", psz_prefix, b_once ? &ppsz_options[i][1] : ppsz_options[i] );
971
972         /* get the type of the variable */
973         i_type = config_GetType( p_this, psz_name );
974         if( !i_type )
975         {
976             msg_Warn( p_this, "unknown option %s (value=%s)",
977                       cfg->psz_name, cfg->psz_value );
978             goto next;
979         }
980         if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
981         {
982             msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
983             goto next;
984         }
985         if( i_type != VLC_VAR_STRING && b_once )
986         {
987             msg_Warn( p_this, "*option_name need to be a string option" );
988             goto next;
989         }
990
991         switch( i_type )
992         {
993             case VLC_VAR_BOOL:
994                 val.b_bool = b_yes;
995                 break;
996             case VLC_VAR_INTEGER:
997                 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
998                                     NULL, 0 );
999                 break;
1000             case VLC_VAR_FLOAT:
1001                 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
1002                 break;
1003             case VLC_VAR_STRING:
1004             case VLC_VAR_MODULE:
1005                 val.psz_string = cfg->psz_value;
1006                 break;
1007             default:
1008                 msg_Warn( p_this, "unhandled config var type" );
1009                 memset( &val, 0, sizeof( vlc_value_t ) );
1010                 break;
1011         }
1012         if( b_once )
1013         {
1014             vlc_value_t val2;
1015
1016             var_Get( p_this, psz_name, &val2 );
1017             if( *val2.psz_string )
1018             {
1019                 free( val2.psz_string );
1020                 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
1021                 goto next;
1022             }
1023             free( val2.psz_string );
1024         }
1025         var_Set( p_this, psz_name, val );
1026         msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
1027
1028     next:
1029         free( psz_name );
1030         cfg = cfg->p_next;
1031     }
1032 }
1033
1034
1035 /*
1036  * XXX name and p_cfg are used (-> do NOT free them)
1037  */
1038 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
1039 {
1040     sout_stream_t *p_stream;
1041
1042     if( !psz_chain )
1043     {
1044         msg_Err( p_sout, "invalid chain" );
1045         return NULL;
1046     }
1047
1048     p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
1049
1050     if( !p_stream )
1051     {
1052         msg_Err( p_sout, "out of memory" );
1053         return NULL;
1054     }
1055
1056     p_stream->p_sout   = p_sout;
1057     p_stream->p_sys    = NULL;
1058
1059     p_stream->psz_next =
1060         sout_CfgCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
1061
1062     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
1063
1064     vlc_object_attach( p_stream, p_sout );
1065
1066     p_stream->p_module =
1067         module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
1068
1069     if( !p_stream->p_module )
1070     {
1071         sout_StreamDelete( p_stream );
1072         return NULL;
1073     }
1074
1075     return p_stream;
1076 }
1077
1078 void sout_StreamDelete( sout_stream_t *p_stream )
1079 {
1080     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
1081
1082     vlc_object_detach( p_stream );
1083     if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
1084
1085     FREE( p_stream->psz_name );
1086     FREE( p_stream->psz_next );
1087
1088     sout_CfgDestroy( p_stream->p_cfg );
1089
1090     msg_Dbg( p_stream, "destroying chain done" );
1091     vlc_object_destroy( p_stream );
1092 }
1093
1094 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
1095 {
1096     mrl_t       mrl;
1097     char        *psz_chain, *p;
1098
1099     mrl_Parse( &mrl, psz_url );
1100     p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
1101                                   strlen( mrl.psz_access ) +
1102                                   strlen( mrl.psz_name ) );
1103
1104
1105     if( config_GetInt( p_this, "sout-display" ) )
1106     {
1107         p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
1108                       "access=\"%s\",url=\"%s\"}}",
1109                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
1110     }
1111     else
1112     {
1113         p += sprintf( p, "std{mux=\"%s\",access=\"%s\",url=\"%s\"}",
1114                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
1115     }
1116
1117     mrl_Clean( &mrl );
1118     return( psz_chain );
1119 }