encoder.c 35.4 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
2
3
/*****************************************************************************
 * encoder.c: video and audio encoder using the ffmpeg library
 *****************************************************************************
4
 * Copyright (C) 1999-2004 the VideoLAN team
gbazin's avatar
gbazin committed
5
 * $Id$
gbazin's avatar
   
gbazin committed
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
9
 *          Christophe Massiot <massiot@via.ecp.fr>
10
11
 * Part of the file Copyright (C) FFMPEG Project Developers
 * (mpeg4_default matrixes)
gbazin's avatar
   
gbazin committed
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * 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
dionoea's avatar
dionoea committed
25
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
gbazin's avatar
   
gbazin committed
26
27
28
29
30
31
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
32
33
34
35
36
#include <vlc_vout.h>
#include <vlc_aout.h>
#include <vlc_sout.h>
#include <vlc_codec.h>
#include <vlc_interface.h>
gbazin's avatar
   
gbazin committed
37
38

/* ffmpeg header */
39
#define HAVE_MMX 1
gbazin's avatar
   
gbazin committed
40
41
42
43
44
45
46
47
#ifdef HAVE_FFMPEG_AVCODEC_H
#   include <ffmpeg/avcodec.h>
#else
#   include <avcodec.h>
#endif

#include "ffmpeg.h"

48
49
50
#define HURRY_UP_GUARD1 (450000)
#define HURRY_UP_GUARD2 (300000)
#define HURRY_UP_GUARD3 (100000)
gbazin's avatar
   
gbazin committed
51

52
53
#define MAX_FRAME_DELAY (FF_MAX_B_FRAMES + 2)

gbazin's avatar
   
gbazin committed
54
55
56
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
57
58
int  E_(OpenEncoder) ( vlc_object_t * );
void E_(CloseEncoder)( vlc_object_t * );
gbazin's avatar
   
gbazin committed
59
60
61
62

static block_t *EncodeVideo( encoder_t *, picture_t * );
static block_t *EncodeAudio( encoder_t *, aout_buffer_t * );

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
struct thread_context_t;
static int FfmpegThread( struct thread_context_t *p_context );
static int FfmpegExecute( AVCodecContext *s,
                          int (*pf_func)(AVCodecContext *c2, void *arg2),
                          void **arg, int *ret, int count );

/*****************************************************************************
 * thread_context_t : for multithreaded encoding
 *****************************************************************************/
struct thread_context_t
{
    VLC_COMMON_MEMBERS

    AVCodecContext  *p_context;
    int             (* pf_func)(AVCodecContext *c, void *arg);
    void            *arg;
    int             i_ret;

    vlc_mutex_t     lock;
    vlc_cond_t      cond;
    vlc_bool_t      b_work, b_done;
};

gbazin's avatar
   
gbazin committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*****************************************************************************
 * encoder_sys_t : ffmpeg encoder descriptor
 *****************************************************************************/
struct encoder_sys_t
{
    /*
     * Ffmpeg properties
     */
    AVCodec         *p_codec;
    AVCodecContext  *p_context;

    /*
     * Common properties
     */
gbazin's avatar
   
gbazin committed
100
101
    char *p_buffer;
    char *p_buffer_out;
gbazin's avatar
   
gbazin committed
102

gbazin's avatar
   
gbazin committed
103
    /*
104
     * Video properties
gbazin's avatar
   
gbazin committed
105
     */
gbazin's avatar
   
gbazin committed
106
107
    mtime_t i_last_ref_pts;
    mtime_t i_buggy_pts_detect;
108
    mtime_t i_last_pts;
109
    vlc_bool_t b_inited;
gbazin's avatar
   
gbazin committed
110

gbazin's avatar
   
gbazin committed
111
112
113
    /*
     * Audio properties
     */
gbazin's avatar
   
gbazin committed
114
    int i_frame_size;
gbazin's avatar
   
gbazin committed
115
116
    int i_samples_delay;
    mtime_t i_pts;
117
118
119
120
121
122
123
124
125
126
127
128
129

    /* Encoding settings */
    int        i_key_int;
    int        i_b_frames;
    int        i_vtolerance;
    int        i_qmin;
    int        i_qmax;
    int        i_hq;
    vlc_bool_t b_strict_rc;
    int        i_rc_buffer_size;
    float      f_rc_buffer_aggressivity;
    vlc_bool_t b_pre_me;
    vlc_bool_t b_hurry_up;
130
    vlc_bool_t b_interlace, b_interlace_me;
131
132
133
134
    float      f_i_quant_factor;
    int        i_noise_reduction;
    vlc_bool_t b_mpeg4_matrix;
    vlc_bool_t b_trellis;
gbazin's avatar
gbazin committed
135
    int        i_quality; /* for VBR */
136
137
    float      f_lumi_masking, f_dark_masking, f_p_masking, f_border_masking;
    int        i_luma_elim, i_chroma_elim;
138
139
140
141

    /* Used to work around stupid timestamping behaviour in libavcodec */
    uint64_t i_framenum;
    mtime_t  pi_delay_pts[MAX_FRAME_DELAY];
142
143
144
};

static const char *ppsz_enc_options[] = {
145
    "keyint", "bframes", "vt", "qmin", "qmax", "hq", "strict-rc",
146
147
    "rc-buffer-size", "rc-buffer-aggressivity", "pre-me", "hurry-up",
    "interlace", "i-quant-factor", "noise-reduction", "mpeg4-matrix",
148
149
150
    "trellis", "qscale", "strict", "lumi-masking", "dark-masking",
    "p-masking", "border-masking", "luma-elim-threshold",
    "chroma-elim-threshold", NULL
gbazin's avatar
   
gbazin committed
151
152
};

153
154
155
156
157
158
159
160
161
static const uint16_t mpa_bitrate_tab[2][15] =
{
    {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384},
    {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}
};

static const uint16_t mpa_freq_tab[6] =
{ 44100, 48000, 32000, 22050, 24000, 16000 };

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
static const int16_t mpeg4_default_intra_matrix[64] = {
  8, 17, 18, 19, 21, 23, 25, 27,
 17, 18, 19, 21, 23, 25, 27, 28,
 20, 21, 22, 23, 24, 26, 28, 30,
 21, 22, 23, 24, 26, 28, 30, 32,
 22, 23, 24, 26, 28, 30, 32, 35,
 23, 24, 26, 28, 30, 32, 35, 38,
 25, 26, 28, 30, 32, 35, 38, 41,
 27, 28, 30, 32, 35, 38, 41, 45,
};

