transcode.c 100 KB
Newer Older
1
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
2
 * transcode.c: transcoding stream output module
3
 *****************************************************************************
4
 * Copyright (C) 2003-2008 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
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
29 30 31 32
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

33
#include <vlc/vlc.h>
Clément Stenac's avatar
Clément Stenac committed
34 35 36 37 38 39
#include <vlc_input.h>
#include <vlc_sout.h>
#include <vlc_aout.h>
#include <vlc_vout.h>
#include <vlc_codec.h>
#include <vlc_block.h>
40 41
#include <vlc_filter.h>
#include <vlc_osd.h>
42

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
43 44
#include <math.h>

45 46
#define MASTER_SYNC_MAX_DRIFT 100000

47
/*****************************************************************************
48
 * Module descriptor
49
 *****************************************************************************/
50 51
#define VENC_TEXT N_("Video encoder")
#define VENC_LONGTEXT N_( \
52 53
    "This is the video encoder module that will be used (and its associated "\
    "options).")
54 55
#define VCODEC_TEXT N_("Destination video codec")
#define VCODEC_LONGTEXT N_( \
56
    "This is the video codec that will be used.")
57 58
#define VB_TEXT N_("Video bitrate")
#define VB_LONGTEXT N_( \
59
    "Target bitrate of the transcoded video stream." )
60 61
#define SCALE_TEXT N_("Video scaling")
#define SCALE_LONGTEXT N_( \
62
    "Scale factor to apply to the video while transcoding (eg: 0.25)")
63 64
#define FPS_TEXT N_("Video frame-rate")
#define FPS_LONGTEXT N_( \
65
    "Target output frame rate for the video stream." )
66 67
#define DEINTERLACE_TEXT N_("Deinterlace video")
#define DEINTERLACE_LONGTEXT N_( \
68
    "Deinterlace the video before encoding." )
69 70
#define DEINTERLACE_MODULE_TEXT N_("Deinterlace module")
#define DEINTERLACE_MODULE_LONGTEXT N_( \
71
    "Specify the deinterlace module to use." )
72 73
#define WIDTH_TEXT N_("Video width")
#define WIDTH_LONGTEXT N_( \
74
    "Output video width." )
75 76
#define HEIGHT_TEXT N_("Video height")
#define HEIGHT_LONGTEXT N_( \
77
    "Output video height." )
78 79
#define MAXWIDTH_TEXT N_("Maximum video width")
#define MAXWIDTH_LONGTEXT N_( \
80
    "Maximum output video width." )
81 82
#define MAXHEIGHT_TEXT N_("Maximum video height")
#define MAXHEIGHT_LONGTEXT N_( \
83
    "Maximum output video height." )
84 85
#define VFILTER_TEXT N_("Video filter")
#define VFILTER_LONGTEXT N_( \
86 87
    "Video filters will be applied to the video streams (after overlays " \
    "are applied). You must enter a comma-separated list of filters." )
88

89
#define CROPTOP_TEXT N_("Video crop (top)")
90
#define CROPTOP_LONGTEXT N_( \
91 92
    "Number of pixels to crop at the top of the video." )
#define CROPLEFT_TEXT N_("Video crop (left)")
93
#define CROPLEFT_LONGTEXT N_( \
94 95
    "Number of pixels to crop at the left of the video." )
#define CROPBOTTOM_TEXT N_("Video crop (bottom)")
96
#define CROPBOTTOM_LONGTEXT N_( \
97 98
    "Number of pixels to crop at the bottom of the video." )
#define CROPRIGHT_TEXT N_("Video crop (right)")
99
#define CROPRIGHT_LONGTEXT N_( \
100
    "Number of pixels to crop at the right of the video." )
101

102
#define PADDTOP_TEXT N_("Video padding (top)")
103
#define PADDTOP_LONGTEXT N_( \
104 105
    "Size of the black border to add at the top of the video." )
