transcode.c 85.6 KB
Newer Older
1
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
2
 * transcode.c: transcoding stream output module
3
 *****************************************************************************
4
 * Copyright (C) 2003-2004 the VideoLAN team
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 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25 26 27 28 29 30
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <string.h>
31
#include <math.h>
32 33 34 35

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/sout.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
36 37
#include <vlc/vout.h>
#include <vlc/decoder.h>
38
#include "vlc_filter.h"
39
#include "vlc_osd.h"
40

41 42
#define MASTER_SYNC_MAX_DRIFT 100000

43
/*****************************************************************************
44
 * Module descriptor
45
 *****************************************************************************/
46 47 48 49
#define VENC_TEXT N_("Video encoder")
#define VENC_LONGTEXT N_( \
    "Allows you to specify the video encoder to use and its associated " \
    "options." )
50 51
#define VCODEC_TEXT N_("Destination video codec")
#define VCODEC_LONGTEXT N_( \
52 53
    "Allows you to specify the destination video codec used for the " \
    "streaming output." )
54 55 56 57 58 59 60
#define VB_TEXT N_("Video bitrate")
#define VB_LONGTEXT N_( \
    "Allows you to specify the video bitrate used for the streaming " \
    "output." )
#define SCALE_TEXT N_("Video scaling")
#define SCALE_LONGTEXT N_( \
    "Allows you to scale the video before encoding." )
61 62 63
#define FPS_TEXT N_("Video frame-rate")
#define FPS_LONGTEXT N_( \
    "Allows you to specify an output frame rate for the video." )
64 65 66
#define DEINTERLACE_TEXT N_("Deinterlace video")
#define DEINTERLACE_LONGTEXT N_( \
    "Allows you to deinterlace the video before encoding." )
67 68
#define DEINTERLACE_MODULE_TEXT N_("Deinterlace module")
#define DEINTERLACE_MODULE_LONGTEXT N_( \
69
    "Specifies the deinterlace module to use." )
70 71 72 73 74 75
#define WIDTH_TEXT N_("Video width")
#define WIDTH_LONGTEXT N_( \
    "Allows you to specify the output video width." )
#define HEIGHT_TEXT N_("Video height")
#define HEIGHT_LONGTEXT N_( \
    "Allows you to specify the output video height." )
76 77 78 79 80 81
#define MAXWIDTH_TEXT N_("Maximum video width")
#define MAXWIDTH_LONGTEXT N_( \
    "Allows you to specify a maximum output video width." )
#define MAXHEIGHT_TEXT N_("Maximum video height")
#define MAXHEIGHT_LONGTEXT N_( \
    "Allows you to specify a maximum output video height." )
82 83 84 85
#define VFILTER_TEXT N_("Video filter")
#define VFILTER_LONGTEXT N_( \
    "Allows you to specify video filters used after the video " \
    "transcoding and subpictures overlaying." )
86 87 88 89 90 91 92 93 94 95 96 97 98 99

#define CROPTOP_TEXT N_("Video crop top")
#define CROPTOP_LONGTEXT N_( \
    "Allows you to specify the top coordinate for the video cropping." )
#define CROPLEFT_TEXT N_("Video crop left")
#define CROPLEFT_LONGTEXT N_( \
    "Allows you to specify the left coordinate for the video cropping." )
#define CROPBOTTOM_TEXT N_("Video crop bottom")
#define CROPBOTTOM_LONGTEXT N_( \
    "Allows you to specify the bottom coordinate for the video cropping." )
#define CROPRIGHT_TEXT N_("Video crop right")
#define CROPRIGHT_LONGTEXT N_( \
    "Allows you to specify the right coordinate for the video cropping." )

100 101 102 103
#define AENC_TEXT N_("Audio encoder")
#define AENC_LONGTEXT N_( \
    "Allows you to specify the audio encoder to use and its associated " \
    "options." )
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
#define ACODEC_TEXT N_("Destination audio codec")
#define ACODEC_LONGTEXT N_( \
    "Allows you to specify the destination audio codec used for the " \
    "streaming output." )
#define AB_TEXT N_("Audio bitrate")
#define AB_LONGTEXT N_( \
    "Allows you to specify the audio bitrate used for the streaming " \
    "output." )
#define ARATE_TEXT N_("Audio sample rate")
#define ARATE_LONGTEXT N_( \
    "Allows you to specify the audio sample rate used for the streaming " \
    "output." )
#define ACHANS_TEXT N_("Audio channels")
#define ACHANS_LONGTEXT N_( \
    "Allows you to specify the number of audio channels used for the " \
    "streaming output." )

121 122 123 124 125 126 127 128
#define SENC_TEXT N_("Subtitles encoder")
#define SENC_LONGTEXT N_( \
    "Allows you to specify the subtitles encoder to use and its associated " \
    "options." )
#define SCODEC_TEXT N_("Destination subtitles codec")
#define SCODEC_LONGTEXT N_( \
    "Allows you to specify the destination subtitles codec used for the " \
    "streaming output." )
129 130 131 132 133
#define SFILTER_TEXT N_("Subpictures filter")
#define SFILTER_LONGTEXT N_( \
    "Allows you to specify subpictures filters used during the video " \
    "transcoding. The subpictures produced by the filters will be overlayed " \
    "directly onto the video." )
134

135 136 137 138
#define OSD_TEXT N_("OSD menu")
#define OSD_LONGTEXT N_(\
    "Enable streaming of the On Screen Display. It uses the osdmenu subfilter." )
                  
139 140 141
#define THREADS_TEXT N_("Number of threads")
#define THREADS_LONGTEXT N_( \
    "Allows you to specify the number of threads used for the transcoding." )
142 143 144 145
#define HP_TEXT N_("High priority")
#define HP_LONGTEXT N_( \
    "Runs the optional encoder thread at the OUTPUT priority instead of " \
    "VIDEO." )
