transcode.c 64.4 KB
Newer Older
1
/*****************************************************************************
gbazin's avatar
   
gbazin committed
2
 * transcode.c: transcoding stream output module
3
 *****************************************************************************
gbazin's avatar
   
gbazin committed
4
 * Copyright (C) 2003-2004 VideoLAN
5
 * $Id$
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 *
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <string.h>

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/sout.h>
gbazin's avatar
   
gbazin committed
34
35
#include <vlc/vout.h>
#include <vlc/decoder.h>
36
37
#include "vlc_filter.h"
#include "osd.h"
38
39

/*****************************************************************************
40
 * Module descriptor
41
 *****************************************************************************/
gbazin's avatar
gbazin committed
42
43
44
45
#define VENC_TEXT N_("Video encoder")
#define VENC_LONGTEXT N_( \
    "Allows you to specify the video encoder to use and its associated " \
    "options." )
46
47
#define VCODEC_TEXT N_("Destination video codec")
#define VCODEC_LONGTEXT N_( \
gbazin's avatar
gbazin committed
48
49
    "Allows you to specify the destination video codec used for the " \
    "streaming output." )
50
51
52
53
54
55
56
#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." )
57
58
59
#define FPS_TEXT N_("Video frame-rate")
#define FPS_LONGTEXT N_( \
    "Allows you to specify an output frame rate for the video." )
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#define DEINTERLACE_TEXT N_("Deinterlace video")
#define DEINTERLACE_LONGTEXT N_( \
    "Allows you to deinterlace the video before encoding." )
#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." )

#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." )

gbazin's avatar
gbazin committed
83
84
85
86
#define AENC_TEXT N_("Audio encoder")
#define AENC_LONGTEXT N_( \
    "Allows you to specify the audio encoder to use and its associated " \
    "options." )
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#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." )

104
105
106
107
108
109
110
111
#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." )
112
113
114
115
116
#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." )
117

118
119
120
121
#define THREADS_TEXT N_("Number of threads")
#define THREADS_LONGTEXT N_( \
    "Allows you to specify the number of threads used for the transcoding." )

122
123
124
125
126
#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." )

127
128
129
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

130
131
#define SOUT_CFG_PREFIX "sout-transcode-"

132
133
134
135
136
vlc_module_begin();
    set_description( _("Transcode stream output") );
    set_capability( "sout stream", 50 );
    add_shortcut( "transcode" );
    set_callbacks( Open, Close );
137

gbazin's avatar
gbazin committed
138
139
    add_string( SOUT_CFG_PREFIX "venc", NULL, NULL, VENC_TEXT,
                VENC_LONGTEXT, VLC_FALSE );
140
141
142
143
144
145
    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 );
146
147
    add_float( SOUT_CFG_PREFIX "fps", 0, NULL, FPS_TEXT,
               FPS_LONGTEXT, VLC_FALSE );
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    add_bool( SOUT_CFG_PREFIX "deinterlace", 0, NULL, DEINTERLACE_TEXT,
              DEINTERLACE_LONGTEXT, VLC_FALSE );
    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 );

    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 );

gbazin's avatar
gbazin committed
164
165
    add_string( SOUT_CFG_PREFIX "aenc", NULL, NULL, AENC_TEXT,
                AENC_LONGTEXT, VLC_FALSE );
166
167
168
169
170
171
172
173
174
    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 );

175
176
177
178
179
180
    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 );
181
182
    add_string( SOUT_CFG_PREFIX "sfilter", NULL, NULL, SFILTER_TEXT,
                SFILTER_LONGTEXT, VLC_FALSE );
183

184
185
    add_integer( SOUT_CFG_PREFIX "threads", 0, NULL, THREADS_TEXT,
                 THREADS_LONGTEXT, VLC_TRUE );
186
187
188

    add_bool( SOUT_CFG_PREFIX "audio-sync", 0, NULL, ASYNC_TEXT,
              ASYNC_LONGTEXT, VLC_FALSE );
189
vlc_module_end();
190

gbazin's avatar
gbazin committed
191
192
static const char *ppsz_sout_options[] = {
    "venc", "vcodec", "vb", "croptop", "cropbottom", "cropleft", "cropright",
193
    "scale", "fps", "width", "height", "deinterlace", "threads",
194
    "aenc", "acodec", "ab", "samplerate", "channels",
195
    "senc", "scodec", "soverlay", "sfilter",
196
    "audio-sync", NULL
gbazin's avatar
gbazin committed
197
198
};

