encoder.c 24 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 VideoLAN
gbazin's avatar
gbazin committed
5
 * $Id$
gbazin's avatar
   
gbazin committed
6
7
8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Gildas Bazin <gbazin@netcourrier.com>
9
 *          Christophe Massiot <massiot@via.ecp.fr>
gbazin's avatar
   
gbazin committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 *
 * 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 <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>

/* ffmpeg header */
gbazin's avatar
   
gbazin committed
35
#define HAVE_MMX
gbazin's avatar
   
gbazin committed
36
37
38
39
40
41
#ifdef HAVE_FFMPEG_AVCODEC_H
#   include <ffmpeg/avcodec.h>
#else
#   include <avcodec.h>
#endif

42
43
44
45
#if LIBAVCODEC_BUILD < 4704
#   define AV_NOPTS_VALUE 0
#endif

gbazin's avatar
   
gbazin committed
46
47
48
#include "ffmpeg.h"

#define AVCODEC_MAX_VIDEO_FRAME_SIZE (3*1024*1024)
49
50
51
#define HURRY_UP_GUARD1 (450000)
#define HURRY_UP_GUARD2 (300000)
#define HURRY_UP_GUARD3 (100000)
gbazin's avatar
   
gbazin committed
52
53
54
55

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

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

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
 *****************************************************************************/
#if LIBAVCODEC_BUILD >= 4702
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;
};
#endif

gbazin's avatar
   
gbazin committed
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*****************************************************************************
 * 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
101
102
    char *p_buffer;
    char *p_buffer_out;
gbazin's avatar
   
gbazin committed
103

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

gbazin's avatar
   
gbazin committed
112
113
114
    /*
     * Audio properties
     */
gbazin's avatar
   
gbazin committed
115
    int i_frame_size;
gbazin's avatar
   
gbazin committed
116
117
    int i_samples_delay;
    mtime_t i_pts;
gbazin's avatar
   
gbazin committed
118
119
120
};

/*****************************************************************************
gbazin's avatar
   
gbazin committed
121
 * OpenEncoder: probe the encoder
gbazin's avatar
   
gbazin committed
122
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
123
124
extern int16_t ff_mpeg4_default_intra_matrix[];
extern int16_t ff_mpeg4_default_non_intra_matrix[];
125

gbazin's avatar
   
gbazin committed
126
int E_(OpenEncoder)( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
127
128
129
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;
gbazin's avatar
   
gbazin committed
130
    AVCodecContext *p_context;
gbazin's avatar
   
gbazin committed
131
    AVCodec *p_codec;
gbazin's avatar
   
gbazin committed
132
133
    int i_codec_id, i_cat;
    char *psz_namecodec;
gbazin's avatar
   
gbazin committed
134

gbazin's avatar
   
gbazin committed
135
    if( !E_(GetFfmpegCodec)( p_enc->fmt_out.i_codec, &i_cat, &i_codec_id,
gbazin's avatar
   
gbazin committed
136
                             &psz_namecodec ) )
gbazin's avatar
   
gbazin committed
137
    {
138
139
140
141
142
143
144
145
        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
146
147
    }

148

gbazin's avatar
   
gbazin committed
149
    if( p_enc->fmt_out.i_cat == VIDEO_ES && i_cat != VIDEO_ES )
gbazin's avatar
   
gbazin committed
150
    {
gbazin's avatar
   
gbazin committed
151
        msg_Err( p_enc, "\"%s\" is not a video encoder", psz_namecodec );
gbazin's avatar
   
gbazin committed
152
153
154
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
155
156
157
158
159
160
    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 );
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
161
    /* Initialization must be done before avcodec_find_decoder() */
gbazin's avatar
   
gbazin committed
162
163
    E_(InitLibavcodec)(p_this);

gbazin's avatar
   
