filter_chain: introduce dedicated filter_chain_NewVideo() for video filters
[vlc.git] / modules / stream_out / transcode / transcode.c
1 /*****************************************************************************
2  * transcode.c: transcoding stream output module
3  *****************************************************************************
4  * Copyright (C) 2003-2009 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
10  *          Antoine Cellerier <dionoea at videolan dot org>
11  *          Ilkka Ollakka <ileoo at videolan dot org>
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU Lesser General Public License as published by
15  * the Free Software Foundation; either version 2.1 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37
38 #include <vlc_spu.h>
39
40 #include "transcode.h"
41
42 /*****************************************************************************
43  * Module descriptor
44  *****************************************************************************/
45 #define VENC_TEXT N_("Video encoder")
46 #define VENC_LONGTEXT N_( \
47     "This is the video encoder module that will be used (and its associated "\
48     "options).")
49 #define VCODEC_TEXT N_("Destination video codec")
50 #define VCODEC_LONGTEXT N_( \
51     "This is the video codec that will be used.")
52 #define VB_TEXT N_("Video bitrate")
53 #define VB_LONGTEXT N_( \
54     "Target bitrate of the transcoded video stream." )
55 #define SCALE_TEXT N_("Video scaling")
56 #define SCALE_LONGTEXT N_( \
57     "Scale factor to apply to the video while transcoding (eg: 0.25)")
58 #define FPS_TEXT N_("Video frame-rate")
59 #define FPS_LONGTEXT N_( \
60     "Target output frame rate for the video stream." )
61 #define DEINTERLACE_TEXT N_("Deinterlace video")
62 #define DEINTERLACE_LONGTEXT N_( \
63     "Deinterlace the video before encoding." )
64 #define DEINTERLACE_MODULE_TEXT N_("Deinterlace module")
65 #define DEINTERLACE_MODULE_LONGTEXT N_( \
66     "Specify the deinterlace module to use." )
67 #define WIDTH_TEXT N_("Video width")
68 #define WIDTH_LONGTEXT N_( \
69     "Output video width." )
70 #define HEIGHT_TEXT N_("Video height")
71 #define HEIGHT_LONGTEXT N_( \
72     "Output video height." )
73 #define MAXWIDTH_TEXT N_("Maximum video width")
74 #define MAXWIDTH_LONGTEXT N_( \
75     "Maximum output video width." )
76 #define MAXHEIGHT_TEXT N_("Maximum video height")
77 #define MAXHEIGHT_LONGTEXT N_( \
78     "Maximum output video height." )
79 #define VFILTER_TEXT N_("Video filter")
80 #define VFILTER_LONGTEXT N_( \
81     "Video filters will be applied to the video streams (after overlays " \
82     "are applied). You can enter a colon-separated list of filters." )
83
84 #define AENC_TEXT N_("Audio encoder")
85 #define AENC_LONGTEXT N_( \
86     "This is the audio encoder module that will be used (and its associated "\
87     "options).")
88 #define ACODEC_TEXT N_("Destination audio codec")
89 #define ACODEC_LONGTEXT N_( \
90     "This is the audio codec that will be used.")
91 #define AB_TEXT N_("Audio bitrate")
92 #define AB_LONGTEXT N_( \
93     "Target bitrate of the transcoded audio stream." )
94 #define ARATE_TEXT N_("Audio sample rate")
95 #define ARATE_LONGTEXT N_( \
96  "Sample rate of the transcoded audio stream (11250, 22500, 44100 or 48000).")
97 #define ALANG_TEXT N_("Audio language")
98 #define ALANG_LONGTEXT N_( \
99     "This is the language of the audio stream.")
100 #define ACHANS_TEXT N_("Audio channels")
101 #define ACHANS_LONGTEXT N_( \
102     "Number of audio channels in the transcoded streams." )
103 #define AFILTER_TEXT N_("Audio filter")
104 #define AFILTER_LONGTEXT N_( \
105     "Audio filters will be applied to the audio streams (after conversion " \
106     "filters are applied). You can enter a colon-separated list of filters." )
107
108 #define SENC_TEXT N_("Subtitle encoder")
109 #define SENC_LONGTEXT N_( \
110     "This is the subtitle encoder module that will be used (and its " \
111     "associated options)." )
112 #define SCODEC_TEXT N_("Destination subtitle codec")
113 #define SCODEC_LONGTEXT N_( \
114     "This is the subtitle codec that will be used." )
115
116 #define SFILTER_TEXT N_("Overlays")
117 #define SFILTER_LONGTEXT N_( \
118     "This allows you to add overlays (also known as \"subpictures\" on the "\
119     "transcoded video stream. The subpictures produced by the filters will "\
120     "be overlayed directly onto the video. You can specify a colon-separated "\
121     "list of subpicture modules" )
122
123 #define OSD_TEXT N_("OSD menu")
124 #define OSD_LONGTEXT N_(\
125     "Stream the On Screen Display menu (using the osdmenu subpicture module)." )
126
127 #define THREADS_TEXT N_("Number of threads")
128 #define THREADS_LONGTEXT N_( \
129     "Number of threads used for the transcoding." )
130 #define HP_TEXT N_("High priority")
131 #define HP_LONGTEXT N_( \
132     "Runs the optional encoder thread at the OUTPUT priority instead of " \
133     "VIDEO." )
134
135
136 static const char *const ppsz_deinterlace_type[] =
137 {
138     "deinterlace", "ffmpeg-deinterlace"
139 };
140
141 static int  Open ( vlc_object_t * );
142 static void Close( vlc_object_t * );
143
144 #define SOUT_CFG_PREFIX "sout-transcode-"
145
146 vlc_module_begin ()
147     set_shortname( N_("Transcode"))
148     set_description( N_("Transcode stream output") )
149     set_capability( "sout stream", 50 )
150     add_shortcut( "transcode" )
151     set_callbacks( Open, Close )
152     set_category( CAT_SOUT )
153     set_subcategory( SUBCAT_SOUT_STREAM )
154     set_section( N_("Video"), NULL )
155     add_module( SOUT_CFG_PREFIX "venc", "encoder", NULL, VENC_TEXT,
156                 VENC_LONGTEXT, false )
157     add_string( SOUT_CFG_PREFIX "vcodec", NULL, VCODEC_TEXT,
158                 VCODEC_LONGTEXT, false )
159     add_integer( SOUT_CFG_PREFIX "vb", 0, VB_TEXT,
160                  VB_LONGTEXT, false )
161     add_float( SOUT_CFG_PREFIX "scale", 0, SCALE_TEXT,
162                SCALE_LONGTEXT, false )
163     add_string( SOUT_CFG_PREFIX "fps", NULL, FPS_TEXT,
164                FPS_LONGTEXT, false )
165     add_obsolete_bool( SOUT_CFG_PREFIX "hurry-up"); /* Since 2.2.0 */
166     add_bool( SOUT_CFG_PREFIX "deinterlace", false, DEINTERLACE_TEXT,
167               DEINTERLACE_LONGTEXT, false )
168     add_string( SOUT_CFG_PREFIX "deinterlace-module", "deinterlace",
169                 DEINTERLACE_MODULE_TEXT, DEINTERLACE_MODULE_LONGTEXT,
170                 false )
171         change_string_list( ppsz_deinterlace_type, ppsz_deinterlace_type )
172     add_integer( SOUT_CFG_PREFIX "width", 0, WIDTH_TEXT,
173                  WIDTH_LONGTEXT, true )
174     add_integer( SOUT_CFG_PREFIX "height", 0, HEIGHT_TEXT,
175                  HEIGHT_LONGTEXT, true )
176     add_integer( SOUT_CFG_PREFIX "maxwidth", 0, MAXWIDTH_TEXT,
177                  MAXWIDTH_LONGTEXT, true )
178     add_integer( SOUT_CFG_PREFIX "maxheight", 0, MAXHEIGHT_TEXT,
179                  MAXHEIGHT_LONGTEXT, true )
180     add_module_list( SOUT_CFG_PREFIX "vfilter", "video filter2",
181                      NULL, VFILTER_TEXT, VFILTER_LONGTEXT, false )
182
183     set_section( N_("Audio"), NULL )
184     add_module( SOUT_CFG_PREFIX "aenc", "encoder", NULL, AENC_TEXT,
185                 AENC_LONGTEXT, false )
186     add_string( SOUT_CFG_PREFIX "acodec", NULL, ACODEC_TEXT,
187                 ACODEC_LONGTEXT, false )
188     add_integer( SOUT_CFG_PREFIX "ab", 96, AB_TEXT,
189                  AB_LONGTEXT, false )
190     add_string( SOUT_CFG_PREFIX "alang", NULL, ALANG_TEXT,
191                 ALANG_LONGTEXT, true )
192     add_integer( SOUT_CFG_PREFIX "channels", 0, ACHANS_TEXT,
193                  ACHANS_LONGTEXT, false )
194         change_integer_range( 0, 9 )
195     add_integer( SOUT_CFG_PREFIX "samplerate", 0, ARATE_TEXT,
196                  ARATE_LONGTEXT, true )
197         change_integer_range( 0, 48000 )
198     add_obsolete_bool( SOUT_CFG_PREFIX "audio-sync" ) /*Since 2.2.0 */
199     add_module_list( SOUT_CFG_PREFIX "afilter",  "audio filter",
200                      NULL, AFILTER_TEXT, AFILTER_LONGTEXT, false )
201
202     set_section( N_("Overlays/Subtitles"), NULL )
203     add_module( SOUT_CFG_PREFIX "senc", "encoder", NULL, SENC_TEXT,
204                 SENC_LONGTEXT, false )
205     add_string( SOUT_CFG_PREFIX "scodec", NULL, SCODEC_TEXT,
206                 SCODEC_LONGTEXT, false )
207     add_bool( SOUT_CFG_PREFIX "soverlay", false, SCODEC_TEXT,
208                SCODEC_LONGTEXT, false )
209     add_module_list( SOUT_CFG_PREFIX "sfilter", "video filter",
210                      NULL, SFILTER_TEXT, SFILTER_LONGTEXT, false )
211
212     set_section( N_("On Screen Display"), NULL )
213     add_bool( SOUT_CFG_PREFIX "osd", false, OSD_TEXT,
214               OSD_LONGTEXT, false )
215
216     set_section( N_("Miscellaneous"), NULL )
217     add_integer( SOUT_CFG_PREFIX "threads", 0, THREADS_TEXT,
218                  THREADS_LONGTEXT, true )
219     add_bool( SOUT_CFG_PREFIX "high-priority", false, HP_TEXT, HP_LONGTEXT,
220               true )
221
222 vlc_module_end ()
223
224 static const char *const ppsz_sout_options[] = {
225     "venc", "vcodec", "vb",
226     "scale", "fps", "width", "height", "vfilter", "deinterlace",
227     "deinterlace-module", "threads", "aenc", "acodec", "ab", "alang",
228     "afilter", "samplerate", "channels", "senc", "scodec", "soverlay",
229     "sfilter", "osd", "high-priority", "maxwidth", "maxheight",
230     NULL
231 };
232
233 /*****************************************************************************
234  * Exported prototypes
235  *****************************************************************************/
236 static sout_stream_id_sys_t *Add ( sout_stream_t *, es_format_t * );
237 static int               Del ( sout_stream_t *, sout_stream_id_sys_t * );
238 static int               Send( sout_stream_t *, sout_stream_id_sys_t *, block_t* );
239
240 /*****************************************************************************
241  * Open:
242  *****************************************************************************/
243 static int Open( vlc_object_t *p_this )
244 {
245     sout_stream_t     *p_stream = (sout_stream_t*)p_this;
246     sout_stream_sys_t *p_sys;
247     char              *psz_string;
248
249     if( !p_stream->p_next )
250     {
251         msg_Err( p_stream, "cannot create chain" );
252         return VLC_EGENERIC;
253     }
254     p_sys = calloc( 1, sizeof( *p_sys ) );
255     p_sys->i_master_drift = 0;
256
257     config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
258                    p_stream->p_cfg );
259
260     /* Audio transcoding parameters */
261     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "aenc" );
262     p_sys->psz_aenc = NULL;
263     p_sys->p_audio_cfg = NULL;
264     if( psz_string && *psz_string )
265     {
266         char *psz_next;
267         psz_next = config_ChainCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
268                                        psz_string );
269         free( psz_next );
270     }
271     free( psz_string );
272
273     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "acodec" );
274     p_sys->i_acodec = 0;
275     if( psz_string && *psz_string )
276     {
277         char fcc[5] = "    \0";
278         memcpy( fcc, psz_string, __MIN( strlen( psz_string ), 4 ) );
279         p_sys->i_acodec = vlc_fourcc_GetCodecFromString( AUDIO_ES, fcc );
280         msg_Dbg( p_stream, "Checking codec mapping for %s got %4.4s ", fcc, (char*)&p_sys->i_acodec);
281     }
282     free( psz_string );
283
284     p_sys->psz_alang = var_GetNonEmptyString( p_stream, SOUT_CFG_PREFIX "alang" );
285
286     p_sys->i_abitrate = var_GetInteger( p_stream, SOUT_CFG_PREFIX "ab" );
287     if( p_sys->i_abitrate < 4000 ) p_sys->i_abitrate *= 1000;
288
289     p_sys->i_sample_rate = var_GetInteger( p_stream, SOUT_CFG_PREFIX "samplerate" );
290
291     p_sys->i_channels = var_GetInteger( p_stream, SOUT_CFG_PREFIX "channels" );
292
293     if( p_sys->i_acodec )
294     {
295         if( ( p_sys->i_acodec == VLC_CODEC_MP3 ||
296               p_sys->i_acodec == VLC_CODEC_MP2 ||
297               p_sys->i_acodec == VLC_CODEC_MPGA ) && p_sys->i_channels > 2 )
298         {
299             msg_Warn( p_stream, "%d channels invalid for mp2/mp3, forcing to 2",
300                       p_sys->i_channels );
301             p_sys->i_channels = 2;
302         }
303         msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s",
304                  (char *)&p_sys->i_acodec, p_sys->i_sample_rate,
305                  p_sys->i_channels, p_sys->i_abitrate / 1000 );
306     }
307
308     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "afilter" );
309     if( psz_string && *psz_string )
310         p_sys->psz_af = strdup( psz_string );
311     else
312         p_sys->psz_af = NULL;
313     free( psz_string );
314
315     /* Video transcoding parameters */
316     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "venc" );
317     p_sys->psz_venc = NULL;
318     p_sys->p_video_cfg = NULL;
319     if( psz_string && *psz_string )
320     {
321         char *psz_next;
322         psz_next = config_ChainCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
323                                    psz_string );
324         free( psz_next );
325     }
326     free( psz_string );
327
328     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "vcodec" );
329     p_sys->i_vcodec = 0;
330     if( psz_string && *psz_string )
331     {
332         char fcc[5] = "    \0";
333         memcpy( fcc, psz_string, __MIN( strlen( psz_string ), 4 ) );
334         p_sys->i_vcodec = vlc_fourcc_GetCodecFromString( VIDEO_ES, fcc );
335         msg_Dbg( p_stream, "Checking video codec mapping for %s got %4.4s ", fcc, (char*)&p_sys->i_vcodec);
336     }
337     free( psz_string );
338
339     p_sys->i_vbitrate = var_GetInteger( p_stream, SOUT_CFG_PREFIX "vb" );
340     if( p_sys->i_vbitrate < 16000 ) p_sys->i_vbitrate *= 1000;
341
342     p_sys->f_scale = var_GetFloat( p_stream, SOUT_CFG_PREFIX "scale" );
343
344     p_sys->b_master_sync = var_InheritURational( p_stream, &p_sys->fps_num, &p_sys->fps_den, SOUT_CFG_PREFIX "fps" );
345
346     p_sys->i_width = var_GetInteger( p_stream, SOUT_CFG_PREFIX "width" );
347
348     p_sys->i_height = var_GetInteger( p_stream, SOUT_CFG_PREFIX "height" );
349
350     p_sys->i_maxwidth = var_GetInteger( p_stream, SOUT_CFG_PREFIX "maxwidth" );
351
352     p_sys->i_maxheight = var_GetInteger( p_stream, SOUT_CFG_PREFIX "maxheight" );
353
354     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "vfilter" );
355     if( psz_string && *psz_string )
356         p_sys->psz_vf2 = strdup(psz_string );
357     else
358         p_sys->psz_vf2 = NULL;
359     free( psz_string );
360
361     p_sys->b_deinterlace = var_GetBool( p_stream, SOUT_CFG_PREFIX "deinterlace" );
362
363     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "deinterlace-module" );
364     p_sys->psz_deinterlace = NULL;
365     p_sys->p_deinterlace_cfg = NULL;
366     if( psz_string && *psz_string )
367     {
368         char *psz_next;
369         psz_next = config_ChainCreate( &p_sys->psz_deinterlace,
370                                    &p_sys->p_deinterlace_cfg,
371                                    psz_string );
372         free( psz_next );
373     }
374     free( psz_string );
375
376     p_sys->i_threads = var_GetInteger( p_stream, SOUT_CFG_PREFIX "threads" );
377     p_sys->b_high_priority = var_GetBool( p_stream, SOUT_CFG_PREFIX "high-priority" );
378
379     if( p_sys->i_vcodec )
380     {
381         msg_Dbg( p_stream, "codec video=%4.4s %dx%d scaling: %f %dkb/s",
382                  (char *)&p_sys->i_vcodec, p_sys->i_width, p_sys->i_height,
383                  p_sys->f_scale, p_sys->i_vbitrate / 1000 );
384     }
385
386     /* Disable hardware decoding by default (unlike normal playback) */
387     psz_string = var_CreateGetString( p_stream, "avcodec-hw" );
388     if( !strcasecmp( "any", psz_string ) )
389         var_SetString( p_stream, "avcodec-hw", "none" );
390     free( psz_string );
391
392     /* Subpictures transcoding parameters */
393     p_sys->p_spu = NULL;
394     p_sys->p_spu_blend = NULL;
395     p_sys->psz_senc = NULL;
396     p_sys->p_spu_cfg = NULL;
397     p_sys->i_scodec = 0;
398
399     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "senc" );
400     if( psz_string && *psz_string )
401     {
402         char *psz_next;
403         psz_next = config_ChainCreate( &p_sys->psz_senc, &p_sys->p_spu_cfg,
404                                    psz_string );
405         free( psz_next );
406     }
407     free( psz_string );
408
409     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "scodec" );
410     if( psz_string && *psz_string )
411     {
412         char fcc[5] = "    \0";
413         memcpy( fcc, psz_string, __MIN( strlen( psz_string ), 4 ) );
414         p_sys->i_scodec = vlc_fourcc_GetCodecFromString( SPU_ES, fcc );
415         msg_Dbg( p_stream, "Checking spu codec mapping for %s got %4.4s ", fcc, (char*)&p_sys->i_scodec);
416     }
417     free( psz_string );
418
419     if( p_sys->i_scodec )
420     {
421         msg_Dbg( p_stream, "codec spu=%4.4s", (char *)&p_sys->i_scodec );
422     }
423
424     p_sys->b_soverlay = var_GetBool( p_stream, SOUT_CFG_PREFIX "soverlay" );
425
426     psz_string = var_GetString( p_stream, SOUT_CFG_PREFIX "sfilter" );
427     if( psz_string && *psz_string )
428     {
429         p_sys->p_spu = spu_Create( p_stream );
430         if( p_sys->p_spu )
431             spu_ChangeSources( p_sys->p_spu, psz_string );
432     }
433     free( psz_string );
434
435     /* OSD menu transcoding parameters */
436     p_sys->psz_osdenc = NULL;
437     p_sys->p_osd_cfg  = NULL;
438     p_sys->i_osdcodec = 0;
439     p_sys->b_osd   = var_GetBool( p_stream, SOUT_CFG_PREFIX "osd" );
440
441     if( p_sys->b_osd )
442     {
443         char *psz_next;
444
445         psz_next = config_ChainCreate( &p_sys->psz_osdenc,
446                                    &p_sys->p_osd_cfg, "dvbsub" );
447         free( psz_next );
448
449         p_sys->i_osdcodec = VLC_CODEC_YUVP;
450
451         msg_Dbg( p_stream, "codec osd=%4.4s", (char *)&p_sys->i_osdcodec );
452
453         if( !p_sys->p_spu )
454         {
455             p_sys->p_spu = spu_Create( p_stream );
456             if( p_sys->p_spu )
457                 spu_ChangeSources( p_sys->p_spu, "osdmenu" );
458         }
459         else
460         {
461             spu_ChangeSources( p_sys->p_spu, "osdmenu" );
462         }
463     }
464
465     p_stream->pf_add    = Add;
466     p_stream->pf_del    = Del;
467     p_stream->pf_send   = Send;
468     p_stream->p_sys     = p_sys;
469
470     return VLC_SUCCESS;
471 }
472
473 /*****************************************************************************
474  * Close:
475  *****************************************************************************/
476 static void Close( vlc_object_t * p_this )
477 {
478     sout_stream_t       *p_stream = (sout_stream_t*)p_this;
479     sout_stream_sys_t   *p_sys = p_stream->p_sys;
480
481     free( p_sys->psz_af );
482
483     config_ChainDestroy( p_sys->p_audio_cfg );
484     free( p_sys->psz_aenc );
485     free( p_sys->psz_alang );
486
487     free( p_sys->psz_vf2 );
488
489     config_ChainDestroy( p_sys->p_video_cfg );
490     free( p_sys->psz_venc );
491
492     config_ChainDestroy( p_sys->p_deinterlace_cfg );
493     free( p_sys->psz_deinterlace );
494
495     config_ChainDestroy( p_sys->p_spu_cfg );
496     free( p_sys->psz_senc );
497
498     if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu );
499     if( p_sys->p_spu_blend ) filter_DeleteBlend( p_sys->p_spu_blend );
500
501     config_ChainDestroy( p_sys->p_osd_cfg );
502     free( p_sys->psz_osdenc );
503
504     free( p_sys );
505 }
506
507 static sout_stream_id_sys_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
508 {
509     sout_stream_sys_t *p_sys = p_stream->p_sys;
510     sout_stream_id_sys_t *id;
511
512     id = calloc( 1, sizeof( sout_stream_id_sys_t ) );
513     if( !id )
514         goto error;
515
516     id->id = NULL;
517     id->p_decoder = NULL;
518     id->p_encoder = NULL;
519
520     /* Create decoder object */
521     id->p_decoder = vlc_object_create( p_stream, sizeof( decoder_t ) );
522     if( !id->p_decoder )
523         goto error;
524     id->p_decoder->p_module = NULL;
525     id->p_decoder->fmt_in = *p_fmt;
526     id->p_decoder->b_pace_control = true;
527
528     /* Create encoder object */
529     id->p_encoder = sout_EncoderCreate( p_stream );
530     if( !id->p_encoder )
531         goto error;
532     id->p_encoder->p_module = NULL;
533
534     /* Create destination format */
535     es_format_Init( &id->p_encoder->fmt_out, p_fmt->i_cat, 0 );
536     id->p_encoder->fmt_out.i_id    = p_fmt->i_id;
537     id->p_encoder->fmt_out.i_group = p_fmt->i_group;
538
539     if( p_sys->psz_alang )
540         id->p_encoder->fmt_out.psz_language = strdup( p_sys->psz_alang );
541     else if( p_fmt->psz_language )
542         id->p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language );
543
544     bool success;
545
546     if( p_fmt->i_cat == AUDIO_ES && p_sys->i_acodec )
547         success = transcode_audio_add(p_stream, p_fmt, id);
548     else if( p_fmt->i_cat == VIDEO_ES && p_sys->i_vcodec )
549         success = transcode_video_add(p_stream, p_fmt, id);
550     else if( ( p_fmt->i_cat == SPU_ES ) &&
551              ( p_sys->i_scodec || p_sys->b_soverlay ) )
552         success = transcode_spu_add(p_stream, p_fmt, id);
553     else if( !p_sys->b_osd && (p_sys->i_osdcodec != 0 || p_sys->psz_osdenc) )
554         success = transcode_osd_add(p_stream, p_fmt, id);
555     else
556     {
557         msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
558                  (char*)&p_fmt->i_codec );
559         id->id = sout_StreamIdAdd( p_stream->p_next, p_fmt );
560         id->b_transcode = false;
561
562         success = id->id;
563     }
564
565     if(!success)
566         goto error;
567
568     return id;
569
570 error:
571     if( id )
572     {
573         if( id->p_decoder )
574         {
575             vlc_object_release( id->p_decoder );
576             id->p_decoder = NULL;
577         }
578
579         if( id->p_encoder )
580         {
581             es_format_Clean( &id->p_encoder->fmt_out );
582             vlc_object_release( id->p_encoder );
583             id->p_encoder = NULL;
584         }
585
586         free( id );
587     }
588     return NULL;
589 }
590
591 static int Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
592 {
593     sout_stream_sys_t *p_sys = p_stream->p_sys;
594
595     if( id->b_transcode )
596     {
597         switch( id->p_decoder->fmt_in.i_cat )
598         {
599         case AUDIO_ES:
600             Send( p_stream, id, NULL );
601             transcode_audio_close( id );
602             break;
603         case VIDEO_ES:
604             Send( p_stream, id, NULL );
605             transcode_video_close( p_stream, id );
606             break;
607         case SPU_ES:
608             if( p_sys->b_osd )
609                 transcode_osd_close( p_stream, id );
610             else
611                 transcode_spu_close( p_stream, id );
612             break;
613         }
614     }
615
616     if( id->id ) sout_StreamIdDel( p_stream->p_next, id->id );
617
618     if( id->p_decoder )
619     {
620         vlc_object_release( id->p_decoder );
621         id->p_decoder = NULL;
622     }
623
624     if( id->p_encoder )
625     {
626         es_format_Clean( &id->p_encoder->fmt_out );
627         vlc_object_release( id->p_encoder );
628         id->p_encoder = NULL;
629     }
630     free( id );
631
632     return VLC_SUCCESS;
633 }
634
635 static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
636                  block_t *p_buffer )
637 {
638     sout_stream_sys_t *p_sys = p_stream->p_sys;
639     block_t *p_out = NULL;
640
641     if( !id->b_transcode )
642     {
643         if( id->id )
644             return sout_StreamIdSend( p_stream->p_next, id->id, p_buffer );
645
646         block_Release( p_buffer );
647         return VLC_EGENERIC;
648     }
649
650     switch( id->p_decoder->fmt_in.i_cat )
651     {
652     case AUDIO_ES:
653         if( transcode_audio_process( p_stream, id, p_buffer, &p_out )
654             != VLC_SUCCESS )
655         {
656             return VLC_EGENERIC;
657         }
658         break;
659
660     case VIDEO_ES:
661         if( transcode_video_process( p_stream, id, p_buffer, &p_out )
662             != VLC_SUCCESS )
663         {
664             return VLC_EGENERIC;
665         }
666         break;
667
668     case SPU_ES:
669         /* Transcode OSD menu pictures. */
670         if( p_sys->b_osd )
671         {
672             if( transcode_osd_process( p_stream, id, p_buffer, &p_out ) !=
673                 VLC_SUCCESS )
674             {
675                 return VLC_EGENERIC;
676             }
677         }
678         else if ( transcode_spu_process( p_stream, id, p_buffer, &p_out ) !=
679             VLC_SUCCESS )
680         {
681             return VLC_EGENERIC;
682         }
683         break;
684
685     default:
686         p_out = NULL;
687         block_Release( p_buffer );
688         break;
689     }
690
691     if( p_out )
692         return sout_StreamIdSend( p_stream->p_next, id->id, p_out );
693     return VLC_SUCCESS;
694 }