199
200
201
/*****************************************************************************
 * Exported prototypes
 *****************************************************************************/
202
static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
203
static int               Del ( sout_stream_t *, sout_stream_id_t * );
204
static int               Send( sout_stream_t *, sout_stream_id_t *, block_t* );
205

206
207
208
209
210
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 ** );

gbazin's avatar
gbazin committed
211
212
213
static aout_buffer_t *audio_new_buffer( decoder_t *, int );
static void audio_del_buffer( decoder_t *, aout_buffer_t * );

214
215
216
217
218
219
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 ** );

220
221
222
223
224
225
226
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 * );
gbazin's avatar
   
gbazin committed
227

228
229
230
231
232
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 ** );

233
234
static int  EncoderThread( struct sout_stream_sys_t * p_sys );

gbazin's avatar
   
gbazin committed
235
236
237
238
239
240
241
242
243
244
245
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
};

246
#define PICTURE_RING_SIZE 64
247
#define SUBPICTURE_RING_SIZE 20
248

249
250
struct sout_stream_sys_t
{
251
252
    VLC_COMMON_MEMBERS

253
254
255
    sout_stream_t   *p_out;
    sout_stream_id_t *id_video;
    block_t         *p_buffers;
256
257
258
259
    vlc_mutex_t     lock_out;
    vlc_cond_t      cond;
    picture_t *     pp_pics[PICTURE_RING_SIZE];
    int             i_first_pic, i_last_pic;
260

261
    /* Audio */
262
    vlc_fourcc_t    i_acodec;   /* codec audio (0 if not transcode) */
gbazin's avatar
gbazin committed
263
    char            *psz_aenc;
264
    sout_cfg_t      *p_audio_cfg;
265
266
267
268
    int             i_sample_rate;
    int             i_channels;
    int             i_abitrate;

269
270
    /* Video */
    vlc_fourcc_t    i_vcodec;   /* codec video (0 if not transcode) */
gbazin's avatar
gbazin committed
271
    char            *psz_venc;
272
    sout_cfg_t      *p_video_cfg;
273
    int             i_vbitrate;
274
    double          f_scale;
275
    double          f_fps;
276
277
278
    int             i_width;
    int             i_height;
    vlc_bool_t      b_deinterlace;
279
    int             i_threads;
280
281
282
283
284

    int             i_crop_top;
    int             i_crop_bottom;
    int             i_crop_right;
    int             i_crop_left;
gbazin's avatar
   
gbazin committed
285

286
287
288
289
290
    /* 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;
291
    spu_t           *p_spu;
292
293

    /* Sync */
294
    vlc_bool_t      b_master_sync;
295
    mtime_t         i_master_drift;
296
297
};

298
299
300
301
302
303
304
305
306
struct decoder_owner_sys_t
{
    picture_t *pp_pics[PICTURE_RING_SIZE];
};
struct filter_owner_sys_t
{
    picture_t *pp_pics[PICTURE_RING_SIZE];
};

307
308
309
310
311
312
313
/*****************************************************************************
 * 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;
314
    vlc_value_t       val;
315

316
    p_sys = vlc_object_create( p_this, sizeof( sout_stream_sys_t ) );
317

Laurent Aimar's avatar
Laurent Aimar committed
318
    p_sys->p_out = sout_StreamNew( p_stream->p_sout, p_stream->psz_next );
319
320
321
322
323
324
    if( !p_sys->p_out )
    {
        msg_Err( p_stream, "cannot create chain" );
        free( p_sys );
        return VLC_EGENERIC;
    }
325

326
    p_sys->i_master_drift = 0;
327

Laurent Aimar's avatar
Laurent Aimar committed
328
    sout_CfgParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
gbazin's avatar
gbazin committed
329
                   p_stream->p_cfg );
330

gbazin's avatar
gbazin committed
331
332
333
334
335
    /* 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 )
336
    {
gbazin's avatar
gbazin committed
337
        char *psz_next;
Laurent Aimar's avatar
Laurent Aimar committed
338
339
        psz_next = sout_CfgCreate( &p_sys->psz_aenc, &p_sys->p_audio_cfg,
                                   val.psz_string );
340
341
        if( psz_next ) free( psz_next );
    }
gbazin's avatar
gbazin committed
342
    if( val.psz_string ) free( val.psz_string );
343
344
345
346
347
348
349

    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 ) );
350
        p_sys->i_acodec = VLC_FOURCC( fcc[0], fcc[1], fcc[2], fcc[3] );
351
352
    }
    if( val.psz_string ) free( val.psz_string );
353

354
355
356
357
358
359
    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;
360

361
362
363
364
365
366
367
368
    var_Get( p_stream, SOUT_CFG_PREFIX "channels", &val );
    p_sys->i_channels = val.i_int;

    if( p_sys->i_acodec )
    {
        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 );
369
370
    }

371
    /* Video transcoding parameters */
