]> git.sesse.net Git - vlc/blob - src/stream_output/stream_output.c
Added stream output. (common work with titer).
[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.6 2002/12/14 21:32:42 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_sout->pf_mux_addstream( p_sout, p_input ) < 0 )
277     {
278         /* vlc_mutex_unlock( &p_sout->lock ); */
279         msg_Err( p_sout, "cannot add this stream" );
280         /* FIXME FIXME */
281     }
282     vlc_mutex_unlock( &p_sout->lock );
283
284     vlc_object_release( p_sout );
285
286     return( p_input );
287 }
288
289
290 int sout_InputDelete( sout_input_t *p_input )
291 {
292     sout_instance_t     *p_sout = p_input->p_sout;
293     int                 i_input;
294
295
296     vlc_mutex_lock( &p_sout->lock );
297     for( i_input = 0; i_input < p_sout->i_nb_inputs; i_input++ )
298     {
299         if( p_sout->pp_inputs[i_input] == p_input )
300         {
301             break;
302         }
303     }
304
305     if( i_input >= p_sout->i_nb_inputs )
306     {
307         msg_Err( p_sout, "cannot find input to delete" );
308         return( -1 );
309     }
310
311     msg_Dbg( p_sout, "removing an input" );
312
313     if( p_sout->pf_mux_delstream( p_sout, p_input ) < 0 )
314     {
315         msg_Err( p_sout, "cannot del this stream" );
316         /* FIXME FIXME */
317     }
318
319     /* remove the entry */
320     if( p_sout->i_nb_inputs > 1 )
321     {
322         memmove( &p_sout->pp_inputs[i_input],
323                  &p_sout->pp_inputs[i_input+1],
324                  (p_sout->i_nb_inputs - i_input - 1) * sizeof( sout_input_t*) );
325     }
326     else
327     {
328         free( p_sout->pp_inputs );
329     }
330     p_sout->i_nb_inputs--;
331
332     /* FIXME --> send message to mux to declare this stream removing */
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     sout_FifoPut( p_input->p_fifo, p_buffer );
353
354     vlc_mutex_lock( &p_input->p_sout->lock );
355     p_input->p_sout->pf_mux( p_input->p_sout );
356     vlc_mutex_unlock( &p_input->p_sout->lock );
357     return( 0 );
358 }
359
360 sout_fifo_t *sout_FifoCreate( sout_instance_t *p_sout )
361 {
362     sout_fifo_t *p_fifo;
363
364     if( !( p_fifo = malloc( sizeof( sout_fifo_t ) ) ) )
365     {
366         return( NULL );
367     }
368
369     vlc_mutex_init( p_sout, &p_fifo->lock );
370     vlc_cond_init ( p_sout, &p_fifo->wait );
371     p_fifo->i_depth = 0;
372     p_fifo->p_first = NULL;
373     p_fifo->pp_last = &p_fifo->p_first;
374
375     return( p_fifo );
376 }
377
378 void       sout_FifoFree( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
379 {
380     sout_buffer_t *p_buffer;
381
382     vlc_mutex_lock( &p_fifo->lock );
383     p_buffer = p_fifo->p_first;
384     while( p_buffer )
385     {
386         sout_buffer_t *p_next;
387         p_next = p_buffer->p_next;
388         sout_BufferDelete( p_sout, p_buffer );
389         p_buffer = p_next;
390     }
391     vlc_mutex_unlock( &p_fifo->lock );
392
393     return;
394 }
395 void       sout_FifoDestroy( sout_instance_t *p_sout, sout_fifo_t *p_fifo )
396 {
397     sout_FifoFree( p_sout, p_fifo );
398     vlc_mutex_destroy( &p_fifo->lock );
399     vlc_cond_destroy ( &p_fifo->wait );
400
401     free( p_fifo );
402 }
403
404 void        sout_FifoPut( sout_fifo_t *p_fifo, sout_buffer_t *p_buffer )
405 {
406     vlc_mutex_lock( &p_fifo->lock );
407
408     do
409     {
410         *p_fifo->pp_last = p_buffer;
411         p_fifo->pp_last = &p_buffer->p_next;
412         p_fifo->i_depth++;
413
414         p_buffer = p_buffer->p_next;
415
416     } while( p_buffer );
417
418     /* warm there is data in this fifo */
419     vlc_cond_signal( &p_fifo->wait );
420     vlc_mutex_unlock( &p_fifo->lock );
421 }
422
423 sout_buffer_t *sout_FifoGet( sout_fifo_t *p_fifo )
424 {
425     sout_buffer_t *p_buffer;
426
427     vlc_mutex_lock( &p_fifo->lock );
428
429     if( p_fifo->p_first == NULL )
430     {
431         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
432     }
433
434     p_buffer = p_fifo->p_first;
435
436     p_fifo->p_first = p_buffer->p_next;
437     p_fifo->i_depth--;
438
439     if( p_fifo->p_first == NULL )
440     {
441         p_fifo->pp_last = &p_fifo->p_first;
442     }
443
444     vlc_mutex_unlock( &p_fifo->lock );
445
446     p_buffer->p_next = NULL;
447     return( p_buffer );
448 }
449
450 sout_buffer_t *sout_FifoShow( sout_fifo_t *p_fifo )
451 {
452     sout_buffer_t *p_buffer;
453
454     vlc_mutex_lock( &p_fifo->lock );
455
456     if( p_fifo->p_first == NULL )
457     {
458         vlc_cond_wait( &p_fifo->wait, &p_fifo->lock );
459     }
460
461     p_buffer = p_fifo->p_first;
462
463     vlc_mutex_unlock( &p_fifo->lock );
464
465     return( p_buffer );
466 }
467
468 sout_buffer_t *sout_BufferNew( sout_instance_t *p_sout, size_t i_size )
469 {
470     sout_buffer_t *p_buffer;
471
472 #ifdef DEBUG_BUFFER
473     msg_Dbg( p_sout, "allocating an new buffer, size:%d", (uint32_t)i_size );
474 #endif
475
476     p_buffer = malloc( sizeof( sout_buffer_t ) );
477     if( i_size > 0 )
478     {
479         p_buffer->p_buffer = malloc( i_size );
480     }
481     else
482     {
483         p_buffer->p_buffer = NULL;
484     }
485     p_buffer->i_allocated_size = i_size;
486     p_buffer->i_size = i_size;
487     p_buffer->p_next = NULL;
488
489     return( p_buffer );
490 }
491 int sout_BufferRealloc( sout_instance_t *p_sout, sout_buffer_t *p_buffer, size_t i_size )
492 {
493 #ifdef DEBUG_BUFFER
494     msg_Dbg( p_sout,
495              "realloc buffer old size:%d new size:%d",
496              (uint32_t)p_buffer->i_allocated_size,
497              (uint32_t)i_size );
498 #endif
499     if( !( p_buffer->p_buffer = realloc( p_buffer->p_buffer, i_size ) ) )
500     {
501         msg_Err( p_sout, "realloc failed" );
502         p_buffer->i_allocated_size = 0;
503         p_buffer->i_size = 0;
504
505         return( -1 );
506     }
507
508     p_buffer->i_allocated_size = i_size;
509     return( 0 );
510 }
511
512 int sout_BufferDelete( sout_instance_t *p_sout, sout_buffer_t *p_buffer )
513 {
514 #ifdef DEBUG_BUFFER
515     msg_Dbg( p_sout, "freeing buffer, size:%d", p_buffer->i_size );
516 #endif
517     if( p_buffer->p_buffer )
518     {
519         free( p_buffer->p_buffer );
520     }
521     free( p_buffer );
522     return( 0 );
523 }
524
525 sout_buffer_t *sout_BufferDuplicate( sout_instance_t *p_sout,
526                                      sout_buffer_t *p_buffer )
527 {
528     sout_buffer_t *p_dup;
529
530     p_dup = sout_BufferNew( p_sout, p_buffer->i_size );
531
532     p_dup->i_bitrate= p_buffer->i_bitrate;
533     p_dup->i_dts    = p_buffer->i_dts;
534     p_dup->i_pts    = p_buffer->i_pts;
535     p_dup->i_length = p_buffer->i_length;
536     memcpy( p_dup->p_buffer, p_buffer->p_buffer, p_buffer->i_size );
537
538     return( p_dup );
539 }
540