]> git.sesse.net Git - vlc/blob - src/stream_output/profiles.c
18c6a11963863fc038e46215a2caeabceb70f6e9
[vlc] / src / stream_output / profiles.c
1 /*****************************************************************************
2  * profiles.c: Streaming profiles
3  *****************************************************************************
4  * Copyright (C) 2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #include <vlc_streaming.h>
25 #include <assert.h>
26
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 ); }
31
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
36
37 /**********************************************************************
38  * General chain manipulation
39  **********************************************************************/
40 sout_duplicate_t *streaming_ChainAddDup( sout_chain_t *p_chain )
41 {
42     DECMALLOC_NULL( p_module, sout_module_t );
43     MALLOC_NULL( DUPM, sout_duplicate_t );
44     p_module->i_type = SOUT_MOD_DUPLICATE;
45     DUPM->i_children = 0;
46     DUPM->pp_children = NULL;
47     INSERT_ELEM( p_chain->pp_modules, p_chain->i_modules, p_chain->i_modules,
48                  p_module );
49     return p_module->typed.p_duplicate;
50 }
51
52 sout_std_t *streaming_ChainAddStd( sout_chain_t *p_chain, char *psz_access,
53                                    char *psz_mux, char *psz_url )
54 {
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,
62                  p_module );
63     return STDM;
64 }
65
66 sout_display_t *streaming_ChainAddDisplay( sout_chain_t *p_chain )
67 {
68     DECMALLOC_NULL( p_module, sout_module_t );
69     MALLOC_NULL( DISM, sout_display_t );
70     p_module->i_type = SOUT_MOD_DISPLAY;
71     return DISM;
72 }
73
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 )
78 {
79     DECMALLOC_NULL( p_module, sout_module_t );
80     MALLOC_NULL( TRAM, sout_transcode_t );
81     p_module->i_type = SOUT_MOD_TRANSCODE;
82
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 );
90     return TRAM;
91 }
92             
93 void streaming_DupAddChild( sout_duplicate_t *p_dup )
94 {
95     if( p_dup )
96     {
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 );
100     }
101 }
102
103 #define DUP_OR_CHAIN p_dup ? p_dup->pp_children[p_dup->i_children-1] : p_chain
104
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,\
108                  psz_opt );\
109     free( psz_opt ); }
110
111 void streaming_ChainClean( sout_chain_t *p_chain )
112 {
113     int i,j;
114     sout_module_t *p_module;
115     if( p_chain->i_modules )
116     {
117         for( i = p_chain->i_modules -1; i >= 0 ; i-- )
118         {
119             p_module = p_chain->pp_modules[i];
120             switch( p_module->i_type )
121             {
122             case SOUT_MOD_DUPLICATE:
123                 if( DUPM->i_children == 0 ) break;
124                 for( j = DUPM->i_children - 1 ; j >= 0; j-- )
125                 {
126                     streaming_ChainClean( DUPM->pp_children[j] );
127                 }
128                 break;
129             case SOUT_MOD_STD:
130                 FREENULL( STDM->psz_url );
131                 FREENULL( STDM->psz_name );
132                 FREENULL( STDM->psz_group );
133                 break;
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 );
141                 break;
142             }
143             REMOVE_ELEM( p_chain->pp_modules, p_chain->i_modules, i );
144             free( p_module );
145         }
146     }
147 }
148
149 /**********************************************************************
150  * Interaction with streaming GUI descriptors
151  **********************************************************************/
152 #define DO_ENABLE_ACCESS \
153     if( !strcmp( STDM->psz_access, "file" ) )\
154     { \
155         pd->b_file = VLC_TRUE; pd->psz_file = strdup( STDM->psz_url ); \
156     } \
157     else if(  !strcmp( STDM->psz_access, "http" ) )\
158     { \
159         pd->b_http = VLC_TRUE; pd->psz_http = strdup( STDM->psz_url ); \
160     } \
161     else if(  !strcmp( STDM->psz_access, "mms" ) )\
162     { \
163         pd->b_mms = VLC_TRUE; pd->psz_mms = strdup( STDM->psz_url ); \
164     } \
165     else if(  !strcmp( STDM->psz_access, "udp" ) )\
166     { \
167         pd->b_udp = VLC_TRUE; pd->psz_udp = strdup( STDM->psz_url ); \
168     } \
169     else \
170     { \
171         msg_Err( p_this, "unahandled access %s", STDM->psz_access ); \
172     }
173
174
175 /**
176  * Try to convert a chain to a gui descriptor. This is only possible for 
177  * "simple" chains. 
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
182  */
183 vlc_bool_t streaming_ChainToGuiDesc( vlc_object_t *p_this,
184                                   sout_chain_t *p_chain, sout_gui_descr_t *pd )
185 {
186     int j, i_last = 0;
187     sout_module_t *p_module;
188     if( p_chain->i_modules == 0 || p_chain->i_modules > 2 ) return VLC_FALSE;
189
190     if( p_chain->pp_modules[0]->i_type == SOUT_MOD_TRANSCODE )
191     {
192         if( p_chain->i_modules == 1 ) return VLC_FALSE;
193         p_module = p_chain->pp_modules[0];
194         i_last++;
195
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 );
202     }
203     if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_DUPLICATE )
204     {
205         p_module = p_chain->pp_modules[i_last];
206         
207         // Nothing allowed after duplicate. Duplicate mustn't be empty
208         if( p_chain->i_modules > i_last +1 || !DUPM->i_children ) 
209             return VLC_FALSE;
210         for( j = 0 ; j<  DUPM->i_children ; j++ )
211         {
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 )
216             {
217                 DO_ENABLE_ACCESS
218             }
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 )
222             {
223                 msg_Err( p_this, "RTP unhandled" );
224                 return VLC_FALSE;
225             }
226         }
227         i_last++;
228     }
229     if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_STD )
230     {
231         p_module = p_chain->pp_modules[i_last];
232         DO_ENABLE_ACCESS;
233     }
234     else if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_DISPLAY )
235     {
236         pd->b_local = VLC_TRUE;
237     }
238     else if( p_chain->pp_modules[i_last]->i_type == SOUT_MOD_RTP )
239     {
240         msg_Err( p_this, "RTP unhandled" );
241         return VLC_FALSE;
242
243     }
244     return VLC_TRUE;
245
246 }
247
248 #define HANDLE_GUI_URL( type, access ) if( pd->b_##type ) { \
249         streaming_DupAddChild( p_dup ); \
250         if( pd->i_##type > 0 ) \
251         { \
252             char *psz_url; \
253             asprintf( &psz_url, "%s:%i", pd->psz_##type, pd->i_##type ); \
254             streaming_ChainAddStd( DUP_OR_CHAIN, access, pd->psz_mux,\
255                                    psz_url ); \
256             free( psz_url ); \
257         } \
258         else \
259         { \
260             streaming_ChainAddStd( DUP_OR_CHAIN, access, pd->psz_mux,\
261                                    pd->psz_##type );\
262         }\
263     }
264
265 void streaming_GuiDescToChain( vlc_object_t *p_obj, sout_chain_t *p_chain,
266                                sout_gui_descr_t *pd )
267 {
268     sout_duplicate_t *p_dup = NULL;
269     /* Clean up the chain */
270     streaming_ChainClean( p_chain );
271
272     /* Transcode */
273     if( pd->psz_vcodec || pd->psz_acodec || pd->psz_scodec || pd->b_soverlay )
274     {
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 );
279     }
280     /* #std{} */
281     if( pd->b_local + pd->b_file + pd->b_http + pd->b_mms + pd->b_rtp + 
282         pd->b_udp > 1 )
283     {
284         p_dup = streaming_ChainAddDup( p_chain );
285     }
286     if( pd->b_local )
287     {
288         streaming_DupAddChild( p_dup );
289         streaming_ChainAddDisplay(  DUP_OR_CHAIN );
290     }
291     if( pd->b_file )
292     {
293         streaming_DupAddChild( p_dup );
294         streaming_ChainAddStd( DUP_OR_CHAIN, "file", pd->psz_mux,
295                                pd->psz_file );
296     }
297     if( pd->b_udp )
298     {
299         sout_std_t *p_std;
300         streaming_DupAddChild( p_dup );
301         if( pd->i_udp > 0 )
302         {
303             char *psz_url;
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 );
307             free( psz_url );
308         }
309         else
310         {
311             p_std = streaming_ChainAddStd( DUP_OR_CHAIN, "udp",
312                                            pd->psz_mux, pd->psz_udp );
313         }
314         if( pd->i_ttl ) ADD_OPT( "ttl=%i", pd->i_ttl );
315         if( pd->b_sap )
316         {
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;
320         }
321     }
322     HANDLE_GUI_URL( http, "http" )
323     HANDLE_GUI_URL( mms, "mms" )
324 }
325 #undef HANDLE_GUI_URL
326
327 /**********************************************************************
328  * Create a sout string from a chain
329  **********************************************************************/
330 char * streaming_ChainToPsz( sout_chain_t *p_chain )
331 {
332     int i;
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++ )
337     {
338         sout_module_t *p_module = p_chain->pp_modules[i];
339         switch( p_module->i_type )
340         {
341         case SOUT_MOD_TRANSCODE:
342             CHAIN_APPEND( "transcode{" );
343             if( TRAM->psz_vcodec )
344             {
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 )
348                     CHAIN_APPEND( "," );
349             }
350             if( TRAM->psz_acodec )
351             {
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 )
355                     CHAIN_APPEND( "," );
356             }
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" );
362             CHAIN_APPEND( "}" );
363             break;
364
365         case SOUT_MOD_DISPLAY:
366             CHAIN_APPEND( "display" )
367             break;
368         case SOUT_MOD_STD:
369             CHAIN_APPEND( "std{access=%s,url=%s,mux=%s}", STDM->psz_access,
370                           STDM->psz_url, STDM->psz_mux );
371         }
372     }
373     return strdup( psz_output );
374 }
375
376 /**********************************************************************
377  * Handle streaming profiles
378  **********************************************************************/
379
380 /**
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
386  */
387 void streaming_ProfilesList( vlc_object_t *p_this, int *pi_profiles, 
388                              streaming_profile_t **pp_profiles )
389 {
390 }
391
392
393 /** Parse a profile */
394 int streaming_ProfileParse( vlc_object_t *p_this,streaming_profile_t *p_profile,
395                             const char *psz_profile )
396 {
397     module_t *p_module;
398     DECMALLOC_ERR( p_parser, profile_parser_t );
399     assert( p_profile ); assert( psz_profile );
400
401     p_parser->psz_profile = strdup( psz_profile );
402     p_parser->p_profile = p_profile;
403
404     p_this->p_private = (void *)p_parser;
405
406     /* And call the module ! All work is done now */
407     p_module = module_Need( p_this, "profile parser", "", VLC_TRUE );
408     if( !p_module )
409     {
410         msg_Warn( p_this, "parsing profile failed" );
411     }
412 }