1 /*****************************************************************************
2 * stream_output.c : stream output module
3 *****************************************************************************
4 * Copyright (C) 2002-2007 the VideoLAN team
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Laurent Aimar <fenrir@via.ecp.fr>
9 * Eric Petit <titer@videolan.org>
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
32 #include <stdlib.h> /* free() */
33 #include <stdio.h> /* sprintf() */
37 #include <vlc_playlist.h>
39 #include "stream_output.h"
43 #include "input/input_internal.h"
46 /*****************************************************************************
48 *****************************************************************************/
49 #define sout_stream_url_to_chain( p, s ) \
50 _sout_stream_url_to_chain( VLC_OBJECT(p), s )
51 static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
65 /* mrl_Parse: parse psz_mrl and fill p_mrl */
66 static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl );
67 /* mrl_Clean: clean p_mrl after a call to mrl_Parse */
68 static void mrl_Clean( mrl_t *p_mrl );
70 /*****************************************************************************
71 * sout_NewInstance: creates a new stream output instance
72 *****************************************************************************/
73 sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
75 sout_instance_t *p_sout;
77 /* *** Allocate descriptor *** */
78 p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
81 msg_Err( p_parent, "out of memory" );
85 /* *** init descriptor *** */
86 p_sout->psz_sout = strdup( psz_dest );
87 p_sout->p_meta = NULL;
88 p_sout->i_out_pace_nocontrol = 0;
91 vlc_mutex_init( p_sout, &p_sout->lock );
92 if( psz_dest && psz_dest[0] == '#' )
94 p_sout->psz_chain = strdup( &psz_dest[1] );
98 p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
99 msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
101 p_sout->p_stream = NULL;
103 /* attach it for inherit */
104 vlc_object_attach( p_sout, p_parent );
107 var_Create( p_sout, "sout-mux-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
110 p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
111 if( p_sout->p_stream == NULL )
113 msg_Err( p_sout, "stream chain failed for `%s'", p_sout->psz_chain );
115 FREENULL( p_sout->psz_sout );
116 FREENULL( p_sout->psz_chain );
118 vlc_object_detach( p_sout );
119 vlc_object_destroy( p_sout );
126 /*****************************************************************************
127 * sout_DeleteInstance: delete a previously allocated instance
128 *****************************************************************************/
129 void sout_DeleteInstance( sout_instance_t * p_sout )
131 /* remove the stream out chain */
132 sout_StreamDelete( p_sout->p_stream );
134 /* *** free all string *** */
135 FREENULL( p_sout->psz_sout );
136 FREENULL( p_sout->psz_chain );
141 vlc_meta_Delete( p_sout->p_meta );
144 vlc_mutex_destroy( &p_sout->lock );
146 /* *** free structure *** */
147 vlc_object_destroy( p_sout );
150 /*****************************************************************************
152 *****************************************************************************/
153 sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
156 sout_packetizer_input_t *p_input;
158 msg_Dbg( p_sout, "adding a new input" );
160 /* *** create a packetizer input *** */
161 p_input = malloc( sizeof( sout_packetizer_input_t ) );
162 p_input->p_sout = p_sout;
163 p_input->p_fmt = p_fmt;
165 if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
167 vlc_object_release( p_sout );
171 /* *** add it to the stream chain */
172 vlc_mutex_lock( &p_sout->lock );
173 p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
174 vlc_mutex_unlock( &p_sout->lock );
176 if( p_input->id == NULL )
185 /*****************************************************************************
187 *****************************************************************************/
188 int sout_InputDelete( sout_packetizer_input_t *p_input )
190 sout_instance_t *p_sout = p_input->p_sout;
192 msg_Dbg( p_sout, "removing an input" );
194 if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
196 vlc_mutex_lock( &p_sout->lock );
197 p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
198 vlc_mutex_unlock( &p_sout->lock );
203 return( VLC_SUCCESS);
206 /*****************************************************************************
208 *****************************************************************************/
209 int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
212 sout_instance_t *p_sout = p_input->p_sout;
215 if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
217 block_Release( p_buffer );
220 if( p_buffer->i_dts <= 0 )
222 msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
223 block_Release( p_buffer );
227 vlc_mutex_lock( &p_sout->lock );
228 i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
229 p_input->id, p_buffer );
230 vlc_mutex_unlock( &p_sout->lock );
235 /*****************************************************************************
236 * sout_AccessOutNew: allocate a new access out
237 *****************************************************************************/
238 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
239 const char *psz_access, const char *psz_name )
241 sout_access_out_t *p_access;
244 if( !( p_access = vlc_object_create( p_sout,
245 sizeof( sout_access_out_t ) ) ) )
247 msg_Err( p_sout, "out of memory" );
251 psz_next = config_ChainCreate( &p_access->psz_access, &p_access->p_cfg,
257 p_access->psz_path = strdup( psz_name ? psz_name : "" );
258 p_access->p_sout = p_sout;
259 p_access->p_sys = NULL;
260 p_access->pf_seek = NULL;
261 p_access->pf_read = NULL;
262 p_access->pf_write = NULL;
263 p_access->pf_control = NULL;
264 p_access->p_module = NULL;
266 p_access->i_writes = 0;
267 p_access->i_sent_bytes = 0;
269 vlc_object_attach( p_access, p_sout );
272 module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
274 if( !p_access->p_module )
276 free( p_access->psz_access );
277 free( p_access->psz_path );
278 vlc_object_detach( p_access );
279 vlc_object_destroy( p_access );
285 /*****************************************************************************
286 * sout_AccessDelete: delete an access out
287 *****************************************************************************/
288 void sout_AccessOutDelete( sout_access_out_t *p_access )
290 vlc_object_detach( p_access );
291 if( p_access->p_module )
293 module_Unneed( p_access, p_access->p_module );
295 free( p_access->psz_access );
297 config_ChainDestroy( p_access->p_cfg );
299 free( p_access->psz_path );
301 vlc_object_destroy( p_access );
304 /*****************************************************************************
306 *****************************************************************************/
307 int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
309 return p_access->pf_seek( p_access, i_pos );
312 /*****************************************************************************
314 *****************************************************************************/
315 int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
317 return( p_access->pf_read ?
318 p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
321 /*****************************************************************************
323 *****************************************************************************/
324 int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
327 p_access->i_writes++;
328 p_access->i_sent_bytes += p_buffer->i_buffer;
329 if( p_access->p_libvlc->b_stats && p_access->i_writes % 30 == 0 )
331 /* Access_out -> sout_instance -> input_thread_t */
332 input_thread_t *p_input =
333 (input_thread_t *)vlc_object_find( p_access, VLC_OBJECT_INPUT,
337 stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_packets,
339 stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_bytes,
340 p_access->i_sent_bytes, &i_total );
341 stats_UpdateFloat( p_input, p_input->p->counters.p_sout_send_bitrate,
342 (float)i_total, NULL );
343 p_access->i_sent_bytes = 0;
344 vlc_object_release( p_input );
347 return p_access->pf_write( p_access, p_buffer );
351 * sout_AccessOutControl
353 int sout_AccessOutControl (sout_access_out_t *access, int query, va_list args)
355 return (access->pf_control) ? access->pf_control (access, query, args)
359 /*****************************************************************************
360 * sout_MuxNew: create a new mux
361 *****************************************************************************/
362 sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
363 sout_access_out_t *p_access )
368 p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
371 msg_Err( p_sout, "out of memory" );
375 p_mux->p_sout = p_sout;
376 psz_next = config_ChainCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
377 if( psz_next ) free( psz_next );
379 p_mux->p_access = p_access;
380 p_mux->pf_control = NULL;
381 p_mux->pf_addstream = NULL;
382 p_mux->pf_delstream = NULL;
383 p_mux->pf_mux = NULL;
384 p_mux->i_nb_inputs = 0;
385 p_mux->pp_inputs = NULL;
388 p_mux->p_module = NULL;
390 p_mux->b_add_stream_any_time = VLC_FALSE;
391 p_mux->b_waiting_stream = VLC_TRUE;
392 p_mux->i_add_stream_start = -1;
394 vlc_object_attach( p_mux, p_sout );
397 module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
399 if( p_mux->p_module == NULL )
401 FREENULL( p_mux->psz_mux );
403 vlc_object_detach( p_mux );
404 vlc_object_destroy( p_mux );
408 /* *** probe mux capacity *** */
409 if( p_mux->pf_control )
411 int b_answer = VLC_FALSE;
413 if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
416 b_answer = VLC_FALSE;
421 msg_Dbg( p_sout, "muxer support adding stream at any time" );
422 p_mux->b_add_stream_any_time = VLC_TRUE;
423 p_mux->b_waiting_stream = VLC_FALSE;
425 /* If we control the output pace then it's better to wait before
426 * starting muxing (generates better streams/files). */
427 if( !p_sout->i_out_pace_nocontrol )
431 else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
434 b_answer = VLC_FALSE;
439 msg_Dbg( p_sout, "muxer prefers to wait for all ES before "
441 p_mux->b_waiting_stream = VLC_TRUE;
449 /*****************************************************************************
451 *****************************************************************************/
452 void sout_MuxDelete( sout_mux_t *p_mux )
454 vlc_object_detach( p_mux );
455 if( p_mux->p_module )
457 module_Unneed( p_mux, p_mux->p_module );
459 free( p_mux->psz_mux );
461 config_ChainDestroy( p_mux->p_cfg );
463 vlc_object_destroy( p_mux );
466 /*****************************************************************************
468 *****************************************************************************/
469 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
471 sout_input_t *p_input;
473 if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
475 msg_Err( p_mux, "cannot add a new stream (unsupported while muxing "
476 "to this format). You can try increasing sout-mux-caching value" );
480 msg_Dbg( p_mux, "adding a new input" );
482 /* create a new sout input */
483 p_input = malloc( sizeof( sout_input_t ) );
484 p_input->p_sout = p_mux->p_sout;
485 p_input->p_fmt = p_fmt;
486 p_input->p_fifo = block_FifoNew( p_mux->p_sout );
487 p_input->p_sys = NULL;
489 TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
490 if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
492 msg_Err( p_mux, "cannot add this stream" );
493 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
494 block_FifoRelease( p_input->p_fifo );
502 /*****************************************************************************
503 * sout_MuxDeleteStream:
504 *****************************************************************************/
505 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
509 if( p_mux->b_waiting_stream
510 && block_FifoCount( p_input->p_fifo ) > 0 )
512 /* We stop waiting, and call the muxer for taking care of the data
513 * before we remove this es */
514 p_mux->b_waiting_stream = VLC_FALSE;
515 p_mux->pf_mux( p_mux );
518 TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
521 if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
523 msg_Err( p_mux, "cannot delete this stream from mux" );
526 /* remove the entry */
527 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
529 if( p_mux->i_nb_inputs == 0 )
531 msg_Warn( p_mux, "no more input streams for this mux" );
534 block_FifoRelease( p_input->p_fifo );
539 /*****************************************************************************
540 * sout_MuxSendBuffer:
541 *****************************************************************************/
542 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
545 block_FifoPut( p_input->p_fifo, p_buffer );
547 if( p_mux->p_sout->i_out_pace_nocontrol )
549 mtime_t current_date = mdate();
550 if ( current_date > p_buffer->i_dts )
551 msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
552 current_date - p_buffer->i_dts );
555 if( p_mux->b_waiting_stream )
557 const int64_t i_caching = var_GetInteger( p_mux->p_sout, "sout-mux-caching" ) * I64C(1000);
559 if( p_mux->i_add_stream_start < 0 )
560 p_mux->i_add_stream_start = p_buffer->i_dts;
562 /* Wait until we have enought data before muxing */
563 if( p_mux->i_add_stream_start < 0 ||
564 p_buffer->i_dts < p_mux->i_add_stream_start + i_caching )
566 p_mux->b_waiting_stream = VLC_FALSE;
568 p_mux->pf_mux( p_mux );
571 /*****************************************************************************
573 *****************************************************************************/
574 static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl )
576 char * psz_dup = strdup( psz_mrl );
577 char * psz_parser = psz_dup;
578 const char * psz_access;
579 const char * psz_way;
582 /* *** first parse psz_dest */
583 while( *psz_parser && *psz_parser != ':' )
585 if( *psz_parser == '{' )
587 while( *psz_parser && *psz_parser != '}' )
601 #if defined( WIN32 ) || defined( UNDER_CE )
602 if( psz_parser - psz_dup == 1 )
604 /* msg_Warn( p_sout, "drive letter %c: found in source string",
612 psz_access = psz_way = "";
617 *psz_parser++ = '\0';
619 /* let's skip '//' */
620 if( psz_parser[0] == '/' && psz_parser[1] == '/' )
625 psz_name = psz_parser ;
627 /* Come back to parse the access and mux plug-ins */
628 psz_parser = psz_dup;
635 else if( *psz_parser == '/' )
643 psz_access = psz_parser;
645 while( *psz_parser && *psz_parser != '/' )
647 if( *psz_parser == '{' )
649 while( *psz_parser && *psz_parser != '}' )
664 if( *psz_parser == '/' )
666 *psz_parser++ = '\0';
677 psz_way = psz_parser;
681 p_mrl->psz_access = strdup( psz_access );
682 p_mrl->psz_way = strdup( psz_way );
683 p_mrl->psz_name = strdup( psz_name );
686 return( VLC_SUCCESS );
690 /* mrl_Clean: clean p_mrl after a call to mrl_Parse */
691 static void mrl_Clean( mrl_t *p_mrl )
693 FREENULL( p_mrl->psz_access );
694 FREENULL( p_mrl->psz_way );
695 FREENULL( p_mrl->psz_name );
699 /****************************************************************************
700 ****************************************************************************
704 ****************************************************************************
705 ****************************************************************************/
707 /* create a complete chain */
709 module{option=*:option=*}[:module{option=*:...}]
713 * parse module{options=str, option="str "}:
714 * return a pointer on the rest
715 * XXX: psz_chain is modified
717 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
718 #define SKIPTRAILINGSPACE( p, e ) \
719 { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
721 /* go accross " " and { } */
722 static char *_get_chain_end( char *str )
730 if( !*p || *p == ',' || *p == '}' ) return p;
732 if( *p != '{' && *p != '"' && *p != '\'' )
738 if( *p == '{' ) c = '}';
746 if( *p == c ) return ++p;
747 else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
754 * XXX name and p_cfg are used (-> do NOT free them)
756 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
758 sout_stream_t *p_stream;
762 msg_Err( p_sout, "invalid chain" );
766 p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
770 msg_Err( p_sout, "out of memory" );
774 p_stream->p_sout = p_sout;
775 p_stream->p_sys = NULL;
778 config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
780 msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
782 vlc_object_attach( p_stream, p_sout );
785 module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
787 if( !p_stream->p_module )
789 sout_StreamDelete( p_stream );
796 void sout_StreamDelete( sout_stream_t *p_stream )
798 msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
800 vlc_object_detach( p_stream );
801 if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
803 FREENULL( p_stream->psz_name );
804 FREENULL( p_stream->psz_next );
806 config_ChainDestroy( p_stream->p_cfg );
808 msg_Dbg( p_stream, "destroying chain done" );
809 vlc_object_destroy( p_stream );
812 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
817 mrl_Parse( &mrl, psz_url );
818 p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
819 strlen( mrl.psz_access ) +
820 strlen( mrl.psz_name ) );
823 if( config_GetInt( p_this, "sout-display" ) )
825 p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
826 "access=\"%s\",dst=\"%s\"}}",
827 mrl.psz_way, mrl.psz_access, mrl.psz_name );
831 p += sprintf( p, "std{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
832 mrl.psz_way, mrl.psz_access, mrl.psz_name );