gbazin's avatar
gbazin committed
372
373
374
375
376
377
    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
378
379
        psz_next = sout_CfgCreate( &p_sys->psz_venc, &p_sys->p_video_cfg,
                                   val.psz_string );
gbazin's avatar
gbazin committed
380
381
382
383
        if( psz_next ) free( psz_next );
    }
    if( val.psz_string ) free( val.psz_string );

384
385
386
    var_Get( p_stream, SOUT_CFG_PREFIX "vcodec", &val );
    p_sys->i_vcodec = 0;
    if( val.psz_string && *val.psz_string )
387
388
    {
        char fcc[4] = "    ";
389
390
391
392
        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 );
393

394
395
396
    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;
397

398
399
    var_Get( p_stream, SOUT_CFG_PREFIX "scale", &val );
    p_sys->f_scale = val.f_float;
400

401
402
403
    var_Get( p_stream, SOUT_CFG_PREFIX "fps", &val );
    p_sys->f_fps = val.f_float;

404
405
    var_Get( p_stream, SOUT_CFG_PREFIX "width", &val );
    p_sys->i_width = val.i_int;
406

407
408
    var_Get( p_stream, SOUT_CFG_PREFIX "height", &val );
    p_sys->i_height = val.i_int;
409

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
    var_Get( p_stream, SOUT_CFG_PREFIX "deinterlace", &val );
    p_sys->b_deinterlace = val.b_bool;

    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;

    if( p_sys->i_vcodec )
426
    {
427
428
429
        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 );
430
    }
431

432
    /* Subpictures transcoding parameters */
433
    p_sys->p_spu = 0;
434
435
    p_sys->psz_senc = NULL;
    p_sys->p_spu_cfg = NULL;
436
437
438
    p_sys->i_scodec = 0;

    var_Get( p_stream, SOUT_CFG_PREFIX "senc", &val );
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
    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 )
    {
        msg_Dbg( p_stream, "codec spu=%4.4s", (char *)&p_sys->i_acodec );
    }

    var_Get( p_stream, SOUT_CFG_PREFIX "soverlay", &val );
    p_sys->b_soverlay = val.b_bool;
464
465
466
467
468
469
470
471
472
473

    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 );
474

475
    var_Get( p_stream, SOUT_CFG_PREFIX "audio-sync", &val );
476
477
    p_sys->b_master_sync = val.b_bool;
    if( p_sys->f_fps > 0 ) p_sys->b_master_sync = VLC_TRUE;
478

479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
    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
495
    sout_StreamDelete( p_sys->p_out );
496
497
498
499
500
501
502
503
504
505
506
507
508

    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;
    }
gbazin's avatar
gbazin committed
509
    if( p_sys->psz_aenc ) free( p_sys->psz_aenc );
510
511
512
513
514
515
516
517
518
519
520
521
522

    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;
    }
gbazin's avatar
gbazin committed
523
    if( p_sys->psz_venc ) free( p_sys->psz_venc );
524

525
526
527
528
529
530
531
532
533
534
535
536
537
538
    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 );

539
    if( p_sys->p_spu ) spu_Destroy( p_sys->p_spu );
540

541
    vlc_object_destroy( p_sys );
542
543
544
545
546
}

struct sout_stream_id_t
{
    vlc_fourcc_t  b_transcode;
547

548
549
550
    /* id of the out stream */
    void *id;

551
552
553
    /* Decoder */
    decoder_t       *p_decoder;

554
555
556
557
    /* Filters */
    filter_t        *pp_filter[10];
    int             i_filter;

gbazin's avatar
   
gbazin committed
558
    /* Encoder */
gbazin's avatar
   
gbazin committed
559
    encoder_t       *p_encoder;
gbazin's avatar
   
gbazin committed
560

561
562
    /* Sync */
    date_t          interpolated_pts;
563
564
565
};