#define PADDLEFT_TEXT N_("Video padding (left)")
106
#define PADDLEFT_LONGTEXT N_( \
107 108
    "Size of the black border to add at the left of the video." )
#define PADDBOTTOM_TEXT N_("Video padding (bottom)")
109
#define PADDBOTTOM_LONGTEXT N_( \
110 111
    "Size of the black border to add at the bottom of the video." )
#define PADDRIGHT_TEXT N_("Video padding (right)")
112
#define PADDRIGHT_LONGTEXT N_( \
113
    "Size of the black border to add at the right of the video." )
114 115 116

#define CANVAS_WIDTH_TEXT N_("Video canvas width")
#define CANVAS_WIDTH_LONGTEXT N_( \
117
    "This will automatically crod and pad the video to a specified width." )
118 119
#define CANVAS_HEIGHT_TEXT N_("Video canvas height")
#define CANVAS_HEIGHT_LONGTEXT N_( \
120
    "This will automatically crod and pad the video to a specified height." )
121 122
#define CANVAS_ASPECT_TEXT N_("Video canvas aspect ratio")
#define CANVAS_ASPECT_LONGTEXT N_( \
123 124
    "This sets aspect (like 4:3) of the video canvas and letterbox the video "\
    "accordingly." )
125

126 127
#define AENC_TEXT N_("Audio encoder")
#define AENC_LONGTEXT N_( \
128 129
    "This is the audio encoder module that will be used (and its associated "\
    "options).")
130 131
#define ACODEC_TEXT N_("Destination audio codec")
#define ACODEC_LONGTEXT N_( \
132
    "This is the audio codec that will be used.")
133 134
#define AB_TEXT N_("Audio bitrate")
#define AB_LONGTEXT N_( \
135
    "Target bitrate of the transcoded audio stream." )
136 137
#define ARATE_TEXT N_("Audio sample rate")
#define ARATE_LONGTEXT N_( \
138
 "Sample rate of the transcoded audio stream (11250, 22500, 44100 or 48000).")
139 140
#define ACHANS_TEXT N_("Audio channels")
#define ACHANS_LONGTEXT N_( \
141
    "Number of audio channels in the transcoded streams." )
142 143 144 145
#define AFILTER_TEXT N_("Audio filter")
#define AFILTER_LONGTEXT N_( \
    "Audio filters will be applied to the audio streams (after conversion " \
    "filters are applied). You must enter a comma-separated list of filters." )
146

147 148
#define SENC_TEXT N_("Subtitles encoder")
#define SENC_LONGTEXT N_( \
149 150
    "This is the subtitles encoder module that will be used (and its " \
    "associated options)." )
151 152
#define SCODEC_TEXT N_("Destination subtitles codec")
#define SCODEC_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
153
    "This is the subtitles codec that will be used." )
154 155

#define SFILTER_TEXT N_("Overlays")
156
#define SFILTER_LONGTEXT N_( \
157 158 159 160
    "This allows you to add overlays (also known as \"subpictures\" on the "\
    "transcoded video stream. The subpictures produced by the filters will "\
    "be overlayed directly onto the video. You must specify a comma-separated "\
    "list of subpicture modules" )
161

162 163
#define OSD_TEXT N_("OSD menu")
#define OSD_LONGTEXT N_(\
164
    "Stream the On Screen Display menu (using the osdmenu subpicture module)." )
165

166 167
#define THREADS_TEXT N_("Number of threads")
#define THREADS_LONGTEXT N_( \
168
    "Number of threads used for the transcoding." )
169 170 171 172
#define HP_TEXT N_("High priority")
#define HP_LONGTEXT N_( \
    "Runs the optional encoder thread at the OUTPUT priority instead of " \
    "VIDEO." )
173

174 175 176 177 178
#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." )