static const int16_t mpeg4_default_non_intra_matrix[64] = {
 16, 17, 18, 19, 20, 21, 22, 23,
 17, 18, 19, 20, 21, 22, 23, 24,
 18, 19, 20, 21, 22, 23, 24, 25,
 19, 20, 21, 22, 23, 24, 26, 27,
 20, 21, 22, 23, 25, 26, 27, 28,
 21, 22, 23, 24, 26, 27, 28, 30,
 22, 23, 24, 26, 27, 28, 30, 31,
 23, 24, 25, 27, 28, 30, 31, 33,
};


gbazin's avatar
   
gbazin committed
185
/*****************************************************************************
gbazin's avatar
   
gbazin committed
186
 * OpenEncoder: probe the encoder
gbazin's avatar
   
gbazin committed
187
 *****************************************************************************/
188

gbazin's avatar
   
gbazin committed
189
int E_(OpenEncoder)( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
190
191
192
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;
gbazin's avatar
   
gbazin committed
193
    AVCodecContext *p_context;
gbazin's avatar
   
gbazin committed
194
    AVCodec *p_codec;
gbazin's avatar
   
gbazin committed
195
    int i_codec_id, i_cat;
196
    const char *psz_namecodec;
197
    vlc_value_t val;
198
199
    vlc_value_t lockval;

200
    var_Get( p_enc->p_libvlc_global, "avcodec", &lockval );
gbazin's avatar
   
gbazin committed
201

gbazin's avatar
   
gbazin committed
202
    if( !E_(GetFfmpegCodec)( p_enc->fmt_out.i_codec, &i_cat, &i_codec_id,
gbazin's avatar
   
gbazin committed
203
                             &psz_namecodec ) )
gbazin's avatar
   
gbazin committed
204
    {
205
206
207
208
209
210
211
212
        if( E_(GetFfmpegChroma)( p_enc->fmt_out.i_codec ) < 0 )
        {
            /* handed chroma output */
            return VLC_EGENERIC;
        }
        i_cat      = VIDEO_ES;
        i_codec_id = CODEC_ID_RAWVIDEO;
        psz_namecodec = "Raw video";
gbazin's avatar
   
gbazin committed
213
214
    }

gbazin's avatar
   
gbazin committed
215
    if( p_enc->fmt_out.i_cat == VIDEO_ES && i_cat != VIDEO_ES )
gbazin's avatar
   
gbazin committed
216
    {
gbazin's avatar
   
gbazin committed
217
        msg_Err( p_enc, "\"%s\" is not a video encoder", psz_namecodec );
218
219
        intf_UserFatal( p_enc, VLC_FALSE, _("Streaming / Transcoding failed"), 
                        _("\"%s\" is no video encoder."), psz_namecodec );
gbazin's avatar
   
gbazin committed
220
221
222
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
223
224
225
    if( p_enc->fmt_out.i_cat == AUDIO_ES && i_cat != AUDIO_ES )
    {
        msg_Err( p_enc, "\"%s\" is not an audio encoder", psz_namecodec );
226
227
        intf_UserFatal( p_enc, VLC_FALSE, _("Streaming / Transcoding failed"), 
                        _("\"%s\" is no audio encoder."), psz_namecodec );
gbazin's avatar
   
gbazin committed
228
229
230
        return VLC_EGENERIC;
    }

Jean-Paul Saman's avatar
Jean-Paul Saman committed
231
    /* Initialization must be done before avcodec_find_encoder() */
gbazin's avatar
   
gbazin committed
232
233
    E_(InitLibavcodec)(p_this);

gbazin's avatar
   
gbazin committed
234
235
236
237
    p_codec = avcodec_find_encoder( i_codec_id );
    if( !p_codec )
    {
        msg_Err( p_enc, "cannot find encoder %s", psz_namecodec );
238
239
        intf_UserFatal( p_enc, VLC_FALSE, _("Streaming / Transcoding failed"), 
                        _("VLC could not find encoder \"%s\"."), psz_namecodec );
gbazin's avatar
   
gbazin committed
240
241
242
        return VLC_EGENERIC;
    }

Jean-Paul Saman's avatar
Jean-Paul Saman committed
243
    /* Allocate the memory needed to store the encoder's structure */
gbazin's avatar
   
gbazin committed
244
245
246
247
248
    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
    {
        msg_Err( p_enc, "out of memory" );
        return VLC_EGENERIC;
    }
249
    memset( p_sys, 0, sizeof(encoder_sys_t) );
gbazin's avatar
   
gbazin committed
250
251
252
253
    p_enc->p_sys = p_sys;
    p_sys->p_codec = p_codec;

    p_enc->pf_encode_video = EncodeVideo;
gbazin's avatar
   
gbazin committed
254
    p_enc->pf_encode_audio = EncodeAudio;
gbazin's avatar
   
gbazin committed
255

gbazin's avatar
   
gbazin committed
256
257
258
259
    p_sys->p_buffer_out = NULL;
    p_sys->p_buffer = NULL;

    p_sys->p_context = p_context = avcodec_alloc_context();
260
261
    p_context->debug = config_GetInt( p_enc, "ffmpeg-debug" );
    p_context->opaque = (void *)p_this;
gbazin's avatar
   
gbazin committed
262
263
264

    /* Set CPU capabilities */
    p_context->dsp_mask = 0;
265
    if( !(p_enc->p_libvlc_global->i_cpu & CPU_CAPABILITY_MMX) )
gbazin's avatar
   
gbazin committed
266
    {
gbazin's avatar
   
gbazin committed
267
        p_context->dsp_mask |= FF_MM_MMX;
gbazin's avatar
   
gbazin committed
268
    }
269
    if( !(p_enc->p_libvlc_global->i_cpu & CPU_CAPABILITY_MMXEXT) )
gbazin's avatar
   
gbazin committed
270
    {
gbazin's avatar
   
gbazin committed
271
        p_context->dsp_mask |= FF_MM_MMXEXT;
gbazin's avatar
   
gbazin committed
272
    }
273
    if( !(p_enc->p_libvlc_global->i_cpu & CPU_CAPABILITY_3DNOW) )
gbazin's avatar
   
gbazin committed
274
    {
gbazin's avatar
   
gbazin committed
275
        p_context->dsp_mask |= FF_MM_3DNOW;
gbazin's avatar
   
gbazin committed
276
    }
277
    if( !(p_enc->p_libvlc_global->i_cpu & CPU_CAPABILITY_SSE) )
gbazin's avatar
   
gbazin committed
278
    {
gbazin's avatar
   
gbazin committed
279
280
        p_context->dsp_mask |= FF_MM_SSE;
        p_context->dsp_mask |= FF_MM_SSE2;
gbazin's avatar
   
gbazin committed
281
282
    }

283
    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
284
285
286
287
288
289
290
291
292
293
294
295
296

    var_Get( p_enc, ENC_CFG_PREFIX "keyint", &val );
    p_sys->i_key_int = val.i_int;

    var_Get( p_enc, ENC_CFG_PREFIX "bframes", &val );
    p_sys->i_b_frames = val.i_int;

    var_Get( p_enc, ENC_CFG_PREFIX "vt", &val );
    p_sys->i_vtolerance = val.i_int;

    var_Get( p_enc, ENC_CFG_PREFIX "interlace", &val );
    p_sys->b_interlace = val.b_bool;

297
298
299
    var_Get( p_enc, ENC_CFG_PREFIX "interlace-me", &val );
    p_sys->b_interlace_me = val.b_bool;

300
    var_Get( p_enc, ENC_CFG_PREFIX "pre-me", &val );
301
302
    p_sys->b_pre_me = val.b_bool;

303
    var_Get( p_enc, ENC_CFG_PREFIX "hurry-up", &val );
304
305
306
307
308
309
310
    p_sys->b_hurry_up = val.b_bool;
    if( p_sys->b_hurry_up )
    {
        /* hurry up mode needs noise reduction, even small */
        p_sys->i_noise_reduction = 1;
    }

311
    var_Get( p_enc, ENC_CFG_PREFIX "strict-rc", &val );
312
    p_sys->b_strict_rc = val.b_bool;
313
    var_Get( p_enc, ENC_CFG_PREFIX "rc-buffer-size", &val );
314
    p_sys->i_rc_buffer_size = val.i_int;
315
    var_Get( p_enc, ENC_CFG_PREFIX "rc-buffer-aggressivity", &val );
316
317
    p_sys->f_rc_buffer_aggressivity = val.f_float;

318
    var_Get( p_enc, ENC_CFG_PREFIX "i-quant-factor", &val );
319
320
    p_sys->f_i_quant_factor = val.f_float;

321
    var_Get( p_enc, ENC_CFG_PREFIX "noise-reduction", &val );
322
323
    p_sys->i_noise_reduction = val.i_int;

324
    var_Get( p_enc, ENC_CFG_PREFIX "mpeg4-matrix", &val );
325
326
    p_sys->b_mpeg4_matrix = val.b_bool;

gbazin's avatar
gbazin committed
327
328
329
330
    var_Get( p_enc, ENC_CFG_PREFIX "qscale", &val );
    if( val.f_float < 0.01 || val.f_float > 255.0 ) val.f_float = 0;
    p_sys->i_quality = (int)(FF_QP2LAMBDA * val.f_float + 0.5);

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
    var_Get( p_enc, ENC_CFG_PREFIX "hq", &val );
    if( val.psz_string && *val.psz_string )
    {
        if( !strcmp( val.psz_string, "rd" ) )
            p_sys->i_hq = FF_MB_DECISION_RD;
        else if( !strcmp( val.psz_string, "bits" ) )
            p_sys->i_hq = FF_MB_DECISION_BITS;
        else if( !strcmp( val.psz_string, "simple" ) )
            p_sys->i_hq = FF_MB_DECISION_SIMPLE;
        else
            p_sys->i_hq = FF_MB_DECISION_RD;
    }
    if( val.psz_string ) free( val.psz_string );

    var_Get( p_enc, ENC_CFG_PREFIX "qmin", &val );
    p_sys->i_qmin = val.i_int;
    var_Get( p_enc, ENC_CFG_PREFIX "qmax", &val );
    p_sys->i_qmax = val.i_int;
    var_Get( p_enc, ENC_CFG_PREFIX "trellis", &val );
    p_sys->b_trellis = val.b_bool;

gbazin's avatar
gbazin committed
352
353
354
355
    var_Get( p_enc, ENC_CFG_PREFIX "strict", &val );
    if( val.i_int < - 1 || val.i_int > 1 ) val.i_int = 0;
    p_context->strict_std_compliance = val.i_int;

356
357
358
359
360
361
362
363
364
365
366
367
368
    var_Get( p_enc, ENC_CFG_PREFIX "lumi-masking", &val );
    p_sys->f_lumi_masking = val.f_float;
    var_Get( p_enc, ENC_CFG_PREFIX "dark-masking", &val );
    p_sys->f_dark_masking = val.f_float;
    var_Get( p_enc, ENC_CFG_PREFIX "p-masking", &val );
    p_sys->f_p_masking = val.f_float;
    var_Get( p_enc, ENC_CFG_PREFIX "border-masking", &val );
    p_sys->f_border_masking = val.f_float;
    var_Get( p_enc, ENC_CFG_PREFIX "luma-elim-threshold", &val );
    p_sys->i_luma_elim = val.i_int;
    var_Get( p_enc, ENC_CFG_PREFIX "chroma-elim-threshold", &val );
    p_sys->i_chroma_elim = val.i_int;

gbazin's avatar
   
gbazin committed
369
370
    if( p_enc->fmt_in.i_cat == VIDEO_ES )
    {
371
372
        int i_aspect_num, i_aspect_den;

373
374
375
376
377
378
379
380
        if( !p_enc->fmt_in.video.i_width || !p_enc->fmt_in.video.i_height )
        {
            msg_Warn( p_enc, "invalid size %ix%i", p_enc->fmt_in.video.i_width,
                      p_enc->fmt_in.video.i_height );
            free( p_sys );
            return VLC_EGENERIC;
        }

gbazin's avatar
   
gbazin committed
381
382
        p_context->width = p_enc->fmt_in.video.i_width;
        p_context->height = p_enc->fmt_in.video.i_height;
383
384
385
        if( p_enc->fmt_out.i_codec == VLC_FOURCC('m', 'p', '2', 'v')
             && (p_context->width > 720 || p_context->height > 576) )
            p_context->level = 4; /* High level */
gbazin's avatar
   
gbazin committed
386

387
388
        p_context->time_base.num = p_enc->fmt_in.video.i_frame_rate_base;
        p_context->time_base.den = p_enc->fmt_in.video.i_frame_rate;
gbazin's avatar
   
gbazin committed
389

390
391
392
393
394
395
396
397
        /* Defaults from ffmpeg.c */
        p_context->qblur = 0.5;
        p_context->qcompress = 0.5;
        p_context->b_quant_offset = 1.25;
        p_context->b_quant_factor = 1.25;
        p_context->i_quant_offset = 0.0;
        p_context->i_quant_factor = -0.8;

398
399
400
401
402
403
404
        p_context->lumi_masking = p_sys->f_lumi_masking;
        p_context->dark_masking = p_sys->f_dark_masking;
        p_context->p_masking = p_sys->f_p_masking;
        p_context->border_masking = p_sys->f_border_masking;
        p_context->luma_elim_threshold = p_sys->i_luma_elim;
        p_context->chroma_elim_threshold = p_sys->i_chroma_elim;

405
406
        if( p_sys->i_key_int > 0 )
            p_context->gop_size = p_sys->i_key_int;
407
        p_context->max_b_frames =
408
            __MAX( __MIN( p_sys->i_b_frames, FF_MAX_B_FRAMES ), 0 );
409
        p_context->b_frame_strategy = 0;
410
411
412
        if( !p_context->max_b_frames  && 
            (  p_enc->fmt_out.i_codec == VLC_FOURCC('m', 'p', '2', 'v') ||
               p_enc->fmt_out.i_codec == VLC_FOURCC('m', 'p', '1', 'v') ) )
413
            p_context->flags |= CODEC_FLAG_LOW_DELAY;
414

415
        av_reduce( &i_aspect_num, &i_aspect_den,
416
417
                   p_enc->fmt_in.video.i_aspect,
                   VOUT_ASPECT_FACTOR, 1 << 30 /* something big */ );
418
419
420
421
        av_reduce( &p_context->sample_aspect_ratio.num,
                   &p_context->sample_aspect_ratio.den,
                   i_aspect_num * (int64_t)p_context->height,
                   i_aspect_den * (int64_t)p_context->width, 1 << 30 );
gbazin's avatar
   
gbazin committed
422

423
        p_sys->p_buffer_out = malloc( p_context->height * p_context->width * 3 );
gbazin's avatar
   
gbazin committed
424

425
        p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
426
427
428
429
430
431
432
433
434
435
436
        p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->fmt_in.i_codec );
        if( p_codec->pix_fmts )
        {
            const enum PixelFormat *p = p_codec->pix_fmts;
            for( ; *p != -1; p++ )
            {
                if( *p == p_context->pix_fmt ) break;
            }
            if( *p == -1 ) p_context->pix_fmt = p_codec->pix_fmts[0];
            p_enc->fmt_in.i_codec = E_(GetVlcChroma)( p_context->pix_fmt );
        }
Christophe Massiot's avatar
Christophe Massiot committed
437

438
        if ( p_sys->b_strict_rc )
Christophe Massiot's avatar
Christophe Massiot committed
439
440
        {
            p_context->rc_max_rate = p_enc->fmt_out.i_bitrate;
441
            p_context->rc_buffer_size = p_sys->i_rc_buffer_size;
442
443
444
            /* This is from ffmpeg's ffmpeg.c : */
            p_context->rc_initial_buffer_occupancy
                = p_sys->i_rc_buffer_size * 3/4;
445
            p_context->rc_buffer_aggressivity = p_sys->f_rc_buffer_aggressivity;
446
447
        }

448
449
        if ( p_sys->f_i_quant_factor != 0.0 )
            p_context->i_quant_factor = p_sys->f_i_quant_factor;
450

451
        p_context->noise_reduction = p_sys->i_noise_reduction;
452

453
        if ( p_sys->b_mpeg4_matrix )
454
        {
455
456
            p_context->intra_matrix = mpeg4_default_intra_matrix;
            p_context->inter_matrix = mpeg4_default_non_intra_matrix;
Christophe Massiot's avatar
Christophe Massiot committed
457
458
        }

459
        if ( p_sys->b_pre_me )
Christophe Massiot's avatar
Christophe Massiot committed
460
461
462
463
        {
            p_context->pre_me = 1;
            p_context->me_pre_cmp = FF_CMP_CHROMA;
        }
464

465
        if ( p_sys->b_interlace )
466
        {
467
468
            if ( p_context->height <= 280 )
            {
469
470
471
472
                if ( p_context->height != 16 || p_context->width != 16 )
                    msg_Warn( p_enc,
                        "disabling interlaced video because height=%d <= 280",
                        p_context->height );
473
474
475
476
477
478
479
            }
            else
            {
                p_context->flags |= CODEC_FLAG_INTERLACED_DCT;
                if ( p_sys->b_interlace_me )
                    p_context->flags |= CODEC_FLAG_INTERLACED_ME;
            }
480
481
        }

482
        if ( p_sys->b_trellis )
483
484
            p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;

485
        if ( p_sys->i_qmin > 0 && p_sys->i_qmin == p_sys->i_qmax )
486
487
            p_context->flags |= CODEC_FLAG_QSCALE;

488
489
490
        if ( p_enc->i_threads >= 1 )
            p_context->thread_count = p_enc->i_threads;

491
492
        if( p_sys->i_vtolerance > 0 )
            p_context->bit_rate_tolerance = p_sys->i_vtolerance;
493

494
495
496
497
        if( p_sys->i_qmin > 0 )
            p_context->mb_qmin = p_context->qmin = p_sys->i_qmin;
        if( p_sys->i_qmax > 0 )
            p_context->mb_qmax = p_context->qmax = p_sys->i_qmax;
498
499
        p_context->max_qdiff = 3;

500
        p_context->mb_decision = p_sys->i_hq;
gbazin's avatar
gbazin committed
501
502
503
504
505
506

        if( p_sys->i_quality )
        {
            p_context->flags |= CODEC_FLAG_QSCALE;
            p_context->global_quality = p_sys->i_quality;
        }
gbazin's avatar
   
gbazin committed
507
508
509
    }
    else if( p_enc->fmt_in.i_cat == AUDIO_ES )
    {
510
511
512
513
        /* work around bug in libmp3lame encoding */
        if( i_codec_id == CODEC_ID_MP3 && p_enc->fmt_in.audio.i_channels > 2 )
            p_enc->fmt_in.audio.i_channels = 2;

gbazin's avatar
   
gbazin committed
514
515
516
517
518
519
        p_enc->fmt_in.i_codec  = AOUT_FMT_S16_NE;
        p_context->sample_rate = p_enc->fmt_in.audio.i_rate;
        p_context->channels    = p_enc->fmt_in.audio.i_channels;
    }

    /* Misc parameters */
gbazin's avatar
   
gbazin committed
520
    p_context->bit_rate = p_enc->fmt_out.i_bitrate;
gbazin's avatar
   
gbazin committed
521

gbazin's avatar
   
gbazin committed
522
    if( i_codec_id == CODEC_ID_RAWVIDEO )
gbazin's avatar
   
gbazin committed
523
    {
524
525
        /* XXX: hack: Force same codec (will be handled by transcode) */
        p_enc->fmt_in.i_codec = p_enc->fmt_out.i_codec;
gbazin's avatar
   
gbazin committed
526
        p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->fmt_in.i_codec );
gbazin's avatar
   
gbazin committed
527
528
529
530
531
532
533
    }

    /* Make sure we get extradata filled by the encoder */
    p_context->extradata_size = 0;
    p_context->extradata = NULL;
    p_context->flags |= CODEC_FLAG_GLOBAL_HEADER;