gbazin committed
164
165
166
167
168
169
170
    p_codec = avcodec_find_encoder( i_codec_id );
    if( !p_codec )
    {
        msg_Err( p_enc, "cannot find encoder %s", psz_namecodec );
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
171
172
173
174
175
176
177
178
179
180
    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
    {
        msg_Err( p_enc, "out of memory" );
        return VLC_EGENERIC;
    }
    p_enc->p_sys = p_sys;
    p_sys->p_codec = p_codec;

    p_enc->pf_encode_video = EncodeVideo;
gbazin's avatar
   
gbazin committed
181
    p_enc->pf_encode_audio = EncodeAudio;
gbazin's avatar
   
gbazin committed
182

gbazin's avatar
   
gbazin committed
183
184
    p_sys->p_buffer_out = NULL;
    p_sys->p_buffer = NULL;
185
    p_sys->b_inited = 0;
gbazin's avatar
   
gbazin committed
186
187
188
189
190

    p_sys->p_context = p_context = avcodec_alloc_context();

    /* Set CPU capabilities */
    p_context->dsp_mask = 0;
gbazin's avatar
   
gbazin committed
191
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) )
gbazin's avatar
   
gbazin committed
192
    {
gbazin's avatar
   
gbazin committed
193
        p_context->dsp_mask |= FF_MM_MMX;
gbazin's avatar
   
gbazin committed
194
    }
gbazin's avatar
   
gbazin committed
195
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) )
gbazin's avatar
   
gbazin committed
196
    {
gbazin's avatar
   
gbazin committed
197
        p_context->dsp_mask |= FF_MM_MMXEXT;
gbazin's avatar
   
gbazin committed
198
    }
gbazin's avatar
   
gbazin committed
199
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW) )
gbazin's avatar
   
gbazin committed
200
    {
gbazin's avatar
   
gbazin committed
201
        p_context->dsp_mask |= FF_MM_3DNOW;
gbazin's avatar
   
gbazin committed
202
    }
gbazin's avatar
   
gbazin committed
203
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) )
gbazin's avatar
   
gbazin committed
204
    {
gbazin's avatar
   
gbazin committed
205
206
        p_context->dsp_mask |= FF_MM_SSE;
        p_context->dsp_mask |= FF_MM_SSE2;
gbazin's avatar
   
gbazin committed
207
208
    }

gbazin's avatar
   