566
static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
567
{
568
569
    sout_stream_sys_t *p_sys = p_stream->p_sys;
    sout_stream_id_t *id;
570
571

    id = malloc( sizeof( sout_stream_id_t ) );
572
573
    memset( id, 0, sizeof(sout_stream_id_t) );

gbazin's avatar
   
gbazin committed
574
    id->id = NULL;
575
    id->p_decoder = NULL;
gbazin's avatar
   
gbazin committed
576
577
    id->p_encoder = NULL;

578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
    /* 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->fmt_out = *p_fmt;
    id->p_decoder->fmt_out.i_extra = 0;
    id->p_decoder->fmt_out.p_extra = 0;
    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;
602
603

    /* Create destination format */
604
605
606
607
608
    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 );
609

610
    if( p_fmt->i_cat == AUDIO_ES && (p_sys->i_acodec || p_sys->psz_aenc) )
611
612
613
    {
        msg_Dbg( p_stream,
                 "creating audio transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
614
615
616
                 (char*)&p_fmt->i_codec, (char*)&p_sys->i_acodec );

        /* Complete destination format */
617
618
619
620
621
622
623
624
625
626
627
        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.audio.i_channels = p_sys->i_channels > 0 ?
            p_sys->i_channels : p_fmt->audio.i_channels;
        id->p_encoder->fmt_out.i_bitrate = p_sys->i_abitrate;
        id->p_encoder->fmt_out.audio.i_bitspersample =
            p_fmt->audio.i_bitspersample;

        /* Build decoder -> filter -> encoder chain */
        if( transcode_audio_new( p_stream, id ) )
628
629
        {
            msg_Err( p_stream, "cannot create audio chain" );
630
            goto error;
631
632
        }

633
634
        /* Open output stream */
        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
635
        id->b_transcode = VLC_TRUE;
636

637
        if( !id->id ) goto error;
638
639

        date_Init( &id->interpolated_pts, p_fmt->audio.i_rate, 1 );
640
    }
641
642
    else if( p_fmt->i_cat == VIDEO_ES &&
             (p_sys->i_vcodec != 0 || p_sys->psz_venc) )
643
644
645
    {
        msg_Dbg( p_stream,
                 "creating video transcoding from fcc=`%4.4s' to fcc=`%4.4s'",
646
                 (char*)&p_fmt->i_codec, (char*)&p_sys->i_vcodec );
647

648
        /* Complete destination format */
649
650
651
652
        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;
653

654
655
        /* Build decoder -> filter -> encoder chain */
        if( transcode_video_new( p_stream, id ) )
656
657
        {
            msg_Err( p_stream, "cannot create video chain" );
658
            goto error;
659
        }
660
661
662

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

665
        if( p_sys->f_fps > 0 )
666
        {
667
668
            id->p_encoder->fmt_out.video.i_frame_rate = p_sys->f_fps * 1000;
            id->p_encoder->fmt_out.video.i_frame_rate_base = 1000;
669
        }
670
    }
671
672
673
674
675
676
    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 );

677
        /* Complete destination format */
678
        id->p_encoder->fmt_out.i_codec = p_sys->i_scodec;
679
680
681
682
683

        /* build decoder -> filter -> encoder */
        if( transcode_spu_new( p_stream, id ) )
        {
            msg_Err( p_stream, "cannot create subtitles chain" );
684
            goto error;
685
686
687
        }

        /* open output stream */
688
        id->id = p_sys->p_out->pf_add( p_sys->p_out, &id->p_encoder->fmt_out );
689
690
        id->b_transcode = VLC_TRUE;

691
        if( !id->id ) goto error;
692
693
694
695
696
697
698
699
    }
    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;

700
        /* Build decoder -> filter -> overlaying chain */
701
702
703
        if( transcode_spu_new( p_stream, id ) )
        {
            msg_Err( p_stream, "cannot create subtitles chain" );
704
            goto error;
705
706
        }
    }
707
708
    else
    {
gbazin's avatar
gbazin committed
709
710
        msg_Dbg( p_stream, "not transcoding a stream (fcc=`%4.4s')",
                 (char*)&p_fmt->i_codec );
711
712
713
        id->id = p_sys->p_out->pf_add( p_sys->p_out, p_fmt );
        id->b_transcode = VLC_FALSE;

714
        if( !id->id ) goto error;
715
716
717
    }

    return id;
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733

 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 );
        vlc_object_destroy( id->p_encoder );
    }

    free( id );
    return NULL;
734
735
}