534
    vlc_mutex_lock( lockval.p_address );
gbazin's avatar
   
gbazin committed
535
    if( avcodec_open( p_context, p_codec ) )
gbazin's avatar
   
gbazin committed
536
    {
537
        vlc_mutex_unlock( lockval.p_address );
538
539
540
        if( p_enc->fmt_in.i_cat == AUDIO_ES &&
             (p_context->channels > 2 || i_codec_id == CODEC_ID_MP2
               || i_codec_id == CODEC_ID_MP3) )
gbazin's avatar
   
gbazin committed
541
        {
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
            if( p_context->channels > 2 )
            {
                p_context->channels = 2;
                p_enc->fmt_in.audio.i_channels = 2; // FIXME
                msg_Warn( p_enc, "stereo mode selected (codec limitation)" );
            }

            if( i_codec_id == CODEC_ID_MP2 || i_codec_id == CODEC_ID_MP3 )
            {
                int i_frequency, i;

                for ( i_frequency = 0; i_frequency < 6; i_frequency++ )
                {
                    if ( p_enc->fmt_out.audio.i_rate
                            == mpa_freq_tab[i_frequency] )
                        break;
                }
                if ( i_frequency == 6 )
                {
                    msg_Err( p_enc, "MPEG audio doesn't support frequency=%d",
                             p_enc->fmt_out.audio.i_rate );
                    free( p_sys );
                    return VLC_EGENERIC;
                }

                for ( i = 1; i < 14; i++ )
                {
                    if ( p_enc->fmt_out.i_bitrate / 1000
                          <= mpa_bitrate_tab[i_frequency / 3][i] )
                        break;
                }
                if ( p_enc->fmt_out.i_bitrate / 1000
                      != mpa_bitrate_tab[i_frequency / 3][i] )
                {
                    msg_Warn( p_enc,
                              "MPEG audio doesn't support bitrate=%d, using %d",
                              p_enc->fmt_out.i_bitrate,
                              mpa_bitrate_tab[i_frequency / 3][i] * 1000 );
                    p_enc->fmt_out.i_bitrate =
                        mpa_bitrate_tab[i_frequency / 3][i] * 1000;
                    p_context->bit_rate = p_enc->fmt_out.i_bitrate;
                }
            }

            p_context->codec = NULL;
587
            vlc_mutex_lock( lockval.p_address );
gbazin's avatar
   
gbazin committed
588
589
            if( avcodec_open( p_context, p_codec ) )
            {
590
                vlc_mutex_unlock( lockval.p_address );
gbazin's avatar
   
gbazin committed
591
                msg_Err( p_enc, "cannot open encoder" );
592
593
                intf_UserFatal( p_enc, VLC_FALSE, _("Streaming / Transcoding failed"), 
                                _("VLC could not open the encoder.") );
594
                free( p_sys );
gbazin's avatar
   
gbazin committed
595
596
597
598
599
600
                return VLC_EGENERIC;
            }
        }
        else
        {
            msg_Err( p_enc, "cannot open encoder" );
601
602
            intf_UserFatal( p_enc, VLC_FALSE, _("Streaming / Transcoding failed"), 
                            _("VLC could not open the encoder.") );
603
            free( p_sys );
gbazin's avatar
   
gbazin committed
604
605
            return VLC_EGENERIC;
        }
gbazin's avatar
   
gbazin committed
606
    }