gbazin committed
209
210
    if( p_enc->fmt_in.i_cat == VIDEO_ES )
    {
211
212
213
214
215
216
217
218
        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
219
220
        p_context->width = p_enc->fmt_in.video.i_width;
        p_context->height = p_enc->fmt_in.video.i_height;
gbazin's avatar
   
gbazin committed
221

gbazin's avatar
   
gbazin committed
222
223
        p_context->frame_rate = p_enc->fmt_in.video.i_frame_rate;
        p_context->frame_rate_base= p_enc->fmt_in.video.i_frame_rate_base;
gbazin's avatar
   
gbazin committed
224

225
226
227
228
229
230
231
232
233
234
235
236
237
        /* 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;

        p_context->gop_size = p_enc->i_key_int > 0 ? p_enc->i_key_int : 50;
        p_context->max_b_frames =
            __MIN( p_enc->i_b_frames, FF_MAX_B_FRAMES );
        p_context->b_frame_strategy = 0;

gbazin's avatar
   
gbazin committed
238
#if LIBAVCODEC_BUILD >= 4687
gbazin's avatar
   
gbazin committed
239
        p_context->sample_aspect_ratio =
gbazin's avatar
   
gbazin committed
240
241
242
            (AVRational){ p_enc->fmt_in.video.i_aspect *
                          (int64_t)p_context->height / p_context->width,
                          VOUT_ASPECT_FACTOR };
gbazin's avatar
   
gbazin committed
243
#else
gbazin's avatar
   
gbazin committed
244
245
        p_context->aspect_ratio = ((float)p_enc->fmt_in.video.i_aspect) /
            VOUT_ASPECT_FACTOR;
gbazin's avatar
   
gbazin committed
246
#endif
gbazin's avatar
   
gbazin committed
247

gbazin's avatar
   
gbazin committed
248
249
        p_sys->p_buffer_out = malloc( AVCODEC_MAX_VIDEO_FRAME_SIZE );

250
        p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
Christophe Massiot's avatar
Christophe Massiot committed
251
252
253
254

        if ( p_enc->b_strict_rc )
        {
            p_context->rc_max_rate = p_enc->fmt_out.i_bitrate;
255
256
257
258
259
260
261
262
263
            p_context->rc_buffer_size = p_enc->i_rc_buffer_size;
            p_context->rc_buffer_aggressivity = p_enc->f_rc_buffer_aggressivity;
        }

        if ( p_enc->f_i_quant_factor != 0.0 )
        {
            p_context->i_quant_factor = p_enc->f_i_quant_factor;
        }

gbazin's avatar
   
gbazin committed
264
#if LIBAVCODEC_BUILD >= 4690
265
        p_context->noise_reduction = p_enc->i_noise_reduction;
gbazin's avatar
   
gbazin committed
266
#endif
267
268
269
270
271

        if ( p_enc->b_mpeg4_matrix )
        {
            p_context->intra_matrix = ff_mpeg4_default_intra_matrix;
            p_context->inter_matrix = ff_mpeg4_default_non_intra_matrix;
Christophe Massiot's avatar
Christophe Massiot committed
272
273
274
275
276
277
278
        }

        if ( p_enc->b_pre_me )
        {
            p_context->pre_me = 1;
            p_context->me_pre_cmp = FF_CMP_CHROMA;
        }
279
280
281
282
283
284
285
286
287
288
289
290
291
292

        if ( p_enc->b_interlace )
        {
            p_context->flags |= CODEC_FLAG_INTERLACED_DCT;
#if LIBAVCODEC_BUILD >= 4698
            p_context->flags |= CODEC_FLAG_INTERLACED_ME;
#endif
        }

        if ( p_enc->b_trellis )
        {
            p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;
        }

gbazin's avatar
   
gbazin committed
293
#if LIBAVCODEC_BUILD >= 4702
294
295
296
297
        if ( p_enc->i_threads >= 1 )
        {
            p_context->thread_count = p_enc->i_threads;
        }
gbazin's avatar
   
gbazin committed
298
#endif
299
300
301
302
303
304
305
306
307
308
309

        if( p_enc->i_vtolerance > 0 )
        {
            p_context->bit_rate_tolerance = p_enc->i_vtolerance;
        }

        p_context->mb_qmin = p_context->qmin = p_enc->i_qmin;
        p_context->mb_qmax = p_context->qmax = p_enc->i_qmax;
        p_context->max_qdiff = 3;

        p_context->mb_decision = p_enc->i_hq;
gbazin's avatar
   
gbazin committed
310
311
312
313
314
315
316
317
318
319
320
321
    }
    else if( p_enc->fmt_in.i_cat == AUDIO_ES )
    {
        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;
        p_sys->i_frame_size = p_context->frame_size * 2 * p_context->channels;
        p_sys->p_buffer = malloc( p_sys->i_frame_size );
        p_sys->p_buffer_out = malloc( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
    }

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

gbazin's avatar
   
gbazin committed
324
    if( i_codec_id == CODEC_ID_RAWVIDEO )
gbazin's avatar
   
gbazin committed
325
    {
326
327
        /* 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
328
        p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->fmt_in.i_codec );
gbazin's avatar
   
gbazin committed
329
330
331
332
333
334
335
    }

    /* 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;

gbazin's avatar
   
gbazin committed
336
    if( avcodec_open( p_context, p_codec ) )
gbazin's avatar
   
gbazin committed
337
    {
gbazin's avatar
   
gbazin committed
338
339
340
341
342
343
344
        if( p_enc->fmt_in.i_cat == AUDIO_ES && p_context->channels > 2 )
        {
            p_context->channels = 2;
            p_enc->fmt_in.audio.i_channels = 2; // FIXME
            if( avcodec_open( p_context, p_codec ) )
            {
                msg_Err( p_enc, "cannot open encoder" );
345
                free( p_sys );
gbazin's avatar
   
gbazin committed
346
347
348
349
350
351
352
                return VLC_EGENERIC;
            }
            msg_Warn( p_enc, "stereo mode selected (codec limitation)" );
        }
        else
        {
            msg_Err( p_enc, "cannot open encoder" );
353
            free( p_sys );
gbazin's avatar
   
gbazin committed
354
355
            return VLC_EGENERIC;
        }
gbazin's avatar
   
gbazin committed
356
357
    }

gbazin's avatar
   
gbazin committed
358
359
    p_enc->fmt_out.i_extra = p_context->extradata_size;
    p_enc->fmt_out.p_extra = p_context->extradata;
gbazin's avatar
   
gbazin committed
360
361
    p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;

gbazin's avatar
   
gbazin committed
362
363
364
365
366
367
    if( p_enc->fmt_in.i_cat == AUDIO_ES )
    {
        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
368
369
    p_sys->i_last_ref_pts = 0;
    p_sys->i_buggy_pts_detect = 0;
gbazin's avatar
   
gbazin committed
370
371
    p_sys->i_samples_delay = 0;
    p_sys->i_pts = 0;
372
    p_sys->i_last_pts = 0;
gbazin's avatar
   
gbazin committed
373

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

gbazin's avatar
   
gbazin committed
376
377
378
    return VLC_SUCCESS;
}

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
/****************************************************************************
 * Ffmpeg threading system
 ****************************************************************************/
#if LIBAVCODEC_BUILD >= 4702
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;
}
#endif

