]> git.sesse.net Git - vlc/blob - src/stream_output/stream_output.c
* src/stream_output/stream_output.c: don't forget to detach an object before destroyi...
[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_cfg_free( 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_stream_new( 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_stream_delete( 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_cfg_parser( &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_cfg_free( 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_cfg_parser( &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_capacity  = 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_capacity )
408     {
409         int b_answer;
410         if( p_mux->pf_capacity( p_mux,
411                                 SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME, NULL,
412                                 (void*)&b_answer ) != SOUT_MUX_CAP_ERR_OK )
413         {
414             b_answer = VLC_FALSE;
415         }
416         if( b_answer )
417         {
418             msg_Dbg( p_sout, "muxer support adding stream at any time" );
419             p_mux->b_add_stream_any_time = VLC_TRUE;
420             p_mux->b_waiting_stream = VLC_FALSE;
421
422             if( p_mux->pf_capacity( p_mux,
423                                     SOUT_MUX_CAP_GET_ADD_STREAM_WAIT, NULL,
424                                     (void*)&b_answer ) != SOUT_MUX_CAP_ERR_OK )
425             {
426                 b_answer = VLC_FALSE;
427             }
428             if( b_answer )
429             {
430                 msg_Dbg( p_sout, "muxer prefers waiting for all ES before "
431                          "starting muxing" );
432                 p_mux->b_waiting_stream = VLC_TRUE;
433             }
434         }
435         else
436         {
437             p_mux->b_add_stream_any_time = VLC_FALSE;
438             p_mux->b_waiting_stream = VLC_TRUE;
439         }
440     }
441     else
442     {
443         p_mux->b_add_stream_any_time = VLC_FALSE;
444         p_mux->b_waiting_stream = VLC_TRUE;
445     }
446     p_mux->i_add_stream_start = -1;
447
448     return p_mux;
449 }
450
451 /*****************************************************************************
452  * sout_MuxDelete:
453  *****************************************************************************/
454 void sout_MuxDelete( sout_mux_t *p_mux )
455 {
456     vlc_object_detach( p_mux );
457     if( p_mux->p_module )
458     {
459         module_Unneed( p_mux, p_mux->p_module );
460     }
461     free( p_mux->psz_mux );
462
463     sout_cfg_free( p_mux->p_cfg );
464
465     vlc_object_destroy( p_mux );
466 }
467
468 /*****************************************************************************
469  * sout_MuxAddStream:
470  *****************************************************************************/
471 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
472 {
473     sout_input_t *p_input;
474
475     if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
476     {
477         msg_Err( p_mux, "cannot add a new stream (unsuported while muxing "
478                         "for this format)" );
479         return NULL;
480     }
481     if( p_mux->i_add_stream_start < 0 )
482     {
483         /* we wait for one second */
484         p_mux->i_add_stream_start = mdate();
485     }
486
487     msg_Dbg( p_mux, "adding a new input" );
488
489     /* create a new sout input */
490     p_input = malloc( sizeof( sout_input_t ) );
491     p_input->p_sout = p_mux->p_sout;
492     p_input->p_fmt  = p_fmt;
493     p_input->p_fifo = block_FifoNew( p_mux->p_sout );
494     p_input->p_sys  = NULL;
495
496     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
497     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
498     {
499             msg_Err( p_mux, "cannot add this stream" );
500             TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
501             block_FifoRelease( p_input->p_fifo );
502             free( p_input );
503             return NULL;
504     }
505
506     return p_input;
507 }
508
509 /*****************************************************************************
510  * sout_MuxDeleteStream:
511  *****************************************************************************/
512 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
513 {
514     int i_index;
515
516     if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
517     {
518         /* We stop waiting, and call the muxer for taking care of the data
519          * before we remove this es */
520         p_mux->b_waiting_stream = VLC_FALSE;
521         p_mux->pf_mux( p_mux );
522     }
523
524     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
525     if( i_index >= 0 )
526     {
527         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
528         {
529             msg_Err( p_mux, "cannot del this stream from mux" );
530         }
531
532         /* remove the entry */
533         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
534
535         if( p_mux->i_nb_inputs == 0 )
536         {
537             msg_Warn( p_mux, "no more input stream for this mux" );
538         }
539
540         block_FifoRelease( p_input->p_fifo );
541         free( p_input );
542     }
543 }
544
545 /*****************************************************************************
546  * sout_MuxSendBuffer:
547  *****************************************************************************/
548 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
549                          block_t *p_buffer )
550 {
551     block_FifoPut( p_input->p_fifo, p_buffer );
552
553     if( p_mux->b_waiting_stream )
554     {
555         if( p_mux->i_add_stream_start > 0 &&
556             p_mux->i_add_stream_start + (mtime_t)1500000 < mdate() )
557         {
558             /* more than 1.5 second, start muxing */
559             p_mux->b_waiting_stream = VLC_FALSE;
560         }
561         else
562         {
563             return;
564         }
565     }
566     p_mux->pf_mux( p_mux );
567 }
568
569 /*****************************************************************************
570  *
571  *****************************************************************************/
572 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
573 {
574     char * psz_dup = strdup( psz_mrl );
575     char * psz_parser = psz_dup;
576     char * psz_access = "";
577     char * psz_way = "";
578     char * psz_name = "";
579
580     /* *** first parse psz_dest */
581     while( *psz_parser && *psz_parser != ':' )
582     {
583         if( *psz_parser == '{' )
584         {
585             while( *psz_parser && *psz_parser != '}' )
586             {
587                 psz_parser++;
588             }
589             if( *psz_parser )
590             {
591                 psz_parser++;
592             }
593         }
594         else
595         {
596             psz_parser++;
597         }
598     }
599 #if defined( WIN32 ) || defined( UNDER_CE )
600     if( psz_parser - psz_dup == 1 )
601     {
602         /* msg_Warn( p_sout, "drive letter %c: found in source string",
603                           *psz_dup ) ; */
604         psz_parser = "";
605     }
606 #endif
607
608     if( !*psz_parser )
609     {
610         psz_access = psz_way = "";
611         psz_name = psz_dup;
612     }
613     else
614     {
615         *psz_parser++ = '\0';
616
617         /* let's skip '//' */
618         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
619         {
620             psz_parser += 2 ;
621         }
622
623         psz_name = psz_parser ;
624
625         /* Come back to parse the access and mux plug-ins */
626         psz_parser = psz_dup;
627
628         if( !*psz_parser )
629         {
630             /* No access */
631             psz_access = "";
632         }
633         else if( *psz_parser == '/' )
634         {
635             /* No access */
636             psz_access = "";
637             psz_parser++;
638         }
639         else
640         {
641             psz_access = psz_parser;
642
643             while( *psz_parser && *psz_parser != '/' )
644             {
645                 if( *psz_parser == '{' )
646                 {
647                     while( *psz_parser && *psz_parser != '}' )
648                     {
649                         psz_parser++;
650                     }
651                     if( *psz_parser )
652                     {
653                         psz_parser++;
654                     }
655                 }
656                 else
657                 {
658                     psz_parser++;
659                 }
660             }
661
662             if( *psz_parser == '/' )
663             {
664                 *psz_parser++ = '\0';
665             }
666         }
667
668         if( !*psz_parser )
669         {
670             /* No mux */
671             psz_way = "";
672         }
673         else
674         {
675             psz_way = psz_parser;
676         }
677     }
678
679     p_mrl->psz_access = strdup( psz_access );
680     p_mrl->psz_way    = strdup( psz_way );
681     p_mrl->psz_name   = strdup( psz_name );
682
683     free( psz_dup );
684     return( VLC_SUCCESS );
685 }
686
687
688 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
689 static void mrl_Clean( mrl_t *p_mrl )
690 {
691     FREE( p_mrl->psz_access );
692     FREE( p_mrl->psz_way );
693     FREE( p_mrl->psz_name );
694 }
695
696
697 /****************************************************************************
698  ****************************************************************************
699  **
700  **
701  **
702  ****************************************************************************
703  ****************************************************************************/
704
705 /* create a complete chain */
706 /* chain format:
707     module{option=*:option=*}[:module{option=*:...}]
708  */
709
710 /*
711  * parse module{options=str, option="str "}:
712  *  return a pointer on the rest
713  *  XXX: psz_chain is modified
714  */
715 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
716 #define SKIPTRAILINGSPACE( p, e ) \
717     { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
718
719 /* go accross " " and { } */
720 static char *_get_chain_end( char *str )
721 {
722     char c, *p = str;
723
724     SKIPSPACE( p );
725
726     for( ;; )
727     {
728         if( !*p || *p == ',' || *p == '}' ) return p;
729
730         if( *p != '{' && *p != '"' && *p != '\'' )
731         {
732             p++;
733             continue;
734         }
735
736         if( *p == '{' ) c = '}';
737         else c = *p;
738         p++;
739
740         for( ;; )
741         {
742             if( !*p ) return p;
743
744             if( *p == c ) return ++p;
745             else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
746             else p++;
747         }
748     }
749 }
750
751 char *sout_cfg_parser( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
752 {
753     sout_cfg_t *p_cfg = NULL;
754     char       *p = psz_chain;
755
756     *ppsz_name = NULL;
757     *pp_cfg    = NULL;
758
759     if( !p ) return NULL;
760
761     SKIPSPACE( p );
762
763     while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
764
765     if( p == psz_chain ) return NULL;
766
767     *ppsz_name = strndup( psz_chain, p - psz_chain );
768
769     SKIPSPACE( p );
770
771     if( *p == '{' )
772     {
773         char *psz_name;
774
775         p++;
776
777         for( ;; )
778         {
779             sout_cfg_t cfg;
780
781             SKIPSPACE( p );
782
783             psz_name = p;
784
785             while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
786                    *p != ' ' && *p != '\t' ) p++;
787
788             /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
789             if( p == psz_name )
790             {
791                 fprintf( stderr, "invalid options (empty)" );
792                 break;
793             }
794
795             cfg.psz_name = strndup( psz_name, p - psz_name );
796
797             SKIPSPACE( p );
798
799             if( *p == '=' || *p == '{' )
800             {
801                 char *end;
802                 vlc_bool_t b_keep_brackets = (*p == '{');
803
804                 if( *p == '=' ) p++;
805
806                 end = _get_chain_end( p );
807                 if( end <= p )
808                 {
809                     cfg.psz_value = NULL;
810                 }
811                 else
812                 {
813                     /* Skip heading and trailing spaces.
814                      * This ain't necessary but will avoid simple
815                      * user mistakes. */
816                     SKIPSPACE( p );
817                 }
818
819                 if( end <= p )
820                 {
821                     cfg.psz_value = NULL;
822                 }
823                 else
824                 {
825                     if( *p == '\'' || *p == '"' ||
826                         ( !b_keep_brackets && *p == '{' ) )
827                     {
828                         p++;
829
830                         if( *(end-1) != '\'' && *(end-1) == '"' )
831                             SKIPTRAILINGSPACE( p, end );
832
833                         if( end - 1 <= p ) cfg.psz_value = NULL;
834                         else cfg.psz_value = strndup( p, end -1 - p );
835                     }
836                     else
837                     {
838                         SKIPTRAILINGSPACE( p, end );
839                         if( end <= p ) cfg.psz_value = NULL;
840                         else cfg.psz_value = strndup( p, end - p );
841                     }
842                 }
843
844                 p = end;
845                 SKIPSPACE( p );
846             }
847             else
848             {
849                 cfg.psz_value = NULL;
850             }
851
852             cfg.p_next = NULL;
853             if( p_cfg )
854             {
855                 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
856                 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
857
858                 p_cfg = p_cfg->p_next;
859             }
860             else
861             {
862                 p_cfg = malloc( sizeof( sout_cfg_t ) );
863                 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
864
865                 *pp_cfg = p_cfg;
866             }
867
868             if( *p == ',' ) p++;
869
870             if( *p == '}' )
871             {
872                 p++;
873                 break;
874             }
875         }
876     }
877
878     if( *p == ':' ) return( strdup( p + 1 ) );
879
880     return NULL;
881 }
882
883 static void sout_cfg_free( sout_cfg_t *p_cfg )
884 {
885     while( p_cfg != NULL )
886     {
887         sout_cfg_t *p_next;
888
889         p_next = p_cfg->p_next;
890
891         FREE( p_cfg->psz_name );
892         FREE( p_cfg->psz_value );
893         free( p_cfg );
894
895         p_cfg = p_next;
896     }
897 }
898
899 void __sout_ParseCfg( vlc_object_t *p_this, char *psz_prefix,
900                       const char **ppsz_options, sout_cfg_t *cfg )
901 {
902     char *psz_name;
903     int  i_type;
904     int  i;
905
906     /* First, var_Create all variables */
907     for( i = 0; ppsz_options[i] != NULL; i++ )
908     {
909         asprintf( &psz_name, "%s%s", psz_prefix, ppsz_options[i] );
910
911         i_type = config_GetType( p_this, psz_name );
912
913         var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
914         free( psz_name );
915     }
916
917     /* Now parse options and set value */
918     if( psz_prefix == NULL ) psz_prefix = "";
919
920     while( cfg )
921     {
922         vlc_value_t val;
923         vlc_bool_t b_yes = VLC_TRUE;
924
925         if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
926         {
927             cfg = cfg->p_next;
928             continue;
929         }
930         for( i = 0; ppsz_options[i] != NULL; i++ )
931         {
932             if( !strcmp( ppsz_options[i], cfg->psz_name ) )
933             {
934                 break;
935             }
936             if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
937                   !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
938                 ( !strncmp( cfg->psz_name, "no", 2 ) &&
939                   !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
940             {
941                 b_yes = VLC_FALSE;
942                 break;
943             }
944         }
945         if( ppsz_options[i] == NULL )
946         {
947             msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
948             cfg = cfg->p_next;
949             continue;
950         }
951
952         /* create name */
953         asprintf( &psz_name, "%s%s", psz_prefix, ppsz_options[i] );
954
955         /* get the type of the variable */
956         i_type = config_GetType( p_this, psz_name );
957         if( !i_type )
958         {
959             msg_Warn( p_this, "unknown option %s (value=%s)",
960                       cfg->psz_name, cfg->psz_value );
961             goto next;
962         }
963         if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
964         {
965             msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
966             goto next;
967         }
968
969         switch( i_type )
970         {
971             case VLC_VAR_BOOL:
972                 val.b_bool = b_yes;
973                 break;
974             case VLC_VAR_INTEGER:
975                 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
976                                     NULL, 0 );
977                 break;
978             case VLC_VAR_FLOAT:
979                 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
980                 break;
981             case VLC_VAR_STRING:
982                 val.psz_string = cfg->psz_value;
983                 break;
984             default:
985                 msg_Warn( p_this, "unhandled config var type" );
986                 memset( &val, 0, sizeof( vlc_value_t ) );
987                 break;
988         }
989         var_Set( p_this, psz_name, val );
990         msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
991
992     next:
993         free( psz_name );
994         cfg = cfg->p_next;
995     }
996 }
997
998
999 /*
1000  * XXX name and p_cfg are used (-> do NOT free them)
1001  */
1002 sout_stream_t *sout_stream_new( sout_instance_t *p_sout, char *psz_chain )
1003 {
1004     sout_stream_t *p_stream;
1005
1006     if( !psz_chain )
1007     {
1008         msg_Err( p_sout, "invalid chain" );
1009         return NULL;
1010     }
1011
1012     p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
1013
1014     if( !p_stream )
1015     {
1016         msg_Err( p_sout, "out of memory" );
1017         return NULL;
1018     }
1019
1020     p_stream->p_sout   = p_sout;
1021     p_stream->p_sys    = NULL;
1022
1023     p_stream->psz_next =
1024         sout_cfg_parser( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
1025
1026     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
1027
1028     vlc_object_attach( p_stream, p_sout );
1029
1030     p_stream->p_module =
1031         module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
1032
1033     if( !p_stream->p_module )
1034     {
1035         sout_stream_delete( p_stream );
1036         return NULL;
1037     }
1038
1039     return p_stream;
1040 }
1041
1042 void sout_stream_delete( sout_stream_t *p_stream )
1043 {
1044     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
1045
1046     vlc_object_detach( p_stream );
1047     if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
1048
1049     FREE( p_stream->psz_name );
1050     FREE( p_stream->psz_next );
1051
1052     sout_cfg_free( p_stream->p_cfg );
1053
1054     msg_Dbg( p_stream, "destroying chain done" );
1055     vlc_object_destroy( p_stream );
1056 }
1057
1058 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
1059 {
1060     mrl_t       mrl;
1061     char        *psz_chain, *p;
1062
1063     mrl_Parse( &mrl, psz_url );
1064     p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
1065                                   strlen( mrl.psz_access ) +
1066                                   strlen( mrl.psz_name ) );
1067
1068
1069     if( config_GetInt( p_this, "sout-display" ) )
1070     {
1071         p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
1072                       "access=\"%s\",url=\"%s\"}}",
1073                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
1074     }
1075     else
1076     {
1077         p += sprintf( p, "std{mux=\"%s\",access=\"%s\",url=\"%s\"}",
1078                       mrl.psz_way, mrl.psz_access, mrl.psz_name );
1079     }
1080
1081     mrl_Clean( &mrl );
1082     return( psz_chain );
1083 }