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