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