607
    vlc_mutex_unlock( lockval.p_address );
gbazin's avatar
   
gbazin committed
608

gbazin's avatar
   
gbazin committed
609
    p_enc->fmt_out.i_extra = p_context->extradata_size;
610
611
612
613
614
615
    if( p_enc->fmt_out.i_extra )
    {
        p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
        memcpy( p_enc->fmt_out.p_extra, p_context->extradata,
                p_enc->fmt_out.i_extra );
    }
gbazin's avatar
   
gbazin committed
616
617
    p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;

gbazin's avatar
   
gbazin committed
618
619
    if( p_enc->fmt_in.i_cat == AUDIO_ES )
    {
620
        p_sys->p_buffer_out = malloc( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
gbazin's avatar
   
gbazin committed
621
622
623
624
        p_sys->i_frame_size = p_context->frame_size * 2 * p_context->channels;
        p_sys->p_buffer = malloc( p_sys->i_frame_size );
    }

gbazin's avatar
   
gbazin committed
625
626
    msg_Dbg( p_enc, "found encoder %s", psz_namecodec );

gbazin's avatar
   
gbazin committed
627
628
629
    return VLC_SUCCESS;
}

630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
/****************************************************************************
 * Ffmpeg threading system
 ****************************************************************************/
static int FfmpegThread( struct thread_context_t *p_context )
{
    while ( !p_context->b_die && !p_context->b_error )
    {
        vlc_mutex_lock( &p_context->lock );
        while ( !p_context->b_work && !p_context->b_die && !p_context->b_error )
        {
            vlc_cond_wait( &p_context->cond, &p_context->lock );
        }
        p_context->b_work = 0;
        vlc_mutex_unlock( &p_context->lock );
        if ( p_context->b_die || p_context->b_error )
            break;

        if ( p_context->pf_func )
        {
            p_context->i_ret = p_context->pf_func( p_context->p_context,
                                                   p_context->arg );
        }

        vlc_mutex_lock( &p_context->lock );
        p_context->b_done = 1;
        vlc_cond_signal( &p_context->cond );
        vlc_mutex_unlock( &p_context->lock );
    }

    return 0;
}