736
static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
737
{
738
    sout_stream_sys_t *p_sys = p_stream->p_sys;
739
740
741

    if( id->b_transcode )
    {
742
        switch( id->p_decoder->fmt_in.i_cat )
743
        {
744
745
746
747
748
749
750
        case AUDIO_ES:
            transcode_audio_close( p_stream, id );
            break;
        case VIDEO_ES:
            transcode_video_close( p_stream, id );
            break;
        case SPU_ES:
751
            transcode_spu_close( p_stream, id );
752
            break;
753
        }
754
755
    }

gbazin's avatar
   
gbazin committed
756
    if( id->id ) p_sys->p_out->pf_del( p_sys->p_out, id->id );
757
758
759
760
761
762
763
764
765
766
767
768
769

    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 );
        vlc_object_destroy( id->p_encoder );
    }

770
771
772
773
774
    free( id );

    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
775
static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
776
                 block_t *p_buffer )
777
{
778
    sout_stream_sys_t *p_sys = p_stream->p_sys;
779
    block_t *p_out;
780

781
782
    if( !id->b_transcode && id->id )
    {
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
        if( p_sys->b_master_sync && p_sys->i_master_drift )
        {
            if( p_buffer->i_dts > 0 )
            {
                p_buffer->i_dts -= p_sys->i_master_drift;
                if( p_buffer->i_dts < 0 )
                {
                    block_Release( p_buffer );
                    return VLC_EGENERIC;
                }
            }
            if( p_buffer->i_pts > 0 )
            {
                p_buffer->i_pts -= p_sys->i_master_drift;
                if( p_buffer->i_pts < 0 )
                {
                    block_Release( p_buffer );
                    return VLC_EGENERIC;
                }
            }
        }

805
806
807
808
809
810
811
812
813
        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 )
814
    {
815
816
817
    case AUDIO_ES:
        transcode_audio_process( p_stream, id, p_buffer, &p_out );
        break;
818

819
820
821
    case VIDEO_ES:
        if( transcode_video_process( p_stream, id, p_buffer, &p_out )
            != VLC_SUCCESS )
822
823
824
        {
            return VLC_EGENERIC;
        }
825
        break;
826

827
828
829
    case SPU_ES:
        if( transcode_spu_process( p_stream, id, p_buffer, &p_out ) !=
            VLC_SUCCESS )
830
        {
831
            return VLC_EGENERIC;
832
        }
833
        break;
834

835
    default:
836
        block_Release( p_buffer );
837
        break;
838
    }
839
840
841

    if( p_out ) return p_sys->p_out->pf_send( p_sys->p_out, id->id, p_out );
    return VLC_SUCCESS;
842
843
844
}

/****************************************************************************
gbazin's avatar
gbazin committed
845
 * decoder reencoder part
846
 ****************************************************************************/
gbazin's avatar
gbazin committed
847
int audio_BitsPerSample( vlc_fourcc_t i_format )
848
{
gbazin's avatar
gbazin committed
849
    switch( i_format )
850
    {
gbazin's avatar
gbazin committed
851
852
    case VLC_FOURCC('u','8',' ',' '):
    case VLC_FOURCC('s','8',' ',' '):
853
        return 8;
gbazin's avatar
gbazin committed
854
855
856
857
858

    case VLC_FOURCC('u','1','6','l'):
    case VLC_FOURCC('s','1','6','l'):
    case VLC_FOURCC('u','1','6','b'):
    case VLC_FOURCC('s','1','6','b'):
859
860
861
862
863
864
865
866
867
868
869
870
        return 16;

    case VLC_FOURCC('u','2','4','l'):
    case VLC_FOURCC('s','2','4','l'):
    case VLC_FOURCC('u','2','4','b'):
    case VLC_FOURCC('s','2','4','b'):
        return 24;

    case VLC_FOURCC('u','3','2','l'):
    case VLC_FOURCC('s','3','2','l'):
    case VLC_FOURCC('u','3','2','b'):
    case VLC_FOURCC('s','3','2','b'):
gbazin's avatar
gbazin committed
871
872
    case VLC_FOURCC('f','l','3','2'):
    case VLC_FOURCC('f','i','3','2'):
873
874
875
876
        return 32;

    case VLC_FOURCC('f','l','6','4'):
        return 64;
877
878
879
880
881
    }

    return 0;
}

882
883
static int transcode_audio_new( sout_stream_t *p_stream,
                                sout_stream_id_t *id )