gbazin's avatar
   
gbazin committed
453
454
455
456
457
458
459
460
/****************************************************************************
 * 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;
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492

#if LIBAVCODEC_BUILD >= 4702
    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;
    }
#endif
gbazin's avatar
   
gbazin committed
493

Laurent Aimar's avatar
Laurent Aimar committed
494
    memset( &frame, 0, sizeof( AVFrame ) );
gbazin's avatar
   
gbazin committed
495
496
497
498
499
500
    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;
    }

501
502
503
504
505
506
507
508
509
510
    /* Let ffmpeg select the frame type */
    frame.pict_type = 0;

    frame.repeat_pict = p_pict->i_nb_fields;

#if LIBAVCODEC_BUILD >= 4685
    frame.interlaced_frame = !p_pict->b_progressive;
    frame.top_field_first = p_pict->b_top_field_first;
#endif

gbazin's avatar
   
gbazin committed
511
    /* Set the pts of the frame being encoded (segfaults with mpeg4!)*/
512
513
514
    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
515
    {
516
        frame.pts = p_pict->date ? p_pict->date : AV_NOPTS_VALUE;
517

518
        if ( p_enc->b_hurry_up && frame.pts != AV_NOPTS_VALUE )
Christophe Massiot's avatar
Christophe Massiot committed
519
        {
520
521
            mtime_t current_date = mdate();

522
            if ( current_date + HURRY_UP_GUARD3 > frame.pts )
523
524
525
526
527
528
529
530
531
            {
                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
            {
                p_sys->p_context->mb_decision = p_enc->i_hq;

532
                if ( current_date + HURRY_UP_GUARD2 > frame.pts )
533
534
                {
                    p_sys->p_context->flags &= ~CODEC_FLAG_TRELLIS_QUANT;
535
536
537
#if LIBAVCODEC_BUILD >= 4690
                    p_sys->p_context->noise_reduction = p_enc->i_noise_reduction
                         + (HURRY_UP_GUARD2 + current_date - frame.pts) / 500;
538
539
540
541
542
543
544
#endif
                    msg_Dbg( p_enc, "hurry up mode 2" );
                }
                else
                {
                    if ( p_enc->b_trellis )
                        p_sys->p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;
545
546
547
#if LIBAVCODEC_BUILD >= 4690
                    p_sys->p_context->noise_reduction =
                                    p_enc->i_noise_reduction;
548
549
550
551
#endif
                }
            }

552
            if ( current_date + HURRY_UP_GUARD1 > frame.pts )
553
            {
554
555
                frame.pict_type = FF_P_TYPE;
                /* msg_Dbg( p_enc, "hurry up mode 1 %lld", current_date + HURRY_UP_GUARD1 - frame.pts ); */
556
            }
Christophe Massiot's avatar
Christophe Massiot committed
557
558
        }
    }
gbazin's avatar
   
gbazin committed
559
    else
Christophe Massiot's avatar
Christophe Massiot committed
560
    {
gbazin's avatar
gbazin committed
561
        frame.pts = 0;
Christophe Massiot's avatar
Christophe Massiot committed
562
    }
gbazin's avatar
   
gbazin committed
563

gbazin's avatar
gbazin committed
564
    if ( frame.pts != AV_NOPTS_VALUE && frame.pts != 0 )
565
566
567
    {
        if ( p_sys->i_last_pts == frame.pts )
        {
gbazin's avatar
gbazin committed
568
569
            msg_Warn( p_enc, "almost fed libavcodec with two frames with the "
                      "same PTS (" I64Fd ")", frame.pts );
570
571
572
573
574
575
576
            return NULL;
        }
        else
        {
            p_sys->i_last_pts = frame.pts;
        }
    }
gbazin's avatar
   
gbazin committed
577
578
579

    i_out = avcodec_encode_video( p_sys->p_context, p_sys->p_buffer_out,
                                  AVCODEC_MAX_VIDEO_FRAME_SIZE, &frame );
Christophe Massiot's avatar
Christophe Massiot committed
580

gbazin's avatar
   
gbazin committed
581
582
583
584
585
    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 );