static int FfmpegExecute( AVCodecContext *s,
                          int (*pf_func)(AVCodecContext *c2, void *arg2),
                          void **arg, int *ret, int count )
{
    struct thread_context_t ** pp_contexts =
                         (struct thread_context_t **)s->thread_opaque;
    int i;

    /* Note, we can be certain that this is not called with the same
     * AVCodecContext by different threads at the same time */
    for ( i = 0; i < count; i++ )
    {
        vlc_mutex_lock( &pp_contexts[i]->lock );
        pp_contexts[i]->arg = arg[i];
        pp_contexts[i]->pf_func = pf_func;
        pp_contexts[i]->i_ret = 12345;
        pp_contexts[i]->b_work = 1;
        vlc_cond_signal( &pp_contexts[i]->cond );
        vlc_mutex_unlock( &pp_contexts[i]->lock );
    }
    for ( i = 0; i < count; i++ )
    {
        vlc_mutex_lock( &pp_contexts[i]->lock );
        while ( !pp_contexts[i]->b_done )
        {
            vlc_cond_wait( &pp_contexts[i]->cond, &pp_contexts[i]->lock );
        }
        pp_contexts[i]->b_done = 0;
        pp_contexts[i]->pf_func = NULL;
        vlc_mutex_unlock( &pp_contexts[i]->lock );

        if ( ret )
        {
            ret[i] = pp_contexts[i]->i_ret;
        }
    }

    return 0;
}