884
{
gbazin's avatar
gbazin committed
885
    sout_stream_sys_t *p_sys = p_stream->p_sys;
886

gbazin's avatar
gbazin committed
887
888
889
    /*
     * Open decoder
     */
890

gbazin's avatar
gbazin committed
891
892
893
894
895
    /* Initialization of decoder structures */
    id->p_decoder->pf_decode_audio = 0;
    id->p_decoder->pf_aout_buffer_new = audio_new_buffer;
    id->p_decoder->pf_aout_buffer_del = audio_del_buffer;
    //id->p_decoder->p_cfg = p_sys->p_video_cfg;
896

gbazin's avatar
gbazin committed
897
898
    id->p_decoder->p_module =
        module_Need( id->p_decoder, "decoder", "$codec", 0 );
899

gbazin's avatar
gbazin committed
900
901
902
903
    if( !id->p_decoder->p_module )
    {
        msg_Err( p_stream, "cannot find decoder" );
        return VLC_EGENERIC;
904
    }
gbazin's avatar
gbazin committed
905
906
    id->p_decoder->fmt_out.audio.i_bitspersample = 
        audio_BitsPerSample( id->p_decoder->fmt_out.i_codec );
907

gbazin's avatar
gbazin committed
908
909
910
911
912
913
914
915
    /*
     * Open encoder
     */

    /* Initialization of encoder format structures */
    es_format_Init( &id->p_encoder->fmt_in, id->p_decoder->fmt_in.i_cat,
                    id->p_decoder->fmt_out.i_codec );
    id->p_encoder->fmt_in.audio.i_format = id->p_decoder->fmt_out.i_codec;
gbazin's avatar
   
gbazin committed
916

gbazin's avatar
   
gbazin committed
917
    /* Sanity check for audio channels */
918
919
    id->p_encoder->fmt_out.audio.i_channels =
        __MIN( id->p_encoder->fmt_out.audio.i_channels,
920
921
922
923
924
925
926
927
928
929
               id->p_decoder->fmt_out.audio.i_channels );
    if( id->p_decoder->fmt_out.audio.i_channels ==
        id->p_encoder->fmt_out.audio.i_channels )
        id->p_encoder->fmt_out.audio.i_physical_channels =
            id->p_encoder->fmt_out.audio.i_original_channels =
                id->p_decoder->fmt_out.audio.i_physical_channels;
    else
        id->p_encoder->fmt_out.audio.i_physical_channels =
            id->p_encoder->fmt_out.audio.i_original_channels =
                pi_channels_maps[id->p_encoder->fmt_out.audio.i_channels];
gbazin's avatar
   
gbazin committed
930
931
932
933

    /* Initialization of encoder format structures */
    es_format_Init( &id->p_encoder->fmt_in, AUDIO_ES, AOUT_FMT_S16_NE );
    id->p_encoder->fmt_in.audio.i_format = AOUT_FMT_S16_NE;
934
    id->p_encoder->fmt_in.audio.i_rate = id->p_encoder->fmt_out.audio.i_rate;
gbazin's avatar
   
gbazin committed
935
936
    id->p_encoder->fmt_in.audio.i_physical_channels =
        id->p_encoder->fmt_in.audio.i_original_channels =
937
            id->p_encoder->fmt_out.audio.i_physical_channels;
938
939
    id->p_encoder->fmt_in.audio.i_channels =
        id->p_encoder->fmt_out.audio.i_channels;
940
941
    id->p_encoder->fmt_in.audio.i_bitspersample =
        audio_BitsPerSample( id->p_encoder->fmt_in.i_codec );
gbazin's avatar
   
gbazin committed
942

943
944
    id->p_encoder->p_cfg = p_stream->p_sys->p_audio_cfg;

gbazin's avatar
   
gbazin committed
945
    id->p_encoder->p_module =
gbazin's avatar
gbazin committed
946
        module_Need( id->p_encoder, "encoder", p_sys->psz_aenc, VLC_TRUE );
gbazin's avatar
   
gbazin committed
947
    if( !id->p_encoder->p_module )
Laurent Aimar's avatar
Laurent Aimar committed
948
    {
gbazin's avatar
gbazin committed
949
950
951
        msg_Err( p_stream, "cannot find encoder" );
        module_Unneed( id->p_decoder, id->p_decoder->p_module );
        id->p_decoder->p_module = 0;
gbazin's avatar
   
gbazin committed
952
        return VLC_EGENERIC;
Laurent Aimar's avatar
Laurent Aimar committed
953
    }
954
    id->p_encoder->fmt_in.audio.i_format = id->p_encoder->fmt_in.i_codec;
955
956
    id->p_encoder->fmt_in.audio.i_bitspersample =
        audio_BitsPerSample( id->p_encoder->fmt_in.i_codec );
957

gbazin's avatar
gbazin committed
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
    /* Check if we need a filter for chroma conversion or resizing */
    if( id->p_decoder->fmt_out.i_codec !=
        id->p_encoder->fmt_in.i_codec )
    {
        id->pp_filter[0] =
            vlc_object_create( p_stream, VLC_OBJECT_FILTER );
        vlc_object_attach( id->pp_filter[0], p_stream );

        id->pp_filter[0]->pf_audio_buffer_new = __block_New;

        id->pp_filter[0]->fmt_in = id->p_decoder->fmt_out;
        id->pp_filter[0]->fmt_out = id->p_encoder->fmt_in;
        id->pp_filter[0]->p_module =
            module_Need( id->pp_filter[0], "audio filter2", 0, 0 );
        if( id->pp_filter[0]->p_module ) id->i_filter++;
        else
        {
975
976
977
            msg_Dbg( p_stream, "no audio filter found (%4.4s->%4.4s)",
                     (char *)&id->pp_filter[0]->fmt_in,
                     (char *)&id->pp_filter[0]->fmt_out );
gbazin's avatar
gbazin committed
978
979
980
981
982
983
984
985
986
            vlc_object_detach( id->pp_filter[0] );
            vlc_object_destroy( id->pp_filter[0] );
            module_Unneed( id->p_decoder, id->p_decoder->p_module );
            id->p_decoder->p_module = 0;
            module_Unneed( id->p_encoder, id->p_encoder->p_module );
            id->p_encoder->p_module = 0;
            return VLC_EGENERIC;
        }

987
988
989
        id->pp_filter[0]->fmt_out.audio.i_bitspersample = 
            audio_BitsPerSample( id->pp_filter[0]->fmt_out.i_codec );

gbazin's avatar
gbazin committed
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
        /* Try a 2 stage conversion */
        if( id->pp_filter[0]->fmt_out.i_codec !=
            id->p_encoder->fmt_in.i_codec )
        {
            id->pp_filter[1] =
                vlc_object_create( p_stream, VLC_OBJECT_FILTER );
            vlc_object_attach( id->pp_filter[1], p_stream );

            id->pp_filter[1]->pf_audio_buffer_new = __block_New;

            id->pp_filter[1]->fmt_in = id->pp_filter[0]->fmt_out;
            id->pp_filter[1]->fmt_out = id->p_encoder->fmt_in;
            id->pp_filter[1]->p_module =
              module_Need( id->pp_filter[1], "audio filter2", 0, 0 );
            if( !id->pp_filter[1]->p_module ||
                id->pp_filter[1]->fmt_out.i_codec !=
                  id->p_encoder->fmt_in.i_codec )
            {
1008
1009
1010
                msg_Dbg( p_stream, "no audio filter found (%4.4s->%4.4s)",
                         (char *)&id->pp_filter[1]->fmt_in,
                         (char *)&id->pp_filter[1]->fmt_out );
gbazin's avatar
gbazin committed
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
                module_Unneed( id->pp_filter[0], id->pp_filter[0]->p_module );
                vlc_object_detach( id->pp_filter[0] );
                vlc_object_destroy( id->pp_filter[0] );
                if( id->pp_filter[1]->p_module )
                module_Unneed( id->pp_filter[0], id->pp_filter[0]->p_module );
                vlc_object_detach( id->pp_filter[1] );
                vlc_object_destroy( id->pp_filter[1] );
                module_Unneed( id->p_decoder, id->p_decoder->p_module );
                id->p_decoder->p_module = 0;
                module_Unneed( id->p_encoder, id->p_encoder->p_module );
                id->p_encoder->p_module = 0;
                return VLC_EGENERIC;
            }
            else id->i_filter++;
        }
    }

1028
1029
1030
    /* FIXME: Hack for mp3 transcoding support */
    if( id->p_encoder->fmt_out.i_codec == VLC_FOURCC( 'm','p','3',' ' ) )
        id->p_encoder->fmt_out.i_codec = VLC_FOURCC( 'm','p','g','a' );
gbazin's avatar
   
gbazin committed
1031

1032
1033
1034
    return VLC_SUCCESS;
}