586
        if( p_sys->p_context->coded_frame->pts != AV_NOPTS_VALUE &&
gbazin's avatar
gbazin committed
587
            p_sys->p_context->coded_frame->pts != 0 &&
gbazin's avatar
   
gbazin committed
588
589
590
591
592
            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;

            /* FIXME, 3-2 pulldown is not handled correctly */
gbazin's avatar
   
gbazin committed
593
594
595
            p_block->i_length = I64C(1000000) *
                p_enc->fmt_in.video.i_frame_rate_base /
                p_enc->fmt_in.video.i_frame_rate;
gbazin's avatar
   
gbazin committed
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
            p_block->i_pts    = p_sys->p_context->coded_frame->pts;

            if( !p_sys->p_context->delay ||
                ( p_sys->p_context->coded_frame->pict_type != FF_I_TYPE &&
                  p_sys->p_context->coded_frame->pict_type != FF_P_TYPE ) )
            {
                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 */
gbazin's avatar
   
gbazin committed
623
624
625
            p_block->i_length = I64C(1000000) *
                p_enc->fmt_in.video.i_frame_rate_base /
                p_enc->fmt_in.video.i_frame_rate;
gbazin's avatar
   
gbazin committed
626
627
628
            p_block->i_dts = p_block->i_pts = p_pict->date;
        }

629
630
631
632
633
634
635
636
637
638
639
640
641
        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
642
643
644
645
646
647
648
649
650
651
652
653
654
        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
655

gbazin's avatar
   
gbazin committed
656
657
658
659
660
661
    char *p_buffer = p_aout_buf->p_buffer;
    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
662
                (mtime_t)p_enc->fmt_in.audio.i_rate;
gbazin's avatar
   
gbazin committed
663
664
665
666
667
668
669
670
671
672
673

    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
674
            int i_delay_size = i_samples_delay * 2 *
gbazin's avatar
   
gbazin committed
675
676
677
678
679
680
                                 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
681
            i_samples += i_samples_delay;
gbazin's avatar
   
gbazin committed
682
683
684
685
686
687
688
689
690
691
            i_samples_delay = 0;
        }
        else
        {
            p_samples = (int16_t *)p_buffer;
        }

        i_out = avcodec_encode_audio( p_sys->p_context, p_sys->p_buffer_out,
                                      2 * AVCODEC_MAX_AUDIO_FRAME_SIZE,
                                      p_samples );
gbazin's avatar
   
gbazin committed
692
693
694
695
696

#if 0
        msg_Warn( p_enc, "avcodec_encode_audio: %d", i_out );
#endif
        if( i_out < 0 ) break;
gbazin's avatar
   
gbazin committed
697
698
699

        p_buffer += p_sys->i_frame_size;
        p_sys->i_samples_delay -= p_sys->p_context->frame_size;
gbazin's avatar
   
gbazin committed
700
701
702
        i_samples -= p_sys->p_context->frame_size;

        if( i_out == 0 ) continue;
gbazin's avatar
   
gbazin committed
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718

        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
719
    if( i_samples )
gbazin's avatar
   
gbazin committed
720
    {
gbazin's avatar
   
gbazin committed
721
722
        memcpy( p_sys->p_buffer + i_samples_delay * 2 *
                p_sys->p_context->channels, p_buffer,
gbazin's avatar
   
gbazin committed
723
724
725
726
727
728
729
                i_samples * 2 * p_sys->p_context->channels );
    }

    return p_chain;
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
730
 * CloseEncoder: ffmpeg encoder destruction
gbazin's avatar
   
gbazin committed
731
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
732
void E_(CloseEncoder)( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
733
734
735
736
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;

737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
#if LIBAVCODEC_BUILD >= 4702
    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] );
        }

        free(pp_contexts);
    }
#endif

gbazin's avatar
   
gbazin committed
757
758
    avcodec_close( p_sys->p_context );
    free( p_sys->p_context );
gbazin's avatar
   
gbazin committed
759
760
761
762

    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
763
764
    free( p_sys );
}