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