146

147 148 149 150 151
#define ASYNC_TEXT N_("Synchronise on audio track")
#define ASYNC_LONGTEXT N_( \
    "This option will drop/duplicate video frames to synchronise the video " \
    "track on the audio track." )

152 153 154 155
#define HURRYUP_TEXT N_( "Hurry up" )
#define HURRYUP_LONGTEXT N_( "Allows you to specify if the transcoder " \
  "should drop frames if your CPU can't keep up with the encoding rate." )

156 157 158 159 160
static char *ppsz_deinterlace_type[] =
{
    "deinterlace", "ffmpeg-deinterlace"
};

161 162 163
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

164 165
#define SOUT_CFG_PREFIX "sout-transcode-"

166
vlc_module_begin();
167
    set_shortname( _("Transcode"));
168 169 170 171
    set_description( _("Transcode stream output") );
    set_capability( "sout stream", 50 );
    add_shortcut( "transcode" );
    set_callbacks( Open, Close );
Clément Stenac's avatar
Clément Stenac committed
172 173
    set_category( CAT_SOUT );
    set_subcategory( SUBCAT_SOUT_STREAM );
174
    set_section( N_("Video"), NULL );
175 176
    add_string( SOUT_CFG_PREFIX "venc", NULL, NULL, VENC_TEXT,
                VENC_LONGTEXT, VLC_FALSE );
177 178 179 180 181 182
    add_string( SOUT_CFG_PREFIX "vcodec", NULL, NULL, VCODEC_TEXT,
                VCODEC_LONGTEXT, VLC_FALSE );
    add_integer( SOUT_CFG_PREFIX "vb", 800 * 1000, NULL, VB_TEXT,
                 VB_LONGTEXT, VLC_FALSE );
    add_float( SOUT_CFG_PREFIX "scale", 1, NULL, SCALE_TEXT,
               SCALE_LONGTEXT, VLC_FALSE );
183 184
    add_float( SOUT_CFG_PREFIX "fps", 0, NULL, FPS_TEXT,
               FPS_LONGTEXT, VLC_FALSE );
185 186
    add_bool( SOUT_CFG_PREFIX "hurry-up", VLC_TRUE, NULL, HURRYUP_TEXT,
               HURRYUP_LONGTEXT, VLC_FALSE );
187 188
    add_bool( SOUT_CFG_PREFIX "deinterlace", 0, NULL, DEINTERLACE_TEXT,
              DEINTERLACE_LONGTEXT, VLC_FALSE );
189 190 191
    add_string( SOUT_CFG_PREFIX "deinterlace-module", "deinterlace", NULL,
                DEINTERLACE_MODULE_TEXT, DEINTERLACE_MODULE_LONGTEXT,
                VLC_FALSE );
192
        change_string_list( ppsz_deinterlace_type, 0, 0 );
193 194 195 196
    add_integer( SOUT_CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
                 WIDTH_LONGTEXT, VLC_TRUE );
    add_integer( SOUT_CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
                 HEIGHT_LONGTEXT, VLC_TRUE );
197 198 199 200
    add_integer( SOUT_CFG_PREFIX "maxwidth", 0, NULL, MAXWIDTH_TEXT,
                 MAXWIDTH_LONGTEXT, VLC_TRUE );
    add_integer( SOUT_CFG_PREFIX "maxheight", 0, NULL, MAXHEIGHT_TEXT,
                 MAXHEIGHT_LONGTEXT, VLC_TRUE );
201 202 203
    add_module_list_cat( SOUT_CFG_PREFIX "vfilter", SUBCAT_VIDEO_VFILTER,
                     NULL, NULL,
                     VFILTER_TEXT, VFILTER_LONGTEXT, VLC_FALSE );
204 205 206 207 208 209 210 211 212 213

    add_integer( SOUT_CFG_PREFIX "croptop", 0, NULL, CROPTOP_TEXT,
                 CROPTOP_LONGTEXT, VLC_TRUE );
    add_integer( SOUT_CFG_PREFIX "cropleft", 0, NULL, CROPLEFT_TEXT,
                 CROPLEFT_LONGTEXT, VLC_TRUE );
    add_integer( SOUT_CFG_PREFIX "cropbottom", 0, NULL, CROPBOTTOM_TEXT,
                 CROPBOTTOM_LONGTEXT, VLC_TRUE );
    add_integer( SOUT_CFG_PREFIX "cropright", 0, NULL, CROPRIGHT_TEXT,
                 CROPRIGHT_LONGTEXT, VLC_TRUE );

214
    set_section( N_("Audio"), NULL );
215 216
    add_string( SOUT_CFG_PREFIX "aenc", NULL, NULL, AENC_TEXT,
                AENC_LONGTEXT, VLC_FALSE );
217 218 219 220 221 222 223 224
    add_string( SOUT_CFG_PREFIX "acodec", NULL, NULL, ACODEC_TEXT,
                ACODEC_LONGTEXT, VLC_FALSE );
    add_integer( SOUT_CFG_PREFIX "ab", 64000, NULL, AB_TEXT,
                 AB_LONGTEXT, VLC_FALSE );
    add_integer( SOUT_CFG_PREFIX "channels", 0, NULL, ACHANS_TEXT,
                 ACHANS_LONGTEXT, VLC_FALSE );
    add_integer( SOUT_CFG_PREFIX "samplerate", 0, NULL, ARATE_TEXT,
                 ARATE_LONGTEXT, VLC_TRUE );
225 226
    add_bool( SOUT_CFG_PREFIX "audio-sync", 0, NULL, ASYNC_TEXT,
              ASYNC_LONGTEXT, VLC_FALSE );
227

228
    set_section( N_("Overlays/Subtitles"), NULL );
