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 );
106 p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
108 if( p_sout->p_stream == NULL )
110 msg_Err( p_sout, "stream chain failed for `%s'", p_sout->psz_chain );
112 FREENULL( p_sout->psz_sout );
113 FREENULL( p_sout->psz_chain );
115 vlc_object_detach( p_sout );
116 vlc_object_destroy( p_sout );
123 /*****************************************************************************
124 * sout_DeleteInstance: delete a previously allocated instance
125 *****************************************************************************/
126 void sout_DeleteInstance( sout_instance_t * p_sout )
128 /* remove the stream out chain */
129 sout_StreamDelete( p_sout->p_stream );
131 /* *** free all string *** */
132 FREENULL( p_sout->psz_sout );
133 FREENULL( p_sout->psz_chain );
138 vlc_meta_Delete( p_sout->p_meta );
141 vlc_mutex_destroy( &p_sout->lock );
143 /* *** free structure *** */
144 vlc_object_destroy( p_sout );
147 /*****************************************************************************
149 *****************************************************************************/
150 sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
153 sout_packetizer_input_t *p_input;
155 msg_Dbg( p_sout, "adding a new input" );
157 /* *** create a packetizer input *** */
158 p_input = malloc( sizeof( sout_packetizer_input_t ) );
159 p_input->p_sout = p_sout;
160 p_input->p_fmt = p_fmt;
162 if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
164 vlc_object_release( p_sout );
168 /* *** add it to the stream chain */
169 vlc_mutex_lock( &p_sout->lock );
170 p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
171 vlc_mutex_unlock( &p_sout->lock );
173 if( p_input->id == NULL )
182 /*****************************************************************************
184 *****************************************************************************/
185 int sout_InputDelete( sout_packetizer_input_t *p_input )
187 sout_instance_t *p_sout = p_input->p_sout;
189 msg_Dbg( p_sout, "removing an input" );
191 if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
193 vlc_mutex_lock( &p_sout->lock );
194 p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
195 vlc_mutex_unlock( &p_sout->lock );
200 return( VLC_SUCCESS);
203 /*****************************************************************************
205 *****************************************************************************/
206 int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
209 sout_instance_t *p_sout = p_input->p_sout;
212 if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
214 block_Release( p_buffer );
217 if( p_buffer->i_dts <= 0 )
219 msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
220 block_Release( p_buffer );
224 vlc_mutex_lock( &p_sout->lock );
225 i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
226 p_input->id, p_buffer );
227 vlc_mutex_unlock( &p_sout->lock );
232 /*****************************************************************************
233 * sout_AccessOutNew: allocate a new access out
234 *****************************************************************************/
235 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
236 const char *psz_access, const char *psz_name )
238 sout_access_out_t *p_access;
241 if( !( p_access = vlc_object_create( p_sout,
242 sizeof( sout_access_out_t ) ) ) )
244 msg_Err( p_sout, "out of memory" );
248 psz_next = config_ChainCreate( &p_access->psz_access, &p_access->p_cfg,
254 p_access->psz_path = strdup( psz_name ? psz_name : "" );
255 p_access->p_sout = p_sout;
256 p_access->p_sys = NULL;
257 p_access->pf_seek = NULL;
258 p_access->pf_read = NULL;
259 p_access->pf_write = NULL;
260 p_access->pf_control = NULL;
261 p_access->p_module = NULL;
263 p_access->i_writes = 0;
264 p_access->i_sent_bytes = 0;
266 vlc_object_attach( p_access, p_sout );
269 module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
271 if( !p_access->p_module )
273 free( p_access->psz_access );
274 free( p_access->psz_path );
275 vlc_object_detach( p_access );
276 vlc_object_destroy( p_access );
282 /*****************************************************************************
283 * sout_AccessDelete: delete an access out
284 *****************************************************************************/
285 void sout_AccessOutDelete( sout_access_out_t *p_access )
287 vlc_object_detach( p_access );
288 if( p_access->p_module )
290 module_Unneed( p_access, p_access->p_module );
292 free( p_access->psz_access );
294 config_ChainDestroy( p_access->p_cfg );
296 free( p_access->psz_path );
298 vlc_object_destroy( p_access );
301 /*****************************************************************************
303 *****************************************************************************/
304 int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
306 return p_access->pf_seek( p_access, i_pos );
309 /*****************************************************************************
311 *****************************************************************************/
312 int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
314 return( p_access->pf_read ?
315 p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
318 /*****************************************************************************
320 *****************************************************************************/
321 int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
324 p_access->i_writes++;
325 p_access->i_sent_bytes += p_buffer->i_buffer;
326 if( p_access->p_libvlc->b_stats && p_access->i_writes % 30 == 0 )
328 /* Access_out -> sout_instance -> input_thread_t */
329 input_thread_t *p_input =
330 (input_thread_t *)vlc_object_find( p_access, VLC_OBJECT_INPUT,
334 stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_packets,
336 stats_UpdateInteger( p_input, p_input->p->counters.p_sout_sent_bytes,
337 p_access->i_sent_bytes, &i_total );
338 stats_UpdateFloat( p_input, p_input->p->counters.p_sout_send_bitrate,
339 (float)i_total, NULL );
340 p_access->i_sent_bytes = 0;
341 vlc_object_release( p_input );
344 return p_access->pf_write( p_access, p_buffer );
348 * sout_AccessOutControl
350 int sout_AccessOutControl (sout_access_out_t *access, int query, va_list args)
352 return (access->pf_control) ? access->pf_control (access, query, args)
356 /*****************************************************************************
357 * sout_MuxNew: create a new mux
358 *****************************************************************************/
359 sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
360 sout_access_out_t *p_access )
365 p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
368 msg_Err( p_sout, "out of memory" );
372 p_mux->p_sout = p_sout;
373 psz_next = config_ChainCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
374 if( psz_next ) free( psz_next );
376 p_mux->p_access = p_access;
377 p_mux->pf_control = NULL;
378 p_mux->pf_addstream = NULL;
379 p_mux->pf_delstream = NULL;
380 p_mux->pf_mux = NULL;
381 p_mux->i_nb_inputs = 0;
382 p_mux->pp_inputs = NULL;
385 p_mux->p_module = NULL;
387 p_mux->b_add_stream_any_time = VLC_FALSE;
388 p_mux->b_waiting_stream = VLC_TRUE;
389 p_mux->i_add_stream_start = -1;
391 vlc_object_attach( p_mux, p_sout );
394 module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
396 if( p_mux->p_module == NULL )
398 FREENULL( p_mux->psz_mux );
400 vlc_object_detach( p_mux );
401 vlc_object_destroy( p_mux );
405 /* *** probe mux capacity *** */
406 if( p_mux->pf_control )
408 int b_answer = VLC_FALSE;
410 if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
413 b_answer = VLC_FALSE;
418 msg_Dbg( p_sout, "muxer support adding stream at any time" );
419 p_mux->b_add_stream_any_time = VLC_TRUE;
420 p_mux->b_waiting_stream = VLC_FALSE;
422 /* If we control the output pace then it's better to wait before
423 * starting muxing (generates better streams/files). */
424 if( !p_sout->i_out_pace_nocontrol )
428 else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
431 b_answer = VLC_FALSE;
436 msg_Dbg( p_sout, "muxer prefers to wait for all ES before "
438 p_mux->b_waiting_stream = VLC_TRUE;
446 /*****************************************************************************
448 *****************************************************************************/
449 void sout_MuxDelete( sout_mux_t *p_mux )
451 vlc_object_detach( p_mux );
452 if( p_mux->p_module )
454 module_Unneed( p_mux, p_mux->p_module );
456 free( p_mux->psz_mux );
458 config_ChainDestroy( p_mux->p_cfg );
460 vlc_object_destroy( p_mux );
463 /*****************************************************************************
465 *****************************************************************************/
466 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
468 sout_input_t *p_input;
470 if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
472 msg_Err( p_mux, "cannot add a new stream (unsupported while muxing "
477 msg_Dbg( p_mux, "adding a new input" );
479 /* create a new sout input */
480 p_input = malloc( sizeof( sout_input_t ) );
481 p_input->p_sout = p_mux->p_sout;
482 p_input->p_fmt = p_fmt;
483 p_input->p_fifo = block_FifoNew( p_mux->p_sout );
484 p_input->p_sys = NULL;
486 TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
487 if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
489 msg_Err( p_mux, "cannot add this stream" );
490 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
491 block_FifoRelease( p_input->p_fifo );
499 /*****************************************************************************
500 * sout_MuxDeleteStream:
501 *****************************************************************************/
502 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
506 if( p_mux->b_waiting_stream
507 && block_FifoCount( p_input->p_fifo ) > 0 )
509 /* We stop waiting, and call the muxer for taking care of the data
510 * before we remove this es */
511 p_mux->b_waiting_stream = VLC_FALSE;
512 p_mux->pf_mux( p_mux );
515 TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
518 if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
520 msg_Err( p_mux, "cannot delete this stream from mux" );
523 /* remove the entry */
524 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
526 if( p_mux->i_nb_inputs == 0 )
528 msg_Warn( p_mux, "no more input streams for this mux" );
531 block_FifoRelease( p_input->p_fifo );
536 /*****************************************************************************
537 * sout_MuxSendBuffer:
538 *****************************************************************************/
539 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
542 block_FifoPut( p_input->p_fifo, p_buffer );
544 if( p_mux->p_sout->i_out_pace_nocontrol )
546 mtime_t current_date = mdate();
547 if ( current_date > p_buffer->i_dts )
548 msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
549 current_date - p_buffer->i_dts );
552 if( p_mux->b_waiting_stream )
554 if( p_mux->i_add_stream_start < 0 )
556 p_mux->i_add_stream_start = p_buffer->i_dts;
559 if( p_mux->i_add_stream_start >= 0 &&
560 p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
562 /* Wait until we have more than 1.5 seconds worth of data
563 * before start muxing */
564 p_mux->b_waiting_stream = VLC_FALSE;
571 p_mux->pf_mux( p_mux );
574 /*****************************************************************************
576 *****************************************************************************/
577 static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl )
579 char * psz_dup = strdup( psz_mrl );
580 char * psz_parser = psz_dup;
581 const char * psz_access;
582 const char * psz_way;
585 /* *** first parse psz_dest */
586 while( *psz_parser && *psz_parser != ':' )
588 if( *psz_parser == '{' )
590 while( *psz_parser && *psz_parser != '}' )
604 #if defined( WIN32 ) || defined( UNDER_CE )
605 if( psz_parser - psz_dup == 1 )
607 /* msg_Warn( p_sout, "drive letter %c: found in source string",
615 psz_access = psz_way = "";
620 *psz_parser++ = '\0';
622 /* let's skip '//' */
623 if( psz_parser[0] == '/' && psz_parser[1] == '/' )
628 psz_name = psz_parser ;
630 /* Come back to parse the access and mux plug-ins */
631 psz_parser = psz_dup;
638 else if( *psz_parser == '/' )
646 psz_access = psz_parser;
648 while( *psz_parser && *psz_parser != '/' )
650 if( *psz_parser == '{' )
652 while( *psz_parser && *psz_parser != '}' )
667 if( *psz_parser == '/' )
669 *psz_parser++ = '\0';
680 psz_way = psz_parser;
684 p_mrl->psz_access = strdup( psz_access );
685 p_mrl->psz_way = strdup( psz_way );
686 p_mrl->psz_name = strdup( psz_name );
689 return( VLC_SUCCESS );
693 /* mrl_Clean: clean p_mrl after a call to mrl_Parse */
694 static void mrl_Clean( mrl_t *p_mrl )
696 FREENULL( p_mrl->psz_access );
697 FREENULL( p_mrl->psz_way );
698 FREENULL( p_mrl->psz_name );
702 /****************************************************************************
703 ****************************************************************************
707 ****************************************************************************
708 ****************************************************************************/
710 /* create a complete chain */
712 module{option=*:option=*}[:module{option=*:...}]
716 * parse module{options=str, option="str "}:
717 * return a pointer on the rest
718 * XXX: psz_chain is modified
720 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
721 #define SKIPTRAILINGSPACE( p, e ) \
722 { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
724 /* go accross " " and { } */
725 static char *_get_chain_end( char *str )
733 if( !*p || *p == ',' || *p == '}' ) return p;
735 if( *p != '{' && *p != '"' && *p != '\'' )
741 if( *p == '{' ) c = '}';
749 if( *p == c ) return ++p;
750 else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
757 * XXX name and p_cfg are used (-> do NOT free them)
759 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
761 sout_stream_t *p_stream;
765 msg_Err( p_sout, "invalid chain" );
769 p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
773 msg_Err( p_sout, "out of memory" );
777 p_stream->p_sout = p_sout;
778 p_stream->p_sys = NULL;
781 config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
783 msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
785 vlc_object_attach( p_stream, p_sout );
788 module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
790 if( !p_stream->p_module )
792 sout_StreamDelete( p_stream );
799 void sout_StreamDelete( sout_stream_t *p_stream )
801 msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
803 vlc_object_detach( p_stream );
804 if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
806 FREENULL( p_stream->psz_name );
807 FREENULL( p_stream->psz_next );
809 config_ChainDestroy( p_stream->p_cfg );
811 msg_Dbg( p_stream, "destroying chain done" );
812 vlc_object_destroy( p_stream );
815 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
820 mrl_Parse( &mrl, psz_url );
821 p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
822 strlen( mrl.psz_access ) +
823 strlen( mrl.psz_name ) );
826 if( config_GetInt( p_this, "sout-display" ) )
828 p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
829 "access=\"%s\",dst=\"%s\"}}",
830 mrl.psz_way, mrl.psz_access, mrl.psz_name );
834 p += sprintf( p, "std{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
835 mrl.psz_way, mrl.psz_access, mrl.psz_name );