]> git.sesse.net Git - vlc/blob - src/stream_output/stream_output.c
* stream_output: * some clean and fixed a little memory leak.
[vlc] / src / stream_output / stream_output.c
1 /*****************************************************************************
2  * stream_output.c : stream output module
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: stream_output.c,v 1.31 2003/07/31 19:24:10 fenrir Exp $
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
35 #include <vlc/sout.h>
36 #undef DEBUG_BUFFER
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static void sout_cfg_free( sout_cfg_t * );
41
42 #define sout_stream_url_to_chain( p, s ) _sout_stream_url_to_chain( VLC_OBJECT(p), s )
43 static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
44
45 #define module_NeedStrict(a,b,c) __module_NeedStrict(VLC_OBJECT(a),b,c)
46 static module_t *__module_NeedStrict( vlc_object_t *, const char *, const char * );
47
48 /*
49  * Generic MRL parser
50  *
51  */
52
53 typedef struct
54 {
55     char            *psz_access;
56
57     char            *psz_way;
58
59     char *psz_name;
60 } mrl_t;
61
62 /* mrl_Parse: parse psz_mrl and fill p_mrl */
63 static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
64 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
65 static void mrl_Clean( mrl_t *p_mrl );
66
67 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
68
69 /*****************************************************************************
70  * sout_NewInstance: creates a new stream output instance
71  *****************************************************************************/
72 sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
73                                        char * psz_dest )
74 {
75     sout_instance_t *p_sout;
76
77     /* *** Allocate descriptor *** */
78     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
79     if( p_sout == NULL )
80     {
81         msg_Err( p_parent, "out of memory" );
82         return NULL;
83     }
84
85     /* *** init descriptor *** */
86     p_sout->psz_sout    = strdup( psz_dest );
87     p_sout->i_preheader = 0;
88     p_sout->p_sys       = NULL;
89
90     vlc_mutex_init( p_sout, &p_sout->lock );
91     if( psz_dest && psz_dest[0] == '#' )
92     {
93         p_sout->psz_chain = strdup( &psz_dest[1] );
94     }
95     else
96     {
97         p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
98         msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
99     }
100
101     p_sout->p_stream = sout_stream_new( p_sout, p_sout->psz_chain );
102
103     if( p_sout->p_stream == NULL )
104     {
105         msg_Err( p_sout, "stream chained failed for `%s'", p_sout->psz_chain );
106
107         FREE( p_sout->psz_sout );
108         FREE( p_sout->psz_chain );
109
110         vlc_object_destroy( p_sout );
111         return( NULL );
112     }
113
114     vlc_object_attach( p_sout, p_parent );
115
116     return p_sout;
117 }
118 /*****************************************************************************
119  * sout_DeleteInstance: delete a previously allocated instance
120  *****************************************************************************/
121 void sout_DeleteInstance( sout_instance_t * p_sout )
122 {
123     /* Unlink object */
124     vlc_object_detach( p_sout );
125
126     /* *** free all string *** */
127     FREE( p_sout->psz_sout );
128     FREE( p_sout->psz_chain );
129
130     sout_stream_delete( p_sout->p_stream );
131     vlc_mutex_destroy( &p_sout->lock );
132
133     /* *** free structure *** */
134     vlc_object_destroy( p_sout );
135 }
136
137 /*****************************************************************************
138  * Packetizer/Input
139  *****************************************************************************/
140 sout_packetizer_input_t *__sout_InputNew( vlc_object_t  *p_this,
141                                           sout_format_t *p_fmt )
142 {
143     sout_instance_t         *p_sout = NULL;
144     sout_packetizer_input_t *p_input;
145
146     int             i_try;
147
148     /* search an stream output */
149     for( i_try = 0; i_try < 12; i_try++ )
150     {
151         p_sout = vlc_object_find( p_this, VLC_OBJECT_SOUT, FIND_ANYWHERE );
152         if( p_sout )
153         {
154             break;
155         }
156
157         msleep( 100*1000 );
158         msg_Dbg( p_this, "waiting for sout" );
159     }
160
161     if( !p_sout )
162     {
163         msg_Err( p_this, "cannot find any stream ouput" );
164         return( NULL );
165     }
166
167     msg_Dbg( p_sout, "adding a new input" );
168
169     /* *** create a packetizer input *** */
170     p_input         = malloc( sizeof( sout_packetizer_input_t ) );
171     p_input->p_sout = p_sout;
172     p_input->p_fmt  = p_fmt;
173
174     if( p_fmt->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
175     {
176         vlc_object_release( p_sout );
177         return p_input;
178     }
179
180     /* *** add it to the stream chain */
181     vlc_mutex_lock( &p_sout->lock );
182     p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream,
183                                             p_fmt );
184     vlc_mutex_unlock( &p_sout->lock );
185
186     vlc_object_release( p_sout );
187
188     if( p_input->id == NULL )
189     {
190         free( p_input );
191         return( NULL );
192     }
193
194     return( p_input );
195 }
196
197
198 int sout_InputDelete( sout_packetizer_input_t *p_input )
199 {
200     sout_instance_t     *p_sout = p_input->p_sout;
201
202     msg_Dbg( p_sout, "removing an input" );
203
204     if( p_input->p_fmt->i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
205     {
206         vlc_mutex_lock( &p_sout->lock );
207         p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
208         vlc_mutex_unlock( &p_sout->lock );
209     }
210
211     free( p_input );
212
213     return( VLC_SUCCESS);
214 }
215
216
217 int sout_InputSendBuffer( sout_packetizer_input_t *p_input, sout_buffer_t *p_buffer )
218 {
219     sout_instance_t     *p_sout = p_input->p_sout;
220     int                 i_ret;
221
222     if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
223     {
224         sout_BufferDelete( p_input->p_sout, p_buffer );
225         return VLC_SUCCESS;
226     }
227
228     vlc_mutex_lock( &p_sout->lock );
229     i_ret = p_sout->p_stream->pf_send( p_sout->p_stream, p_input->id, p_buffer );
230     vlc_mutex_unlock( &p_sout->lock );
231
232     return i_ret;
233 }
234
235 /*****************************************************************************
236  * sout_AccessOutNew: allocate a new access out
237  *****************************************************************************/
238 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
239                                       char *psz_access, char *psz_name )
240 {
241     sout_access_out_t *p_access;
242     char              *psz_next;
243
244     if( !( p_access = vlc_object_create( p_sout,
245                                          sizeof( sout_access_out_t ) ) ) )
246     {
247         msg_Err( p_sout, "out of memory" );
248         return NULL;
249     }
250
251     psz_next = sout_cfg_parser( &p_access->psz_access, &p_access->p_cfg, psz_access );
252     if( psz_next )
253     {
254         free( psz_next );
255     }
256     p_access->psz_name   = strdup( psz_name ? psz_name : "" );
257     p_access->p_sout     = p_sout;
258     p_access->p_sys = NULL;
259     p_access->pf_seek    = NULL;
260     p_access->pf_write   = NULL;
261
262     p_access->p_module   =
263         module_NeedStrict( p_access, "sout access", p_access->psz_access );
264
265     if( !p_access->p_module )
266     {
267         free( p_access->psz_access );
268         free( p_access->psz_name );
269         vlc_object_destroy( p_access );
270         return( NULL );
271     }
272
273     return p_access;
274 }
275 /*****************************************************************************
276  * sout_AccessDelete: delete an access out
277  *****************************************************************************/
278 void sout_AccessOutDelete( sout_access_out_t *p_access )
279 {
280     if( p_access->p_module )
281     {
282         module_Unneed( p_access, p_access->p_module );
283     }
284     free( p_access->psz_access );
285
286     sout_cfg_free( p_access->p_cfg );
287
288     free( p_access->psz_name );
289
290     vlc_object_destroy( p_access );
291 }
292
293 /*****************************************************************************
294  * sout_AccessSeek:
295  *****************************************************************************/
296 int  sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
297 {
298     return( p_access->pf_seek( p_access, i_pos ) );
299 }
300
301 /*****************************************************************************
302  * sout_AccessWrite:
303  *****************************************************************************/
304 int  sout_AccessOutWrite( sout_access_out_t *p_access, sout_buffer_t *p_buffer )
305 {
306     return( p_access->pf_write( p_access, p_buffer ) );
307 }
308
309
310 /*****************************************************************************
311  * MuxNew: allocate a new mux
312  *****************************************************************************/
313 sout_mux_t * sout_MuxNew         ( sout_instance_t *p_sout,
314                                    char *psz_mux,
315                                    sout_access_out_t *p_access )
316 {
317     sout_mux_t *p_mux;
318     char       *psz_next;
319
320     p_mux = vlc_object_create( p_sout,
321                                sizeof( sout_mux_t ) );
322     if( p_mux == NULL )
323     {
324         msg_Err( p_sout, "out of memory" );
325         return NULL;
326     }
327
328     p_mux->p_sout       = p_sout;
329     psz_next = sout_cfg_parser( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
330     if( psz_next )
331     {
332         free( psz_next );
333     }
334     p_mux->p_access     = p_access;
335     p_mux->i_preheader  = 0;
336     p_mux->pf_capacity  = NULL;
337     p_mux->pf_addstream = NULL;
338     p_mux->pf_delstream = NULL;
339     p_mux->pf_mux       = NULL;
340     p_mux->i_nb_inputs  = 0;
341     p_mux->pp_inputs    = NULL;
342
343     p_mux->p_sys        = NULL;
344
345     p_mux->p_module     =
346         module_NeedStrict( p_mux, "sout mux", p_mux->psz_mux );
347
348     if( p_mux->p_module == NULL )
349     {
350         FREE( p_mux->psz_mux );
351
352         vlc_object_destroy( p_mux );
353         return NULL;
354     }
355
356     /* *** probe mux capacity *** */
357     if( p_mux->pf_capacity )
358     {
359         int b_answer;
360         if( p_mux->pf_capacity( p_mux,
361                                 SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME,
362                                 NULL, (void*)&b_answer ) != SOUT_MUX_CAP_ERR_OK )
363         {
364             b_answer = VLC_FALSE;
365         }
366         if( b_answer )
367         {
368             msg_Dbg( p_sout, "muxer support adding stream at any time" );
369             p_mux->b_add_stream_any_time = VLC_TRUE;
370             p_mux->b_waiting_stream = VLC_FALSE;
371         }
372         else
373         {
374             p_mux->b_add_stream_any_time = VLC_FALSE;
375             p_mux->b_waiting_stream = VLC_TRUE;
376         }
377     }
378     else
379     {
380         p_mux->b_add_stream_any_time = VLC_FALSE;
381         p_mux->b_waiting_stream = VLC_TRUE;
382     }
383     p_mux->i_add_stream_start = -1;
384
385     return p_mux;
386 }
387
388 void sout_MuxDelete              ( sout_mux_t *p_mux )
389 {
390     if( p_mux->p_module )
391     {
392         module_Unneed( p_mux, p_mux->p_module );
393     }
394     free( p_mux->psz_mux );
395
396     sout_cfg_free( p_mux->p_cfg );
397
398     vlc_object_destroy( p_mux );
399 }
400
401 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux,
402                                  sout_format_t *p_fmt )
403 {
404     sout_input_t *p_input;
405
406     if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream)
407     {
408         msg_Err( p_mux, "cannot add a new stream (unsuported while muxing for this format)" );
409         return NULL;
410     }
411     if( p_mux->i_add_stream_start < 0 )
412     {
413         /* we wait for one second */
414         p_mux->i_add_stream_start = mdate();
415     }
416
417     msg_Dbg( p_mux, "adding a new input" );
418
419     /* create a new sout input */
420     p_input = malloc( sizeof( sout_input_t ) );
421     p_input->p_sout = p_mux->p_sout;
422     p_input->p_fmt  = p_fmt;
423     p_input->p_fifo = sout_FifoCreate( p_mux->p_sout );
424     p_input->p_sys  = NULL;
425
426     TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
427     if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
428     {
429             msg_Err( p_mux, "cannot add this stream" );
430             TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
431             sout_FifoDestroy( p_mux->p_sout, p_input->p_fifo );
432             free( p_input );
433             return( NULL );
434     }
435
436     return( p_input );
437 }
438
439 void sout_MuxDeleteStream     ( sout_mux_t *p_mux,
440                                 sout_input_t *p_input )
441 {
442     int i_index;
443
444     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
445     if( i_index >= 0 )
446     {
447         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
448         {
449             msg_Err( p_mux, "cannot del this stream from mux" );
450         }
451
452         /* remove the entry */
453         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
454
455         if( p_mux->i_nb_inputs == 0 )
456         {
457             msg_Warn( p_mux, "no more input stream for this mux" );
458         }
459
460         sout_FifoDestroy( p_mux->p_sout, p_input->p_fifo );
461         free( p_input );
462     }
463 }
464
465 void sout_MuxSendBuffer       ( sout_mux_t    *p_mux,
466                                 sout_input_t  *p_input,
467                                 sout_buffer_t *p_buffer )
468 {
469     sout_FifoPut( p_input->p_fifo, p_buffer );
470
471     if( p_mux->b_waiting_stream )
472     {
473         if( p_mux->i_add_stream_start > 0 &&
474             p_mux->i_add_stream_start + (mtime_t)1500000 < mdate() )
475         {
476             /* more than 1.5 second, start muxing */
477             p_mux->b_waiting_stream = VLC_FALSE;
478         }
479         else
480         {
481             return;
482         }
483     }
484     p_mux->pf_mux( p_mux );
485 }
486
487
488
489 sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
490 {
491     sout_fifo_t *p_fifo;
492
493     if( !( p_fifo = malloc( sizeof( sout_fifo_t ) ) ) )
494     {
495         return( NULL );
496     }
497
498     vlc_mutex_init( p_sout, &p_fifo->lock );
499     vlc_cond_init ( p_sout, &p_fifo->wait );
500     p_fifo->i_depth = 0;
501     p_fifo->p_first = NULL;
502     p_fifo->pp_last = &p_fifo->p_first;
503
504     return( p_fifo );
505 }
506
507 void       sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
508 {
509     sout_buffer_t *p_buffer;
510
511     vlc_mutex_lock( &p_fifo->lock );
512     p_buffer = p_fifo->p_first;
513     while( p_buffer )
514     {
515         sout_buffer_t *p_next;
516         p_next = p_buffer->p_next;
517         sout_BufferDelete( p_sout, p_buffer );
518         p_buffer = p_next;
519     }
520     vlc_mutex_unlock( &p_fifo->lock );
521
522     return;
523 }
524 void       sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
525 {
526     sout_FifoFree( p_sout, p_fifo );
527     vlc_mutex_destroy( &p_fifo->lock );
528     vlc_cond_destroy ( &p_fifo->wait );
529
530     free( p_fifo );
531 }
532
533 void        sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
534 {
535     vlc_mutex_lock( &p_fifo->lock );
536
537     do
538     {
539         *p_fifo->pp_last = p_buffer;
540         p_fifo->pp_last = &p_buffer->p_next;
541         p_fifo->i_depth++;
542
543         p_buffer = p_buffer->p_next;
544
545     } while( p_buffer );
546
547     /* warm there is data in this fifo */
548     vlc_cond_signal( &p_fifo->wait );
549     vlc_mutex_unlock( &p_fifo->lock );
550 }
551
552 sout_buffer_t *sout_FifoGet( sout_fifo_t *p_fifo )
553 {
554     sout_buffer_t *p_buffer;
555
556     vlc_mutex_lock( &p_fifo->lock );
557
558     if( p_fifo->p_first == NULL )
559     {
560         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
561     }
562
563     p_buffer = p_fifo->p_first;
564
565     p_fifo->p_first = p_buffer->p_next;
566     p_fifo->i_depth--;
567
568     if( p_fifo->p_first == NULL )
569     {
570         p_fifo->pp_last = &p_fifo->p_first;
571     }
572
573     vlc_mutex_unlock( &p_fifo->lock );
574
575     p_buffer->p_next = NULL;
576     return( p_buffer );
577 }
578
579 sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo )
580 {
581     sout_buffer_t *p_buffer;
582
583     vlc_mutex_lock( &p_fifo->lock );
584
585     if( p_fifo->p_first == NULL )
586     {
587         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
588     }
589
590     p_buffer = p_fifo->p_first;
591
592     vlc_mutex_unlock( &p_fifo->lock );
593
594     return( p_buffer );
595 }
596
597 sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
598 {
599     sout_buffer_t *p_buffer;
600     size_t        i_preheader;
601
602 #ifdef DEBUG_BUFFER
603     msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
604 #endif
605
606     p_buffer = malloc( sizeof( sout_buffer_t ) );
607     i_preheader = p_sout->i_preheader;
608
609     if( i_size > 0 )
610     {
611         p_buffer->p_allocated_buffer = malloc( i_size + i_preheader );
612         p_buffer->p_buffer = p_buffer->p_allocated_buffer + i_preheader;
613     }
614     else
615     {
616         p_buffer->p_allocated_buffer = NULL;
617         p_buffer->p_buffer = NULL;
618     }
619     p_buffer->i_allocated_size = i_size + i_preheader;
620     p_buffer->i_buffer_size = i_size;
621
622     p_buffer->i_size    = i_size;
623     p_buffer->i_length  = 0;
624     p_buffer->i_dts     = 0;
625     p_buffer->i_pts     = 0;
626     p_buffer->i_bitrate = 0;
627     p_buffer->i_flags   = 0x0000;
628     p_buffer->p_next = NULL;
629
630     return( p_buffer );
631 }
632 int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
633 {
634     size_t          i_preheader;
635
636 #ifdef DEBUG_BUFFER
637     msg_Dbg( p_sout,
638              "realloc buffer old size:%d new size:%d",
639              (uint32_t)p_buffer->i_allocated_size,
640              (uint32_t)i_size );
641 #endif
642
643     i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;
644
645     if( !( p_buffer->p_allocated_buffer = realloc( p_buffer->p_allocated_buffer, i_size + i_preheader ) ) )
646     {
647         msg_Err( p_sout, "realloc failed" );
648         p_buffer->i_allocated_size = 0;
649         p_buffer->i_buffer_size = 0;
650         p_buffer->i_size = 0;
651         p_buffer->p_buffer = NULL;
652         return( -1 );
653     }
654     p_buffer->p_buffer = p_buffer->p_allocated_buffer + i_preheader;
655
656     p_buffer->i_allocated_size = i_size + i_preheader;
657     p_buffer->i_buffer_size = i_size;
658
659     return( 0 );
660 }
661
662 int sout_BufferReallocFromPreHeader( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
663 {
664     size_t  i_preheader;
665
666     i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;
667
668     if( i_preheader < i_size )
669     {
670         return( -1 );
671     }
672
673     p_buffer->p_buffer -= i_size;
674     p_buffer->i_size += i_size;
675     p_buffer->i_buffer_size += i_size;
676
677     return( 0 );
678 }
679
680 int sout_BufferDelete( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
681 {
682 #ifdef DEBUG_BUFFER
683     msg_Dbg( p_sout, "freeing buffer, size:%d", p_buffer->i_size );
684 #endif
685     if( p_buffer->p_allocated_buffer )
686     {
687         free( p_buffer->p_allocated_buffer );
688     }
689     free( p_buffer );
690     return( 0 );
691 }
692
693 sout_buffer_t *sout_BufferDuplicate( sout_instance_t *p_sout,
694                                      sout_buffer_t *p_buffer )
695 {
696     sout_buffer_t *p_dup;
697
698     p_dup = sout_BufferNew( p_sout, p_buffer->i_size );
699
700     p_dup->i_bitrate= p_buffer->i_bitrate;
701     p_dup->i_dts    = p_buffer->i_dts;
702     p_dup->i_pts    = p_buffer->i_pts;
703     p_dup->i_length = p_buffer->i_length;
704     p_dup->i_flags  = p_buffer->i_flags;
705     p_sout->p_vlc->pf_memcpy( p_dup->p_buffer, p_buffer->p_buffer, p_buffer->i_size );
706
707     return( p_dup );
708 }
709
710 void sout_BufferChain( sout_buffer_t **pp_chain,
711                        sout_buffer_t *p_buffer )
712 {
713     if( *pp_chain == NULL )
714     {
715         *pp_chain = p_buffer;
716     }
717     else if( p_buffer != NULL )
718     {
719         sout_buffer_t *p = *pp_chain;
720
721         while( p->p_next )
722         {
723             p = p->p_next;
724         }
725
726         p->p_next = p_buffer;
727     }
728 }
729
730 static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
731 {
732     char * psz_dup = strdup( psz_mrl );
733     char * psz_parser = psz_dup;
734     char * psz_access = "";
735     char * psz_way = "";
736     char * psz_name = "";
737
738     /* *** first parse psz_dest */
739     while( *psz_parser && *psz_parser != ':' )
740     {
741         if( *psz_parser == '{' )
742         {
743             while( *psz_parser && *psz_parser != '}' )
744             {
745                 psz_parser++;
746             }
747             if( *psz_parser )
748             {
749                 psz_parser++;
750             }
751         }
752         else
753         {
754             psz_parser++;
755         }
756     }
757 #if defined( WIN32 ) || defined( UNDER_CE )
758     if( psz_parser - psz_dup == 1 )
759     {
760         /* msg_Warn( p_sout, "drive letter %c: found in source string",
761                           *psz_dup ) ; */
762         psz_parser = "";
763     }
764 #endif
765
766     if( !*psz_parser )
767     {
768         psz_access = psz_way = "";
769         psz_name = psz_dup;
770     }
771     else
772     {
773         *psz_parser++ = '\0';
774
775         /* let's skip '//' */
776         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
777         {
778             psz_parser += 2 ;
779         }
780
781         psz_name = psz_parser ;
782
783         /* Come back to parse the access and mux plug-ins */
784         psz_parser = psz_dup;
785
786         if( !*psz_parser )
787         {
788             /* No access */
789             psz_access = "";
790         }
791         else if( *psz_parser == '/' )
792         {
793             /* No access */
794             psz_access = "";
795             psz_parser++;
796         }
797         else
798         {
799             psz_access = psz_parser;
800
801             while( *psz_parser && *psz_parser != '/' )
802             {
803                 if( *psz_parser == '{' )
804                 {
805                     while( *psz_parser && *psz_parser != '}' )
806                     {
807                         psz_parser++;
808                     }
809                     if( *psz_parser )
810                     {
811                         psz_parser++;
812                     }
813                 }
814                 else
815                 {
816                     psz_parser++;
817                 }
818             }
819
820             if( *psz_parser == '/' )
821             {
822                 *psz_parser++ = '\0';
823             }
824         }
825
826         if( !*psz_parser )
827         {
828             /* No mux */
829             psz_way = "";
830         }
831         else
832         {
833             psz_way = psz_parser;
834         }
835     }
836
837     p_mrl->psz_access = strdup( psz_access );
838     p_mrl->psz_way    = strdup( psz_way );
839     p_mrl->psz_name   = strdup( psz_name );
840
841     free( psz_dup );
842     return( VLC_SUCCESS );
843 }
844
845
846 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
847 static void mrl_Clean( mrl_t *p_mrl )
848 {
849     FREE( p_mrl->psz_access );
850     FREE( p_mrl->psz_way );
851     FREE( p_mrl->psz_name );
852 }
853
854
855 /****************************************************************************
856  ****************************************************************************
857  **
858  **
859  **
860  ****************************************************************************
861  ****************************************************************************/
862
863 /* create a complete chain */
864 /* chain format:
865     module{option=*:option=*}[:module{option=*:...}]
866  */
867
868 static char *_strndup( char *str, int i_len )
869 {
870     char *p;
871
872     p = malloc( i_len + 1 );
873     strncpy( p, str, i_len );
874     p[i_len] = '\0';
875
876     return( p );
877 }
878
879 /*
880  * parse module{options=str, option="str "}:
881  *  return a pointer on the rest
882  *  XXX: psz_chain is modified
883  */
884 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
885 /* go accross " " and { } */
886 static char *_get_chain_end( char *str )
887 {
888     char *p = str;
889
890     SKIPSPACE( p );
891
892     for( ;; )
893     {
894         if( *p == '{' || *p == '"' || *p == '\'')
895         {
896             char c;
897
898             if( *p == '{' )
899             {
900                 c = '}';
901             }
902             else
903             {
904                 c = *p;
905             }
906             p++;
907
908             for( ;; )
909             {
910                 if( *p == '\0' )
911                 {
912                     return p;
913                 }
914
915                 if( *p == c )
916                 {
917                     p++;
918                     return p;
919                 }
920                 else if( *p == '{' && c == '}' )
921                 {
922                     p = _get_chain_end( p );
923                 }
924                 else
925                 {
926                     p++;
927                 }
928             }
929         }
930         else if( *p == '\0' || *p == ',' || *p == '}' || *p == ' ' || *p == '\t' )
931         {
932             return p;
933         }
934         else
935         {
936             p++;
937         }
938     }
939 }
940
941 char * sout_cfg_parser( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
942 {
943     sout_cfg_t *p_cfg = NULL;
944     char       *p = psz_chain;
945
946     *ppsz_name = NULL;
947     *pp_cfg    = NULL;
948
949     SKIPSPACE( p );
950
951     while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' )
952     {
953         p++;
954     }
955
956     if( p == psz_chain )
957     {
958         return NULL;
959     }
960
961     *ppsz_name = _strndup( psz_chain, p - psz_chain );
962
963     /* fprintf( stderr, "name=%s - rest=%s\n", *ppsz_name, p ); */
964
965     SKIPSPACE( p );
966
967     if( *p == '{' )
968     {
969         char *psz_name;
970
971         p++;
972
973         for( ;; )
974         {
975             sout_cfg_t cfg;
976
977             SKIPSPACE( p );
978
979             psz_name = p;
980
981             while( *p && *p != '=' && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' )
982             {
983                 p++;
984             }
985
986             /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
987             if( p == psz_name )
988             {
989                 fprintf( stderr, "invalid options (empty)" );
990                 break;
991             }
992
993             cfg.psz_name = _strndup( psz_name, p - psz_name );
994
995             SKIPSPACE( p );
996
997             if( *p == '=' )
998             {
999                 char *end;
1000
1001                 p++;
1002 #if 0
1003                 SKIPSPACE( p );
1004
1005                 if( *p == '"' )
1006                 {
1007                     char *end;
1008
1009                     p++;
1010                     end = strchr( p, '"' );
1011
1012                     if( end )
1013                     {
1014 /*                        fprintf( stderr, "##%s -- %s\n", p, end ); */
1015                         cfg.psz_value = _strndup( p, end - p );
1016                         p = end + 1;
1017                     }
1018                     else
1019                     {
1020                         cfg.psz_value = strdup( p );
1021                         p += strlen( p );
1022                     }
1023
1024                 }
1025                 else
1026                 {
1027                     psz_value = p;
1028                     while( *p && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' )
1029                     {
1030                         p++;
1031                     }
1032                     cfg.psz_value = _strndup( psz_value, p - psz_value );
1033                 }
1034 #endif
1035                 end = _get_chain_end( p );
1036                 if( end <= p )
1037                 {
1038                     cfg.psz_value = NULL;
1039                 }
1040                 else
1041                 {
1042                     if( *p == '\'' || *p =='"' || *p == '{' )
1043                     {
1044                         p++;
1045                         end--;
1046                     }
1047                     if( end <= p )
1048                     {
1049                         cfg.psz_value = NULL;
1050                     }
1051                     else
1052                     {
1053                         cfg.psz_value = _strndup( p, end - p );
1054                     }
1055                 }
1056
1057                 p = end;
1058                 SKIPSPACE( p );
1059             }
1060             else
1061             {
1062                 cfg.psz_value = NULL;
1063             }
1064
1065             cfg.p_next = NULL;
1066             if( p_cfg )
1067             {
1068                 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
1069                 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
1070
1071                 p_cfg = p_cfg->p_next;
1072             }
1073             else
1074             {
1075                 p_cfg = malloc( sizeof( sout_cfg_t ) );
1076                 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
1077
1078                 *pp_cfg = p_cfg;
1079             }
1080
1081             if( *p == ',' )
1082             {
1083                 p++;
1084             }
1085
1086             if( *p == '}' )
1087             {
1088                 p++;
1089
1090                 break;
1091             }
1092         }
1093     }
1094
1095     if( *p == ':' )
1096     {
1097         return( strdup( p + 1 ) );
1098     }
1099
1100     return( NULL );
1101 }
1102
1103 static void sout_cfg_free( sout_cfg_t *p_cfg )
1104 {
1105     while( p_cfg != NULL )
1106     {
1107         sout_cfg_t *p_next;
1108
1109         p_next = p_cfg->p_next;
1110
1111         FREE( p_cfg->psz_name );
1112         FREE( p_cfg->psz_value );
1113         free( p_cfg );
1114
1115         p_cfg = p_next;
1116     }
1117 }
1118
1119
1120 /*
1121  * XXX name and p_cfg are used (-> do NOT free them)
1122  */
1123 sout_stream_t *sout_stream_new( sout_instance_t *p_sout,
1124                                 char *psz_chain )
1125 {
1126     sout_stream_t *p_stream;
1127
1128     if( !psz_chain )
1129     {
1130         msg_Err( p_sout, "invalid chain" );
1131         return NULL;
1132     }
1133
1134     p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
1135
1136     if( !p_stream )
1137     {
1138         msg_Err( p_sout, "out of memory" );
1139         return NULL;
1140     }
1141
1142     p_stream->p_sout   = p_sout;
1143     p_stream->p_sys    = NULL;
1144
1145     p_stream->psz_next =
1146         sout_cfg_parser( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
1147
1148     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
1149
1150     p_stream->p_module =
1151         module_NeedStrict( p_stream, "sout stream", p_stream->psz_name );
1152
1153     if( !p_stream->p_module )
1154     {
1155         sout_stream_delete( p_stream );
1156         return NULL;
1157     }
1158
1159     return p_stream;
1160 }
1161
1162 void sout_stream_delete( sout_stream_t *p_stream )
1163 {
1164     sout_cfg_t *p_cfg;
1165
1166     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
1167     if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
1168
1169     FREE( p_stream->psz_name );
1170     FREE( p_stream->psz_next );
1171
1172     sout_cfg_free( p_stream->p_cfg );
1173
1174     msg_Dbg( p_stream, "destroying chain done" );
1175     vlc_object_destroy( p_stream );
1176 }
1177
1178 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
1179 {
1180     mrl_t       mrl;
1181     char        *psz_chain, *p;
1182     char        *psz_vcodec, *psz_acodec;
1183
1184     mrl_Parse( &mrl, psz_url );
1185     p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) + strlen( mrl.psz_access ) + strlen( mrl.psz_name ) );
1186
1187     psz_vcodec = config_GetPsz( p_this, "sout-vcodec" );
1188     if( psz_vcodec && *psz_vcodec == '\0')
1189     {
1190         FREE( psz_vcodec );
1191     }
1192     psz_acodec = config_GetPsz( p_this, "sout-acodec" );
1193     if( psz_acodec && *psz_acodec == '\0' )
1194     {
1195         FREE( psz_acodec );
1196     }
1197     /* set transcoding */
1198     if( psz_vcodec || psz_acodec )
1199     {
1200         p += sprintf( p, "transcode{" );
1201         if( psz_vcodec )
1202         {
1203             int br;
1204
1205             p += sprintf( p, "vcodec=%s,", psz_vcodec );
1206
1207             if( ( br = config_GetInt( p_this, "sout-vbitrate" ) ) > 0 )
1208             {
1209                 p += sprintf( p, "vb=%d,", br * 1000 );
1210             }
1211             free( psz_vcodec );
1212         }
1213         if( psz_acodec )
1214         {
1215             int br;
1216
1217             p += sprintf( p, "acodec=%s,", psz_acodec );
1218             if( ( br = config_GetInt( p_this, "sout-abitrate" ) ) > 0 )
1219             {
1220                 p += sprintf( p, "ab=%d,", br * 1000 );
1221             }
1222
1223             free( psz_acodec );
1224         }
1225         p += sprintf( p, "}:" );
1226     }
1227
1228
1229     if( config_GetInt( p_this, "sout-display" ) )
1230     {
1231         p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\",access=\"%s\",url=\"%s\"}}", mrl.psz_way, mrl.psz_access, mrl.psz_name );
1232     }
1233     else
1234     {
1235         p += sprintf( p, "std{mux=\"%s\",access=\"%s\",url=\"%s\"}", mrl.psz_way, mrl.psz_access, mrl.psz_name );
1236     }
1237
1238     mrl_Clean( &mrl );
1239     return( psz_chain );
1240 }
1241
1242 /*****************************************************************************/
1243 static module_t *__module_NeedStrict( vlc_object_t *p_obj, const char *psz_capacity, const char *psz_name )
1244 {
1245     module_t *p_module;
1246
1247     if( !psz_name || !*psz_name )
1248     {
1249         p_module = module_Need( p_obj, psz_capacity, psz_name );
1250     }
1251     else
1252     {
1253         char *psz_name_strict = malloc( strlen( psz_name ) + 6 );
1254         strcpy( psz_name_strict, psz_name );
1255         strcat( psz_name_strict, ",none" );
1256
1257         p_module = module_Need( p_obj, psz_capacity, psz_name_strict );
1258
1259         free( psz_name_strict );
1260     }
1261
1262     return p_module;
1263 }
1264
1265