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