179
#define HURRYUP_TEXT N_( "Hurry up" )
180 181
#define HURRYUP_LONGTEXT N_( "The transcoder will drop frames if your CPU " \
                "can't keep up with the encoding rate." )
182

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
183
static const char *ppsz_deinterlace_type[] =
184 185 186 187
{
    "deinterlace", "ffmpeg-deinterlace"
};

188 189 190
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

191 192
#define SOUT_CFG_PREFIX "sout-transcode-"

193
vlc_module_begin();
194
    set_shortname( _("Transcode"));
195 196 197 198
    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
199 200
    set_category( CAT_SOUT );
    set_subcategory( SUBCAT_SOUT_STREAM );
201
    set_section( N_("Video"), NULL );
202
    add_string( SOUT_CFG_PREFIX "venc", NULL, NULL, VENC_TEXT,
203
                VENC_LONGTEXT, false );
204
    add_string( SOUT_CFG_PREFIX "vcodec", NULL, NULL, VCODEC_TEXT,
205
                VCODEC_LONGTEXT, false );
206
    add_integer( SOUT_CFG_PREFIX "vb", 800 * 1000, NULL, VB_TEXT,
207
                 VB_LONGTEXT, false );
208
    add_float( SOUT_CFG_PREFIX "scale", 1, NULL, SCALE_TEXT,
209
               SCALE_LONGTEXT, false );
210
    add_float( SOUT_CFG_PREFIX "fps", 0, NULL, FPS_TEXT,
211 212 213
               FPS_LONGTEXT, false );
    add_bool( SOUT_CFG_PREFIX "hurry-up", true, NULL, HURRYUP_TEXT,
               HURRYUP_LONGTEXT, false );
214
    add_bool( SOUT_CFG_PREFIX "deinterlace", 0, NULL, DEINTERLACE_TEXT,
215
              DEINTERLACE_LONGTEXT, false );
216 217
    add_string( SOUT_CFG_PREFIX "deinterlace-module", "deinterlace", NULL,
                DEINTERLACE_MODULE_TEXT, DEINTERLACE_MODULE_LONGTEXT,
218
                false );
219
        change_string_list( ppsz_deinterlace_type, 0, 0 );
220
    add_integer( SOUT_CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
221
                 WIDTH_LONGTEXT, true );
222
    add_integer( SOUT_CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
223
                 HEIGHT_LONGTEXT, true );
224
    add_integer( SOUT_CFG_PREFIX "maxwidth", 0, NULL, MAXWIDTH_TEXT,
225
                 MAXWIDTH_LONGTEXT, true );
226
    add_integer( SOUT_CFG_PREFIX "maxheight", 0, NULL, MAXHEIGHT_TEXT,
227
                 MAXHEIGHT_LONGTEXT, true );
228
    add_module_list( SOUT_CFG_PREFIX "vfilter", "video filter2",
229
                     NULL, NULL,
230
                     VFILTER_TEXT, VFILTER_LONGTEXT, false );
231 232

    add_integer( SOUT_CFG_PREFIX "croptop", 0, NULL, CROPTOP_TEXT,
233
                 CROPTOP_LONGTEXT, true );
234
    add_integer( SOUT_CFG_PREFIX "cropleft", 0, NULL, CROPLEFT_TEXT,
235
                 CROPLEFT_LONGTEXT, true );
236
    add_integer( SOUT_CFG_PREFIX "cropbottom", 0, NULL, CROPBOTTOM_TEXT,
237
                 CROPBOTTOM_LONGTEXT, true );
238
    add_integer( SOUT_CFG_PREFIX "cropright", 0, NULL, CROPRIGHT_TEXT,
239
                 CROPRIGHT_LONGTEXT, true );
240

241
    add_integer( SOUT_CFG_PREFIX "paddtop", 0, NULL, PADDTOP_TEXT,
242
                 PADDTOP_LONGTEXT, true );
