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