229 230 231 232 233 234
    add_string( SOUT_CFG_PREFIX "senc", NULL, NULL, SENC_TEXT,
                SENC_LONGTEXT, VLC_FALSE );
    add_string( SOUT_CFG_PREFIX "scodec", NULL, NULL, SCODEC_TEXT,
                SCODEC_LONGTEXT, VLC_FALSE );
    add_bool( SOUT_CFG_PREFIX "soverlay", 0, NULL, SCODEC_TEXT,
               SCODEC_LONGTEXT, VLC_FALSE );
235 236 237
    add_module_list_cat( SOUT_CFG_PREFIX "sfilter", SUBCAT_VIDEO_SUBPIC,
                     NULL, NULL,
                     SFILTER_TEXT, SFILTER_LONGTEXT, VLC_FALSE );
238

239 240 241 242
    set_section( N_("On Screen Display"), NULL );
    add_bool( SOUT_CFG_PREFIX "osd", 0, NULL, OSD_TEXT,
              OSD_LONGTEXT, VLC_FALSE );
    
243
    set_section( N_("Miscellaneous"), NULL );
244 245
    add_integer( SOUT_CFG_PREFIX "threads", 0, NULL, THREADS_TEXT,
                 THREADS_LONGTEXT, VLC_TRUE );
246 247
    add_bool( SOUT_CFG_PREFIX "high-priority", 0, NULL, HP_TEXT, HP_LONGTEXT,
              VLC_TRUE );
248

249
vlc_module_end();
250

251 252
static const char *ppsz_sout_options[] = {
    "venc", "vcodec", "vb", "croptop", "cropbottom", "cropleft", "cropright",
253 254 255
    "scale", "fps", "width", "height", "vfilter", "deinterlace",
    "deinterlace-module", "threads", "hurry-up", "aenc", "acodec", "ab",
    "samplerate", "channels", "senc", "scodec", "soverlay", "sfilter",
256
    "osd", "audio-sync", "high-priority", "maxwidth", "maxheight", NULL
257 258
};

259 260 261
/*****************************************************************************
 * Exported prototypes
 *****************************************************************************/
262
static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
263
static int               Del ( sout_stream_t *, sout_stream_id_t * );
264
static int               Send( sout_stream_t *, sout_stream_id_t *, block_t* );
265

266 267 268 269 270
static int  transcode_audio_new    ( sout_stream_t *, sout_stream_id_t * );
static void transcode_audio_close  ( sout_stream_t *, sout_stream_id_t * );
static int  transcode_audio_process( sout_stream_t *, sout_stream_id_t *,
                                     block_t *, block_t ** );

271 272 273
static aout_buffer_t *audio_new_buffer( decoder_t *, int );
static void audio_del_buffer( decoder_t *, aout_buffer_t * );

274 275 276 277 278 279
static int  transcode_video_new    ( sout_stream_t *, sout_stream_id_t * );
static void transcode_video_close  ( sout_stream_t *, sout_stream_id_t * );
static int  transcode_video_encoder_open( sout_stream_t *, sout_stream_id_t *);
static int  transcode_video_process( sout_stream_t *, sout_stream_id_t *,
                                     block_t *, block_t ** );

280 281 282 283 284 285 286
static void video_del_buffer( vlc_object_t *, picture_t * );
static picture_t *video_new_buffer_decoder( decoder_t * );
static void video_del_buffer_decoder( decoder_t *, picture_t * );
static void video_link_picture_decoder( decoder_t *, picture_t * );
static void video_unlink_picture_decoder( decoder_t *, picture_t * );
static picture_t *video_new_buffer_filter( filter_t * );
static void video_del_buffer_filter( filter_t *, picture_t * );
Gildas Bazin's avatar
 
Gildas Bazin committed
287

288 289 290 291 292
static int  transcode_spu_new    ( sout_stream_t *, sout_stream_id_t * );
static void transcode_spu_close  ( sout_stream_t *, sout_stream_id_t * );
static int  transcode_spu_process( sout_stream_t *, sout_stream_id_t *,
                                   block_t *, block_t ** );

293 294 295 296
static int  transcode_osd_new    ( sout_stream_t *, sout_stream_id_t * );
static void transcode_osd_close  ( sout_stream_t *, sout_stream_id_t * );
static int  transcode_osd_process( sout_stream_t *, sout_stream_id_t *,
                                   block_t *, block_t ** );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
297

298 299
static int  EncoderThread( struct sout_stream_sys_t * p_sys );

Gildas Bazin's avatar
 
Gildas Bazin committed
300 301 302 303 304 305 306 307 308 309 310
static int pi_channels_maps[6] =
{
    0,
    AOUT_CHAN_CENTER,   AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
    AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
     | AOUT_CHAN_REARRIGHT,
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
     | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
};

311
#define PICTURE_RING_SIZE 64
312
#define SUBPICTURE_RING_SIZE 20
313

314 315
struct sout_stream_sys_t
{
316 317
    VLC_COMMON_MEMBERS

318 319 320
    sout_stream_t   *p_out;
    sout_stream_id_t *id_video;
    block_t         *p_buffers;
321 322 323 324
    vlc_mutex_t     lock_out;
    vlc_cond_t      cond;
    picture_t *     pp_pics[PICTURE_RING_SIZE];
    int             i_first_pic, i_last_pic;
325

326
    /* Audio */
327
    vlc_fourcc_t    i_acodec;   /* codec audio (0 if not transcode) */
328
    char            *psz_aenc;
329
    sout_cfg_t      *p_audio_cfg;
330 331 332 333
    int             i_sample_rate;
    int             i_channels;
    int             i_abitrate;

334 335
    /* Video */
    vlc_fourcc_t    i_vcodec;   /* codec video (0 if not transcode) */
336
    char            *psz_venc;
337
    sout_cfg_t      *p_video_cfg;
338
    int             i_vbitrate;
339
    double          f_scale;
340
    double          f_fps;
341 342
    unsigned int    i_width, i_maxwidth;
    unsigned int    i_height, i_maxheight;
343
    vlc_bool_t      b_deinterlace;
344 345
    char            *psz_deinterlace;
    sout_cfg_t      *p_deinterlace_cfg;
346
    int             i_threads;
347
    vlc_bool_t      b_high_priority;
348
    vlc_bool_t      b_hurry_up;
349 350 351
    char            *psz_vfilters[10];
    sout_cfg_t      *p_vfilters_cfg[10];
    int             i_vfilters;
352 353 354 355 356