243
    add_integer( SOUT_CFG_PREFIX "paddleft", 0, NULL, PADDLEFT_TEXT,
244
                 PADDLEFT_LONGTEXT, true );
245
    add_integer( SOUT_CFG_PREFIX "paddbottom", 0, NULL, PADDBOTTOM_TEXT,
246
                 PADDBOTTOM_LONGTEXT, true );
247
    add_integer( SOUT_CFG_PREFIX "paddright", 0, NULL, PADDRIGHT_TEXT,
248
                 PADDRIGHT_LONGTEXT, true );
249 250

    add_integer( SOUT_CFG_PREFIX "canvas-width", 0, NULL, CANVAS_WIDTH_TEXT,
251
                 CANVAS_WIDTH_LONGTEXT, true );
252
    add_integer( SOUT_CFG_PREFIX "canvas-height", 0, NULL, CANVAS_HEIGHT_TEXT,
253
                 CANVAS_HEIGHT_LONGTEXT, true );
254
    add_string( SOUT_CFG_PREFIX "canvas-aspect", NULL, NULL, CANVAS_ASPECT_TEXT,
255
                CANVAS_ASPECT_LONGTEXT, false );
256

257
    set_section( N_("Audio"), NULL );
258
    add_string( SOUT_CFG_PREFIX "aenc", NULL, NULL, AENC_TEXT,
259
                AENC_LONGTEXT, false );
260
    add_string( SOUT_CFG_PREFIX "acodec", NULL, NULL, ACODEC_TEXT,
261
                ACODEC_LONGTEXT, false );
262
    add_integer( SOUT_CFG_PREFIX "ab", 0, NULL, AB_TEXT,
263
                 AB_LONGTEXT, false );
264
    add_integer( SOUT_CFG_PREFIX "channels", 0, NULL, ACHANS_TEXT,
265
                 ACHANS_LONGTEXT, false );
266
    add_integer( SOUT_CFG_PREFIX "samplerate", 0, NULL, ARATE_TEXT,
267
                 ARATE_LONGTEXT, true );
268
    add_bool( SOUT_CFG_PREFIX "audio-sync", 0, NULL, ASYNC_TEXT,
269
              ASYNC_LONGTEXT, false );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
270
    add_module_list( SOUT_CFG_PREFIX "afilter",  "audio filter2",
271
                     NULL, NULL,
272
                     AFILTER_TEXT, AFILTER_LONGTEXT, false );
273

274
    set_section( N_("Overlays/Subtitles"), NULL );
275
    add_string( SOUT_CFG_PREFIX "senc", NULL, NULL, SENC_TEXT,
276
                SENC_LONGTEXT, false );
277
    add_string( SOUT_CFG_PREFIX "scodec", NULL, NULL, SCODEC_TEXT,
278
                SCODEC_LONGTEXT, false );
279
    add_bool( SOUT_CFG_PREFIX "soverlay", 0, NULL, SCODEC_TEXT,
280
               SCODEC_LONGTEXT, false );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
281
    add_module_list( SOUT_CFG_PREFIX "sfilter", "video filter",
282
                     NULL, NULL,
283
                     SFILTER_TEXT, SFILTER_LONGTEXT, false );
284

285 286
    set_section( N_("On Screen Display"), NULL );
    add_bool( SOUT_CFG_PREFIX "osd", 0, NULL, OSD_TEXT,
287
              OSD_LONGTEXT, false );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
288

289
    set_section( N_("Miscellaneous"), NULL );
290
    add_integer( SOUT_CFG_PREFIX "threads", 0, NULL, THREADS_TEXT,
291
                 THREADS_LONGTEXT, true );
292
    add_bool( SOUT_CFG_PREFIX "high-priority", 0, NULL, HP_TEXT, HP_LONGTEXT,
293
              true );
294

295
vlc_module_end();
296

