]> git.sesse.net Git - vlc/blob - src/stream_output/stream_output.c
* src/stream_output/stream_output.c, modules/stream_out/duplicate.c: bug fixes for...
[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.29 2003/05/19 11:38:05 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             sout_MuxDeleteStream( p_mux, p_input );
413             return( NULL );
414     }
415
416     return( p_input );
417 }
418
419 void sout_MuxDeleteStream     ( sout_mux_t *p_mux,
420                                 sout_input_t *p_input )
421 {
422     int i_index;
423
424     TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
425     if( i_index >= 0 )
426     {
427         if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
428         {
429             msg_Err( p_mux, "cannot del this stream from mux" );
430         }
431
432         /* remove the entry */
433         TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
434
435         if( p_mux->i_nb_inputs == 0 )
436         {
437             msg_Warn( p_mux, "no more input stream for this mux" );
438         }
439
440         sout_FifoDestroy( p_mux->p_sout, p_input->p_fifo );
441         free( p_input );
442     }
443 }
444
445 void sout_MuxSendBuffer       ( sout_mux_t    *p_mux,
446                                 sout_input_t  *p_input,
447                                 sout_buffer_t *p_buffer )
448 {
449     sout_FifoPut( p_input->p_fifo, p_buffer );
450
451     if( p_mux->b_waiting_stream )
452     {
453         if( p_mux->i_add_stream_start > 0 &&
454             p_mux->i_add_stream_start + (mtime_t)1500000 < mdate() )
455         {
456             /* more than 1.5 second, start muxing */
457             p_mux->b_waiting_stream = VLC_FALSE;
458         }
459         else
460         {
461             return;
462         }
463     }
464     p_mux->pf_mux( p_mux );
465 }
466
467
468
469 sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
470 {
471     sout_fifo_t *p_fifo;
472
473     if( !( p_fifo = malloc( sizeof( sout_fifo_t ) ) ) )
474     {
475         return( NULL );
476     }
477
478     vlc_mutex_init( p_sout, &p_fifo->lock );
479     vlc_cond_init ( p_sout, &p_fifo->wait );
480     p_fifo->i_depth = 0;
481     p_fifo->p_first = NULL;
482     p_fifo->pp_last = &p_fifo->p_first;
483
484     return( p_fifo );
485 }
486
487 void       sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
488 {
489     sout_buffer_t *p_buffer;
490
491     vlc_mutex_lock( &p_fifo->lock );
492     p_buffer = p_fifo->p_first;
493     while( p_buffer )
494     {
495         sout_buffer_t *p_next;
496         p_next = p_buffer->p_next;
497         sout_BufferDelete( p_sout, p_buffer );
498         p_buffer = p_next;
499     }
500     vlc_mutex_unlock( &p_fifo->lock );
501
502     return;
503 }
504 void       sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
505 {
506     sout_FifoFree( p_sout, p_fifo );
507     vlc_mutex_destroy( &p_fifo->lock );
508     vlc_cond_destroy ( &p_fifo->wait );
509
510     free( p_fifo );
511 }
512
513 void        sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
514 {
515     vlc_mutex_lock( &p_fifo->lock );
516
517     do
518     {
519         *p_fifo->pp_last = p_buffer;
520         p_fifo->pp_last = &p_buffer->p_next;
521         p_fifo->i_depth++;
522
523         p_buffer = p_buffer->p_next;
524
525     } while( p_buffer );
526
527     /* warm there is data in this fifo */
528     vlc_cond_signal( &p_fifo->wait );
529     vlc_mutex_unlock( &p_fifo->lock );
530 }
531
532 sout_buffer_t *sout_FifoGet( sout_fifo_t *p_fifo )
533 {
534     sout_buffer_t *p_buffer;
535
536     vlc_mutex_lock( &p_fifo->lock );
537
538     if( p_fifo->p_first == NULL )
539     {
540         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
541     }
542
543     p_buffer = p_fifo->p_first;
544
545     p_fifo->p_first = p_buffer->p_next;
546     p_fifo->i_depth--;
547
548     if( p_fifo->p_first == NULL )
549     {
550         p_fifo->pp_last = &p_fifo->p_first;
551     }
552
553     vlc_mutex_unlock( &p_fifo->lock );
554
555     p_buffer->p_next = NULL;
556     return( p_buffer );
557 }
558
559 sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo )
560 {
561     sout_buffer_t *p_buffer;
562
563     vlc_mutex_lock( &p_fifo->lock );
564
565     if( p_fifo->p_first == NULL )
566     {
567         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
568     }
569
570     p_buffer = p_fifo->p_first;
571
572     vlc_mutex_unlock( &p_fifo->lock );
573
574     return( p_buffer );
575 }
576
577 sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
578 {
579     sout_buffer_t *p_buffer;
580     size_t        i_preheader;
581
582 #ifdef DEBUG_BUFFER
583     msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
584 #endif
585
586     p_buffer = malloc( sizeof( sout_buffer_t ) );
587     i_preheader = p_sout->i_preheader;
588
589     if( i_size > 0 )
590     {
591         p_buffer->p_allocated_buffer = malloc( i_size + i_preheader );
592         p_buffer->p_buffer = p_buffer->p_allocated_buffer + i_preheader;
593     }
594     else
595     {
596         p_buffer->p_allocated_buffer = NULL;
597         p_buffer->p_buffer = NULL;
598     }
599     p_buffer->i_allocated_size = i_size + i_preheader;
600     p_buffer->i_buffer_size = i_size;
601
602     p_buffer->i_size    = i_size;
603     p_buffer->i_length  = 0;
604     p_buffer->i_dts     = 0;
605     p_buffer->i_pts     = 0;
606     p_buffer->i_bitrate = 0;
607     p_buffer->i_flags   = 0x0000;
608     p_buffer->p_next = NULL;
609
610     return( p_buffer );
611 }
612 int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
613 {
614     size_t          i_preheader;
615
616 #ifdef DEBUG_BUFFER
617     msg_Dbg( p_sout,
618              "realloc buffer old size:%d new size:%d",
619              (uint32_t)p_buffer->i_allocated_size,
620              (uint32_t)i_size );
621 #endif
622
623     i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;
624
625     if( !( p_buffer->p_allocated_buffer = realloc( p_buffer->p_allocated_buffer, i_size + i_preheader ) ) )
626     {
627         msg_Err( p_sout, "realloc failed" );
628         p_buffer->i_allocated_size = 0;
629         p_buffer->i_buffer_size = 0;
630         p_buffer->i_size = 0;
631         p_buffer->p_buffer = NULL;
632         return( -1 );
633     }
634     p_buffer->p_buffer = p_buffer->p_allocated_buffer + i_preheader;
635
636     p_buffer->i_allocated_size = i_size + i_preheader;
637     p_buffer->i_buffer_size = i_size;
638
639     return( 0 );
640 }
641
642 int sout_BufferReallocFromPreHeader( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
643 {
644     size_t  i_preheader;
645
646     i_preheader = p_buffer->p_buffer - p_buffer->p_allocated_buffer;
647
648     if( i_preheader < i_size )
649     {
650         return( -1 );
651     }
652
653     p_buffer->p_buffer -= i_size;
654     p_buffer->i_size += i_size;
655     p_buffer->i_buffer_size += i_size;
656
657     return( 0 );
658 }
659
660 int sout_BufferDelete( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
661 {
662 #ifdef DEBUG_BUFFER
663     msg_Dbg( p_sout, "freeing buffer, size:%d", p_buffer->i_size );
664 #endif
665     if( p_buffer->p_allocated_buffer )
666     {
667         free( p_buffer->p_allocated_buffer );
668     }
669     free( p_buffer );
670     return( 0 );
671 }
672
673 sout_buffer_t *sout_BufferDuplicate( sout_instance_t *p_sout,
674                                      sout_buffer_t *p_buffer )
675 {
676     sout_buffer_t *p_dup;
677
678     p_dup = sout_BufferNew( p_sout, p_buffer->i_size );
679
680     p_dup->i_bitrate= p_buffer->i_bitrate;
681     p_dup->i_dts    = p_buffer->i_dts;
682     p_dup->i_pts    = p_buffer->i_pts;
683     p_dup->i_length = p_buffer->i_length;
684     p_dup->i_flags  = p_buffer->i_flags;
685     p_sout->p_vlc->pf_memcpy( p_dup->p_buffer, p_buffer->p_buffer, p_buffer->i_size );
686
687     return( p_dup );
688 }
689
690 void sout_BufferChain( sout_buffer_t **pp_chain,
691                        sout_buffer_t *p_buffer )
692 {
693     if( *pp_chain == NULL )
694     {
695         *pp_chain = p_buffer;
696     }
697     else if( p_buffer != NULL )
698     {
699         sout_buffer_t *p = *pp_chain;
700
701         while( p->p_next )
702         {
703             p = p->p_next;
704         }
705
706         p->p_next = p_buffer;
707     }
708 }
709
710 static int  mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
711 {
712     char * psz_dup = strdup( psz_mrl );
713     char * psz_parser = psz_dup;
714     char * psz_access = "";
715     char * psz_way = "";
716     char * psz_name = "";
717
718     /* *** first parse psz_dest */
719     while( *psz_parser && *psz_parser != ':' )
720     {
721         if( *psz_parser == '{' )
722         {
723             while( *psz_parser && *psz_parser != '}' )
724             {
725                 psz_parser++;
726             }
727             if( *psz_parser )
728             {
729                 psz_parser++;
730             }
731         }
732         else
733         {
734             psz_parser++;
735         }
736     }
737 #if defined( WIN32 ) || defined( UNDER_CE )
738     if( psz_parser - psz_dup == 1 )
739     {
740         /* msg_Warn( p_sout, "drive letter %c: found in source string",
741                           *psz_dup ) ; */
742         psz_parser = "";
743     }
744 #endif
745
746     if( !*psz_parser )
747     {
748         psz_access = psz_way = "";
749         psz_name = psz_dup;
750     }
751     else
752     {
753         *psz_parser++ = '\0';
754
755         /* let's skip '//' */
756         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
757         {
758             psz_parser += 2 ;
759         }
760
761         psz_name = psz_parser ;
762
763         /* Come back to parse the access and mux plug-ins */
764         psz_parser = psz_dup;
765
766         if( !*psz_parser )
767         {
768             /* No access */
769             psz_access = "";
770         }
771         else if( *psz_parser == '/' )
772         {
773             /* No access */
774             psz_access = "";
775             psz_parser++;
776         }
777         else
778         {
779             psz_access = psz_parser;
780
781             while( *psz_parser && *psz_parser != '/' )
782             {
783                 if( *psz_parser == '{' )
784                 {
785                     while( *psz_parser && *psz_parser != '}' )
786                     {
787                         psz_parser++;
788                     }
789                     if( *psz_parser )
790                     {
791                         psz_parser++;
792                     }
793                 }
794                 else
795                 {
796                     psz_parser++;
797                 }
798             }
799
800             if( *psz_parser == '/' )
801             {
802                 *psz_parser++ = '\0';
803             }
804         }
805
806         if( !*psz_parser )
807         {
808             /* No mux */
809             psz_way = "";
810         }
811         else
812         {
813             psz_way = psz_parser;
814         }
815     }
816
817     p_mrl->psz_access = strdup( psz_access );
818     p_mrl->psz_way    = strdup( psz_way );
819     p_mrl->psz_name   = strdup( psz_name );
820
821     free( psz_dup );
822     return( VLC_SUCCESS );
823 }
824
825
826 /* mrl_Clean: clean p_mrl  after a call to mrl_Parse */
827 static void mrl_Clean( mrl_t *p_mrl )
828 {
829     FREE( p_mrl->psz_access );
830     FREE( p_mrl->psz_way );
831     FREE( p_mrl->psz_name );
832 }
833
834
835 /****************************************************************************
836  ****************************************************************************
837  **
838  **
839  **
840  ****************************************************************************
841  ****************************************************************************/
842
843 /* create a complete chain */
844 /* chain format:
845     module{option=*:option=*}[:module{option=*:...}]
846  */
847
848 static char *_strndup( char *str, int i_len )
849 {
850     char *p;
851
852     p = malloc( i_len + 1 );
853     strncpy( p, str, i_len );
854     p[i_len] = '\0';
855
856     return( p );
857 }
858
859 /*
860  * parse module{options=str, option="str "}:
861  *  return a pointer on the rest
862  *  XXX: psz_chain is modified
863  */
864 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
865 /* go accross " " and { } */
866 static char *_get_chain_end( char *str )
867 {
868     char *p = str;
869
870     SKIPSPACE( p );
871
872     for( ;; )
873     {
874         if( *p == '{' || *p == '"' || *p == '\'')
875         {
876             char c;
877
878             if( *p == '{' )
879             {
880                 c = '}';
881             }
882             else
883             {
884                 c = *p;
885             }
886             p++;
887
888             for( ;; )
889             {
890                 if( *p == '\0' )
891                 {
892                     return p;
893                 }
894
895                 if( *p == c )
896                 {
897                     p++;
898                     return p;
899                 }
900                 else if( *p == '{' && c == '}' )
901                 {
902                     p = _get_chain_end( p );
903                 }
904                 else
905                 {
906                     p++;
907                 }
908             }
909         }
910         else if( *p == '\0' || *p == ',' || *p == '}' || *p == ' ' || *p == '\t' )
911         {
912             return p;
913         }
914         else
915         {
916             p++;
917         }
918     }
919 }
920
921 char * sout_cfg_parser( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
922 {
923     sout_cfg_t *p_cfg = NULL;
924     char       *p = psz_chain;
925
926     *ppsz_name = NULL;
927     *pp_cfg    = NULL;
928
929     SKIPSPACE( p );
930
931     while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' )
932     {
933         p++;
934     }
935
936     if( p == psz_chain )
937     {
938         return NULL;
939     }
940
941     *ppsz_name = _strndup( psz_chain, p - psz_chain );
942
943     /* fprintf( stderr, "name=%s - rest=%s\n", *ppsz_name, p ); */
944
945     SKIPSPACE( p );
946
947     if( *p == '{' )
948     {
949         char *psz_name;
950
951         p++;
952
953         for( ;; )
954         {
955             sout_cfg_t cfg;
956
957             SKIPSPACE( p );
958
959             psz_name = p;
960
961             while( *p && *p != '=' && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' )
962             {
963                 p++;
964             }
965
966             /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
967             if( p == psz_name )
968             {
969                 fprintf( stderr, "invalid options (empty)" );
970                 break;
971             }
972
973             cfg.psz_name = _strndup( psz_name, p - psz_name );
974
975             SKIPSPACE( p );
976
977             if( *p == '=' )
978             {
979                 char *end;
980
981                 p++;
982 #if 0
983                 SKIPSPACE( p );
984
985                 if( *p == '"' )
986                 {
987                     char *end;
988
989                     p++;
990                     end = strchr( p, '"' );
991
992                     if( end )
993                     {
994 /*                        fprintf( stderr, "##%s -- %s\n", p, end ); */
995                         cfg.psz_value = _strndup( p, end - p );
996                         p = end + 1;
997                     }
998                     else
999                     {
1000                         cfg.psz_value = strdup( p );
1001                         p += strlen( p );
1002                     }
1003
1004                 }
1005                 else
1006                 {
1007                     psz_value = p;
1008                     while( *p && *p != ',' && *p != '}' && *p != ' ' && *p != '\t' )
1009                     {
1010                         p++;
1011                     }
1012                     cfg.psz_value = _strndup( psz_value, p - psz_value );
1013                 }
1014 #endif
1015                 end = _get_chain_end( p );
1016                 if( end <= p )
1017                 {
1018                     cfg.psz_value = NULL;
1019                 }
1020                 else
1021                 {
1022                     if( *p == '\'' || *p =='"' || *p == '{' )
1023                     {
1024                         p++;
1025                         end--;
1026                     }
1027                     if( end <= p )
1028                     {
1029                         cfg.psz_value = NULL;
1030                     }
1031                     else
1032                     {
1033                         cfg.psz_value = _strndup( p, end - p );
1034                     }
1035                 }
1036
1037                 p = end;
1038                 SKIPSPACE( p );
1039             }
1040             else
1041             {
1042                 cfg.psz_value = NULL;
1043             }
1044
1045             cfg.p_next = NULL;
1046             if( p_cfg )
1047             {
1048                 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
1049                 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
1050
1051                 p_cfg = p_cfg->p_next;
1052             }
1053             else
1054             {
1055                 p_cfg = malloc( sizeof( sout_cfg_t ) );
1056                 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
1057
1058                 *pp_cfg = p_cfg;
1059             }
1060
1061             if( *p == ',' )
1062             {
1063                 p++;
1064             }
1065
1066             if( *p == '}' )
1067             {
1068                 p++;
1069
1070                 break;
1071             }
1072         }
1073     }
1074
1075     if( *p == ':' )
1076     {
1077         return( strdup( p + 1 ) );
1078     }
1079
1080     return( NULL );
1081 }
1082
1083
1084
1085
1086
1087 /*
1088  * XXX name and p_cfg are used (-> do NOT free them)
1089  */
1090 sout_stream_t *sout_stream_new( sout_instance_t *p_sout,
1091                                 char *psz_chain )
1092 {
1093     sout_stream_t *p_stream;
1094
1095     if( !psz_chain )
1096     {
1097         msg_Err( p_sout, "invalid chain" );
1098         return NULL;
1099     }
1100
1101     p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
1102
1103     if( !p_stream )
1104     {
1105         msg_Err( p_sout, "out of memory" );
1106         return NULL;
1107     }
1108
1109     p_stream->p_sout   = p_sout;
1110     p_stream->p_sys    = NULL;
1111
1112     p_stream->psz_next =
1113         sout_cfg_parser( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
1114
1115     msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
1116
1117     p_stream->p_module =
1118         module_NeedStrict( p_stream, "sout stream", p_stream->psz_name );
1119
1120     if( !p_stream->p_module )
1121     {
1122         sout_stream_delete( p_stream );
1123         return NULL;
1124     }
1125
1126     return p_stream;
1127 }
1128
1129 void sout_stream_delete( sout_stream_t *p_stream )
1130 {
1131     sout_cfg_t *p_cfg;
1132
1133     msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
1134     if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
1135
1136     FREE( p_stream->psz_name );
1137     FREE( p_stream->psz_next );
1138
1139     p_cfg = p_stream->p_cfg;
1140     while( p_cfg != NULL )
1141     {
1142         sout_cfg_t *p_next;
1143
1144         p_next = p_cfg->p_next;
1145
1146         FREE( p_cfg->psz_name );
1147         FREE( p_cfg->psz_value );
1148         free( p_cfg );
1149
1150         p_cfg = p_next;
1151     }
1152
1153     msg_Dbg( p_stream, "destroying chain done" );
1154     vlc_object_destroy( p_stream );
1155 }
1156
1157 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
1158 {
1159     mrl_t       mrl;
1160     char        *psz_chain, *p;
1161     char        *psz_vcodec, *psz_acodec;
1162
1163     mrl_Parse( &mrl, psz_url );
1164     p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) + strlen( mrl.psz_access ) + strlen( mrl.psz_name ) );
1165
1166     psz_vcodec = config_GetPsz( p_this, "sout-vcodec" );
1167     if( psz_vcodec && *psz_vcodec == '\0')
1168     {
1169         FREE( psz_vcodec );
1170     }
1171     psz_acodec = config_GetPsz( p_this, "sout-acodec" );
1172     if( psz_acodec && *psz_acodec == '\0' )
1173     {
1174         FREE( psz_acodec );
1175     }
1176     /* set transcoding */
1177     if( psz_vcodec || psz_acodec )
1178     {
1179         p += sprintf( p, "transcode{" );
1180         if( psz_vcodec )
1181         {
1182             int br;
1183
1184             p += sprintf( p, "vcodec=%s,", psz_vcodec );
1185
1186             if( ( br = config_GetInt( p_this, "sout-vbitrate" ) ) > 0 )
1187             {
1188                 p += sprintf( p, "vb=%d,", br * 1000 );
1189             }
1190             free( psz_vcodec );
1191         }
1192         if( psz_acodec )
1193         {
1194             int br;
1195
1196             p += sprintf( p, "acodec=%s,", psz_acodec );
1197             if( ( br = config_GetInt( p_this, "sout-abitrate" ) ) > 0 )
1198             {
1199                 p += sprintf( p, "ab=%d,", br * 1000 );
1200             }
1201
1202             free( psz_acodec );
1203         }
1204         p += sprintf( p, "}:" );
1205     }
1206
1207
1208     if( config_GetInt( p_this, "sout-display" ) )
1209     {
1210         p += sprintf( p, "duplicate{dst=display,dst=std{mux=%s,access=%s,url=\"%s\"}}", mrl.psz_way, mrl.psz_access, mrl.psz_name );
1211     }
1212     else
1213     {
1214         p += sprintf( p, "std{mux=%s,access=%s,url=\"%s\"}", mrl.psz_way, mrl.psz_access, mrl.psz_name );
1215     }
1216
1217     return( psz_chain );
1218 }
1219
1220 /*****************************************************************************/
1221 static module_t *__module_NeedStrict( vlc_object_t *p_obj, const char *psz_capacity, const char *psz_name )
1222 {
1223     module_t *p_module;
1224
1225     if( !psz_name || !*psz_name )
1226     {
1227         p_module = module_Need( p_obj, psz_capacity, psz_name );
1228     }
1229     else
1230     {
1231         char *psz_name_strict = malloc( strlen( psz_name ) + 6 );
1232         strcpy( psz_name_strict, psz_name );
1233         strcat( psz_name_strict, ",none" );
1234
1235         p_module = module_Need( p_obj, psz_capacity, psz_name_strict );
1236
1237         free( psz_name_strict );
1238     }
1239
1240     return p_module;
1241 }
1242
1243