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