297 298
static const char *ppsz_sout_options[] = {
    "venc", "vcodec", "vb", "croptop", "cropbottom", "cropleft", "cropright",
Antoine Cellerier's avatar
Antoine Cellerier committed
299 300
    "paddtop", "paddbottom", "paddleft", "paddright",
    "canvas-width", "canvas-height", "canvas-aspect",
301 302
    "scale", "fps", "width", "height", "vfilter", "deinterlace",
    "deinterlace-module", "threads", "hurry-up", "aenc", "acodec", "ab",
303 304 305
    "afilter", "samplerate", "channels", "senc", "scodec", "soverlay",
    "sfilter", "osd", "audio-sync", "high-priority", "maxwidth", "maxheight",
    NULL
306 307
};

308 309 310
/*****************************************************************************
 * Exported prototypes
 *****************************************************************************/
311
static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
312
static int               Del ( sout_stream_t *, sout_stream_id_t * );
313
static int               Send( sout_stream_t *, sout_stream_id_t *, block_t* );
314

315
static int  transcode_audio_new    ( sout_stream_t *, sout_stream_id_t * );
Rafaël Carré's avatar
Rafaël Carré committed
316
static void transcode_audio_close  ( sout_stream_id_t * );
317 318 319
static int  transcode_audio_process( sout_stream_t *, sout_stream_id_t *,
                                     block_t *, block_t ** );

320 321 322
static aout_buffer_t *audio_new_buffer( decoder_t *, int );
static void audio_del_buffer( decoder_t *, aout_buffer_t * );

323 324 325 326 327 328
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 ** );

329 330 331 332 333 334 335
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
336

337
static int  transcode_spu_new    ( sout_stream_t *, sout_stream_id_t * );
Rafaël Carré's avatar
Rafaël Carré committed
338
static void transcode_spu_close  ( sout_stream_id_t * );
339 340 341
static int  transcode_spu_process( sout_stream_t *, sout_stream_id_t *,
                                   block_t *, block_t ** );

342 343 344 345
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
346

347 348
static int  EncoderThread( struct sout_stream_sys_t * p_sys );

Gildas Bazin's avatar
 
Gildas Bazin committed
349 350 351 352 353 354 355 356 357 358 359
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
};

360
#define PICTURE_RING_SIZE 64
361
#define SUBPICTURE_RING_SIZE 20
362
#define TRANSCODE_FILTERS 10
363

364 365
struct sout_stream_sys_t
{
366 367
    VLC_COMMON_MEMBERS

368 369 370
    sout_stream_t   *p_out;
    sout_stream_id_t *id_video;
    block_t         *p_buffers;
371 372 373 374
    vlc_mutex_t     lock_out;
    vlc_cond_t      cond;
    picture_t *     pp_pics[PICTURE_RING_SIZE];
    int             i_first_pic, i_last_pic;
375

376
    /* Audio */
377
    vlc_fourcc_t    i_acodec;   /* codec audio (0 if not transcode) */
378
    char            *psz_aenc;
379
    config_chain_t  *p_audio_cfg;
380 381
    uint32_t        i_sample_rate;
    uint32_t        i_channels;
382
    int             i_abitrate;
383
    char            *psz_afilters[TRANSCODE_FILTERS];
384
    config_chain_t  *p_afilters_cfg[TRANSCODE_FILTERS];
385
    int             i_afilters;
386

387 388
    /* Video */
    vlc_fourcc_t    i_vcodec;   /* codec video (0 if not transcode) */
389
    char            *psz_venc;
390
    config_chain_t  *p_video_cfg;
391
    int             i_vbitrate;
392
    double          f_scale;
393
    double          f_fps;
394 395
    unsigned int    i_width, i_maxwidth;
    unsigned int    i_height, i_maxheight;
396
    bool      b_deinterlace;
397
    char            *psz_deinterlace;
398
    config_chain_t  *p_deinterlace_cfg;
399
    int             i_threads;
400 401
    bool      b_high_priority;
    bool      b_hurry_up;
402
    char            *psz_vfilters[TRANSCODE_FILTERS];
403
    config_chain_t  *p_vfilters_cfg[TRANSCODE_FILTERS];
404
    int             i_vfilters;
405 406 407 408 409

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

411 412 413 414 415 416 417 418
    int             i_padd_top;
    int             i_padd_bottom;
    int             i_padd_right;
    int             i_padd_left;