gbazin's avatar
   
gbazin committed
702
703
704
705
706
707
708
709
/****************************************************************************
 * EncodeVideo: the whole thing
 ****************************************************************************/
static block_t *EncodeVideo( encoder_t *p_enc, picture_t *p_pict )
{
    encoder_sys_t *p_sys = p_enc->p_sys;
    AVFrame frame;
    int i_out, i_plane;
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739

    if ( !p_sys->b_inited && p_enc->i_threads >= 1 )
    {
        struct thread_context_t ** pp_contexts;
        int i;

        p_sys->b_inited = 1;
        pp_contexts = malloc( sizeof(struct thread_context_t *)
                                 * p_enc->i_threads );
        p_sys->p_context->thread_opaque = (void *)pp_contexts;

        for ( i = 0; i < p_enc->i_threads; i++ )
        {
            pp_contexts[i] = vlc_object_create( p_enc,
                                     sizeof(struct thread_context_t) );
            pp_contexts[i]->p_context = p_sys->p_context;
            vlc_mutex_init( p_enc, &pp_contexts[i]->lock );
            vlc_cond_init( p_enc, &pp_contexts[i]->cond );
            pp_contexts[i]->b_work = 0;
            pp_contexts[i]->b_done = 0;
            if ( vlc_thread_create( pp_contexts[i], "encoder", FfmpegThread,
                                    VLC_THREAD_PRIORITY_VIDEO, VLC_FALSE ) )
            {
                msg_Err( p_enc, "cannot spawn encoder thread, expect to die soon" );
                return NULL;
            }
        }

        p_sys->p_context->execute = FfmpegExecute;
    }
gbazin's avatar
   
gbazin committed
740

Laurent Aimar's avatar
Laurent Aimar committed
741
    memset( &frame, 0, sizeof( AVFrame ) );
gbazin's avatar
   
gbazin committed
742
743
744
745
746
747
    for( i_plane = 0; i_plane < p_pict->i_planes; i_plane++ )
    {
        frame.data[i_plane] = p_pict->p[i_plane].p_pixels;
        frame.linesize[i_plane] = p_pict->p[i_plane].i_pitch;
    }

748
749
750
    /* Let ffmpeg select the frame type */
    frame.pict_type = 0;

751
    frame.repeat_pict = p_pict->i_nb_fields - 2;
752
    frame.interlaced_frame = !p_pict->b_progressive;
753
    frame.top_field_first = !!p_pict->b_top_field_first;
754

gbazin's avatar
   
gbazin committed
755
    /* Set the pts of the frame being encoded (segfaults with mpeg4!)*/
756
757
758
    if( p_enc->fmt_out.i_codec == VLC_FOURCC( 'm', 'p', 'g', 'v' ) ||
        p_enc->fmt_out.i_codec == VLC_FOURCC( 'm', 'p', '1', 'v' ) ||
        p_enc->fmt_out.i_codec == VLC_FOURCC( 'm', 'p', '2', 'v' ) )
Christophe Massiot's avatar
Christophe Massiot committed
759
    {
760
        frame.pts = p_pict->date ? p_pict->date : (int64_t)AV_NOPTS_VALUE;
761

762
        if ( p_sys->b_hurry_up && frame.pts != (int64_t)AV_NOPTS_VALUE )
Christophe Massiot's avatar
Christophe Massiot committed
763
        {
764
765
            mtime_t current_date = mdate();

766
            if ( current_date + HURRY_UP_GUARD3 > frame.pts )
767
768
769
770
771
772
773
            {
                p_sys->p_context->mb_decision = FF_MB_DECISION_SIMPLE;
                p_sys->p_context->flags &= ~CODEC_FLAG_TRELLIS_QUANT;
                msg_Dbg( p_enc, "hurry up mode 3" );
            }
            else
            {
774
                p_sys->p_context->mb_decision = p_sys->i_hq;
775

776
                if ( current_date + HURRY_UP_GUARD2 > frame.pts )
777
778
                {
                    p_sys->p_context->flags &= ~CODEC_FLAG_TRELLIS_QUANT;
779
                    p_sys->p_context->noise_reduction = p_sys->i_noise_reduction
780
                         + (HURRY_UP_GUARD2 + current_date - frame.pts) / 500;
781
782
783
784
                    msg_Dbg( p_enc, "hurry up mode 2" );
                }
                else
                {
785
                    if ( p_sys->b_trellis )
786
                        p_sys->p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;
787
                        
788
                    p_sys->p_context->noise_reduction =
789
                        p_sys->i_noise_reduction;
790
791
792
                }
            }

793
            if ( current_date + HURRY_UP_GUARD1 > frame.pts )
794
            {
795
796
                frame.pict_type = FF_P_TYPE;
                /* msg_Dbg( p_enc, "hurry up mode 1 %lld", current_date + HURRY_UP_GUARD1 - frame.pts ); */
797
            }
Christophe Massiot's avatar
Christophe Massiot committed
798
799
        }
    }
gbazin's avatar
   
gbazin committed
800
    else
Christophe Massiot's avatar
Christophe Massiot committed
801
    {
802
        frame.pts = (int64_t)AV_NOPTS_VALUE;
Christophe Massiot's avatar
Christophe Massiot committed
803
    }
gbazin's avatar
   
gbazin committed
804

805
    if ( frame.pts != (int64_t)AV_NOPTS_VALUE && frame.pts != 0 )
806
807
808
    {
        if ( p_sys->i_last_pts == frame.pts )
        {
gbazin's avatar
gbazin committed
809
810
            msg_Warn( p_enc, "almost fed libavcodec with two frames with the "
                      "same PTS (" I64Fd ")", frame.pts );
811
812
            return NULL;
        }
813
814
815
816
817
818
819
        else if ( p_sys->i_last_pts > frame.pts )
        {
            msg_Warn( p_enc, "almost fed libavcodec with a frame in the "
                      "past (current: " I64Fd ", last: "I64Fd")",
                      frame.pts, p_sys->i_last_pts );
            return NULL;
        }
820
821
822
823
824
        else
        {
            p_sys->i_last_pts = frame.pts;
        }
    }
gbazin's avatar
   
gbazin committed
825

gbazin's avatar
gbazin committed
826
827
    frame.quality = p_sys->i_quality;

828
829
830
831
832
833
834
835
836
    /* Ugly work-around for stupid libavcodec behaviour */
    p_sys->i_framenum++;
    p_sys->pi_delay_pts[p_sys->i_framenum % MAX_FRAME_DELAY] = frame.pts;
    frame.pts = p_sys->i_framenum * AV_TIME_BASE *
        p_enc->fmt_in.video.i_frame_rate_base;
    frame.pts += p_enc->fmt_in.video.i_frame_rate - 1;
    frame.pts /= p_enc->fmt_in.video.i_frame_rate;
    /* End work-around */

837
    i_out = avcodec_encode_video( p_sys->p_context, (uint8_t*)p_sys->p_buffer_out,
hartman's avatar
hartman committed
838
                                  p_sys->p_context->height * p_sys->p_context->width * 3, &frame );
Christophe Massiot's avatar
Christophe Massiot committed
839

gbazin's avatar
   
gbazin committed
840
841
842
843
844
    if( i_out > 0 )
    {
        block_t *p_block = block_New( p_enc, i_out );
        memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out );

845
846
847
848
849
850
851
852
853
854
        /* FIXME, 3-2 pulldown is not handled correctly */
        p_block->i_length = I64C(1000000) *
            p_enc->fmt_in.video.i_frame_rate_base /
                p_enc->fmt_in.video.i_frame_rate;

        if( !p_sys->p_context->max_b_frames || !p_sys->p_context->delay )
        {
            /* No delay -> output pts == input pts */
            p_block->i_pts = p_block->i_dts = p_pict->date;
        }
855
        else if( p_sys->p_context->coded_frame->pts != (int64_t)AV_NOPTS_VALUE &&
gbazin's avatar
gbazin committed
856
            p_sys->p_context->coded_frame->pts != 0 &&
gbazin's avatar
   
gbazin committed
857
858
859
            p_sys->i_buggy_pts_detect != p_sys->p_context->coded_frame->pts )
        {
            p_sys->i_buggy_pts_detect = p_sys->p_context->coded_frame->pts;
860
            p_block->i_pts = p_sys->p_context->coded_frame->pts;
gbazin's avatar
   
gbazin committed
861

862
863
            /* Ugly work-around for stupid libavcodec behaviour */
            {
864
865
866
                int64_t i_framenum = p_block->i_pts *
                    p_enc->fmt_in.video.i_frame_rate /
                    p_enc->fmt_in.video.i_frame_rate_base / AV_TIME_BASE;
gbazin's avatar
   
gbazin committed
867

868
                p_block->i_pts = p_sys->pi_delay_pts[i_framenum % MAX_FRAME_DELAY];
869
870
871
872
873
            }
            /* End work-around */

            if( p_sys->p_context->coded_frame->pict_type != FF_I_TYPE &&
                p_sys->p_context->coded_frame->pict_type != FF_P_TYPE )
gbazin's avatar
   
gbazin committed
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
            {
                p_block->i_dts = p_block->i_pts;
            }
            else
            {
                if( p_sys->i_last_ref_pts )
                {
                    p_block->i_dts = p_sys->i_last_ref_pts;
                }
                else
                {
                    /* Let's put something sensible */
                    p_block->i_dts = p_block->i_pts;
                }

                p_sys->i_last_ref_pts = p_block->i_pts;
            }
        }
        else
        {
            /* Buggy libavcodec which doesn't update coded_frame->pts
             * correctly */
            p_block->i_dts = p_block->i_pts = p_pict->date;
        }

899
900
901
902
903
904
905
906
907
908
909
910
911
        switch ( p_sys->p_context->coded_frame->pict_type )
        {
        case FF_I_TYPE:
            p_block->i_flags |= BLOCK_FLAG_TYPE_I;
            break;
        case FF_P_TYPE:
            p_block->i_flags |= BLOCK_FLAG_TYPE_P;
            break;
        case FF_B_TYPE:
            p_block->i_flags |= BLOCK_FLAG_TYPE_B;
            break;
        }

gbazin's avatar
   
gbazin committed
912
913
914
915
916
917
918
919
920
921
922
923
924
        return p_block;
    }

    return NULL;
}

