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