    int             i_canvas_width;
    int             i_canvas_height;
    int             i_canvas_aspect;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
419

420 421 422 423 424 425 426 427 428 429 430
    /* Video, calculated */
    int             i_src_x_offset;
    int             i_src_y_offset;
    int             i_crop_width;
    int             i_crop_height;

    int             i_dst_x_offset;
    int             i_dst_y_offset;
    int             i_nopadd_width;
    int             i_nopadd_height;

431 432 433
    /* SPU */
    vlc_fourcc_t    i_scodec;   /* codec spu (0 if not transcode) */
    char            *psz_senc;
434
    bool      b_soverlay;
435
    config_chain_t  *p_spu_cfg;
436
    spu_t           *p_spu;
437

438 439 440
    /* OSD Menu */
    vlc_fourcc_t    i_osdcodec; /* codec osd menu (0 if not transcode) */
    char            *psz_osdenc;
441
    config_chain_t  *p_osd_cfg;
442
    bool      b_osd;   /* true when osd es is registered */
Jean-Paul Saman's avatar
Jean-Paul Saman committed
443

444
    /* Sync */
445
    bool      b_master_sync;
446
    mtime_t         i_master_drift;
447 448
};

449 450 451
struct decoder_owner_sys_t
{
    picture_t *pp_pics[PICTURE_RING_SIZE];
452
    sout_stream_sys_t *p_sys;
453 454 455 456
};
struct filter_owner_sys_t
{
    picture_t *pp_pics[PICTURE_RING_SIZE];
457
    sout_stream_sys_t *p_sys;
458 459
};

460 461 462 463 464 465 466
/*****************************************************************************
 * 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;
467
    vlc_value_t       val;
468

469
    p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) );
470

Laurent Aimar's avatar
Laurent Aimar committed
471
    p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
472 473 474
    if( !p_sys->p_out )
    {
        msg_Err( p_stream, "cannot create chain" );
475
        vlc_object_release( p_sys );
476 477
        return VLC_EGENERIC;
    }
478

479
    p_sys->i_master_drift = 0;
480

481
    config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
482
                   p_stream->p_cfg );
483

484 485 486 487 488
    /* 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 )
489
    {
490
        char *psz_next;
491 492
        psz_next = config_ChainCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
                                       val.psz_string );
493
        free( psz_next );
494
    }
495
    free( val.psz_string );
496 497 498 499 500 501 502

    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 ) );
503
        p_sys->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
504
    }
505
    free( val.psz_string );
506

507 508 509 510 511 512
    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;
513

514 515 516 517 518
    var_Get( p_stream, SOUT_CFG_PREFIX "channels", &val );
    p_sys->i_channels = val.i_int;

    if( p_sys->i_acodec )
    {
519 520
        if( p_sys->i_acodec == VLC_FOURCC('m','p','3',0) &&
            p_sys->i_channels > 2 )
521 522 523 524
        {
            msg_Warn( p_stream, "%d channels invalid for mp3, forcing to 2",
                      p_sys->i_channels );
            p_sys->i_channels = 2;
525
        }
526 527 528
        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 );
529 530
    }

531 532 533 534 535 536 537 538 539
    var_Get( p_stream, SOUT_CFG_PREFIX "afilter", &val );
    p_sys->i_afilters = 0;
    if( val.psz_string && *val.psz_string )
    {
        char *psz_parser = val.psz_string;

        while( (psz_parser != NULL) && (*psz_parser != '\0')
                && (p_sys->i_afilters < TRANSCODE_FILTERS) )
        {
540
            psz_parser = config_ChainCreate(
541 542 543 544 545 546 547
                                   &p_sys->psz_afilters[p_sys->i_afilters],
                                   &p_sys->p_afilters_cfg[p_sys->i_afilters],
                                   psz_parser );
            p_sys->i_afilters++;
            if( (psz_parser != NULL) && (*psz_parser != '\0') ) psz_parser++;
        }
    }
548
    free( val.psz_string );
549 550 551 552 553 554
    if( p_sys->i_afilters < TRANSCODE_FILTERS-1 )
    {
        p_sys->psz_afilters[p_sys->i_afilters] = NULL;
        p_sys->p_afilters_cfg[p_sys->i_afilters] = NULL;
    }

555
    /* Video transcoding parameters */
