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