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