dd4b0381bc3c5b61b0e4bed4d75c5074700c11a7
[vlc.git] / modules / stream_out / es.c
1 /*****************************************************************************
2  * es.c: Elementary stream output module
3  *****************************************************************************
4  * Copyright (C) 2003-2004 VLC authors and VideoLAN
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_sout.h>
34 #include <vlc_dialog.h>
35 #include <vlc_memstream.h>
36
37 typedef struct
38 {
39     int  i_count_audio;
40     int  i_count_video;
41     int  i_count;
42     unsigned int count_sync;
43
44     char *psz_mux;
45     char *psz_mux_audio;
46     char *psz_mux_video;
47
48     char *psz_access;
49     char *psz_access_audio;
50     char *psz_access_video;
51
52     char *psz_dst;
53     char *psz_dst_audio;
54     char *psz_dst_video;
55 } sout_stream_sys_t;
56
57 typedef struct
58 {
59     sout_input_t *p_input;
60     sout_mux_t   *p_mux;
61     bool synchronous;
62 } sout_stream_id_sys_t;
63
64 static char * es_print_url( const char *psz_fmt, vlc_fourcc_t i_fourcc, int i_count,
65                             const char *psz_access, const char *psz_mux )
66 {
67     struct vlc_memstream stream;
68     unsigned char c;
69
70     if (vlc_memstream_open(&stream))
71         return NULL;
72
73     if( psz_fmt == NULL || !*psz_fmt )
74         psz_fmt = "stream-%n-%c.%m";
75
76     while ((c = *(psz_fmt++)) != '\0')
77     {
78         if (c != '%')
79         {
80             vlc_memstream_putc(&stream, c);
81             continue;
82         }
83
84         switch (c = *(psz_fmt++))
85         {
86             case 'n':
87                 vlc_memstream_printf(&stream, "%d", i_count);
88                 break;
89             case 'c':
90                 vlc_memstream_printf(&stream, "%4.4s", (char *)&i_fourcc);
91                 break;
92             case 'm':
93                 vlc_memstream_puts(&stream, psz_mux);
94                 break;
95             case 'a':
96                 vlc_memstream_puts(&stream, psz_access);
97                 break;
98             case '\0':
99                 vlc_memstream_putc(&stream, '%');
100                 goto out;
101             default:
102                 vlc_memstream_printf(&stream, "%%%c", (int) c);
103                 break;
104         }
105     }
106 out:
107     if (vlc_memstream_close(&stream))
108         return NULL;
109     return stream.ptr;
110 }
111
112 static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
113 {
114     sout_stream_sys_t *p_sys = p_stream->p_sys;
115
116     const char        *psz_access;
117     const char        *psz_mux;
118     char              *psz_dst;
119
120     sout_access_out_t *p_access;
121
122     /* *** get access name *** */
123     if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_access_audio && *p_sys->psz_access_audio )
124     {
125         psz_access = p_sys->psz_access_audio;
126     }
127     else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_access_video && *p_sys->psz_access_video )
128     {
129         psz_access = p_sys->psz_access_video;
130     }
131     else
132     {
133         psz_access = p_sys->psz_access;
134     }
135
136     /* *** get mux name *** */
137     if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_mux_audio && *p_sys->psz_mux_audio )
138     {
139         psz_mux = p_sys->psz_mux_audio;
140     }
141     else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_mux_video && *p_sys->psz_mux_video )
142     {
143         psz_mux = p_sys->psz_mux_video;
144     }
145     else
146     {
147         psz_mux = p_sys->psz_mux;
148     }
149
150     /* Get url (%d expanded as a codec count, %c expanded as codec fcc ) */
151     if( p_fmt->i_cat == AUDIO_ES && p_sys->psz_dst_audio && *p_sys->psz_dst_audio )
152     {
153         psz_dst = es_print_url( p_sys->psz_dst_audio, p_fmt->i_codec,
154                                 p_sys->i_count_audio, psz_access, psz_mux );
155     }
156     else if( p_fmt->i_cat == VIDEO_ES && p_sys->psz_dst_video && *p_sys->psz_dst_video )
157     {
158         psz_dst = es_print_url( p_sys->psz_dst_video, p_fmt->i_codec,
159                                 p_sys->i_count_video, psz_access, psz_mux );
160     }
161     else
162     {
163         int i_count;
164         if( p_fmt->i_cat == VIDEO_ES )
165         {
166             i_count = p_sys->i_count_video;
167         }
168         else if( p_fmt->i_cat == AUDIO_ES )
169         {
170             i_count = p_sys->i_count_audio;
171         }
172         else
173         {
174             i_count = p_sys->i_count;
175         }
176
177         psz_dst = es_print_url( p_sys->psz_dst, p_fmt->i_codec,
178                                 i_count, psz_access, psz_mux );
179     }
180
181     p_sys->i_count++;
182     if( p_fmt->i_cat == VIDEO_ES )
183     {
184         p_sys->i_count_video++;
185     }
186     else if( p_fmt->i_cat == AUDIO_ES )
187     {
188         p_sys->i_count_audio++;
189     }
190     msg_Dbg( p_stream, "creating `%s/%s://%s'",
191              psz_access, psz_mux, psz_dst );
192
193     /* *** find and open appropriate access module *** */
194     p_access = sout_AccessOutNew( p_stream, psz_access, psz_dst );
195     if( p_access == NULL )
196     {
197         msg_Err( p_stream, "no suitable sout access module for `%s/%s://%s'",
198                  psz_access, psz_mux, psz_dst );
199         vlc_dialog_display_error( p_stream, _("Streaming / Transcoding failed"),
200             _("There is no suitable stream-output access module for \"%s/%s://%s\"."),
201             psz_access, psz_mux, psz_dst );
202         free( psz_dst );
203         return( NULL );
204     }
205
206     sout_stream_id_sys_t *id = malloc(sizeof (*id));
207     if (unlikely(id == NULL))
208     {
209         sout_AccessOutDelete(p_access);
210         free(psz_dst);
211         return NULL;
212     }
213
214     id->synchronous = !sout_AccessOutCanControlPace(p_access);
215
216     /* *** find and open appropriate mux module *** */
217     id->p_mux = sout_MuxNew( p_access, psz_mux );
218     if (id->p_mux == NULL)
219     {
220         msg_Err( p_stream, "no suitable sout mux module for `%s/%s://%s'",
221                  psz_access, psz_mux, psz_dst );
222         vlc_dialog_display_error( p_stream, _("Streaming / Transcoding failed"),
223             _("There is no suitable stream-output access module "\
224             "for \"%s/%s://%s\"."), psz_access, psz_mux, psz_dst );
225         sout_AccessOutDelete( p_access );
226         free( psz_dst );
227         return( NULL );
228     }
229     free( psz_dst );
230
231     id->p_input = sout_MuxAddStream(id->p_mux, p_fmt);
232
233     if( id->p_input == NULL )
234     {
235         sout_MuxDelete(id->p_mux);
236         sout_AccessOutDelete( p_access );
237         free( id );
238         return NULL;
239     }
240
241     p_sys->count_sync += id->synchronous;
242     return id;
243 }
244
245 static void Del( sout_stream_t *p_stream, void *_id )
246 {
247     sout_stream_sys_t *sys = p_stream->p_sys;
248     sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
249     sout_access_out_t *p_access = id->p_mux->p_access;
250
251     sout_MuxDeleteStream( id->p_mux, id->p_input );
252     sout_MuxDelete( id->p_mux );
253     sout_AccessOutDelete( p_access );
254
255     sys->count_sync -= id->synchronous;
256     free( id );
257 }
258
259 static int Send( sout_stream_t *p_stream, void *_id, block_t *p_buffer )
260 {
261     VLC_UNUSED(p_stream);
262     sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
263     return sout_MuxSendBuffer( id->p_mux, id->p_input, p_buffer );
264 }
265
266 static const struct sout_stream_operations ops = {
267     Add, Del, Send, NULL, NULL,
268 };
269
270 #define SOUT_CFG_PREFIX "sout-es-"
271
272 static const char *const ppsz_sout_options[] = {
273     "access", "access-audio", "access-video",
274     "mux", "mux-audio", "mux-video",
275     "dst", "dst-audio", "dst-video",
276     NULL
277 };
278
279 /*****************************************************************************
280  * Open:
281  *****************************************************************************/
282 static int Open( vlc_object_t *p_this )
283 {
284     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
285     sout_stream_sys_t *p_sys = vlc_obj_malloc(p_this, sizeof (*p_sys));
286
287     if (unlikely(p_sys == NULL))
288         return VLC_ENOMEM;
289
290     config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options, p_stream->p_cfg );
291
292     p_sys->i_count          = 0;
293     p_sys->i_count_audio    = 0;
294     p_sys->i_count_video    = 0;
295
296     p_sys->psz_access = var_GetString( p_stream, SOUT_CFG_PREFIX "access" );
297     p_sys->psz_access_audio = var_GetString( p_stream, SOUT_CFG_PREFIX "access-audio" );
298     p_sys->psz_access_video = var_GetString( p_stream, SOUT_CFG_PREFIX "access-video" );
299
300     p_sys->psz_mux = var_GetString( p_stream, SOUT_CFG_PREFIX "mux" );
301     p_sys->psz_mux_audio = var_GetString( p_stream, SOUT_CFG_PREFIX "mux-audio" );
302     p_sys->psz_mux_video = var_GetString( p_stream, SOUT_CFG_PREFIX "mux-video" );
303
304     p_sys->psz_dst       = var_GetString( p_stream, SOUT_CFG_PREFIX "dst" );
305     p_sys->psz_dst_audio = var_GetString( p_stream, SOUT_CFG_PREFIX "dst-audio" );
306     p_sys->psz_dst_video = var_GetString( p_stream, SOUT_CFG_PREFIX "dst-video" );
307
308     p_stream->ops = &ops;
309     p_stream->p_sys = p_sys;
310
311     return VLC_SUCCESS;
312 }
313
314 /*****************************************************************************
315  * Close:
316  *****************************************************************************/
317
318 static void Close( vlc_object_t * p_this )
319 {
320     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
321     sout_stream_sys_t *p_sys = p_stream->p_sys;
322
323     free( p_sys->psz_access );
324     free( p_sys->psz_access_audio );
325     free( p_sys->psz_access_video );
326
327     free( p_sys->psz_mux );
328     free( p_sys->psz_mux_audio );
329     free( p_sys->psz_mux_video );
330
331     free( p_sys->psz_dst );
332     free( p_sys->psz_dst_audio );
333     free( p_sys->psz_dst_video );
334 }
335
336 /*****************************************************************************
337  * Module descriptor
338  *****************************************************************************/
339 #define ACCESS_TEXT N_("Output access method")
340 #define ACCESS_LONGTEXT N_( \
341     "This is the default output access method that will be used." )
342
343 #define ACCESSA_TEXT N_("Audio output access method")
344 #define ACCESSA_LONGTEXT N_( \
345     "This is the output access method that will be used for audio." )
346 #define ACCESSV_TEXT N_("Video output access method")
347 #define ACCESSV_LONGTEXT N_( \
348     "This is the output access method that will be used for video." )
349
350 #define MUX_TEXT N_("Output muxer")
351 #define MUX_LONGTEXT N_( \
352     "This is the default muxer method that will be used." )
353 #define MUXA_TEXT N_("Audio output muxer")
354 #define MUXA_LONGTEXT N_( \
355     "This is the muxer that will be used for audio." )
356 #define MUXV_TEXT N_("Video output muxer")
357 #define MUXV_LONGTEXT N_( \
358     "This is the muxer that will be used for video." )
359
360 #define DEST_TEXT N_("Output URL")
361 #define DEST_LONGTEXT N_( \
362     "This is the default output URI." )
363 #define DESTA_TEXT N_("Audio output URL")
364 #define DESTA_LONGTEXT N_( \
365     "This is the output URI that will be used for audio." )
366 #define DESTV_TEXT N_("Video output URL")
367 #define DESTV_LONGTEXT N_( \
368     "This is the output URI that will be used for video." )
369
370 vlc_module_begin()
371     set_shortname("ES")
372     set_description(N_("Elementary stream output"))
373     set_capability("sout output", 50)
374     add_shortcut("es")
375     set_category(CAT_SOUT)
376     set_subcategory(SUBCAT_SOUT_STREAM)
377
378     set_section(N_("Generic"), NULL)
379     add_string(SOUT_CFG_PREFIX "access", "",
380                ACCESS_TEXT, ACCESS_LONGTEXT, true)
381     add_string(SOUT_CFG_PREFIX "mux", "", MUX_TEXT, MUX_LONGTEXT, true)
382     add_string(SOUT_CFG_PREFIX "dst", "", DEST_TEXT, DEST_LONGTEXT, true )
383
384     set_section(N_("Audio"), NULL)
385     add_string(SOUT_CFG_PREFIX "access-audio", "",
386                ACCESSA_TEXT, ACCESSA_LONGTEXT, true )
387     add_string(SOUT_CFG_PREFIX "mux-audio", "", MUXA_TEXT, MUXA_LONGTEXT, true)
388     add_string(SOUT_CFG_PREFIX "dst-audio", "",
389                DESTA_TEXT, DESTA_LONGTEXT, true)
390
391     set_section(N_("Video"), NULL)
392     add_string(SOUT_CFG_PREFIX "access-video", "", ACCESSV_TEXT,
393                ACCESSV_LONGTEXT, true)
394     add_string(SOUT_CFG_PREFIX "mux-video", "", MUXV_TEXT,
395                MUXV_LONGTEXT, true)
396     add_string(SOUT_CFG_PREFIX "dst-video", "", DESTV_TEXT,
397                DESTV_LONGTEXT, true)
398
399     set_callbacks(Open, Close)
400 vlc_module_end()