1035
1036
static void transcode_audio_close( sout_stream_t *p_stream,
                                   sout_stream_id_t *id )
1037
{
gbazin's avatar
gbazin committed
1038
    int i;
gbazin's avatar
   
gbazin committed
1039

gbazin's avatar
gbazin committed
1040
1041
1042
    /* Close decoder */
    if( id->p_decoder->p_module )
        module_Unneed( id->p_decoder, id->p_decoder->p_module );
1043

gbazin's avatar
gbazin committed
1044
1045
1046
    /* Close encoder */
    if( id->p_encoder->p_module )
        module_Unneed( id->p_encoder, id->p_encoder->p_module );
1047

gbazin's avatar
gbazin committed
1048
1049
1050
1051
1052
1053
1054
1055
    /* Close filters */
    for( i = 0; i < id->i_filter; i++ )
    {
        vlc_object_detach( id->pp_filter[i] );
        if( id->pp_filter[i]->p_module )
            module_Unneed( id->pp_filter[i], id->pp_filter[i]->p_module );
        vlc_object_destroy( id->pp_filter[i] );
    }
1056
1057
}

1058
1059
1060
static int transcode_audio_process( sout_stream_t *p_stream,
                                    sout_stream_id_t *id,
                                    block_t *in, block_t **out )
