1 /*****************************************************************************
2 * profiles.c: Streaming profiles
3 *****************************************************************************
4 * Copyright (C) 2006 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <vlc_streaming.h>
27 #define MAX_CHAIN 32768
28 #define CHAIN_APPEND( format, args... ) { \
29 memcpy( psz_temp, psz_output, MAX_CHAIN ); \
30 snprintf( psz_output, MAX_CHAIN - 1, "%s" format , psz_temp, ## args ); }
32 #define DUPM p_module->typed.p_duplicate
33 #define STDM p_module->typed.p_std
34 #define DISM p_module->typed.p_display
35 #define TRAM p_module->typed.p_transcode
37 /**********************************************************************
38 * General chain manipulation
39 **********************************************************************/
40 sout_duplicate_t *streaming_ChainAddDup( sout_chain_t *p_chain )
42 DECMALLOC_NULL( p_module, sout_module_t );
43 MALLOC_NULL( DUPM, sout_duplicate_t );
44 p_module->i_type = SOUT_MOD_DUPLICATE;
46 DUPM->pp_children = NULL;
47 INSERT_ELEM( p_chain->pp_modules, p_chain->i_modules, p_chain->i_modules,
49 return p_module->typed.p_duplicate;
52 sout_std_t *streaming_ChainAddStd( sout_chain_t *p_chain, char *psz_access,
53 char *psz_mux, char *psz_url )
55 DECMALLOC_NULL( p_module, sout_module_t );
56 MALLOC_NULL( STDM, sout_std_t );
57 p_module->i_type = SOUT_MOD_STD;
58 STDM->psz_mux = strdup( psz_mux );
59 STDM->psz_access = strdup( psz_access );
60 STDM->psz_url = strdup( psz_url );
61 INSERT_ELEM( p_chain->pp_modules, p_chain->i_modules, p_chain->i_modules,
66 sout_display_t *streaming_ChainAddDisplay( sout_chain_t *p_chain )
68 DECMALLOC_NULL( p_module, sout_module_t );
69 MALLOC_NULL( DISM, sout_display_t );
70 p_module->i_type = SOUT_MOD_DISPLAY;
74 sout_transcode_t *streaming_ChainAddTranscode( sout_chain_t *p_chain,
75 char *psz_vcodec, char * psz_acodec, char * psz_scodec,
76 int i_vb, float f_scale, int i_ab, int i_channels,
77 vlc_bool_t b_soverlay, char *psz_additional )
79 DECMALLOC_NULL( p_module, sout_module_t );
80 MALLOC_NULL( TRAM, sout_transcode_t );
81 p_module->i_type = SOUT_MOD_TRANSCODE;
83 assert( !( b_soverlay && psz_scodec ) );
84 if( psz_vcodec ) TRAM->psz_vcodec = strdup( psz_vcodec );
85 if( psz_acodec ) TRAM->psz_acodec = strdup( psz_acodec );
86 if( psz_scodec ) TRAM->psz_scodec = strdup( psz_scodec );
87 TRAM->i_vb = i_vb; TRAM->i_ab = i_ab; TRAM->f_scale = f_scale;
88 TRAM->i_channels = i_channels; TRAM->b_soverlay = b_soverlay;
89 if( TRAM->psz_additional ) TRAM->psz_additional = strdup( psz_additional );
93 void streaming_DupAddChild( sout_duplicate_t *p_dup )
97 sout_chain_t * p_child = streaming_ChainNew();
98 INSERT_ELEM( p_dup->pp_children, p_dup->i_children,
99 p_dup->i_children, p_child );
103 #define DUP_OR_CHAIN p_dup ? p_dup->pp_children[p_dup->i_children-1] : p_chain
105 #define ADD_OPT( format, args... ) { \
106 char *psz_opt; asprintf( &psz_opt, format, ##args ); \
107 INSERT_ELEM( p_chain->ppsz_options, p_chain->i_options, p_chain->i_options,\
111 void streaming_ChainClean( sout_chain_t *p_chain )
114 sout_module_t *p_module;
115 if( p_chain->i_modules )
117 for( i = p_chain->i_modules -1; i >= 0 ; i-- )
119 p_module = p_chain->pp_modules[i];
120 switch( p_module->i_type )
122 case SOUT_MOD_DUPLICATE:
123 if( DUPM->i_children == 0 ) break;
124 for( j = DUPM->i_children - 1 ; j >= 0; j-- )
126 streaming_ChainClean( DUPM->pp_children[j] );
130 FREENULL( STDM->psz_url );
131 FREENULL( STDM->psz_name );
132 FREENULL( STDM->psz_group );
134 case SOUT_MOD_TRANSCODE:
135 FREENULL( TRAM->psz_vcodec );
136 FREENULL( TRAM->psz_acodec );
137 FREENULL( TRAM->psz_scodec );
138 FREENULL( TRAM->psz_venc );
139 FREENULL( TRAM->psz_aenc );
140 FREENULL( TRAM->psz_additional );
143 REMOVE_ELEM( p_chain->pp_modules, p_chain->i_modules, i );
149 /**********************************************************************
150 * Interaction with streaming GUI descriptors
151 **********************************************************************/
152 #define DO_ENABLE_ACCESS \
153 if( !strcmp( STDM->psz_access, "file" ) )\
155 pd->b_file = VLC_TRUE; pd->psz_file = strdup( STDM->psz_url ); \
157 else if( !strcmp( STDM->psz_access, "http" ) )\
159 pd->b_http = VLC_TRUE; pd->psz_http = strdup( STDM->psz_url ); \
161 else if( !strcmp( STDM->psz_access, "mms" ) )\
163 pd->b_mms = VLC_TRUE; pd->psz_mms = strdup( STDM->psz_url ); \
165 else if( !strcmp( STDM->psz_access, "udp" ) )\
167 pd->b_udp = VLC_TRUE; pd->psz_udp = strdup( STDM->psz_url ); \
171 msg_Err( p_this, "unahandled access %s", STDM->psz_access ); \
176 * Try to convert a chain to a gui descriptor. This is only possible for
178 * \param p_this vlc object
179 * \param p_chain the source streaming chain
180 * \param pd the destination gui descriptor object
181 * \return TRUE if the conversion succeeded, false else
183 vlc_bool_t streaming_ChainToGuiDesc( vlc_object_t *p_this,
184 sout_chain_t *p_chain, sout_gui_descr_t *pd )
187 sout_module_t *p_module;
188 if( p_chain->i_modules == 0 || p_chain->i_modules > 2 ) return VLC_FALSE;
190 if( p_chain->pp_modules[0]->i_type == SOUT_MOD_TRANSCODE )
192 if( p_chain->i_modules == 1 ) return VLC_FALSE;
193 p_module = p_chain->pp_modules[0];
196 pd->b_soverlay = TRAM->b_soverlay;
197 pd->i_vb = TRAM->i_vb; pd->i_ab = TRAM->i_ab;
198 pd->i_channels = TRAM->i_channels; pd->f_scale = TRAM->f_scale;
199 if( TRAM->psz_vcodec ) pd->psz_vcodec = strdup( TRAM->psz_vcodec );
200 if( TRAM->psz_acodec ) pd->psz_acodec = strdup( TRAM->psz_acodec );
201 if( TRAM->psz_scodec ) pd->psz_scodec = strdup( TRAM->psz_scodec );
203 if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_DUPLICATE )
205 p_module = p_chain->pp_modules[i_last];
207 // Nothing allowed after duplicate. Duplicate mustn't be empty
208 if( p_chain->i_modules > i_last +1 || !DUPM->i_children )
210 for( j = 0 ; j< DUPM->i_children ; j++ )
212 sout_chain_t *p_child = DUPM->pp_children[j];
213 if( p_child->i_modules != 1 ) return VLC_FALSE;
214 p_module = p_child->pp_modules[0];
215 if( p_module->i_type == SOUT_MOD_STD )
219 else if( p_module->i_type == SOUT_MOD_DISPLAY )
220 pd->b_local = VLC_TRUE;
221 else if( p_module->i_type == SOUT_MOD_RTP )
223 msg_Err( p_this, "RTP unhandled" );
229 if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_STD )
231 p_module = p_chain->pp_modules[i_last];
234 else if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_DISPLAY )
236 pd->b_local = VLC_TRUE;
238 else if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_RTP )
240 msg_Err( p_this, "RTP unhandled" );
248 #define HANDLE_GUI_URL( type, access ) if( pd->b_##type ) { \
249 streaming_DupAddChild( p_dup ); \
250 if( pd->i_##type > 0 ) \
253 asprintf( &psz_url, "%s:%i", pd->psz_##type, pd->i_##type ); \
254 streaming_ChainAddStd( DUP_OR_CHAIN, access, pd->psz_mux,\
260 streaming_ChainAddStd( DUP_OR_CHAIN, access, pd->psz_mux,\
265 void streaming_GuiDescToChain( vlc_object_t *p_obj, sout_chain_t *p_chain,
266 sout_gui_descr_t *pd )
268 sout_duplicate_t *p_dup = NULL;
269 /* Clean up the chain */
270 streaming_ChainClean( p_chain );
273 if( pd->psz_vcodec || pd->psz_acodec || pd->psz_scodec || pd->b_soverlay )
275 streaming_ChainAddTranscode( p_chain, pd->psz_vcodec, pd->psz_acodec,
276 pd->psz_scodec, pd->i_vb, pd->f_scale,
277 pd->i_ab, pd->i_channels,
278 pd->b_soverlay, NULL );
281 if( pd->b_local + pd->b_file + pd->b_http + pd->b_mms + pd->b_rtp +
284 p_dup = streaming_ChainAddDup( p_chain );
288 streaming_DupAddChild( p_dup );
289 streaming_ChainAddDisplay( DUP_OR_CHAIN );
293 streaming_DupAddChild( p_dup );
294 streaming_ChainAddStd( DUP_OR_CHAIN, "file", pd->psz_mux,
300 streaming_DupAddChild( p_dup );
304 asprintf( &psz_url, "%s:%i", pd->psz_udp, pd->i_udp );
305 p_std = streaming_ChainAddStd( DUP_OR_CHAIN, "udp",
306 pd->psz_mux, psz_url );
311 p_std = streaming_ChainAddStd( DUP_OR_CHAIN, "udp",
312 pd->psz_mux, pd->psz_udp );
314 if( pd->i_ttl ) ADD_OPT( "ttl=%i", pd->i_ttl );
317 pd->b_sap = VLC_TRUE;
318 p_std->psz_name = strdup( pd->psz_name );
319 p_std->psz_group = pd->psz_group ? strdup( pd->psz_group ) : NULL;
322 HANDLE_GUI_URL( http, "http" )
323 HANDLE_GUI_URL( mms, "mms" )
325 #undef HANDLE_GUI_URL
327 /**********************************************************************
328 * Create a sout string from a chain
329 **********************************************************************/
330 char * streaming_ChainToPsz( sout_chain_t *p_chain )
333 char psz_output[MAX_CHAIN];
334 char psz_temp[MAX_CHAIN];
335 sprintf( psz_output, "#" );
336 for( i = 0 ; i< p_chain->i_modules; i++ )
338 sout_module_t *p_module = p_chain->pp_modules[i];
339 switch( p_module->i_type )
341 case SOUT_MOD_TRANSCODE:
342 CHAIN_APPEND( "transcode{" );
343 if( TRAM->psz_vcodec )
345 CHAIN_APPEND( "vcodec=%s,vb=%i,scale=%f", TRAM->psz_vcodec,
346 TRAM->i_vb, TRAM->f_scale );
347 if( TRAM->psz_acodec || TRAM->psz_scodec || TRAM->b_soverlay )
350 if( TRAM->psz_acodec )
352 CHAIN_APPEND( "acodec=%s,ab=%i,channels=%i", TRAM->psz_acodec,
353 TRAM->i_ab, TRAM->i_channels );
354 if( TRAM->psz_scodec || TRAM->b_soverlay )
357 assert( !(TRAM->psz_scodec && TRAM->b_soverlay) );
358 if( TRAM->psz_scodec )
359 CHAIN_APPEND( "scodec=%s", TRAM->psz_scodec) ;
360 if( TRAM->b_soverlay )
361 CHAIN_APPEND( "soverlay" );
365 case SOUT_MOD_DISPLAY:
366 CHAIN_APPEND( "display" )
369 CHAIN_APPEND( "std{access=%s,url=%s,mux=%s}", STDM->psz_access,
370 STDM->psz_url, STDM->psz_mux );
373 return strdup( psz_output );
376 /**********************************************************************
377 * Handle streaming profiles
378 **********************************************************************/
381 * List the available profiles. Fills the pp_profiles list with preinitialized
382 * values. Only metadata is decoded
383 * \param p_this vlc object
384 * \param pi_profiles number of listed profiles
385 * \param pp_profiles array of profiles
387 void streaming_ProfilesList( vlc_object_t *p_this, int *pi_profiles,
388 streaming_profile_t **pp_profiles )
393 /** Parse a profile */
394 int streaming_ProfileParse( vlc_object_t *p_this,streaming_profile_t *p_profile,
395 const char *psz_profile )
398 DECMALLOC_ERR( p_parser, profile_parser_t );
399 assert( p_profile ); assert( psz_profile );
401 p_parser->psz_profile = strdup( psz_profile );
402 p_parser->p_profile = p_profile;
404 p_this->p_private = (void *)p_parser;
406 /* And call the module ! All work is done now */
407 p_module = module_Need( p_this, "profile parser", "", VLC_TRUE );
410 msg_Warn( p_this, "parsing profile failed" );