]> git.sesse.net Git - vlc/blob - src/stream_output/stream_output.c
* all: added a new function (sout_BufferChain) and allowed dummy
[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.7 2003/01/08 10:38:32 fenrir Exp $
6  *
7  * Authors: Christophe Massiot <massiot@via.ecp.fr>
8  *          Laurent Aimar <fenrir@via.ecp.fr>
9  *          Erioc Petit <titer@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                                /* free() */
30 #include <stdio.h>                                              /* sprintf() */
31 #include <string.h>                                            /* strerror() */
32
33 #include <vlc/vlc.h>
34
35 #include <vlc/sout.h>
36 #undef DEBUG_BUFFER
37 /*****************************************************************************
38  * Local prototypes
39  *****************************************************************************/
40 static int      InitInstance      ( sout_instance_t * );
41
42 /*****************************************************************************
43  * sout_NewInstance: creates a new stream output instance
44  *****************************************************************************/
45 sout_instance_t * __sout_NewInstance ( vlc_object_t *p_parent,
46                                        char * psz_dest )
47 {
48     sout_instance_t * p_sout;
49
50     /* Allocate descriptor */
51     p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
52     if( p_sout == NULL )
53     {
54         msg_Err( p_parent, "out of memory" );
55         return NULL;
56     }
57
58     p_sout->psz_dest = strdup( psz_dest );
59
60     if ( InitInstance( p_sout ) == -1 )
61     {
62         vlc_object_destroy( p_sout );
63         return NULL;
64     }
65
66     vlc_object_attach( p_sout, p_parent );
67
68     return p_sout;
69 }
70
71 /*****************************************************************************
72  * InitInstance: opens appropriate modules
73  *****************************************************************************/
74 static int InitInstance( sout_instance_t * p_sout )
75 {
76     /* Parse dest string. Syntax : [[<access>][/<mux>]:][<dest>] */
77     /* This code is identical to input.c:InitThread. FIXME : factorize it ? */
78     char * psz_parser = p_sout->psz_dest;
79
80     p_sout->psz_access = "";
81     p_sout->psz_mux = "";
82     p_sout->psz_name = "";
83     p_sout->p_access = NULL;
84     p_sout->p_mux = NULL;
85     p_sout->i_nb_inputs = 0;
86     p_sout->pp_inputs = NULL;
87     vlc_mutex_init( p_sout, &p_sout->lock );
88
89     /* Skip the plug-in names */
90     while( *psz_parser && *psz_parser != ':' )
91     {
92         psz_parser++;
93     }
94 #if defined( WIN32 ) || defined( UNDER_CE )
95     if( psz_parser - p_sout->psz_dest == 1 )
96     {
97         msg_Warn( p_sout, "drive letter %c: found in source string",
98                            p_sout->psz_dest ) ;
99         psz_parser = "";
100     }
101 #endif
102
103     if( !*psz_parser )
104     {
105         p_sout->psz_access = p_sout->psz_mux = "";
106         p_sout->psz_name = p_sout->psz_dest;
107     }
108     else
109     {
110         *psz_parser++ = '\0';
111
112         /* let's skip '//' */
113         if( psz_parser[0] == '/' && psz_parser[1] == '/' )
114         {
115             psz_parser += 2 ;
116         } 
117
118         p_sout->psz_name = psz_parser ;
119
120         /* Come back to parse the access and mux plug-ins */
121         psz_parser = p_sout->psz_dest;
122
123         if( !*psz_parser )
124         {
125             /* No access */
126             p_sout->psz_access = "";
127         }
128         else if( *psz_parser == '/' )
129         {
130             /* No access */
131             p_sout->psz_access = "";
132             psz_parser++;
133         }
134         else
135         {
136             p_sout->psz_access = psz_parser;
137
138             while( *psz_parser && *psz_parser != '/' )
139             {
140                 psz_parser++;
141             }
142
143             if( *psz_parser == '/' )
144             {
145                 *psz_parser++ = '\0';
146             }
147         }
148
149         if( !*psz_parser )
150         {
151             /* No mux */
152             p_sout->psz_mux = "";
153         }
154         else
155         {
156             p_sout->psz_mux = psz_parser;
157         }
158     }
159
160     msg_Dbg( p_sout, "access `%s', mux `%s', name `%s'",
161              p_sout->psz_access, p_sout->psz_mux, p_sout->psz_name );
162
163
164     /* Find and open appropriate access module */
165     p_sout->p_access =
166         module_Need( p_sout, "sout access", p_sout->psz_access );
167
168     if( p_sout->p_access == NULL )
169     {
170         msg_Err( p_sout, "no suitable sout access module for `%s/%s://%s'",
171                  p_sout->psz_access, p_sout->psz_mux, p_sout->psz_name );
172         return -1;
173     }
174
175     /* Find and open appropriate mux module */
176     p_sout->p_mux =
177         module_Need( p_sout, "sout mux", p_sout->psz_mux );
178
179     if( p_sout->p_mux == NULL )
180     {
181         msg_Err( p_sout, "no suitable mux module for `%s/%s://%s'",
182                  p_sout->psz_access, p_sout->psz_mux, p_sout->psz_name );
183         module_Unneed( p_sout, p_sout->p_access );
184         return -1;
185     }
186
187     p_sout->i_nb_inputs = 0;
188     p_sout->pp_inputs = NULL;
189
190     return 0;
191 }
192
193
194 /*****************************************************************************
195  * sout_DeleteInstance: delete a previously allocated instance
196  *****************************************************************************/
197 void sout_DeleteInstance( sout_instance_t * p_sout )
198 {
199     /* Unlink object */
200     vlc_object_detach( p_sout );
201     if( p_sout->p_mux )
202     {
203         module_Unneed( p_sout, p_sout->p_mux );
204     }
205     if( p_sout->p_access )
206     {
207         module_Unneed( p_sout, p_sout->p_access );
208     }
209
210     vlc_mutex_destroy( &p_sout->lock );
211
212     /* Free structure */
213     vlc_object_destroy( p_sout );
214 }
215
216
217 /*****************************************************************************
218  *
219  *****************************************************************************/
220 sout_input_t *__sout_InputNew( vlc_object_t *p_this,
221                                 sout_packet_format_t *p_format )
222 {
223     sout_instance_t *p_sout = NULL;
224     sout_input_t    *p_input;
225     int             i_try;
226
227     /* search an stream output */
228     for( i_try = 0; i_try < 200; i_try++ )
229     {
230         p_sout = vlc_object_find( p_this, VLC_OBJECT_SOUT, FIND_ANYWHERE );
231         if( !p_sout )
232         {
233             msleep( 100*1000 );
234             msg_Dbg( p_this, "waiting for sout" );
235         }
236         else
237         {
238             break;
239         }
240     }
241
242     if( !p_sout )
243     {
244         msg_Err( p_this, "cannot find any stream ouput" );
245         return( NULL );
246     }
247
248     msg_Dbg( p_sout, "adding a new input" );
249
250     /* create a new sout input */
251     p_input = malloc( sizeof( sout_input_t ) );
252
253     p_input->p_sout = p_sout;
254     vlc_mutex_init( p_sout, &p_input->lock );
255     memcpy( &p_input->input_format,
256             p_format,
257             sizeof( sout_packet_format_t ) );
258     p_input->p_fifo = sout_FifoCreate( p_sout );
259     p_input->p_mux_data = NULL;
260
261     /* add this new one to p_sout */
262     vlc_mutex_lock( &p_sout->lock );
263     if( p_sout->i_nb_inputs == 0 )
264     {
265         p_sout->pp_inputs = malloc( sizeof( sout_input_t * ) );
266     }
267     else
268     {
269         p_sout->pp_inputs = realloc( p_sout->pp_inputs,
270                                     sizeof( sout_input_t * ) *
271                                             ( p_sout->i_nb_inputs + 1 ) );
272     }
273     p_sout->pp_inputs[p_sout->i_nb_inputs] = p_input;
274     p_sout->i_nb_inputs++;
275
276     if( p_input->input_format.i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) &&
277         p_sout->pf_mux_addstream( p_sout, p_input ) < 0 )
278     {
279         /* vlc_mutex_unlock( &p_sout->lock ); */
280         msg_Err( p_sout, "cannot add this stream" );
281         /* FIXME FIXME */
282     }
283     vlc_mutex_unlock( &p_sout->lock );
284
285     vlc_object_release( p_sout );
286
287     return( p_input );
288 }
289
290
291 int sout_InputDelete( sout_input_t *p_input )
292 {
293     sout_instance_t     *p_sout = p_input->p_sout;
294     int                 i_input;
295
296
297     vlc_mutex_lock( &p_sout->lock );
298     for( i_input = 0; i_input < p_sout->i_nb_inputs; i_input++ )
299     {
300         if( p_sout->pp_inputs[i_input] == p_input )
301         {
302             break;
303         }
304     }
305
306     if( i_input >= p_sout->i_nb_inputs )
307     {
308         msg_Err( p_sout, "cannot find input to delete" );
309         return( -1 );
310     }
311
312     msg_Dbg( p_sout, "removing an input" );
313
314     if( p_input->input_format.i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) &&
315         p_sout->pf_mux_delstream( p_sout, p_input ) < 0 )
316     {
317         msg_Err( p_sout, "cannot del this stream" );
318         /* FIXME FIXME */
319     }
320
321     /* remove the entry */
322     if( p_sout->i_nb_inputs > 1 )
323     {
324         memmove( &p_sout->pp_inputs[i_input],
325                  &p_sout->pp_inputs[i_input+1],
326                  (p_sout->i_nb_inputs - i_input - 1) * sizeof( sout_input_t*) );
327     }
328     else
329     {
330         free( p_sout->pp_inputs );
331     }
332     p_sout->i_nb_inputs--;
333
334     sout_FifoDestroy( p_sout, p_input->p_fifo );
335     vlc_mutex_destroy( &p_input->lock );
336     free( p_input );
337
338     if( p_sout->i_nb_inputs == 0 )
339     {
340         msg_Warn( p_sout, "no more input stream" );
341     }
342     vlc_mutex_unlock( &p_sout->lock );
343
344     return( 0 );
345 }
346
347
348 int sout_InputSendBuffer( sout_input_t *p_input, sout_buffer_t *p_buffer )
349 {
350 /*    msg_Dbg( p_input->p_sout,
351              "send buffer, size:%d", p_buffer->i_size ); */
352
353     if( p_input->input_format.i_fourcc != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
354     {
355         sout_FifoPut( p_input->p_fifo, p_buffer );
356
357         vlc_mutex_lock( &p_input->p_sout->lock );
358         p_input->p_sout->pf_mux( p_input->p_sout );
359         vlc_mutex_unlock( &p_input->p_sout->lock );
360
361     }
362     else
363     {
364         sout_BufferDelete( p_input->p_sout, p_buffer );
365     }
366
367     return( 0 );
368 }
369
370 sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
371 {
372     sout_fifo_t *p_fifo;
373
374     if( !( p_fifo = malloc( sizeof( sout_fifo_t ) ) ) )
375     {
376         return( NULL );
377     }
378
379     vlc_mutex_init( p_sout, &p_fifo->lock );
380     vlc_cond_init ( p_sout, &p_fifo->wait );
381     p_fifo->i_depth = 0;
382     p_fifo->p_first = NULL;
383     p_fifo->pp_last = &p_fifo->p_first;
384
385     return( p_fifo );
386 }
387
388 void       sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
389 {
390     sout_buffer_t *p_buffer;
391
392     vlc_mutex_lock( &p_fifo->lock );
393     p_buffer = p_fifo->p_first;
394     while( p_buffer )
395     {
396         sout_buffer_t *p_next;
397         p_next = p_buffer->p_next;
398         sout_BufferDelete( p_sout, p_buffer );
399         p_buffer = p_next;
400     }
401     vlc_mutex_unlock( &p_fifo->lock );
402
403     return;
404 }
405 void       sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
406 {
407     sout_FifoFree( p_sout, p_fifo );
408     vlc_mutex_destroy( &p_fifo->lock );
409     vlc_cond_destroy ( &p_fifo->wait );
410
411     free( p_fifo );
412 }
413
414 void        sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
415 {
416     vlc_mutex_lock( &p_fifo->lock );
417
418     do
419     {
420         *p_fifo->pp_last = p_buffer;
421         p_fifo->pp_last = &p_buffer->p_next;
422         p_fifo->i_depth++;
423
424         p_buffer = p_buffer->p_next;
425
426     } while( p_buffer );
427
428     /* warm there is data in this fifo */
429     vlc_cond_signal( &p_fifo->wait );
430     vlc_mutex_unlock( &p_fifo->lock );
431 }
432
433 sout_buffer_t *sout_FifoGet( sout_fifo_t *p_fifo )
434 {
435     sout_buffer_t *p_buffer;
436
437     vlc_mutex_lock( &p_fifo->lock );
438
439     if( p_fifo->p_first == NULL )
440     {
441         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
442     }
443
444     p_buffer = p_fifo->p_first;
445
446     p_fifo->p_first = p_buffer->p_next;
447     p_fifo->i_depth--;
448
449     if( p_fifo->p_first == NULL )
450     {
451         p_fifo->pp_last = &p_fifo->p_first;
452     }
453
454     vlc_mutex_unlock( &p_fifo->lock );
455
456     p_buffer->p_next = NULL;
457     return( p_buffer );
458 }
459
460 sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo )
461 {
462     sout_buffer_t *p_buffer;
463
464     vlc_mutex_lock( &p_fifo->lock );
465
466     if( p_fifo->p_first == NULL )
467     {
468         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
469     }
470
471     p_buffer = p_fifo->p_first;
472
473     vlc_mutex_unlock( &p_fifo->lock );
474
475     return( p_buffer );
476 }
477
478 sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
479 {
480     sout_buffer_t *p_buffer;
481
482 #ifdef DEBUG_BUFFER
483     msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
484 #endif
485
486     p_buffer = malloc( sizeof( sout_buffer_t ) );
487     if( i_size > 0 )
488     {
489         p_buffer->p_buffer = malloc( i_size );
490     }
491     else
492     {
493         p_buffer->p_buffer = NULL;
494     }
495     p_buffer->i_allocated_size = i_size;
496     p_buffer->i_size = i_size;
497     p_buffer->p_next = NULL;
498
499     return( p_buffer );
500 }
501 int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
502 {
503 #ifdef DEBUG_BUFFER
504     msg_Dbg( p_sout,
505              "realloc buffer old size:%d new size:%d",
506              (uint32_t)p_buffer->i_allocated_size,
507              (uint32_t)i_size );
508 #endif
509     if( !( p_buffer->p_buffer = realloc( p_buffer->p_buffer, i_size ) ) )
510     {
511         msg_Err( p_sout, "realloc failed" );
512         p_buffer->i_allocated_size = 0;
513         p_buffer->i_size = 0;
514
515         return( -1 );
516     }
517
518     p_buffer->i_allocated_size = i_size;
519     return( 0 );
520 }
521
522 int sout_BufferDelete( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
523 {
524 #ifdef DEBUG_BUFFER
525     msg_Dbg( p_sout, "freeing buffer, size:%d", p_buffer->i_size );
526 #endif
527     if( p_buffer->p_buffer )
528     {
529         free( p_buffer->p_buffer );
530     }
531     free( p_buffer );
532     return( 0 );
533 }
534
535 sout_buffer_t *sout_BufferDuplicate( sout_instance_t *p_sout,
536                                      sout_buffer_t *p_buffer )
537 {
538     sout_buffer_t *p_dup;
539
540     p_dup = sout_BufferNew( p_sout, p_buffer->i_size );
541
542     p_dup->i_bitrate= p_buffer->i_bitrate;
543     p_dup->i_dts    = p_buffer->i_dts;
544     p_dup->i_pts    = p_buffer->i_pts;
545     p_dup->i_length = p_buffer->i_length;
546     memcpy( p_dup->p_buffer, p_buffer->p_buffer, p_buffer->i_size );
547
548     return( p_dup );
549 }
550
551 void sout_BufferChain( sout_buffer_t **pp_chain,
552                        sout_buffer_t *p_buffer )
553 {
554     if( *pp_chain == NULL )
555     {
556         *pp_chain = p_buffer;
557     }
558     else
559     {
560         sout_buffer_t *p = *pp_chain;
561
562         while( p->p_next )
563         {
564             p = p->p_next;
565         }
566
567         p->p_next = p_buffer;
568     }
569 }