    int             i_crop_top;
    int             i_crop_bottom;
    int             i_crop_right;
    int             i_crop_left;
Gildas Bazin's avatar
 
Gildas Bazin committed
357

358 359 360 361 362
    /* SPU */
    vlc_fourcc_t    i_scodec;   /* codec spu (0 if not transcode) */
    char            *psz_senc;
    vlc_bool_t      b_soverlay;
    sout_cfg_t      *p_spu_cfg;
363
    spu_t           *p_spu;
364

365 366 367 368 369
    /* OSD Menu */
    sout_stream_id_t *id_osd;   /* extension for streaming OSD menus */
    vlc_fourcc_t    i_osdcodec; /* codec osd menu (0 if not transcode) */
    char            *psz_osdenc;
    sout_cfg_t      *p_osd_cfg;
370 371
    vlc_bool_t      b_es_osd;      /* VLC_TRUE when osd es is registered */
    vlc_bool_t      b_sout_osd;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
372

373
    /* Sync */
374
    vlc_bool_t      b_master_sync;
375
    mtime_t         i_master_drift;
376 377
};

378 379 380
struct decoder_owner_sys_t
{
    picture_t *pp_pics[PICTURE_RING_SIZE];
381
    sout_stream_sys_t *p_sys;
382 383 384 385
};
struct filter_owner_sys_t
{
    picture_t *pp_pics[PICTURE_RING_SIZE];
386
    sout_stream_sys_t *p_sys;
387 388
};

389 390 391 392 393 394 395
/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
    sout_stream_sys_t *p_sys;
396
    vlc_value_t       val;
397

398
    p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) );
399

Laurent Aimar's avatar
Laurent Aimar committed
400
    p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
401 402 403
    if( !p_sys->p_out )
    {
        msg_Err( p_stream, "cannot create chain" );
404
        vlc_object_destroy( p_sys );
405 406
        return VLC_EGENERIC;
    }
407

408
    p_sys->i_master_drift = 0;
409

Laurent Aimar's avatar
Laurent Aimar committed
410
    sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
411
                   p_stream->p_cfg );
412

413 414 415 416 417
    /* Audio transcoding parameters */
    var_Get( p_stream, SOUT_CFG_PREFIX "aenc", &val );
    p_sys->psz_aenc = NULL;
    p_sys->p_audio_cfg = NULL;
    if( val.psz_string && *val.psz_string )
418
    {
419
        char *psz_next;
Laurent Aimar's avatar
Laurent Aimar committed
420 421
        psz_next = sout_CfgCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
                                   val.psz_string );
422 423
        if( psz_next ) free( psz_next );
    }
424
    if( val.psz_string ) free( val.psz_string );
425 426 427 428 429 430 431

    var_Get( p_stream, SOUT_CFG_PREFIX "acodec", &val );
    p_sys->i_acodec = 0;
    if( val.psz_string && *val.psz_string )
    {
        char fcc[4] = "    ";
        memcpy( fcc, val.psz_string, __MIN( strlen( val.psz_string ), 4 ) );
432
        p_sys->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
433 434
    }
    if( val.psz_string ) free( val.psz_string );
435

436 437 438 439 440 441
    var_Get( p_stream, SOUT_CFG_PREFIX "ab", &val );
    p_sys->i_abitrate = val.i_int;
    if( p_sys->i_abitrate < 4000 ) p_sys->i_abitrate *= 1000;

    var_Get( p_stream, SOUT_CFG_PREFIX "samplerate", &val );
    p_sys->i_sample_rate = val.i_int;
442

443 444 445 446 447
    var_Get( p_stream, SOUT_CFG_PREFIX "channels", &val );
    p_sys->i_channels = val.i_int;

    if( p_sys->i_acodec )
    {
448 449 450 451 452 453 454
        if( (strncmp( (char *)&p_sys->i_acodec, "mp3", 3) == 0) &&
                            (p_sys->i_channels > 2) )
        {
            msg_Warn( p_stream, "%d channels invalid for mp3, forcing to 2",
                      p_sys->i_channels );
            p_sys->i_channels = 2;
        }                    
455 456 457
        msg_Dbg( p_stream, "codec audio=%4.4s %dHz %d channels %dKb/s",
                 (char *)&p_sys->i_acodec, p_sys->i_sample_rate,
                 p_sys->i_channels, p_sys->i_abitrate / 1000 );
458 459
    }

460
    /* Video transcoding parameters */
461 462 463 464 465 466
    var_Get( p_stream, SOUT_CFG_PREFIX "venc", &val );
    p_sys->psz_venc = NULL;
    p_sys->p_video_cfg = NULL;
    if( val.psz_string && *val.psz_string )
    {
        char *psz_next;
Laurent Aimar's avatar
Laurent Aimar committed
467 468
        psz_next = sout_CfgCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
                                   val.psz_string );
469 470 471 472
        if( psz_next ) free( psz_next );
    }
    if( val.psz_string ) free( val.psz_string );

473 474 475
    var_Get( p_stream, SOUT_CFG_PREFIX "vcodec", &val );
    p_sys->i_vcodec = 0;
    if( val.psz_string && *val.psz_string )
