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