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