476 477
    {
        char fcc[4] = "    ";
478 479 480 481
        memcpy( fcc, val.psz_string, __MIN( strlen( val.psz_string ), 4 ) );
        p_sys->i_vcodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
    }
    if( val.psz_string ) free( val.psz_string );
482

483 484 485
    var_Get( p_stream, SOUT_CFG_PREFIX "vb", &val );
    p_sys->i_vbitrate = val.i_int;
    if( p_sys->i_vbitrate < 16000 ) p_sys->i_vbitrate *= 1000;
486

487 488
    var_Get( p_stream, SOUT_CFG_PREFIX "scale", &val );
    p_sys->f_scale = val.f_float;
489

490 491 492
    var_Get( p_stream, SOUT_CFG_PREFIX "fps", &val );
    p_sys->f_fps = val.f_float;

493 494 495
    var_Get( p_stream, SOUT_CFG_PREFIX "hurry-up", &val );
    p_sys->b_hurry_up = val.b_bool;

496 497
    var_Get( p_stream, SOUT_CFG_PREFIX "width", &val );
    p_sys->i_width = val.i_int;
498

499 500
    var_Get( p_stream, SOUT_CFG_PREFIX "height", &val );
    p_sys->i_height = val.i_int;
501

502 503 504 505 506 507
    var_Get( p_stream, SOUT_CFG_PREFIX "maxwidth", &val );
    p_sys->i_maxwidth = val.i_int;

    var_Get( p_stream, SOUT_CFG_PREFIX "maxheight", &val );
    p_sys->i_maxheight = val.i_int;

508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
    var_Get( p_stream, SOUT_CFG_PREFIX "vfilter", &val );
    p_sys->i_vfilters = 0;
    if( val.psz_string && *val.psz_string )
    {
        char *psz_parser = val.psz_string;

        while( psz_parser != NULL && *psz_parser != '\0' )
        {
            psz_parser = sout_CfgCreate(
                                   &p_sys->psz_vfilters[p_sys->i_vfilters],
                                   &p_sys->p_vfilters_cfg[p_sys->i_vfilters],
                                   psz_parser );
            p_sys->i_vfilters++;
            if( psz_parser != NULL && *psz_parser != '\0' ) psz_parser++;
        }
    }
    if( val.psz_string ) free( val.psz_string );
    p_sys->psz_vfilters[p_sys->i_vfilters] = NULL;
    p_sys->p_vfilters_cfg[p_sys->i_vfilters] = NULL;

528 529 530
    var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace", &val );
    p_sys->b_deinterlace = val.b_bool;

531 532 533 534 535 536 537 538 539 540 541 542 543
    var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace-module", &val );
    p_sys->psz_deinterlace = NULL;
    p_sys->p_deinterlace_cfg = NULL;
    if( val.psz_string && *val.psz_string )
    {
        char *psz_next;
        psz_next = sout_CfgCreate( &p_sys->psz_deinterlace,
                                   &p_sys->p_deinterlace_cfg,
                                   val.psz_string );
        if( psz_next ) free( psz_next );
    }
    if( val.psz_string ) free( val.psz_string );

544 545 546 547 548 549 550 551 552 553 554
    var_Get( p_stream, SOUT_CFG_PREFIX "croptop", &val );
    p_sys->i_crop_top = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "cropbottom", &val );
    p_sys->i_crop_bottom = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "cropleft", &val );
    p_sys->i_crop_left = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "cropright", &val );
    p_sys->i_crop_right = val.i_int;

    var_Get( p_stream, SOUT_CFG_PREFIX "threads", &val );
    p_sys->i_threads = val.i_int;
555 556
    var_Get( p_stream, SOUT_CFG_PREFIX "high-priority", &val );
    p_sys->b_high_priority = val.b_bool;
557 558

    if( p_sys->i_vcodec )
559
    {
560 561 562
        msg_Dbg( p_stream, "codec video=%4.4s %dx%d scaling: %f %dkb/s",
                 (char *)&p_sys->i_vcodec, p_sys->i_width, p_sys->i_height,
                 p_sys->f_scale, p_sys->i_vbitrate / 1000 );
563
    }
564

565
    /* Subpictures transcoding parameters */
566
    p_sys->p_spu = NULL;
567 568
    p_sys->psz_senc = NULL;
    p_sys->p_spu_cfg = NULL;
569 570 571
    p_sys->i_scodec = 0;

    var_Get( p_stream, SOUT_CFG_PREFIX "senc", &val );
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
    if( val.psz_string && *val.psz_string )
    {
        char *psz_next;
        psz_next = sout_CfgCreate( &p_sys->psz_senc, &p_sys->p_spu_cfg,
                                   val.psz_string );
        if( psz_next ) free( psz_next );
    }
    if( val.psz_string ) free( val.psz_string );

    var_Get( p_stream, SOUT_CFG_PREFIX "scodec", &val );
    if( val.psz_string && *val.psz_string )
    {
        char fcc[4] = "    ";
        memcpy( fcc, val.psz_string, __MIN( strlen( val.psz_string ), 4 ) );
        p_sys->i_scodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
    }
    if( val.psz_string ) free( val.psz_string );

    if( p_sys->i_scodec )
    {
592
        msg_Dbg( p_stream, "codec spu=%4.4s", (char *)&p_sys->i_scodec );
593 594 595 596
    }

    var_Get( p_stream, SOUT_CFG_PREFIX "soverlay", &val );
    p_sys->b_soverlay = val.b_bool;
597 598 599 600 601 602 603 604 605 606

    var_Get( p_stream, SOUT_CFG_PREFIX "sfilter", &val );
    if( val.psz_string && *val.psz_string )
    {
        p_sys->p_spu = spu_Create( p_stream );
        var_Create( p_sys->p_spu, "sub-filter", VLC_VAR_STRING );
        var_Set( p_sys->p_spu, "sub-filter", val );
        spu_Init( p_sys->p_spu );
    }
    if( val.psz_string ) free( val.psz_string );