1061
{
1062
    sout_stream_sys_t *p_sys = p_stream->p_sys;
gbazin's avatar
gbazin committed
1063
1064
1065
    aout_buffer_t *p_audio_buf;
    block_t *p_block, *p_audio_block;
    int i;
1066
1067
    *out = NULL;

gbazin's avatar
gbazin committed
1068
1069
    while( (p_audio_buf = id->p_decoder->pf_decode_audio( id->p_decoder,
                                                          &in )) )
1070
    {
1071
        if( p_sys->b_master_sync )
1072
        {
gbazin's avatar
gbazin committed
1073
1074
1075
1076
1077
            mtime_t i_dts = date_Get( &id->interpolated_pts ) + 1;
            p_sys->i_master_drift = p_audio_buf->start_date - i_dts;
            date_Increment( &id->interpolated_pts, p_audio_buf->i_nb_samples );
            p_audio_buf->start_date -= p_sys->i_master_drift;
            p_audio_buf->end_date -= p_sys->i_master_drift;
1078
        }
1079

gbazin's avatar
gbazin committed
1080
1081
1082
1083
1084
1085
1086
        p_audio_block = p_audio_buf->p_sys;
        p_audio_block->i_buffer = p_audio_buf->i_nb_bytes;
        p_audio_block->i_dts = p_audio_block->i_pts =
            p_audio_buf->start_date;
        p_audio_block->i_length = p_audio_buf->end_date -
            p_audio_buf->start_date;
        p_audio_block->i_samples = p_audio_buf->i_nb_samples;
1087

gbazin's avatar
gbazin committed
1088
1089
        /* Run filter chain */
        for( i = 0; i < id->i_filter; i++ )
1090
        {
gbazin's avatar
gbazin committed
1091
1092
1093
            p_audio_block =
                id->pp_filter[i]->pf_audio_filter( id->pp_filter[i],
                                                   p_audio_block );
1094
1095
        }

gbazin's avatar
gbazin committed
1096
1097
1098
1099
1100
        p_audio_buf->p_buffer = p_audio_block->p_buffer;
        p_audio_buf->i_nb_bytes = p_audio_block->i_buffer;
        p_audio_buf->i_nb_samples = p_audio_block->i_samples;
        p_audio_buf->start_date = p_audio_block->i_dts;
        p_audio_buf->end_date = p_audio_block->i_dts + p_audio_block->i_length;
1101

gbazin's avatar
gbazin committed
1102
1103
1104
1105
1106
        p_block = id->p_encoder->pf_encode_audio( id->p_encoder, p_audio_buf );
        block_ChainAppend( out, p_block );
        block_Release( p_audio_block );
        free( p_audio_buf );
    }
1107

gbazin's avatar
gbazin committed
1108
1109
    return VLC_SUCCESS;
}
1110

gbazin's avatar
gbazin committed
1111
1112
1113
1114
1115
static void audio_release_buffer( aout_buffer_t *p_buffer )
{
    if( p_buffer && p_buffer->p_sys ) block_Release( p_buffer->p_sys );
    if( p_buffer ) free( p_buffer );
}
1116

gbazin's avatar
gbazin committed
1117
1118
1119
1120
1121
static aout_buffer_t *audio_new_buffer( decoder_t *p_dec, int i_samples )
{
    aout_buffer_t *p_buffer;
    block_t *p_block;
    int i_size;
1122