1 /*****************************************************************************
2 * stream_output.c : stream output module
3 *****************************************************************************
4 * Copyright (C) 2002-2004 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/input.h>
42 /*****************************************************************************
44 *****************************************************************************/
45 static void sout_CfgDestroy( sout_cfg_t * );
47 #define sout_stream_url_to_chain( p, s ) \
48 _sout_stream_url_to_chain( VLC_OBJECT(p), s )
49 static char *_sout_stream_url_to_chain( vlc_object_t *, char * );
63 /* mrl_Parse: parse psz_mrl and fill p_mrl */
64 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl );
65 /* mrl_Clean: clean p_mrl after a call to mrl_Parse */
66 static void mrl_Clean( mrl_t *p_mrl );
68 /*****************************************************************************
69 * sout_NewInstance: creates a new stream output instance
70 *****************************************************************************/
71 sout_instance_t *__sout_NewInstance( vlc_object_t *p_parent, char * psz_dest )
73 sout_instance_t *p_sout;
76 if( var_Get( p_parent, "sout-keep", &keep ) < 0 )
78 msg_Warn( p_parent, "cannot get sout-keep value" );
79 keep.b_bool = VLC_FALSE;
83 if( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
84 FIND_ANYWHERE ) ) != NULL )
86 if( !strcmp( p_sout->psz_sout, psz_dest ) )
88 msg_Dbg( p_parent, "sout keep: reusing sout" );
89 msg_Dbg( p_parent, "sout keep: you probably want to use "
90 "gather stream_out" );
91 vlc_object_detach( p_sout );
92 vlc_object_attach( p_sout, p_parent );
93 vlc_object_release( p_sout );
98 msg_Dbg( p_parent, "sout keep: destroying unusable sout" );
99 vlc_object_release( p_sout );
100 sout_DeleteInstance( p_sout );
104 else if( !keep.b_bool )
106 while( ( p_sout = vlc_object_find( p_parent, VLC_OBJECT_SOUT,
107 FIND_PARENT ) ) != NULL )
109 msg_Dbg( p_parent, "sout keep: destroying old sout" );
110 vlc_object_release( p_sout );
111 sout_DeleteInstance( p_sout );
115 /* *** Allocate descriptor *** */
116 p_sout = vlc_object_create( p_parent, VLC_OBJECT_SOUT );
119 msg_Err( p_parent, "out of memory" );
123 /* *** init descriptor *** */
124 p_sout->psz_sout = strdup( psz_dest );
125 p_sout->p_meta = NULL;
126 p_sout->i_out_pace_nocontrol = 0;
127 p_sout->p_sys = NULL;
129 vlc_mutex_init( p_sout, &p_sout->lock );
130 if( psz_dest && psz_dest[0] == '#' )
132 p_sout->psz_chain = strdup( &psz_dest[1] );
136 p_sout->psz_chain = sout_stream_url_to_chain( p_sout, psz_dest );
137 msg_Dbg( p_sout, "using sout chain=`%s'", p_sout->psz_chain );
139 p_sout->p_stream = NULL;
141 /* attach it for inherit */
142 vlc_object_attach( p_sout, p_parent );
144 p_sout->p_stream = sout_StreamNew( p_sout, p_sout->psz_chain );
146 if( p_sout->p_stream == NULL )
148 msg_Err( p_sout, "stream chain failed for `%s'", p_sout->psz_chain );
150 FREENULL( p_sout->psz_sout );
151 FREENULL( p_sout->psz_chain );
153 vlc_object_detach( p_sout );
154 vlc_object_destroy( p_sout );
161 /*****************************************************************************
162 * sout_DeleteInstance: delete a previously allocated instance
163 *****************************************************************************/
164 void sout_DeleteInstance( sout_instance_t * p_sout )
167 vlc_object_detach( p_sout );
169 /* remove the stream out chain */
170 sout_StreamDelete( p_sout->p_stream );
172 /* *** free all string *** */
173 FREENULL( p_sout->psz_sout );
174 FREENULL( p_sout->psz_chain );
179 vlc_meta_Delete( p_sout->p_meta );
182 vlc_mutex_destroy( &p_sout->lock );
184 /* *** free structure *** */
185 vlc_object_destroy( p_sout );
188 /*****************************************************************************
190 *****************************************************************************/
191 sout_packetizer_input_t *sout_InputNew( sout_instance_t *p_sout,
194 sout_packetizer_input_t *p_input;
196 msg_Dbg( p_sout, "adding a new input" );
198 /* *** create a packetizer input *** */
199 p_input = malloc( sizeof( sout_packetizer_input_t ) );
200 p_input->p_sout = p_sout;
201 p_input->p_fmt = p_fmt;
203 if( p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
205 vlc_object_release( p_sout );
209 /* *** add it to the stream chain */
210 vlc_mutex_lock( &p_sout->lock );
211 p_input->id = p_sout->p_stream->pf_add( p_sout->p_stream, p_fmt );
212 vlc_mutex_unlock( &p_sout->lock );
214 if( p_input->id == NULL )
223 /*****************************************************************************
225 *****************************************************************************/
226 int sout_InputDelete( sout_packetizer_input_t *p_input )
228 sout_instance_t *p_sout = p_input->p_sout;
230 msg_Dbg( p_sout, "removing an input" );
232 if( p_input->p_fmt->i_codec != VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
234 vlc_mutex_lock( &p_sout->lock );
235 p_sout->p_stream->pf_del( p_sout->p_stream, p_input->id );
236 vlc_mutex_unlock( &p_sout->lock );
241 return( VLC_SUCCESS);
244 /*****************************************************************************
246 *****************************************************************************/
247 int sout_InputSendBuffer( sout_packetizer_input_t *p_input,
250 sout_instance_t *p_sout = p_input->p_sout;
253 if( p_input->p_fmt->i_codec == VLC_FOURCC( 'n', 'u', 'l', 'l' ) )
255 block_Release( p_buffer );
258 if( p_buffer->i_dts <= 0 )
260 msg_Warn( p_sout, "trying to send non-dated packet to stream output!");
261 block_Release( p_buffer );
265 vlc_mutex_lock( &p_sout->lock );
266 i_ret = p_sout->p_stream->pf_send( p_sout->p_stream,
267 p_input->id, p_buffer );
268 vlc_mutex_unlock( &p_sout->lock );
273 /*****************************************************************************
274 * sout_AccessOutNew: allocate a new access out
275 *****************************************************************************/
276 sout_access_out_t *sout_AccessOutNew( sout_instance_t *p_sout,
277 char *psz_access, char *psz_name )
279 sout_access_out_t *p_access;
282 if( !( p_access = vlc_object_create( p_sout,
283 sizeof( sout_access_out_t ) ) ) )
285 msg_Err( p_sout, "out of memory" );
289 psz_next = sout_CfgCreate( &p_access->psz_access, &p_access->p_cfg,
295 p_access->psz_name = strdup( psz_name ? psz_name : "" );
296 p_access->p_sout = p_sout;
297 p_access->p_sys = NULL;
298 p_access->pf_seek = NULL;
299 p_access->pf_read = NULL;
300 p_access->pf_write = NULL;
301 p_access->p_module = NULL;
303 p_access->i_writes = 0;
304 p_access->i_sent_bytes = 0;
306 vlc_object_attach( p_access, p_sout );
309 module_Need( p_access, "sout access", p_access->psz_access, VLC_TRUE );
311 if( !p_access->p_module )
313 free( p_access->psz_access );
314 free( p_access->psz_name );
315 vlc_object_detach( p_access );
316 vlc_object_destroy( p_access );
322 /*****************************************************************************
323 * sout_AccessDelete: delete an access out
324 *****************************************************************************/
325 void sout_AccessOutDelete( sout_access_out_t *p_access )
327 vlc_object_detach( p_access );
328 if( p_access->p_module )
330 module_Unneed( p_access, p_access->p_module );
332 free( p_access->psz_access );
334 sout_CfgDestroy( p_access->p_cfg );
336 free( p_access->psz_name );
338 vlc_object_destroy( p_access );
341 /*****************************************************************************
343 *****************************************************************************/
344 int sout_AccessOutSeek( sout_access_out_t *p_access, off_t i_pos )
346 return p_access->pf_seek( p_access, i_pos );
349 /*****************************************************************************
351 *****************************************************************************/
352 int sout_AccessOutRead( sout_access_out_t *p_access, block_t *p_buffer )
354 return( p_access->pf_read ?
355 p_access->pf_read( p_access, p_buffer ) : VLC_EGENERIC );
358 /*****************************************************************************
360 *****************************************************************************/
361 int sout_AccessOutWrite( sout_access_out_t *p_access, block_t *p_buffer )
364 p_access->i_writes++;
365 p_access->i_sent_bytes += p_buffer->i_buffer;
366 if( p_access->p_libvlc->b_stats && p_access->i_writes % 30 == 0 )
368 /* Access_out -> sout_instance -> input_thread_t */
369 input_thread_t *p_input =
370 (input_thread_t *)vlc_object_find( p_access, VLC_OBJECT_INPUT,
374 stats_UpdateInteger( p_input, p_input->counters.p_sout_sent_packets,
376 stats_UpdateInteger( p_input, p_input->counters.p_sout_sent_bytes,
377 p_access->i_sent_bytes, &i_total );
378 stats_UpdateFloat( p_input, p_input->counters.p_sout_send_bitrate,
379 (float)i_total, NULL );
380 p_access->i_sent_bytes = 0;
381 vlc_object_release( p_input );
384 return p_access->pf_write( p_access, p_buffer );
387 /*****************************************************************************
388 * sout_MuxNew: create a new mux
389 *****************************************************************************/
390 sout_mux_t * sout_MuxNew( sout_instance_t *p_sout, char *psz_mux,
391 sout_access_out_t *p_access )
396 p_mux = vlc_object_create( p_sout, sizeof( sout_mux_t ) );
399 msg_Err( p_sout, "out of memory" );
403 p_mux->p_sout = p_sout;
404 psz_next = sout_CfgCreate( &p_mux->psz_mux, &p_mux->p_cfg, psz_mux );
405 if( psz_next ) free( psz_next );
407 p_mux->p_access = p_access;
408 p_mux->pf_control = NULL;
409 p_mux->pf_addstream = NULL;
410 p_mux->pf_delstream = NULL;
411 p_mux->pf_mux = NULL;
412 p_mux->i_nb_inputs = 0;
413 p_mux->pp_inputs = NULL;
416 p_mux->p_module = NULL;
418 p_mux->b_add_stream_any_time = VLC_FALSE;
419 p_mux->b_waiting_stream = VLC_TRUE;
420 p_mux->i_add_stream_start = -1;
422 vlc_object_attach( p_mux, p_sout );
425 module_Need( p_mux, "sout mux", p_mux->psz_mux, VLC_TRUE );
427 if( p_mux->p_module == NULL )
429 FREENULL( p_mux->psz_mux );
431 vlc_object_detach( p_mux );
432 vlc_object_destroy( p_mux );
436 /* *** probe mux capacity *** */
437 if( p_mux->pf_control )
439 int b_answer = VLC_FALSE;
441 if( sout_MuxControl( p_mux, MUX_CAN_ADD_STREAM_WHILE_MUXING,
444 b_answer = VLC_FALSE;
449 msg_Dbg( p_sout, "muxer support adding stream at any time" );
450 p_mux->b_add_stream_any_time = VLC_TRUE;
451 p_mux->b_waiting_stream = VLC_FALSE;
453 /* If we control the output pace then it's better to wait before
454 * starting muxing (generates better streams/files). */
455 if( !p_sout->i_out_pace_nocontrol )
459 else if( sout_MuxControl( p_mux, MUX_GET_ADD_STREAM_WAIT,
462 b_answer = VLC_FALSE;
467 msg_Dbg( p_sout, "muxer prefers to wait for all ES before "
469 p_mux->b_waiting_stream = VLC_TRUE;
477 /*****************************************************************************
479 *****************************************************************************/
480 void sout_MuxDelete( sout_mux_t *p_mux )
482 vlc_object_detach( p_mux );
483 if( p_mux->p_module )
485 module_Unneed( p_mux, p_mux->p_module );
487 free( p_mux->psz_mux );
489 sout_CfgDestroy( p_mux->p_cfg );
491 vlc_object_destroy( p_mux );
494 /*****************************************************************************
496 *****************************************************************************/
497 sout_input_t *sout_MuxAddStream( sout_mux_t *p_mux, es_format_t *p_fmt )
499 sout_input_t *p_input;
501 if( !p_mux->b_add_stream_any_time && !p_mux->b_waiting_stream )
503 msg_Err( p_mux, "cannot add a new stream (unsupported while muxing "
508 msg_Dbg( p_mux, "adding a new input" );
510 /* create a new sout input */
511 p_input = malloc( sizeof( sout_input_t ) );
512 p_input->p_sout = p_mux->p_sout;
513 p_input->p_fmt = p_fmt;
514 p_input->p_fifo = block_FifoNew( p_mux->p_sout );
515 p_input->p_sys = NULL;
517 TAB_APPEND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
518 if( p_mux->pf_addstream( p_mux, p_input ) < 0 )
520 msg_Err( p_mux, "cannot add this stream" );
521 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
522 block_FifoRelease( p_input->p_fifo );
530 /*****************************************************************************
531 * sout_MuxDeleteStream:
532 *****************************************************************************/
533 void sout_MuxDeleteStream( sout_mux_t *p_mux, sout_input_t *p_input )
537 if( p_mux->b_waiting_stream && p_input->p_fifo->i_depth > 0 )
539 /* We stop waiting, and call the muxer for taking care of the data
540 * before we remove this es */
541 p_mux->b_waiting_stream = VLC_FALSE;
542 p_mux->pf_mux( p_mux );
545 TAB_FIND( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input, i_index );
548 if( p_mux->pf_delstream( p_mux, p_input ) < 0 )
550 msg_Err( p_mux, "cannot delete this stream from mux" );
553 /* remove the entry */
554 TAB_REMOVE( p_mux->i_nb_inputs, p_mux->pp_inputs, p_input );
556 if( p_mux->i_nb_inputs == 0 )
558 msg_Warn( p_mux, "no more input streams for this mux" );
561 block_FifoRelease( p_input->p_fifo );
566 /*****************************************************************************
567 * sout_MuxSendBuffer:
568 *****************************************************************************/
569 void sout_MuxSendBuffer( sout_mux_t *p_mux, sout_input_t *p_input,
572 block_FifoPut( p_input->p_fifo, p_buffer );
574 if( p_mux->p_sout->i_out_pace_nocontrol )
576 mtime_t current_date = mdate();
577 if ( current_date > p_buffer->i_dts )
578 msg_Warn( p_mux, "late buffer for mux input ("I64Fd")",
579 current_date - p_buffer->i_dts );
582 if( p_mux->b_waiting_stream )
584 if( p_mux->i_add_stream_start < 0 )
586 p_mux->i_add_stream_start = p_buffer->i_dts;
589 if( p_mux->i_add_stream_start >= 0 &&
590 p_mux->i_add_stream_start + I64C(1500000) < p_buffer->i_dts )
592 /* Wait until we have more than 1.5 seconds worth of data
593 * before start muxing */
594 p_mux->b_waiting_stream = VLC_FALSE;
601 p_mux->pf_mux( p_mux );
604 /*****************************************************************************
606 *****************************************************************************/
607 static int mrl_Parse( mrl_t *p_mrl, char *psz_mrl )
609 char * psz_dup = strdup( psz_mrl );
610 char * psz_parser = psz_dup;
611 char * psz_access = "";
613 char * psz_name = "";
615 /* *** first parse psz_dest */
616 while( *psz_parser && *psz_parser != ':' )
618 if( *psz_parser == '{' )
620 while( *psz_parser && *psz_parser != '}' )
634 #if defined( WIN32 ) || defined( UNDER_CE )
635 if( psz_parser - psz_dup == 1 )
637 /* msg_Warn( p_sout, "drive letter %c: found in source string",
645 psz_access = psz_way = "";
650 *psz_parser++ = '\0';
652 /* let's skip '//' */
653 if( psz_parser[0] == '/' && psz_parser[1] == '/' )
658 psz_name = psz_parser ;
660 /* Come back to parse the access and mux plug-ins */
661 psz_parser = psz_dup;
668 else if( *psz_parser == '/' )
676 psz_access = psz_parser;
678 while( *psz_parser && *psz_parser != '/' )
680 if( *psz_parser == '{' )
682 while( *psz_parser && *psz_parser != '}' )
697 if( *psz_parser == '/' )
699 *psz_parser++ = '\0';
710 psz_way = psz_parser;
714 p_mrl->psz_access = strdup( psz_access );
715 p_mrl->psz_way = strdup( psz_way );
716 p_mrl->psz_name = strdup( psz_name );
719 return( VLC_SUCCESS );
723 /* mrl_Clean: clean p_mrl after a call to mrl_Parse */
724 static void mrl_Clean( mrl_t *p_mrl )
726 FREENULL( p_mrl->psz_access );
727 FREENULL( p_mrl->psz_way );
728 FREENULL( p_mrl->psz_name );
732 /****************************************************************************
733 ****************************************************************************
737 ****************************************************************************
738 ****************************************************************************/
740 /* create a complete chain */
742 module{option=*:option=*}[:module{option=*:...}]
746 * parse module{options=str, option="str "}:
747 * return a pointer on the rest
748 * XXX: psz_chain is modified
750 #define SKIPSPACE( p ) { while( *p && ( *p == ' ' || *p == '\t' ) ) p++; }
751 #define SKIPTRAILINGSPACE( p, e ) \
752 { while( e > p && ( *(e-1) == ' ' || *(e-1) == '\t' ) ) e--; }
754 /* go accross " " and { } */
755 static char *_get_chain_end( char *str )
763 if( !*p || *p == ',' || *p == '}' ) return p;
765 if( *p != '{' && *p != '"' && *p != '\'' )
771 if( *p == '{' ) c = '}';
779 if( *p == c ) return ++p;
780 else if( *p == '{' && c == '}' ) p = _get_chain_end( p );
786 char *sout_CfgCreate( char **ppsz_name, sout_cfg_t **pp_cfg, char *psz_chain )
788 sout_cfg_t *p_cfg = NULL;
794 if( !p ) return NULL;
798 while( *p && *p != '{' && *p != ':' && *p != ' ' && *p != '\t' ) p++;
800 if( p == psz_chain ) return NULL;
802 *ppsz_name = strndup( psz_chain, p - psz_chain );
820 while( *p && *p != '=' && *p != ',' && *p != '{' && *p != '}' &&
821 *p != ' ' && *p != '\t' ) p++;
823 /* fprintf( stderr, "name=%s - rest=%s\n", psz_name, p ); */
826 fprintf( stderr, "invalid options (empty)" );
830 cfg.psz_name = strndup( psz_name, p - psz_name );
834 if( *p == '=' || *p == '{' )
837 vlc_bool_t b_keep_brackets = (*p == '{');
841 end = _get_chain_end( p );
844 cfg.psz_value = NULL;
848 /* Skip heading and trailing spaces.
849 * This ain't necessary but will avoid simple
856 cfg.psz_value = NULL;
860 if( *p == '\'' || *p == '"' ||
861 ( !b_keep_brackets && *p == '{' ) )
865 if( *(end-1) != '\'' && *(end-1) == '"' )
866 SKIPTRAILINGSPACE( p, end );
868 if( end - 1 <= p ) cfg.psz_value = NULL;
869 else cfg.psz_value = strndup( p, end -1 - p );
873 SKIPTRAILINGSPACE( p, end );
874 if( end <= p ) cfg.psz_value = NULL;
875 else cfg.psz_value = strndup( p, end - p );
884 cfg.psz_value = NULL;
890 p_cfg->p_next = malloc( sizeof( sout_cfg_t ) );
891 memcpy( p_cfg->p_next, &cfg, sizeof( sout_cfg_t ) );
893 p_cfg = p_cfg->p_next;
897 p_cfg = malloc( sizeof( sout_cfg_t ) );
898 memcpy( p_cfg, &cfg, sizeof( sout_cfg_t ) );
913 if( *p == ':' ) return( strdup( p + 1 ) );
918 static void sout_CfgDestroy( sout_cfg_t *p_cfg )
920 while( p_cfg != NULL )
924 p_next = p_cfg->p_next;
926 FREENULL( p_cfg->psz_name );
927 FREENULL( p_cfg->psz_value );
934 void __sout_CfgParse( vlc_object_t *p_this, char *psz_prefix,
935 const char **ppsz_options, sout_cfg_t *cfg )
941 /* First, var_Create all variables */
942 for( i = 0; ppsz_options[i] != NULL; i++ )
944 asprintf( &psz_name, "%s%s", psz_prefix,
945 *ppsz_options[i] == '*' ? &ppsz_options[i][1] : ppsz_options[i] );
947 i_type = config_GetType( p_this, psz_name );
949 var_Create( p_this, psz_name, i_type | VLC_VAR_DOINHERIT );
953 /* Now parse options and set value */
954 if( psz_prefix == NULL ) psz_prefix = "";
959 vlc_bool_t b_yes = VLC_TRUE;
960 vlc_bool_t b_once = VLC_FALSE;
961 module_config_t *p_conf;
963 if( cfg->psz_name == NULL || *cfg->psz_name == '\0' )
968 for( i = 0; ppsz_options[i] != NULL; i++ )
970 if( !strcmp( ppsz_options[i], cfg->psz_name ) )
974 if( ( !strncmp( cfg->psz_name, "no-", 3 ) &&
975 !strcmp( ppsz_options[i], cfg->psz_name + 3 ) ) ||
976 ( !strncmp( cfg->psz_name, "no", 2 ) &&
977 !strcmp( ppsz_options[i], cfg->psz_name + 2 ) ) )
983 if( *ppsz_options[i] == '*' &&
984 !strcmp( &ppsz_options[i][1], cfg->psz_name ) )
991 if( ppsz_options[i] == NULL )
993 msg_Warn( p_this, "option %s is unknown", cfg->psz_name );
999 asprintf( &psz_name, "%s%s", psz_prefix, b_once ? &ppsz_options[i][1] : ppsz_options[i] );
1001 /* Check if the option is deprecated */
1002 p_conf = config_FindConfig( p_this, psz_name );
1004 /* This is basically cut and paste from src/misc/configuration.c
1005 * with slight changes */
1006 if( p_conf && p_conf->psz_current )
1008 if( !strcmp( p_conf->psz_current, "SUPPRESSED" ) )
1010 msg_Err( p_this, "Option %s is no longer used.",
1014 else if( p_conf->b_strict )
1016 msg_Err( p_this, "Option %s is deprecated. Use %s instead.",
1017 p_conf->psz_name, p_conf->psz_current );
1018 /* TODO: this should return an error and end option parsing
1019 * ... but doing this would change the VLC API and all the
1020 * modules so i'll do it later */
1025 msg_Warn( p_this, "Option %s is deprecated. You should use "
1026 "%s instead.", p_conf->psz_name, p_conf->psz_current );
1028 psz_name = strdup( p_conf->psz_current );
1031 /* </Check if the option is deprecated> */
1033 /* get the type of the variable */
1034 i_type = config_GetType( p_this, psz_name );
1037 msg_Warn( p_this, "unknown option %s (value=%s)",
1038 cfg->psz_name, cfg->psz_value );
1041 if( i_type != VLC_VAR_BOOL && cfg->psz_value == NULL )
1043 msg_Warn( p_this, "missing value for option %s", cfg->psz_name );
1046 if( i_type != VLC_VAR_STRING && b_once )
1048 msg_Warn( p_this, "*option_name need to be a string option" );
1057 case VLC_VAR_INTEGER:
1058 val.i_int = strtol( cfg->psz_value ? cfg->psz_value : "0",
1062 val.f_float = atof( cfg->psz_value ? cfg->psz_value : "0" );
1064 case VLC_VAR_STRING:
1065 case VLC_VAR_MODULE:
1066 val.psz_string = cfg->psz_value;
1069 msg_Warn( p_this, "unhandled config var type" );
1070 memset( &val, 0, sizeof( vlc_value_t ) );
1077 var_Get( p_this, psz_name, &val2 );
1078 if( *val2.psz_string )
1080 free( val2.psz_string );
1081 msg_Dbg( p_this, "ignoring option %s (not first occurrence)", psz_name );
1084 free( val2.psz_string );
1086 var_Set( p_this, psz_name, val );
1087 msg_Dbg( p_this, "set sout option: %s to %s", psz_name, cfg->psz_value );
1097 * XXX name and p_cfg are used (-> do NOT free them)
1099 sout_stream_t *sout_StreamNew( sout_instance_t *p_sout, char *psz_chain )
1101 sout_stream_t *p_stream;
1105 msg_Err( p_sout, "invalid chain" );
1109 p_stream = vlc_object_create( p_sout, sizeof( sout_stream_t ) );
1113 msg_Err( p_sout, "out of memory" );
1117 p_stream->p_sout = p_sout;
1118 p_stream->p_sys = NULL;
1120 p_stream->psz_next =
1121 sout_CfgCreate( &p_stream->psz_name, &p_stream->p_cfg, psz_chain);
1123 msg_Dbg( p_sout, "stream=`%s'", p_stream->psz_name );
1125 vlc_object_attach( p_stream, p_sout );
1127 p_stream->p_module =
1128 module_Need( p_stream, "sout stream", p_stream->psz_name, VLC_TRUE );
1130 if( !p_stream->p_module )
1132 sout_StreamDelete( p_stream );
1139 void sout_StreamDelete( sout_stream_t *p_stream )
1141 msg_Dbg( p_stream, "destroying chain... (name=%s)", p_stream->psz_name );
1143 vlc_object_detach( p_stream );
1144 if( p_stream->p_module ) module_Unneed( p_stream, p_stream->p_module );
1146 FREENULL( p_stream->psz_name );
1147 FREENULL( p_stream->psz_next );
1149 sout_CfgDestroy( p_stream->p_cfg );
1151 msg_Dbg( p_stream, "destroying chain done" );
1152 vlc_object_destroy( p_stream );
1155 static char *_sout_stream_url_to_chain( vlc_object_t *p_this, char *psz_url )
1158 char *psz_chain, *p;
1160 mrl_Parse( &mrl, psz_url );
1161 p = psz_chain = malloc( 500 + strlen( mrl.psz_way ) +
1162 strlen( mrl.psz_access ) +
1163 strlen( mrl.psz_name ) );
1166 if( config_GetInt( p_this, "sout-display" ) )
1168 p += sprintf( p, "duplicate{dst=display,dst=std{mux=\"%s\","
1169 "access=\"%s\",dst=\"%s\"}}",
1170 mrl.psz_way, mrl.psz_access, mrl.psz_name );
1174 p += sprintf( p, "std{mux=\"%s\",access=\"%s\",dst=\"%s\"}",
1175 mrl.psz_way, mrl.psz_access, mrl.psz_name );
1179 return( psz_chain );