607

608 609 610 611
    /* OSD menu transcoding parameters */
    p_sys->psz_osdenc = NULL;
    p_sys->p_osd_cfg  = NULL;
    p_sys->i_osdcodec = 0;
612 613 614 615 616
    p_sys->b_es_osd   = VLC_FALSE;

    var_Get( p_stream, SOUT_CFG_PREFIX "osd", &val );
    p_sys->b_sout_osd = val.b_bool;
    if( p_sys->b_sout_osd )
617
    {
618
        vlc_value_t osd_val;
619
        char *psz_next;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
620

621 622 623
        psz_next = sout_CfgCreate( &p_sys->psz_osdenc,
                                   &p_sys->p_osd_cfg, strdup( "dvbsub") );
        if( psz_next ) free( psz_next );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
624 625

        p_sys->i_osdcodec = VLC_FOURCC('Y','U','V','P' );
626 627 628 629 630

        msg_Dbg( p_stream, "codec osd=%4.4s", (char *)&p_sys->i_osdcodec );

        if( !p_sys->p_spu )
        {
631
            osd_val.psz_string = strdup("osdmenu");
632 633
            p_sys->p_spu = spu_Create( p_stream );
            var_Create( p_sys->p_spu, "sub-filter", VLC_VAR_STRING );
634
            var_Set( p_sys->p_spu, "sub-filter", osd_val );
635
            spu_Init( p_sys->p_spu );
636 637 638 639 640 641 642
            if( osd_val.psz_string ) free( osd_val.psz_string );
        }
        else
        {
            osd_val.psz_string = strdup("osdmenu");
            var_Set( p_sys->p_spu, "sub-filter", osd_val );
            if( osd_val.psz_string ) free( osd_val.psz_string );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
643
        }
644 645 646
    }

    /* Audio settings */
647
    var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val );
648 649
    p_sys->b_master_sync = val.b_bool;
    if( p_sys->f_fps > 0 ) p_sys->b_master_sync = VLC_TRUE;
650

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
    p_stream->pf_add    = Add;
    p_stream->pf_del    = Del;
    p_stream->pf_send   = Send;
    p_stream->p_sys     = p_sys;

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
    sout_stream_t       *p_stream = (sout_stream_t*)p_this;
    sout_stream_sys_t   *p_sys = p_stream->p_sys;

Laurent Aimar's avatar
Laurent Aimar committed
667
    sout_StreamDelete( p_sys->p_out );
668 669 670 671 672 673 674 675 676 677 678 679 680

    while( p_sys->p_audio_cfg != NULL )
    {
        sout_cfg_t *p_next = p_sys->p_audio_cfg->p_next;

        if( p_sys->p_audio_cfg->psz_name )
            free( p_sys->p_audio_cfg->psz_name );
        if( p_sys->p_audio_cfg->psz_value )
            free( p_sys->p_audio_cfg->psz_value );
        free( p_sys->p_audio_cfg );

        p_sys->p_audio_cfg = p_next;
    }
681
    if( p_sys->psz_aenc ) free( p_sys->psz_aenc );
682 683 684 685 686 687 688 689 690 691 692 693 694

    while( p_sys->p_video_cfg != NULL )
    {
        sout_cfg_t *p_next = p_sys->p_video_cfg->p_next;

        if( p_sys->p_video_cfg->psz_name )
            free( p_sys->p_video_cfg->psz_name );
        if( p_sys->p_video_cfg->psz_value )
            free( p_sys->p_video_cfg->psz_value );
        free( p_sys->p_video_cfg );

        p_sys->p_video_cfg = p_next;
    }
695
    if( p_sys->psz_venc ) free( p_sys->psz_venc );
696

697 698 699 700 701 702 703 704 705 706 707 708 709 710
    while( p_sys->p_deinterlace_cfg != NULL )
    {
        sout_cfg_t *p_next = p_sys->p_deinterlace_cfg->p_next;

        if( p_sys->p_deinterlace_cfg->psz_name )
            free( p_sys->p_deinterlace_cfg->psz_name );
        if( p_sys->p_deinterlace_cfg->psz_value )
            free( p_sys->p_deinterlace_cfg->psz_value );
        free( p_sys->p_deinterlace_cfg );

        p_sys->p_deinterlace_cfg = p_next;
    }
    if( p_sys->psz_deinterlace ) free( p_sys->psz_deinterlace );

711 712 713 714 715 716 717 718 719 720 721 722 723 724
    while( p_sys->p_spu_cfg != NULL )
    {
        sout_cfg_t *p_next = p_sys->p_spu_cfg->p_next;

        if( p_sys->p_spu_cfg->psz_name )
            free( p_sys->p_spu_cfg->psz_name );
        if( p_sys->p_spu_cfg->psz_value )
            free( p_sys->p_spu_cfg->psz_value );
        free( p_sys->p_spu_cfg );

        p_sys->p_spu_cfg = p_next;
    }
    if( p_sys->psz_senc ) free( p_sys->psz_senc );

725
    if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
726

727 728 729 730 731 732 733 734 735 736 737 738
    while( p_sys->p_osd_cfg != NULL )
    {
        sout_cfg_t *p_next = p_sys->p_osd_cfg->p_next;

        if( p_sys->p_osd_cfg->psz_name )
            free( p_sys->p_osd_cfg->psz_name );
        if( p_sys->p_osd_cfg->psz_value )
            free( p_sys->p_osd_cfg->psz_value );
        free( p_sys->p_osd_cfg );

        p_sys->p_osd_cfg = p_next;
    }
Jean-Paul Saman's avatar
Jean-Paul Saman committed
739
    if( p_sys->psz_osdenc ) free( p_sys->psz_osdenc );
