encoder.c 26.8 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
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
 *          Gildas Bazin <gbazin@videolan.org>
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
 *
 * 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>
32
#include <vlc/sout.h>
gbazin's avatar
 
gbazin committed
33 34 35
#include <vlc/decoder.h>

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

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

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

#define AVCODEC_MAX_VIDEO_FRAME_SIZE (3*1024*1024)
50 51 52
#define HURRY_UP_GUARD1 (450000)
#define HURRY_UP_GUARD2 (300000)
#define HURRY_UP_GUARD3 (100000)
gbazin's avatar
 
gbazin committed
53 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 86 87
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
88 89 90 91 92 93 94 95 96 97 98 99 100 101
/*****************************************************************************
 * 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
102 103
    char *p_buffer;
    char *p_buffer_out;
gbazin's avatar
 
gbazin committed
104

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

gbazin's avatar
 
gbazin committed
113 114 115
    /*
     * Audio properties
     */
gbazin's avatar
 
gbazin committed
116
    int i_frame_size;
gbazin's avatar
 
gbazin committed
117 118
    int i_samples_delay;
    mtime_t i_pts;
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

    /* 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;
    vlc_bool_t b_interlace;
    float      f_i_quant_factor;
    int        i_noise_reduction;
    vlc_bool_t b_mpeg4_matrix;
    vlc_bool_t b_trellis;
};

static const char *ppsz_enc_options[] = {
    "keyint", "bframes", "vt", "qmin", "qmax", "hq", "strict_rc",
141 142
    "rc-buffer-size", "rc-buffer-aggressivity", "pre-me", "hurry-up",
    "interlace", "i-quant-factor", "noise-reduction", "mpeg4-matrix",
143
    "trellis", NULL
gbazin's avatar
 
gbazin committed
144 145 146
};

/*****************************************************************************
gbazin's avatar
 
gbazin committed
147
 * OpenEncoder: probe the encoder
gbazin's avatar
 
gbazin committed
148
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
149 150
extern int16_t ff_mpeg4_default_intra_matrix[];
extern int16_t ff_mpeg4_default_non_intra_matrix[];
151

gbazin's avatar
 
gbazin committed
152
int E_(OpenEncoder)( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
153 154 155
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;
gbazin's avatar
 
gbazin committed
156
    AVCodecContext *p_context;
gbazin's avatar
 
gbazin committed
157
    AVCodec *p_codec;
gbazin's avatar
 
gbazin committed
158 159
    int i_codec_id, i_cat;
    char *psz_namecodec;
160
    vlc_value_t val;
gbazin's avatar
 
gbazin committed
161

gbazin's avatar
 
gbazin committed
162
    if( !E_(GetFfmpegCodec)( p_enc->fmt_out.i_codec, &i_cat, &i_codec_id,
gbazin's avatar
 
gbazin committed
163
                             &psz_namecodec ) )
gbazin's avatar
 
gbazin committed
164
    {
165 166 167 168 169 170 171 172
        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
173 174
    }

175

gbazin's avatar
 
gbazin committed
176
    if( p_enc->fmt_out.i_cat == VIDEO_ES && i_cat != VIDEO_ES )
gbazin's avatar
 
gbazin committed
177
    {
gbazin's avatar
 
gbazin committed
178
        msg_Err( p_enc, "\"%s\" is not a video encoder", psz_namecodec );
gbazin's avatar
 
gbazin committed
179 180 181
        return VLC_EGENERIC;
    }

gbazin's avatar
 
gbazin committed
182 183 184 185 186 187
    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
188
    /* Initialization must be done before avcodec_find_decoder() */
gbazin's avatar
 
gbazin committed
189 190
    E_(InitLibavcodec)(p_this);

gbazin's avatar
 
gbazin committed
191 192 193 194 195 196 197
    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