556 557 558 559 560 561
    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;
562
        psz_next = config_ChainCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
Laurent Aimar's avatar
Laurent Aimar committed
563
                                   val.psz_string );
564
        free( psz_next );
565
    }
566
    free( val.psz_string );
567

568 569 570
    var_Get( p_stream, SOUT_CFG_PREFIX "vcodec", &val );
    p_sys->i_vcodec = 0;
    if( val.psz_string && *val.psz_string )
571 572
    {
        char fcc[4] = "    ";
573 574 575
        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] );
    }
576
    free( val.psz_string );
577

578 579 580
    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;
581

582 583
    var_Get( p_stream, SOUT_CFG_PREFIX "scale", &val );
    p_sys->f_scale = val.f_float;
584

585 586 587
    var_Get( p_stream, SOUT_CFG_PREFIX "fps", &val );
    p_sys->f_fps = val.f_float;

588 589 590
    var_Get( p_stream, SOUT_CFG_PREFIX "hurry-up", &val );
    p_sys->b_hurry_up = val.b_bool;

591 592
    var_Get( p_stream, SOUT_CFG_PREFIX "width", &val );
    p_sys->i_width = val.i_int;
593

594 595
    var_Get( p_stream, SOUT_CFG_PREFIX "height", &val );
    p_sys->i_height = val.i_int;
596

597 598 599 600 601 602
    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;

603 604 605 606 607 608
    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;

609 610
        while( (psz_parser != NULL) && (*psz_parser != '\0')
                && (p_sys->i_vfilters < TRANSCODE_FILTERS) )
611
        {
612
            psz_parser = config_ChainCreate(
613 614 615 616 617 618 619
                                   &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++;
        }
    }
620
    free( val.psz_string );
621 622 623 624 625
    if( p_sys->i_vfilters < TRANSCODE_FILTERS-1 )
    {
        p_sys->psz_vfilters[p_sys->i_vfilters] = NULL;
        p_sys->p_vfilters_cfg[p_sys->i_vfilters] = NULL;
    }
626

627 628 629
    var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace", &val );
    p_sys->b_deinterlace = val.b_bool;

630 631 632 633 634 635
    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;
636
        psz_next = config_ChainCreate( &p_sys->psz_deinterlace,
637 638
                                   &p_sys->p_deinterlace_cfg,
                                   val.psz_string );
639
        free( psz_next );
640
    }
641
    free( val.psz_string );
642

643 644 645 646 647 648 649 650 651
    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;

652 653 654 655 656 657 658 659
    var_Get( p_stream, SOUT_CFG_PREFIX "paddtop", &val );
    p_sys->i_padd_top = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "paddbottom", &val );
    p_sys->i_padd_bottom = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "paddleft", &val );
    p_sys->i_padd_left = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "paddright", &val );
    p_sys->i_padd_right = val.i_int;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
660

661 662 663 664
    var_Get( p_stream, SOUT_CFG_PREFIX "canvas-width", &val );
    p_sys->i_canvas_width = val.i_int;
    var_Get( p_stream, SOUT_CFG_PREFIX "canvas-height", &val );
    p_sys->i_canvas_height = val.i_int;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
