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