198 199 200 201 202 203 204 205 206 207
    /* 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
208
    p_enc->pf_encode_audio = EncodeAudio;
gbazin's avatar
 
gbazin committed
209

gbazin's avatar
 
gbazin committed
210 211
    p_sys->p_buffer_out = NULL;
    p_sys->p_buffer = NULL;
212
    p_sys->b_inited = 0;
gbazin's avatar
 
gbazin committed
213 214 215 216 217

    p_sys->p_context = p_context = avcodec_alloc_context();

    /* Set CPU capabilities */
    p_context->dsp_mask = 0;
gbazin's avatar
 
gbazin committed
218
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) )
gbazin's avatar
 
gbazin committed
219
    {
gbazin's avatar
 
gbazin committed
220
        p_context->dsp_mask |= FF_MM_MMX;
gbazin's avatar
 
gbazin committed
221
    }
gbazin's avatar
 
gbazin committed
222
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) )
gbazin's avatar
 
gbazin committed
223
    {
gbazin's avatar
 
gbazin committed
224
        p_context->dsp_mask |= FF_MM_MMXEXT;
gbazin's avatar
 
gbazin committed
225
    }
gbazin's avatar
 
gbazin committed
226
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW) )
gbazin's avatar
 
gbazin committed
227
    {
gbazin's avatar
 
gbazin committed
228
        p_context->dsp_mask |= FF_MM_3DNOW;
gbazin's avatar
 
gbazin committed
229
    }
gbazin's avatar
 
gbazin committed
230
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) )
gbazin's avatar
 
gbazin committed
231
    {
gbazin's avatar
 
gbazin committed
232 233
        p_context->dsp_mask |= FF_MM_SSE;
        p_context->dsp_mask |= FF_MM_SSE2;
gbazin's avatar
 
gbazin committed
234 235
    }

236 237 238 239 240 241 242 243 244 245 246 247 248 249
    sout_ParseCfg( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );

    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;

250
    var_Get( p_enc, ENC_CFG_PREFIX "pre-me", &val );
251 252
    p_sys->b_pre_me = val.b_bool;

253
    var_Get( p_enc, ENC_CFG_PREFIX "hurry-up", &val );
254 255 256 257 258 259 260
    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;
    }

261
    var_Get( p_enc, ENC_CFG_PREFIX "strict-rc", &val );
262
    p_sys->b_strict_rc = val.b_bool;
263
    var_Get( p_enc, ENC_CFG_PREFIX "rc-buffer-size", &val );
264
    p_sys->i_rc_buffer_size = val.i_int;
265
    var_Get( p_enc, ENC_CFG_PREFIX "rc-buffer-aggressivity", &val );
266 267
    p_sys->f_rc_buffer_aggressivity = val.f_float;

268
    var_Get( p_enc, ENC_CFG_PREFIX "i-quant-factor", &val );
269 270
    p_sys->f_i_quant_factor = val.f_float;

271
    var_Get( p_enc, ENC_CFG_PREFIX "noise-reduction", &val );
272 273
    p_sys->i_noise_reduction = val.i_int;

274
    var_Get( p_enc, ENC_CFG_PREFIX "mpeg4-matrix", &val );
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
    p_sys->b_mpeg4_matrix = val.b_bool;

    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
