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