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() */
34 #include <string.h> /* strerror() */
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 && p_input->p_fifo->i_depth > 0 )
508 /* We stop waiting, and call the muxer for taking care of the data
509 * before we remove this es */
510 p_mux->b_waiting_stream = VLC_FALSE;
511 p_mux->pf_mux( p_mux );
514 TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
517 if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
519 msg_Err( p_mux, "cannot delete this stream from mux" );
522 /* remove the entry */
523 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
525 if( p_mux->i_nb_inputs == 0 )
527 msg_Warn( p_mux, "no more input streams for this mux" );
530 block_FifoRelease( p_input->p_fifo );
535 /*****************************************************************************
536 * sout_MuxSendBuffer:
537 *****************************************************************************/
538 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
541 block_FifoPut( p_input->p_fifo, p_buffer );
543 if( p_mux->p_sout->i_out_pace_nocontrol )
545 mtime_t current_date = mdate();
546 if ( current_date > p_buffer->i_dts )
547 msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
548 current_date - p_buffer->i_dts );
551 if( p_mux->b_waiting_stream )
553 if( p_mux->i_add_stream_start < 0 )
555 p_mux->i_add_stream_start = p_buffer->i_dts;
558 if( p_mux->i_add_stream_start >= 0 &&
559 p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
561 /* Wait until we have more than 1.5 seconds worth of data
562 * before start muxing */
563 p_mux->b_waiting_stream = VLC_FALSE;
570 p_mux->pf_mux( p_mux );
573 /*****************************************************************************
575 *****************************************************************************/
576 static int mrl_Parse( mrl_t *p_mrl, const char *psz_mrl )
578 char * psz_dup = strdup( psz_mrl );
579 char * psz_parser = psz_dup;
580 const char * psz_access;
581 const char * psz_way;
584 /* *** first parse psz_dest */
585 while( *psz_parser && *psz_parser != ':' )
587 if( *psz_parser == '{' )
589 while( *psz_parser && *psz_parser != '}' )
603 #if defined( WIN32 ) || defined( UNDER_CE )
604 if( psz_parser - psz_dup == 1 )
606 /* msg_Warn( p_sout, "drive letter %c: found in source string",
614 psz_access = psz_way = "";
619 *psz_parser++ = '\0';
621 /* let's skip '//' */
622 if( psz_parser[0] == '/' && psz_parser[1] == '/' )
627 psz_name = psz_parser ;
629 /* Come back to parse the access and mux plug-ins */
630 psz_parser = psz_dup;
637 else if( *psz_parser == '/' )
645 psz_access = psz_parser;
647 while( *psz_parser && *psz_parser != '/' )
649 if( *psz_parser == '{' )
651 while( *psz_parser && *psz_parser != '}' )
666 if( *psz_parser == '/' )
668 *psz_parser++ = '\0';
679 psz_way = psz_parser;
683 p_mrl->psz_access = strdup( psz_access );
684 p_mrl->psz_way = strdup( psz_way );
685 p_mrl->psz_name = strdup( psz_name );
688 return( VLC_SUCCESS );
692 /* mrl_Clean: clean p_mrl after a call to mrl_Parse */
693 static void mrl_Clean( mrl_t *p_mrl )
695 FREENULL( p_mrl->psz_access );
696 FREENULL( p_mrl->psz_way );
697 FREENULL( p_mrl->psz_name );
701 /****************************************************************************
702 ****************************************************************************
706 ****************************************************************************
707 ****************************************************************************/
709 /* create a complete chain */
711 module{option=*:option=*}[:module{option=*:...}]
715 * parse module{options=str, option="str "}:
716 * return a pointer on the rest
717 * XXX: psz_chain is modified
719 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
720 #define SKIPTRAILINGSPACE( p, e ) \
721 { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
723 /* go accross " " and { } */
724 static char *_get_chain_end( char *str )
732 if( !*p || *p == ',' || *p == '}' ) return p;
734 if( *p != '{' && *p != '"' && *p != '\'' )
740 if( *p == '{' ) c = '}';
748 if( *p == c ) return ++p;
749 else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
756 * XXX name and p_cfg are used (-> do NOT free them)
758 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
760 sout_stream_t *p_stream;
764 msg_Err( p_sout, "invalid chain" );
768 p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
772 msg_Err( p_sout, "out of memory" );
776 p_stream->p_sout = p_sout;
777 p_stream->p_sys = NULL;
780 config_ChainCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
782 msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
784 vlc_object_attach( p_stream, p_sout );
787 module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
789 if( !p_stream->p_module )
791 sout_StreamDelete( p_stream );
798 void sout_StreamDelete( sout_stream_t *p_stream )
800 msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
802 vlc_object_detach( p_stream );
803 if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
805 FREENULL( p_stream->psz_name );
806 FREENULL( p_stream->psz_next );
808 config_ChainDestroy( p_stream->p_cfg );
810 msg_Dbg( p_stream, "destroying chain done" );
811 vlc_object_destroy( p_stream );
814 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
819 mrl_Parse( &mrl, psz_url );
820 p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
821 strlen( mrl.psz_access ) +
822 strlen( mrl.psz_name ) );
825 if( config_GetInt( p_this, "sout-display" ) )
827 p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
828 "access=\"%s\",dst=\"%s\"}}",
829 mrl.psz_way, mrl.psz_access, mrl.psz_name );
833 p += sprintf( p, "std{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
834 mrl.psz_way, mrl.psz_access, mrl.psz_name );