665

666
    var_Get( p_stream, SOUT_CFG_PREFIX "canvas-aspect", &val );
667 668
    p_sys->i_canvas_aspect = 0;
    if( val.psz_string && *val.psz_string )
669 670 671 672 673
    {
        char *psz_parser = strchr( val.psz_string, ':' );
        if( psz_parser )
        {
            *psz_parser++ = '\0';
674 675
            p_sys->i_canvas_aspect = atoi( val.psz_string ) *
                VOUT_ASPECT_FACTOR / atoi( psz_parser );
676
        }
677
        else msg_Warn( p_stream, "bad aspect ratio %s", val.psz_string );
678 679

    }
680
    free( val.psz_string );
681

682 683
    var_Get( p_stream, SOUT_CFG_PREFIX "threads", &val );
    p_sys->i_threads = val.i_int;
684 685
    var_Get( p_stream, SOUT_CFG_PREFIX "high-priority", &val );
    p_sys->b_high_priority = val.b_bool;
686 687

    if( p_sys->i_vcodec )
688
    {
689 690 691
        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 );
692
    }
693

694
    /* Subpictures transcoding parameters */
695
    p_sys->p_spu = NULL;
696 697
    p_sys->psz_senc = NULL;
    p_sys->p_spu_cfg = NULL;
698 699 700
    p_sys->i_scodec = 0;

    var_Get( p_stream, SOUT_CFG_PREFIX "senc", &val );
701 702 703
    if( val.psz_string && *val.psz_string )
    {
        char *psz_next;
704
        psz_next = config_ChainCreate( &p_sys->psz_senc, &p_sys->p_spu_cfg,
705
                                   val.psz_string );
706
        free( psz_next );
707
    }
708
    free( val.psz_string );
709 710 711 712 713 714 715 716

    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] );
    }
717
    free( val.psz_string );
718 719 720

    if( p_sys->i_scodec )
    {
721
        msg_Dbg( p_stream, "codec spu=%4.4s", (char *)&p_sys->i_scodec );
722 723 724 725
    }

    var_Get( p_stream, SOUT_CFG_PREFIX "soverlay", &val );
    p_sys->b_soverlay = val.b_bool;
726 727 728 729 730 731 732 733 734

    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 );
    }
735
    free( val.psz_string );
736

737 738 739 740
    /* OSD menu transcoding parameters */
    p_sys->psz_osdenc = NULL;
    p_sys->p_osd_cfg  = NULL;
    p_sys->i_osdcodec = 0;
741
    p_sys->b_osd   = false;
742 743

    var_Get( p_stream, SOUT_CFG_PREFIX "osd", &val );
744
    if( val.b_bool )
745
    {
746
        vlc_value_t osd_val;
747
        char *psz_next;
Jean-Paul Saman's avatar
Jean-Paul Saman committed
748

749
        psz_next = config_ChainCreate( &p_sys->psz_osdenc,
750
                                   &p_sys->p_osd_cfg, strdup( "dvbsub") );
751
        free( psz_next );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
752 753

        p_sys->i_osdcodec = VLC_FOURCC('Y','U','V','P' );
754 755 756 757 758

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

        if( !p_sys->p_spu )
        {
759
            osd_val.psz_string = strdup("osdmenu");
760 761
            p_sys->p_spu = spu_Create( p_stream );
            var_Create( p_sys->p_spu, "sub-filter", VLC_VAR_STRING );
762
            var_Set( p_sys->p_spu, "sub-filter", osd_val );
763
            spu_Init( p_sys->p_spu );
764
            free( osd_val.psz_string );
765 766 767 768 769
        }
        else
        {
            osd_val.psz_string = strdup("osdmenu");
            var_Set( p_sys->p_spu, "sub-filter", osd_val );
770
            free( osd_val.psz_string );