* modules/stream_out/*: coding style changes + strings review.
[vlc.git] / modules / stream_out / es.c
1 /*****************************************************************************
2  * es.c: Elementary stream output module
3  *****************************************************************************
4  * Copyright (C) 2003-2004 VideoLAN
5  * $Id: es.c,v 1.5 2004/01/25 14:34:25 gbazin Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/sout.h>
33
34 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
35 /*****************************************************************************
36  * Exported prototypes
37  *****************************************************************************/
38 static int      Open    ( vlc_object_t * );
39 static void     Close   ( vlc_object_t * );
40
41 static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
42 static int               Del ( sout_stream_t *, sout_stream_id_t * );
43 static int               Send( sout_stream_t *, sout_stream_id_t *, sout_buffer_t* );
44
45 /*****************************************************************************
46  * Module descriptor
47  *****************************************************************************/
48 vlc_module_begin();
49     set_description( _("Elementary stream output") );
50     set_capability( "sout stream", 50 );
51     add_shortcut( "es" );
52     set_callbacks( Open, Close );
53 vlc_module_end();
54
55 struct sout_stream_sys_t
56 {
57     int  i_count_audio;
58     int  i_count_video;
59     int  i_count;
60
61     char *psz_mux;
62     char *psz_mux_audio;
63     char *psz_mux_video;
64
65     char *psz_access;
66     char *psz_access_audio;
67     char *psz_access_video;
68
69     char *psz_url;
70     char *psz_url_audio;
71     char *psz_url_video;
72 };
73
74 /*****************************************************************************
75  * Open:
76  *****************************************************************************/
77 static int Open( vlc_object_t *p_this )
78 {
79     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
80     sout_stream_sys_t   *p_sys;
81
82     /* p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader ); */
83
84     p_sys                   = malloc( sizeof( sout_stream_sys_t ) );
85
86     p_sys->i_count          = 0;
87     p_sys->i_count_audio    = 0;
88     p_sys->i_count_video    = 0;
89
90     p_sys->psz_access       = sout_cfg_find_value( p_stream->p_cfg, "access" );
91     p_sys->psz_access_audio = sout_cfg_find_value( p_stream->p_cfg, "access_audio" );
92     p_sys->psz_access_video = sout_cfg_find_value( p_stream->p_cfg, "access_video" );
93
94     p_sys->psz_mux       = sout_cfg_find_value( p_stream->p_cfg, "mux" );
95     p_sys->psz_mux_audio = sout_cfg_find_value( p_stream->p_cfg, "mux_audio" );
96     p_sys->psz_mux_video = sout_cfg_find_value( p_stream->p_cfg, "mux_video" );
97
98     p_sys->psz_url       = sout_cfg_find_value( p_stream->p_cfg, "url" );
99     p_sys->psz_url_audio = sout_cfg_find_value( p_stream->p_cfg, "url_audio" );
100     p_sys->psz_url_video = sout_cfg_find_value( p_stream->p_cfg, "url_video" );
101
102     p_stream->pf_add    = Add;
103     p_stream->pf_del    = Del;
104     p_stream->pf_send   = Send;
105
106     p_stream->p_sys     = p_sys;
107
108     return VLC_SUCCESS;
109 }
110
111 /*****************************************************************************
112  * Close:
113  *****************************************************************************/
114
115 static void Close( vlc_object_t * p_this )
116 {
117     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
118     sout_stream_sys_t *p_sys = p_stream->p_sys;
119
120     free( p_sys );
121 }
122
123 struct sout_stream_id_t
124 {
125     sout_input_t *p_input;
126     sout_mux_t   *p_mux;
127 };
128
129 static char * es_print_url( char *psz_fmt, vlc_fourcc_t i_fourcc, int i_count,
130                             char *psz_access, char *psz_mux )
131 {
132     char *psz_url, *p;
133
134     if( psz_fmt == NULL || !*psz_fmt )
135     {
136         psz_fmt = "stream-%n-%c.%m";
137     }
138
139     p = psz_url = malloc( 4096 );
140     memset( p, 0, 4096 );
141     for( ;; )
142     {
143         if( *psz_fmt == '\0' )
144         {
145             *p = '\0';
146             break;
147         }
148
149         if( *psz_fmt != '%' )
150         {
151             *p++ = *psz_fmt++;
152         }
153         else
154         {
155             if( psz_fmt[1] == 'n' )
156             {
157                 p += sprintf( p, "%d", i_count );
158             }
159             else if( psz_fmt[1] == 'c' )
160             {
161                 p += sprintf( p, "%4.4s", (char*)&i_fourcc );
162             }
163             else if( psz_fmt[1] == 'm' )
164             {
165                 p += sprintf( p, "%s", psz_mux );
166             }
167             else if( psz_fmt[1] == 'a' )
168             {
169                 p += sprintf( p, "%s", psz_access );
170             }
171             else if( psz_fmt[1] != '\0' )
172             {
173                 p += sprintf( p, "%c%c", psz_fmt[0], psz_fmt[1] );
174             }
175             else
176             {
177                 p += sprintf( p, "%c", psz_fmt[0] );
178                 *p++ = '\0';
179                 break;
180             }
181             psz_fmt += 2;
182         }
183     }
184
185     return( psz_url );
186 }
187
188 static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
189 {
190     sout_stream_sys_t *p_sys = p_stream->p_sys;
191     sout_instance_t   *p_sout = p_stream->p_sout;
192     sout_stream_id_t  *id;
193
194     char              *psz_access;
195     char              *psz_mux;
196     char              *psz_url;
197
198     sout_access_out_t *p_access;
199     sout_mux_t        *p_mux;
200
201     /* *** get access name *** */
202     if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_access_audio )
203     {
204         psz_access = p_sys->psz_access_audio;
205     }
206     else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_access_video )
207     {
208         psz_access = p_sys->psz_access_video;
209     }
210     else
211     {
212         psz_access = p_sys->psz_access;
213     }
214
215     /* *** get mux name *** */
216     if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_mux_audio )
217     {
218         psz_mux = p_sys->psz_mux_audio;
219     }
220     else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_mux_video )
221     {
222         psz_mux = p_sys->psz_mux_video;
223     }
224     else
225     {
226         psz_mux = p_sys->psz_mux;
227     }
228
229     /* Get url (%d expanded as a codec count, %c expanded as codec fcc ) */
230     if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_url_audio )
231     {
232         psz_url = es_print_url( p_sys->psz_url_audio, p_fmt->i_codec,
233                                 p_sys->i_count_audio, psz_access, psz_mux );
234     }
235     else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_url_video )
236     {
237         psz_url = es_print_url( p_sys->psz_url_video, p_fmt->i_codec,
238                                 p_sys->i_count_video, psz_access, psz_mux );
239     }
240     else
241     {
242         int i_count;
243         if( p_fmt->i_cat == VIDEO_ES )
244         {
245             i_count = p_sys->i_count_video;
246         }
247         else if( p_fmt->i_cat == AUDIO_ES )
248         {
249             i_count = p_sys->i_count_audio;
250         }
251         else
252         {
253             i_count = p_sys->i_count;
254         }
255
256         psz_url = es_print_url( p_sys->psz_url, p_fmt->i_codec,
257                                 i_count, psz_access, psz_mux );
258     }
259
260     p_sys->i_count++;
261     if( p_fmt->i_cat == VIDEO_ES )
262     {
263         p_sys->i_count_video++;
264     }
265     else if( p_fmt->i_cat == AUDIO_ES )
266     {
267         p_sys->i_count_audio++;
268     }
269     msg_Dbg( p_stream, "creating `%s/%s://%s'",
270              psz_access, psz_mux, psz_url );
271
272     /* *** find and open appropriate access module *** */
273     p_access = sout_AccessOutNew( p_sout, psz_access, psz_url );
274     if( p_access == NULL )
275     {
276         msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'",
277                  psz_access, psz_mux, psz_url );
278         return( NULL );
279     }
280
281     /* *** find and open appropriate mux module *** */
282     p_mux = sout_MuxNew( p_sout, psz_mux, p_access );
283     if( p_mux == NULL )
284     {
285         msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'",
286                  psz_access, psz_mux, psz_url );
287         sout_AccessOutDelete( p_access );
288         return( NULL );
289     }
290
291     /* XXX beurk */
292     p_sout->i_preheader = __MAX( p_sout->i_preheader, p_mux->i_preheader );
293
294     id = malloc( sizeof( sout_stream_id_t ) );
295     id->p_mux = p_mux;
296     id->p_input = sout_MuxAddStream( p_mux, p_fmt );
297
298     if( id->p_input == NULL )
299     {
300         free( id );
301
302         sout_MuxDelete( p_mux );
303         sout_AccessOutDelete( p_access );
304         free( id );
305         return NULL;
306     }
307
308     return id;
309 }
310
311 static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
312 {
313     sout_access_out_t *p_access = id->p_mux->p_access;
314
315     sout_MuxDeleteStream( id->p_mux, id->p_input );
316     sout_AccessOutDelete( p_access );
317
318     free( id );
319     return VLC_SUCCESS;
320 }
321
322 static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
323                  sout_buffer_t *p_buffer )
324 {
325     sout_MuxSendBuffer( id->p_mux, id->p_input, p_buffer );
326
327     return VLC_SUCCESS;
328 }
329