740

741
    vlc_object_destroy( p_sys );
742 743 744 745 746
}

struct sout_stream_id_t
{
    vlc_fourcc_t  b_transcode;
747

748 749 750
    /* id of the out stream */
    void *id;

751 752 753
    /* Decoder */
    decoder_t       *p_decoder;

754 755 756
    /* Filters */
    filter_t        *pp_filter[10];
    int             i_filter;
757 758
    filter_t        *pp_vfilter[10];
    int             i_vfilter;
759

Gildas Bazin's avatar
 
Gildas Bazin committed
760
    /* Encoder */
Gildas Bazin's avatar
 
Gildas Bazin committed
761
    encoder_t       *p_encoder;
Gildas Bazin's avatar
 
Gildas Bazin committed
762

763 764
    /* Sync */
    date_t          interpolated_pts;
765 766
};

767
static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
768
{
769 770
    sout_stream_sys_t *p_sys = p_stream->p_sys;
    sout_stream_id_t *id;
771 772

    id = malloc( sizeof( sout_stream_id_t ) );
773 774
    memset( id, 0, sizeof(sout_stream_id_t) );

Gildas Bazin's avatar
 
Gildas Bazin committed
775
    id->id = NULL;
776
    id->p_decoder = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
777 778
    id->p_encoder = NULL;

779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
    /* Create decoder object */
    id->p_decoder = vlc_object_create( p_stream, VLC_OBJECT_DECODER );
    if( !id->p_decoder )
    {
        msg_Err( p_stream, "out of memory" );
        goto error;
    }
    vlc_object_attach( id->p_decoder, p_stream );
    id->p_decoder->p_module = NULL;
    id->p_decoder->fmt_in = *p_fmt;
    id->p_decoder->b_pace_control = VLC_TRUE;

    /* Create encoder object */
    id->p_encoder = vlc_object_create( p_stream, VLC_OBJECT_ENCODER );
    if( !id->p_encoder )
    {
        msg_Err( p_stream, "out of memory" );
        goto error;
    }
    vlc_object_attach( id->p_encoder, p_stream );
    id->p_encoder->p_module = NULL;
800 801

    /* Create destination format */
802 803 804 805 806
    es_format_Init( &id->p_encoder->fmt_out, p_fmt->i_cat, 0 );
    id->p_encoder->fmt_out.i_id    = p_fmt->i_id;
    id->p_encoder->fmt_out.i_group = p_fmt->i_group;
    if( p_fmt->psz_language )
        id->p_encoder->fmt_out.psz_language = strdup( p_fmt->psz_language );
807

808
    if( p_fmt->i_cat == AUDIO_ES && (p_sys->i_acodec || p_sys->psz_aenc) )
809 810 811
    {
        msg_Dbg( p_stream,
                 "creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
812 813 814
                 (char*)&p_fmt->i_codec, (char*)&p_sys->i_acodec );

        /* Complete destination format */
815 816 817 818 819 820
        id->p_encoder->fmt_out.i_codec = p_sys->i_acodec;
        id->p_encoder->fmt_out.audio.i_rate = p_sys->i_sample_rate > 0 ?
            p_sys->i_sample_rate : (int)p_fmt->audio.i_rate;
        id->p_encoder->fmt_out.i_bitrate = p_sys->i_abitrate;
        id->p_encoder->fmt_out.audio.i_bitspersample =
            p_fmt->audio.i_bitspersample;
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
        id->p_encoder->fmt_out.audio.i_channels = p_sys->i_channels > 0 ?
            p_sys->i_channels : p_fmt->audio.i_channels;
        /* Sanity check for audio channels */
        id->p_encoder->fmt_out.audio.i_channels =
            __MIN( id->p_encoder->fmt_out.audio.i_channels,
                   id->p_decoder->fmt_in.audio.i_channels );
        id->p_encoder->fmt_out.audio.i_original_channels =
            id->p_decoder->fmt_in.audio.i_physical_channels;
        if( id->p_decoder->fmt_in.audio.i_channels ==
            id->p_encoder->fmt_out.audio.i_channels )
        {
            id->p_encoder->fmt_out.audio.i_physical_channels =
                id->p_decoder->fmt_in.audio.i_physical_channels;
        }
        else
        {
            id->p_encoder->fmt_out.audio.i_physical_channels =
                pi_channels_maps[id->p_encoder->fmt_out.audio.i_channels];
        }
840 841 842

        /* Build decoder -> filter -> encoder chain */
        if( transcode_audio_new( p_stream, id ) )
843 844
        {
            msg_Err( p_stream, "cannot create audio chain" );
845
            goto error;
846 847
        }

848 849
        /* Open output stream */
        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
850
        id->b_transcode = VLC_TRUE;
851

852 853 854 855 856
        if( !id->id )
        {
            transcode_audio_close( p_stream, id );
            goto error;
        }
857 858

        date_Init( &id->interpolated_pts, p_fmt->audio.i_rate, 1 );
859
    }
860 861
    else if( p_fmt->i_cat == VIDEO_ES &&
             (p_sys->i_vcodec != 0 || p_sys->psz_venc) )
862 863 864
    {
        msg_Dbg( p_stream,
                 "creating video transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
865
                 (char*)&p_fmt->i_codec, (char*)&p_sys->i_vcodec );
866

867
        /* Complete destination format */
868 869 870 871
        id->p_encoder->fmt_out.i_codec = p_sys->i_vcodec;
        id->p_encoder->fmt_out.video.i_width  = p_sys->i_width;
        id->p_encoder->fmt_out.video.i_height = p_sys->i_height;
        id->p_encoder->fmt_out.i_bitrate = p_sys->i_vbitrate;
872

873 874
        /* Build decoder -> filter -> encoder chain */
        if( transcode_video_new( p_stream, id ) )
875 876
        {
            msg_Err( p_stream, "cannot create video chain" );
877
            goto error;
878
        }
879 880 881

        /* Stream will be added later on because we don't know
         * all the characteristics of the decoded stream yet */
882
        id->b_transcode = VLC_TRUE;
883

884
        if( p_sys->f_fps > 0 )
885
        {
886
            id->p_encoder->fmt_out.video.i_frame_rate =
887
                (p_sys->f_fps * 1001) + 0.5;
888
            id->p_encoder->fmt_out.video.i_frame_rate_base = 1001;
889
        }
890
    }
891 892 893 894 895 896
    else if( p_fmt->i_cat == SPU_ES && (p_sys->i_scodec || p_sys->psz_senc) )
    {
        msg_Dbg( p_stream, "creating subtitles transcoding from fcc=`%4.4s' "
                 "to fcc=`%4.4s'", (char*)&p_fmt->i_codec,
                 (char*)&p_sys->i_scodec );

897
        /* Complete destination format */
898
        id->p_encoder->fmt_out.i_codec = p_sys->i_scodec;
899 900 901 902 903

        /* build decoder -> filter -> encoder */
        if( transcode_spu_new( p_stream, id ) )
        {
            msg_Err( p_stream, "cannot create subtitles chain" );
904
            goto error;
905 906 907
        }

        /* open output stream */
908
        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
909 910
        id->b_transcode = VLC_TRUE;

911 912 913 914 915
        if( !id->id )
        {
            transcode_spu_close( p_stream, id );
            goto error;
        }
916 917 918 919 920 921 922 923
    }
    else if( p_fmt->i_cat == SPU_ES && p_sys->b_soverlay )
    {
        msg_Dbg( p_stream, "subtitles (fcc=`%4.4s') overlaying",
                 (char*)&p_fmt->i_codec );

        id->b_transcode = VLC_TRUE;

924
        /* Build decoder -> filter -> overlaying chain */
925 926 927
        if( transcode_spu_new( p_stream, id ) )
        {
            msg_Err( p_stream, "cannot create subtitles chain" );
928
            goto error;
929 930
        }
    }
931 932
    else
    {
933 934
        msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
                 (char*)&p_fmt->i_codec );
935 936 937
        id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
        id->b_transcode = VLC_FALSE;

938
        if( !id->id ) goto error;
939 940
    }