/****************************************************************************
 * EncodeAudio: the whole thing
 ****************************************************************************/
static block_t *EncodeAudio( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
{
    encoder_sys_t *p_sys = p_enc->p_sys;
    block_t *p_block, *p_chain = NULL;
gbazin's avatar
   
gbazin committed
925

926
    uint8_t *p_buffer = p_aout_buf->p_buffer;
gbazin's avatar
   
gbazin committed
927
928
929
930
931
    int i_samples = p_aout_buf->i_nb_samples;
    int i_samples_delay = p_sys->i_samples_delay;

    p_sys->i_pts = p_aout_buf->start_date -
                (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
gbazin's avatar
   
gbazin committed
932
                (mtime_t)p_enc->fmt_in.audio.i_rate;
gbazin's avatar
   
gbazin committed
933
934
935
936
937
938
939
940
941
942
943

    p_sys->i_samples_delay += i_samples;

    while( p_sys->i_samples_delay >= p_sys->p_context->frame_size )
    {
        int16_t *p_samples;
        int i_out;

        if( i_samples_delay )
        {
            /* Take care of the left-over from last time */
gbazin's avatar
   
gbazin committed
944
            int i_delay_size = i_samples_delay * 2 *
gbazin's avatar
   
gbazin committed
945
946
947
948
949
950
                                 p_sys->p_context->channels;
            int i_size = p_sys->i_frame_size - i_delay_size;

            p_samples = (int16_t *)p_sys->p_buffer;
            memcpy( p_sys->p_buffer + i_delay_size, p_buffer, i_size );
            p_buffer -= i_delay_size;
gbazin's avatar
   
gbazin committed
951
            i_samples += i_samples_delay;
gbazin's avatar
   
gbazin committed
952
953
954
955
956
957
958
            i_samples_delay = 0;
        }
        else
        {
            p_samples = (int16_t *)p_buffer;
        }

959
        i_out = avcodec_encode_audio( p_sys->p_context, (uint8_t *)p_sys->p_buffer_out,
gbazin's avatar
   
gbazin committed
960
961
                                      2 * AVCODEC_MAX_AUDIO_FRAME_SIZE,
                                      p_samples );
gbazin's avatar
   
gbazin committed
962
963
964
965
966

#if 0
        msg_Warn( p_enc, "avcodec_encode_audio: %d", i_out );
#endif
        if( i_out < 0 ) break;
gbazin's avatar
   
gbazin committed
967
968
969

        p_buffer += p_sys->i_frame_size;
        p_sys->i_samples_delay -= p_sys->p_context->frame_size;
gbazin's avatar
   
gbazin committed
970
971
972
        i_samples -= p_sys->p_context->frame_size;

        if( i_out == 0 ) continue;
gbazin's avatar
   
gbazin committed
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988

        p_block = block_New( p_enc, i_out );
        memcpy( p_block->p_buffer, p_sys->p_buffer_out, i_out );

        p_block->i_length = (mtime_t)1000000 *
            (mtime_t)p_sys->p_context->frame_size /
            (mtime_t)p_sys->p_context->sample_rate;

        p_block->i_dts = p_block->i_pts = p_sys->i_pts;

        /* Update pts */
        p_sys->i_pts += p_block->i_length;
        block_ChainAppend( &p_chain, p_block );
    }

    /* Backup the remaining raw samples */
gbazin's avatar
   
gbazin committed
989
    if( i_samples )
gbazin's avatar
   
gbazin committed
990
    {
gbazin's avatar
   
gbazin committed
991
992
        memcpy( p_sys->p_buffer + i_samples_delay * 2 *
                p_sys->p_context->channels, p_buffer,
gbazin's avatar
   
gbazin committed
993
994
995
996
997
998
999
                i_samples * 2 * p_sys->p_context->channels );
    }

    return p_chain;
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
1000
 * CloseEncoder: ffmpeg encoder destruction
gbazin's avatar
   
gbazin committed
1001
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
1002
void E_(CloseEncoder)( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
1003
1004
1005
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;
1006
1007
    vlc_value_t lockval;

1008
    var_Get( p_enc->p_libvlc_global, "avcodec", &lockval );
gbazin's avatar
   
gbazin committed
1009

1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
    if ( p_sys->b_inited && p_enc->i_threads >= 1 )
    {
        int i;
        struct thread_context_t ** pp_contexts =
                (struct thread_context_t **)p_sys->p_context->thread_opaque;
        for ( i = 0; i < p_enc->i_threads; i++ )
        {
            pp_contexts[i]->b_die = 1;
            vlc_cond_signal( &pp_contexts[i]->cond );
            vlc_thread_join( pp_contexts[i] );
            vlc_mutex_destroy( &pp_contexts[i]->lock );
            vlc_cond_destroy( &pp_contexts[i]->cond );
            vlc_object_destroy( pp_contexts[i] );
        }

1025
        free( pp_contexts );
1026
1027
    }

1028
    vlc_mutex_lock( lockval.p_address );
gbazin's avatar
   
gbazin committed
1029
    avcodec_close( p_sys->p_context );
1030
    vlc_mutex_unlock( lockval.p_address );
1031
    av_free( p_sys->p_context );
gbazin's avatar
   
gbazin committed
1032
1033
1034
1035

    if( p_sys->p_buffer ) free( p_sys->p_buffer );
    if( p_sys->p_buffer_out ) free( p_sys->p_buffer_out );

gbazin's avatar
   
gbazin committed
1036
1037
    free( p_sys );
}