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