941
    if( p_sys->b_sout_osd )
942 943
    {
        /* Create a fake OSD menu elementary stream */
944
        if( !p_sys->b_es_osd && (p_sys->i_osdcodec != 0 || p_sys->psz_osdenc) )
945 946 947 948 949 950
        {
            if( transcode_osd_new( p_stream, p_sys->id_osd ) )
            {
                msg_Err( p_stream, "cannot create osd chain" );
                goto error;
            }
951
            p_sys->b_es_osd = VLC_TRUE;
952 953
        }
    }
954
    return id;
955 956 957 958 959 960 961 962 963 964 965

 error:
    if( id->p_decoder )
    {
        vlc_object_detach( id->p_decoder );
        vlc_object_destroy( id->p_decoder );
    }

    if( id->p_encoder )
    {
        vlc_object_detach( id->p_encoder );
966
        es_format_Clean( &id->p_encoder->fmt_out );
967 968 969 970 971
        vlc_object_destroy( id->p_encoder );
    }

    free( id );
    return NULL;
972 973
}

974
static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
975
{
976
    sout_stream_sys_t *p_sys = p_stream->p_sys;
977

978
    if( p_sys->b_es_osd )
979 980
        transcode_osd_close( p_stream, p_sys->id_osd );

981 982
    if( id->b_transcode )
    {
983
        switch( id->p_decoder->fmt_in.i_cat )
984
        {
985 986 987 988 989 990 991
        case AUDIO_ES:
            transcode_audio_close( p_stream, id );
            break;
        case VIDEO_ES:
            transcode_video_close( p_stream, id );
            break;
        case SPU_ES:
992
            transcode_spu_close( p_stream, id );
993
            break;
994
        }
995 996
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
997
    if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id );
998 999 1000 1001 1002 1003 1004 1005 1006 1007

    if( id->p_decoder )
    {
        vlc_object_detach( id->p_decoder );
        vlc_object_destroy( id->p_decoder );
    }

    if( id->p_encoder )
    {
        vlc_object_detach( id->p_encoder );
1008
        es_format_Clean( &id->p_encoder->fmt_out );
1009 1010 1011
        vlc_object_destroy( id->p_encoder );
    }

1012 1013 1014 1015 1016
    free( id );

    return VLC_SUCCESS;
}

Gildas Bazin's avatar
 
Gildas Bazin committed
1017
static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
1018
                 block_t *p_buffer )
1019
{
1020
    sout_stream_sys_t *p_sys = p_stream->p_sys;
1021
    block_t *p_out = NULL;
1022

1023 1024
    if( !id->b_transcode && id->id )
    {
1025
        /* Transcode OSD menu pictures. */
1026
        if( p_sys->b_es_osd )
1027 1028 1029
        {
            transcode_osd_process( p_stream, id, p_buffer, &p_out );                
        }
1030 1031 1032 1033 1034 1035 1036 1037 1038
        return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_buffer );
    }
    else if( !id->b_transcode )
    {
        block_Release( p_buffer );
        return VLC_EGENERIC;
    }

    switch( id->p_decoder->fmt_in.i_cat )
1039
    {
1040 1041 1042
    case AUDIO_ES:
        transcode_audio_process( p_stream, id, p_buffer, &p_out );
        break;
1043

1044 1045 1046
    case VIDEO_ES:
        if( transcode_video_process( p_stream, id, p_buffer, &p_out )
            != VLC_SUCCESS )