298 299
    if( p_enc->fmt_in.i_cat == VIDEO_ES )
    {
300 301 302 303 304 305 306 307
        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
308 309
        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
310

gbazin's avatar
 
gbazin committed
311 312
        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
313

314 315 316 317 318 319 320 321
        /* 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;

322 323
        if( p_sys->i_key_int > 0 )
            p_context->gop_size = p_sys->i_key_int;
324
        p_context->max_b_frames =
325
            __MIN( p_sys->i_b_frames, FF_MAX_B_FRAMES );
326 327
        p_context->b_frame_strategy = 0;

gbazin's avatar
 
gbazin committed
328
#if LIBAVCODEC_BUILD >= 4687
329 330 331 332 333
        av_reduce( &p_context->sample_aspect_ratio.num,
		   &p_context->sample_aspect_ratio.den,
		   p_enc->fmt_in.video.i_aspect *
		   (int64_t)p_context->height / p_context->width,
		   VOUT_ASPECT_FACTOR, INT_MAX );
gbazin's avatar
 
gbazin committed
334
#else
gbazin's avatar
 
gbazin committed
335 336
        p_context->aspect_ratio = ((float)p_enc->fmt_in.video.i_aspect) /
            VOUT_ASPECT_FACTOR;
gbazin's avatar
 
gbazin committed
337
#endif
gbazin's avatar
 
gbazin committed
338

gbazin's avatar
 
gbazin committed
339 340
        p_sys->p_buffer_out = malloc( AVCODEC_MAX_VIDEO_FRAME_SIZE );

341
        p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
Christophe Massiot's avatar
Christophe Massiot committed
342

343
        if ( p_sys->b_strict_rc )
Christophe Massiot's avatar
Christophe Massiot committed
344 345
        {
            p_context->rc_max_rate = p_enc->fmt_out.i_bitrate;
346 347
            p_context->rc_buffer_size = p_sys->i_rc_buffer_size;
            p_context->rc_buffer_aggressivity = p_sys->f_rc_buffer_aggressivity;
348 349
        }

350 351
        if ( p_sys->f_i_quant_factor != 0.0 )
            p_context->i_quant_factor = p_sys->f_i_quant_factor;
352

gbazin's avatar
 
gbazin committed
353
#if LIBAVCODEC_BUILD >= 4690
354
        p_context->noise_reduction = p_sys->i_noise_reduction;
gbazin's avatar
 
gbazin committed
355
#endif
356

357
        if ( p_sys->b_mpeg4_matrix )
358 359 360
        {
            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
361 362
        }

363
        if ( p_sys->b_pre_me )
Christophe Massiot's avatar
Christophe Massiot committed
364 365 366 367
        {
            p_context->pre_me = 1;
            p_context->me_pre_cmp = FF_CMP_CHROMA;
        }
368

369
        if ( p_sys->b_interlace )
370 371 372 373 374 375 376
        {
            p_context->flags |= CODEC_FLAG_INTERLACED_DCT;
#if LIBAVCODEC_BUILD >= 4698
            p_context->flags |= CODEC_FLAG_INTERLACED_ME;
#endif
        }

377
        if ( p_sys->b_trellis )
378 379
            p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;

gbazin's avatar
 
gbazin committed
380
#if LIBAVCODEC_BUILD >= 4702
381 382
        if ( p_enc->i_threads >= 1 )
            p_context->thread_count = p_enc->i_threads;
gbazin's avatar
 
gbazin committed
383
#endif
384

385 386
        if( p_sys->i_vtolerance > 0 )
            p_context->bit_rate_tolerance = p_sys->i_vtolerance;
387

388 389 390 391
        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;
392 393
        p_context->max_qdiff = 3;

394
        p_context->mb_decision = p_sys->i_hq;
gbazin's avatar
 
gbazin committed
395 396 397 398 399 400 401 402 403
    }
    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;
    }

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

gbazin's avatar
 
gbazin committed
406
    if( i_codec_id == CODEC_ID_RAWVIDEO )
gbazin's avatar
 
gbazin committed
407
    {
408 409
        /* 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
410
        p_context->pix_fmt = E_(GetFfmpegChroma)( p_enc->fmt_in.i_codec );
gbazin's avatar
 
gbazin committed
411 412 413 414 415 416 417
    }

    /* 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
418
    if( avcodec_open( p_context, p_codec ) )
gbazin's avatar
 
gbazin committed
419
    {
gbazin's avatar
 
gbazin committed
420 421 422 423 424 425 426
        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" );
427
                free( p_sys );
gbazin's avatar
 
gbazin committed
428 429 430 431 432 433 434
                return VLC_EGENERIC;
            }
            msg_Warn( p_enc, "stereo mode selected (codec limitation)" );
        }
        else
        {
            msg_Err( p_enc, "cannot open encoder" );
435
            free( p_sys );
gbazin's avatar
 
gbazin committed
436 437
            return VLC_EGENERIC;
        }
gbazin's avatar
 
gbazin committed
438 439
    }

gbazin's avatar
 
gbazin committed
440 441
    p_enc->fmt_out.i_extra = p_context->extradata_size;
    p_enc->fmt_out.p_extra = p_context->extradata;
gbazin's avatar
 
gbazin committed
442 443
    p_context->flags &= ~CODEC_FLAG_GLOBAL_HEADER;

gbazin's avatar
 
gbazin committed
444 445
    if( p_enc->fmt_in.i_cat == AUDIO_ES )
    {
446
        p_sys->p_buffer_out = malloc( 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
gbazin's avatar
 
gbazin committed
447 448 449 450
        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
451 452
    p_sys->i_last_ref_pts = 0;
    p_sys->i_buggy_pts_detect = 0;
gbazin's avatar
 
gbazin committed
453 454
    p_sys->i_samples_delay = 0;
    p_sys->i_pts = 0;
455
    p_sys->i_last_pts = 0;
gbazin's avatar
 
gbazin committed
456

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

gbazin's avatar
 
gbazin committed
459 460 461
    return VLC_SUCCESS;
}

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 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
/****************************************************************************
 * 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
536 537 538 539 540 541 542 543
/****************************************************************************
 * 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;
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

#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
576

Laurent Aimar's avatar
Laurent Aimar committed
577
    memset( &frame, 0, sizeof( AVFrame ) );
gbazin's avatar
 
gbazin committed
578 579 580 581 582 583
    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;
    }

584 585 586 587 588 589 590 591 592 593
    /* 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

594
#if LIBAVCODEC_BUILD < 4702
gbazin's avatar
 
gbazin committed
595
    /* Set the pts of the frame being encoded (segfaults with mpeg4!)*/
596 597 598
    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' ) )
599 600 601
#else
    if( 1 )
#endif
Christophe Massiot's avatar
Christophe Massiot committed
602
    {
603
        frame.pts = p_pict->date ? p_pict->date : AV_NOPTS_VALUE;
604

605
        if ( p_sys->b_hurry_up && frame.pts != AV_NOPTS_VALUE )
Christophe Massiot's avatar
Christophe Massiot committed
606
        {
607 608
            mtime_t current_date = mdate();

609
            if ( current_date + HURRY_UP_GUARD3 > frame.pts )
610 611 612 613 614 615 616
            {
                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
            {
617
                p_sys->p_context->mb_decision = p_sys->i_hq;
618

619
                if ( current_date + HURRY_UP_GUARD2 > frame.pts )
620 621
                {
                    p_sys->p_context->flags &= ~CODEC_FLAG_TRELLIS_QUANT;
622
#if LIBAVCODEC_BUILD >= 4690
623
                    p_sys->p_context->noise_reduction = p_sys->i_noise_reduction
624
                         + (HURRY_UP_GUARD2 + current_date - frame.pts) / 500;
625 626 627 628 629
#endif
                    msg_Dbg( p_enc, "hurry up mode 2" );
                }
                else
                {
630
                    if ( p_sys->b_trellis )
631
                        p_sys->p_context->flags |= CODEC_FLAG_TRELLIS_QUANT;
632 633
#if LIBAVCODEC_BUILD >= 4690
                    p_sys->p_context->noise_reduction =
634
                        p_sys->i_noise_reduction;
635 636 637 638
#endif
                }
            }

639
            if ( current_date + HURRY_UP_GUARD1 > frame.pts )
640
            {
641 642
                frame.pict_type = FF_P_TYPE;
                /* msg_Dbg( p_enc, "hurry up mode 1 %lld", current_date + HURRY_UP_GUARD1 - frame.pts ); */
643
            }
Christophe Massiot's avatar
Christophe Massiot committed
644 645
        }
    }
gbazin's avatar
 
gbazin committed
646
    else
Christophe Massiot's avatar
Christophe Massiot committed
647
    {
648
        frame.pts = AV_NOPTS_VALUE;
Christophe Massiot's avatar
Christophe Massiot committed
649
    }
gbazin's avatar
 
gbazin committed
650

gbazin's avatar
gbazin committed
651
    if ( frame.pts != AV_NOPTS_VALUE && frame.pts != 0 )
652 653 654
    {
        if ( p_sys->i_last_pts == frame.pts )
        {
gbazin's avatar
gbazin committed
655 656
            msg_Warn( p_enc, "almost fed libavcodec with two frames with the "
                      "same PTS (" I64Fd ")", frame.pts );
657 658 659 660 661 662 663
            return NULL;
        }
        else
        {
            p_sys->i_last_pts = frame.pts;
        }
    }
gbazin's avatar
 
gbazin committed
664 665 666

    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
667

gbazin's avatar
 
gbazin committed
668 669 670 671 672
    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 );

673
        if( p_sys->p_context->coded_frame->pts != AV_NOPTS_VALUE &&
gbazin's avatar
gbazin committed
674
            p_sys->p_context->coded_frame->pts != 0 &&
gbazin's avatar
 
gbazin committed
675 676 677 678 679
            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
680 681 682
            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
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
            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
710 711 712
            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
713 714 715
            p_block->i_dts = p_block->i_pts = p_pict->date;
        }

716 717 718 719 720 721 722 723 724 725 726 727 728
        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
729 730 731 732 733 734 735 736 737 738 739 740 741
        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
742

gbazin's avatar
 
gbazin committed
743 744 745 746 747 748
    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
749
                (mtime_t)p_enc->fmt_in.audio.i_rate;
gbazin's avatar
 
gbazin committed
750 751 752 753 754 755 756 757 758 759 760

    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
761
            int i_delay_size = i_samples_delay * 2 *
gbazin's avatar
 
gbazin committed
762 763 764 765 766 767
                                 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
768
            i_samples += i_samples_delay;
gbazin's avatar
 
gbazin committed
769 770 771 772 773 774 775 776 777 778
            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
779 780 781 782 783

#if 0
        msg_Warn( p_enc, "avcodec_encode_audio: %d", i_out );
#endif
        if( i_out < 0 ) break;
gbazin's avatar
 
gbazin committed
784 785 786

        p_buffer += p_sys->i_frame_size;
        p_sys->i_samples_delay -= p_sys->p_context->frame_size;
gbazin's avatar
 
gbazin committed
787 788 789
        i_samples -= p_sys->p_context->frame_size;

        if( i_out == 0 ) continue;
gbazin's avatar
 
gbazin committed
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805

        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
806
    if( i_samples )
gbazin's avatar
 
gbazin committed
807
    {
gbazin's avatar
 
gbazin committed
808 809
        memcpy( p_sys->p_buffer + i_samples_delay * 2 *
                p_sys->p_context->channels, p_buffer,
gbazin's avatar
 
gbazin committed
810 811 812 813 814 815 816
                i_samples * 2 * p_sys->p_context->channels );
    }

    return p_chain;
}

/*****************************************************************************
gbazin's avatar
 
gbazin committed
817
 * CloseEncoder: ffmpeg encoder destruction
gbazin's avatar
 
gbazin committed
818
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
819
void E_(CloseEncoder)( vlc_object_t *p_this )
gbazin's avatar
 
gbazin committed
820 821 822 823
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;

824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
#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] );
        }

840
        free( pp_contexts );
841 842 843
    }
#endif

gbazin's avatar
 
gbazin committed
844
    avcodec_close( p_sys->p_context );
845
    av_free( p_sys->p_context );
gbazin's avatar
 
gbazin committed
846 847 848 849

    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
850 851
    free( p_sys );
}