x264.c 19.2 KB
Newer Older
1
2
3
/*****************************************************************************
 * x264.c: h264 video encoder
 *****************************************************************************
4
 * Copyright (C) 2004 the VideoLAN team
5
 * $Id$
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * 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>
Laurent Aimar's avatar
Laurent Aimar committed
29
#include <vlc/sout.h>
30
31
32
33
#include <vlc/decoder.h>

#include <x264.h>

34
35
#define SOUT_CFG_PREFIX "sout-x264-"

36
37
38
39
40
41
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#define QP_TEXT N_("Quantizer parameter")
#define QP_LONGTEXT N_( \
    "This selects the quantizer to use (1 to 51). Lower values result in " \
    "better fidelity, but higher bitrates. 26 is a good default value." )

#define QPMIN_TEXT N_("Minimum quantizer parameter")
#define QPMIN_LONGTEXT N_( "Minimum quantizer, 15/35 seems to be a useful " \
    "range." )

#define QPMAX_TEXT N_("Maximum quantizer parameter")
#define QPMAX_LONGTEXT N_( "Maximum quantizer parameter." )

#define CABAC_TEXT N_("Enable CABAC")
#define CABAC_LONGTEXT N_( "Enable CABAC (Context-Adaptive Binary Arithmetic "\
    "Coding). Slightly slows down encoding and decoding, but should save " \
    "10-15% bitrate." )

#define LOOPF_TEXT N_("Enable loop filter")
#define LOOPF_LONGTEXT N_( "Use deblocking loop filter (increases quality).")

#define ANALYSE_TEXT N_("Analyse mode")
#define ANALYSE_LONGTEXT N_( "This selects the analysing mode.")

65
66
67
68
69
70
71
72
#define TOLERANCE_TEXT N_("Bitrate tolerance")
#define TOLERANCE_LONGTEXT N_( "Sets the allowed variance in average " \
    "bitrate.")

#define VBV_MAXRATE_TEXT N_("Maximum local bitrate")
#define VBV_MAXRATE_LONGTEXT N_( "Sets a maximum local bitrate in kbits/s.")

#define VBV_BUFSIZE_TEXT N_("Averaging period for the maximum local bitrate")
73
#define VBV_BUFSIZE_LONGTEXT N_( "Sets an averaging period for the maximum " \
74
75
76
77
78
79
    "local bitrate, in kbits/s.")

#define VBV_INIT_TEXT N_("Initial buffer occupancy")
#define VBV_INIT_LONGTEXT N_( "Sets the initial buffer occupancy as a " \
    "fraction of the buffer size.")

80
#define KEYINT_TEXT N_("Sets maximum interval between IDR-frames")
zorglub's avatar
zorglub committed
81
82
#define KEYINT_LONGTEXT N_( "Larger values save bits, thus improve quality "\
    "for a given bitrate, at the cost of seeking precision." )
83

84
85
86
#define KEYINT_MIN_TEXT N_("Sets minimum interval between IDR-frames")
#define KEYINT_MIN_LONGTEXT N_("In H.264, I-Frames do not necessarily bound " \
    "a closed GOP because it is allowable for a P-frame to be predicted from "\
87
88
89
    "more frames than just the one frame before it (also see frameref). " \
    "Therefore, I-frames are not necessarily seekable. " \
    "IDR-Frames restrict subsequent P-frames from referring to any frame " \
90
91
92
    "prior to the IDR-Frame. \n" \
    "If scenecuts appear within this interval, they are still encoded as " \
    "I-frames, but do not start a new GOP. Default value is keyint * 0.4." )
93
94
95
96
97

#define BFRAMES_TEXT N_("B frames")
#define BFRAMES_LONGTEXT N_( "Number of consecutive B-Frames between I and " \
    "P-frames." )

98
99
100
101
#define BPYRAMID_TEXT N_("B pyramid")
#define BPYRAMID_LONGTEXT N_( "Allows B-frames to be used as references for " \
    "predicting other frames." )

102
103
104
105
106
107
108
109
110
111
112
113
114
115
#define FRAMEREF_TEXT N_("Number of previous frames used as predictors.")
#define FRAMEREF_LONGTEXT N_( "This is effective in Anime, but seems to " \
    "make little difference in live-action source material. Some decoders " \
    "are unable to deal with large frameref values." )

#define SCENE_TEXT N_("Scene-cut detection.")
#define SCENE_LONGTEXT N_( "Controls how aggressively to insert extra " \
    "I-frames. With small values of scenecut, the codec often has to force " \
    "an I-frame when it would exceed keyint. " \
    "Good values of scenecut may find a better location for the I-frame. " \
    "Large values use more I-frames than necessary, thus wasting bits. " \
    "-1 disables scene-cut detection, so I-frames are be inserted only every "\
    "other keyint frames, which probably leads to ugly encoding artifacts." )

116
117
118
119
120
#define SUBPEL_TEXT N_("Sub-pixel refinement quality.")
#define SUBPEL_LONGTEXT N_( "This parameter controls quality versus speed " \
    "tradeoffs involved in the motion estimation decision process " \
    "(lower = quicker and higher = better quality)." )

121
122
123
static char *enc_analyse_list[] =
  { "", "all", "normal", "fast", "none" };
static char *enc_analyse_list_text[] =
124
125
  { N_("default"), N_("all"), N_("slow"), N_("normal"),
    N_("fast"), N_("none") };
Laurent Aimar's avatar
Laurent Aimar committed
126

127
128
vlc_module_begin();
    set_description( _("h264 video encoder using x264 library"));
129
    set_capability( "encoder", 200 );
130
    set_callbacks( Open, Close );
zorglub's avatar
zorglub committed
131
132
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_VCODEC );
133
134
135
136
137
138
139
140
141
142

    add_integer( SOUT_CFG_PREFIX "qp", 0, NULL, QP_TEXT, QP_LONGTEXT,
                 VLC_FALSE );
        change_integer_range( 0, 51 );
    add_integer( SOUT_CFG_PREFIX "qp-min", 10, NULL, QPMIN_TEXT,
                 QPMIN_LONGTEXT, VLC_FALSE );
        change_integer_range( 0, 51 );
    add_integer( SOUT_CFG_PREFIX "qp-max", 51, NULL, QPMAX_TEXT,
                 QPMAX_LONGTEXT, VLC_FALSE );
        change_integer_range( 0, 51 );
Laurent Aimar's avatar
Laurent Aimar committed
143

144
145
    add_bool( SOUT_CFG_PREFIX "cabac", 1, NULL, CABAC_TEXT, CABAC_LONGTEXT,
              VLC_FALSE );
Laurent Aimar's avatar
Laurent Aimar committed
146

147
148
149
150
151
    add_bool( SOUT_CFG_PREFIX "loopfilter", 1, NULL, LOOPF_TEXT,
              LOOPF_LONGTEXT, VLC_FALSE );

    add_string( SOUT_CFG_PREFIX "analyse", "", NULL, ANALYSE_TEXT,
                ANALYSE_LONGTEXT, VLC_FALSE );
Laurent Aimar's avatar
Laurent Aimar committed
152
        change_string_list( enc_analyse_list, enc_analyse_list_text, 0 );
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
    add_float( SOUT_CFG_PREFIX "tolerance", 1.0, NULL, TOLERANCE_TEXT,
               TOLERANCE_LONGTEXT, VLC_FALSE );
        change_float_range( 0, 100 );

    add_integer( SOUT_CFG_PREFIX "vbv-maxrate", 0, NULL, VBV_MAXRATE_TEXT,
                 VBV_MAXRATE_LONGTEXT, VLC_FALSE );

    add_integer( SOUT_CFG_PREFIX "vbv-bufsize", 0, NULL, VBV_BUFSIZE_TEXT,
                 VBV_BUFSIZE_LONGTEXT, VLC_FALSE );

    add_float( SOUT_CFG_PREFIX "vbv-init", 0.9, NULL, VBV_INIT_TEXT,
               VBV_INIT_LONGTEXT, VLC_FALSE );
        change_float_range( 0, 1 );

168
169
170
    add_integer( SOUT_CFG_PREFIX "keyint", 250, NULL, KEYINT_TEXT,
                 KEYINT_LONGTEXT, VLC_FALSE );

171
172
    add_integer( SOUT_CFG_PREFIX "keyint-min", 0, NULL, KEYINT_MIN_TEXT,
                 KEYINT_MIN_LONGTEXT, VLC_FALSE );
173
174
175
176
177

    add_integer( SOUT_CFG_PREFIX "bframes", 0, NULL, BFRAMES_TEXT,
                 BFRAMES_LONGTEXT, VLC_FALSE );
        change_integer_range( 0, 16 );

178
179
180
    add_bool( SOUT_CFG_PREFIX "bpyramid", 0, NULL, BPYRAMID_TEXT,
              BPYRAMID_LONGTEXT, VLC_FALSE );

181
182
183
184
185
186
187
188
    add_integer( SOUT_CFG_PREFIX "frameref", 1, NULL, FRAMEREF_TEXT,
                 FRAMEREF_LONGTEXT, VLC_FALSE );
        change_integer_range( 1, 15 );

    add_integer( SOUT_CFG_PREFIX "scenecut", 40, NULL, SCENE_TEXT,
                 SCENE_LONGTEXT, VLC_FALSE );
        change_integer_range( -1, 100 );

189
    add_integer( SOUT_CFG_PREFIX "subpel", 5, NULL, SUBPEL_TEXT,
190
191
192
                 SUBPEL_LONGTEXT, VLC_FALSE );
        change_integer_range( 1, 5 );

193
vlc_module_end();
194
195
196
197

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
198
static const char *ppsz_sout_options[] = {
199
    "qp", "qp-min", "qp-max", "cabac", "loopfilter", "analyse",
200
    "keyint", "keyint-min", "bframes", "bpyramid", "frameref", "scenecut",
201
    "subpel", "tolerance", "vbv-maxrate", "vbv-bufsize", "vbv-init", NULL
Laurent Aimar's avatar
Laurent Aimar committed
202
203
};

204
205
206
207
208
209
210
211
212
static block_t *Encode( encoder_t *, picture_t * );

struct encoder_sys_t
{
    x264_t          *h;
    x264_param_t    param;

    int             i_buffer;
    uint8_t         *p_buffer;
213
214

    mtime_t         i_last_ref_pts;
215
216
217
218
219
220
221
222
223
};

/*****************************************************************************
 * Open: probe the encoder
 *****************************************************************************/
static int  Open ( vlc_object_t *p_this )
{
    encoder_t     *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys;
Laurent Aimar's avatar
Laurent Aimar committed
224
    vlc_value_t    val;
225
    int i_qmin = 0, i_qmax = 0;
226

227
228
    if( p_enc->fmt_out.i_codec != VLC_FOURCC( 'h', '2', '6', '4' ) &&
        !p_enc->b_force )
229
230
231
    {
        return VLC_EGENERIC;
    }
232

233
234
235
    if( p_enc->fmt_in.video.i_width % 16 != 0 ||
        p_enc->fmt_in.video.i_height % 16!= 0 )
    {
236
237
238
239
240
241
242
243
244
245
246
247
248
        msg_Warn( p_enc, "size is not a multiple of 16 (%ix%i)",
                  p_enc->fmt_in.video.i_width, p_enc->fmt_in.video.i_height );

        if( p_enc->fmt_in.video.i_width < 16 ||
            p_enc->fmt_in.video.i_height < 16 )
        {
            msg_Err( p_enc, "video is too small to be cropped" );
            return VLC_EGENERIC;
        }

        msg_Warn( p_enc, "cropping video to %ix%i",
                  p_enc->fmt_in.video.i_width >> 4 << 4,
                  p_enc->fmt_in.video.i_height >> 4 << 4 );
249
250
    }

251
    sout_CfgParse( p_enc, SOUT_CFG_PREFIX, ppsz_sout_options, p_enc->p_cfg );
Laurent Aimar's avatar
Laurent Aimar committed
252
253

    p_enc->fmt_out.i_codec = VLC_FOURCC( 'h', '2', '6', '4' );
254
    p_enc->fmt_in.i_codec = VLC_FOURCC('I','4','2','0');
Laurent Aimar's avatar
Laurent Aimar committed
255

256
257
258
    p_enc->pf_encode_video = Encode;
    p_enc->pf_encode_audio = NULL;
    p_enc->p_sys = p_sys = malloc( sizeof( encoder_sys_t ) );
259
    p_sys->i_last_ref_pts = 0;
260
261

    x264_param_default( &p_sys->param );
262
263
    p_sys->param.i_width  = p_enc->fmt_in.video.i_width >> 4 << 4;
    p_sys->param.i_height = p_enc->fmt_in.video.i_height >> 4 << 4;
264
265
266
267
268
269

    var_Get( p_enc, SOUT_CFG_PREFIX "qp-min", &val );
    if( val.i_int >= 1 && val.i_int <= 51 ) i_qmin = val.i_int;
    var_Get( p_enc, SOUT_CFG_PREFIX "qp-max", &val );
    if( val.i_int >= 1 && val.i_int <= 51 ) i_qmax = val.i_int;

Laurent Aimar's avatar
Laurent Aimar committed
270
271
272
    var_Get( p_enc, SOUT_CFG_PREFIX "qp", &val );
    if( val.i_int >= 1 && val.i_int <= 51 )
    {
273
274
275
        if( i_qmin > val.i_int ) i_qmin = val.i_int;
        if( i_qmax < val.i_int ) i_qmax = val.i_int;

276
277
#if X264_BUILD >= 0x000a
        p_sys->param.rc.i_qp_constant = val.i_int;
278
279
        p_sys->param.rc.i_qp_min = i_qmin;
        p_sys->param.rc.i_qp_max = i_qmax;
280
#else
Laurent Aimar's avatar
Laurent Aimar committed
281
        p_sys->param.i_qp_constant = val.i_int;
282
#endif
Laurent Aimar's avatar
Laurent Aimar committed
283
    }
284
285
286
287
    else
    {
        /* No QP -> constant bitrate */
#if X264_BUILD >= 0x000a
288
        p_sys->param.rc.b_cbr = 1;
289
        p_sys->param.rc.i_bitrate = p_enc->fmt_out.i_bitrate / 1000;
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305

#if X264_BUILD >= 24
        var_Get( p_enc, SOUT_CFG_PREFIX "tolerance", &val );
        p_sys->param.rc.f_rate_tolerance = val.f_float;

        var_Get( p_enc, SOUT_CFG_PREFIX "vbv-maxrate", &val );
        p_sys->param.rc.i_vbv_max_bitrate = val.i_int;

        var_Get( p_enc, SOUT_CFG_PREFIX "vbv-bufsize", &val );
        p_sys->param.rc.i_vbv_buffer_size = val.i_int;
        if( !val.i_int )
            p_sys->param.rc.i_vbv_buffer_size = p_sys->param.rc.i_bitrate;

        var_Get( p_enc, SOUT_CFG_PREFIX "vbv-init", &val );
        p_sys->param.rc.f_vbv_buffer_init = val.f_float;
#else
306
307
        p_sys->param.rc.i_rc_buffer_size = p_sys->param.rc.i_bitrate;
        p_sys->param.rc.i_rc_init_buffer = p_sys->param.rc.i_bitrate / 4;
308
#endif
309
310
#endif
    }
Laurent Aimar's avatar
Laurent Aimar committed
311
312
313
314
315
316

    var_Get( p_enc, SOUT_CFG_PREFIX "cabac", &val );
    p_sys->param.b_cabac = val.b_bool;

    var_Get( p_enc, SOUT_CFG_PREFIX "loopfilter", &val );
    p_sys->param.b_deblocking_filter = val.b_bool;
317

318
    var_Get( p_enc, SOUT_CFG_PREFIX "keyint", &val );
319
320
321
322
#if X264_BUILD >= 0x000e
    if( val.i_int > 0 ) p_sys->param.i_keyint_max = val.i_int;
    if( val.i_int > 0 ) p_sys->param.i_keyint_min = val.i_int * 0.4;
#else
323
    if( val.i_int > 0 ) p_sys->param.i_iframe = val.i_int;
324
#endif
325

326
327
328
329
    var_Get( p_enc, SOUT_CFG_PREFIX "keyint-min", &val );
#if X264_BUILD >= 0x000e
    if( val.i_int > 0 ) p_sys->param.i_keyint_min = val.i_int;
#else
330
    if( val.i_int > 0 ) p_sys->param.i_idrframe = val.i_int;
331
#endif
332
333
334
335

    var_Get( p_enc, SOUT_CFG_PREFIX "bframes", &val );
    if( val.i_int >= 0 && val.i_int <= 16 ) p_sys->param.i_bframe = val.i_int;

336
#if X264_BUILD >= 22
337
338
339
340
    var_Get( p_enc, SOUT_CFG_PREFIX "bpyramid", &val );
    p_sys->param.b_bframe_pyramid = val.b_bool;
#endif

341
342
343
344
345
    var_Get( p_enc, SOUT_CFG_PREFIX "frameref", &val );
    if( val.i_int > 0 && val.i_int <= 15 )
        p_sys->param.i_frame_reference = val.i_int;

    var_Get( p_enc, SOUT_CFG_PREFIX "scenecut", &val );
346
#if X264_BUILD >= 0x000b
347
348
    if( val.i_int >= -1 && val.i_int <= 100 )
        p_sys->param.i_scenecut_threshold = val.i_int;
349
#endif
350

351
#if X264_BUILD >= 22
352
353
354
355
356
    var_Get( p_enc, SOUT_CFG_PREFIX "subpel", &val );
    if( val.i_int >= 1 && val.i_int <= 5 )
        p_sys->param.analyse.i_subpel_refine = val.i_int;
#endif

357
358
359
#ifndef X264_ANALYSE_BSUB16x16
#   define X264_ANALYSE_BSUB16x16 0
#endif
360
361
362
363
364
365
366
367
368
369
370
371
372
373
    var_Get( p_enc, SOUT_CFG_PREFIX "analyse", &val );
    if( !strcmp( val.psz_string, "none" ) )
    {
        p_sys->param.analyse.inter = 0;
    }
    else if( !strcmp( val.psz_string, "fast" ) )
    {
        p_sys->param.analyse.inter = X264_ANALYSE_I4x4;
    }
    else if( !strcmp( val.psz_string, "normal" ) )
    {
        p_sys->param.analyse.inter =
            X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16;
    }
374
375
376
377
378
379
380
    else if( !strcmp( val.psz_string, "slow" ) )
    {
        p_sys->param.analyse.inter =
            X264_ANALYSE_I4x4 |
            X264_ANALYSE_PSUB16x16 | X264_ANALYSE_PSUB8x8 |
            X264_ANALYSE_BSUB16x16;
    }
381
382
383
    else if( !strcmp( val.psz_string, "all" ) )
    {
        p_sys->param.analyse.inter =
384
385
            X264_ANALYSE_I4x4 |
            X264_ANALYSE_PSUB16x16 | X264_ANALYSE_PSUB8x8 |
386
            X264_ANALYSE_BSUB16x16;
387
388
389
390
#ifdef X264_ANALYSE_I8x8
        p_sys->param.analyse.inter |= X264_ANALYSE_I8x8;
        p_sys->param.analyse.b_transform_8x8 = 1;
#endif
391
    }
392
    if( val.psz_string ) free( val.psz_string );
393

394
395
    if( p_enc->fmt_in.video.i_aspect > 0 )
    {
396
397
398
399
400
401
        int64_t i_num, i_den;
        int i_dst_num, i_dst_den;

        i_num = p_enc->fmt_in.video.i_aspect *
            (int64_t)p_enc->fmt_in.video.i_height;
        i_den = VOUT_ASPECT_FACTOR * p_enc->fmt_in.video.i_width;
402
        vlc_ureduce( &i_dst_num, &i_dst_den, i_num, i_den, 0 );
403
404
405

        p_sys->param.vui.i_sar_width = i_dst_num;
        p_sys->param.vui.i_sar_height = i_dst_den;
406
407
408
    }
    if( p_enc->fmt_in.video.i_frame_rate_base > 0 )
    {
Laurent Aimar's avatar
Laurent Aimar committed
409
410
        p_sys->param.i_fps_num = p_enc->fmt_in.video.i_frame_rate;
        p_sys->param.i_fps_den = p_enc->fmt_in.video.i_frame_rate_base;
411
412
413
414
415
416
417
418
419
420
421
    }
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMX) )
    {
        p_sys->param.cpu &= ~X264_CPU_MMX;
    }
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT) )
    {
        p_sys->param.cpu &= ~X264_CPU_MMXEXT;
    }
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_SSE) )
    {
422
423
424
425
426
        p_sys->param.cpu &= ~X264_CPU_SSE;
    }
    if( !(p_enc->p_libvlc->i_cpu & CPU_CAPABILITY_SSE2) )
    {
        p_sys->param.cpu &= ~X264_CPU_SSE2;
427
    }
Laurent Aimar's avatar
Laurent Aimar committed
428

429
430
431
432
433
#if X264_BUILD >= 29
    if( p_enc->i_threads >= 1 )
        p_sys->param.i_threads = p_enc->i_threads;
#endif

434
435
436
437
    /* Open the encoder */
    p_sys->h = x264_encoder_open( &p_sys->param );

    /* alloc mem */
438
439
    p_sys->i_buffer = 4 * p_enc->fmt_in.video.i_width *
        p_enc->fmt_in.video.i_height + 1000;
440
441
442
443
444
    p_sys->p_buffer = malloc( p_sys->i_buffer );

    /* get the globals headers */
    p_enc->fmt_out.i_extra = 0;
    p_enc->fmt_out.p_extra = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
445

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
#if 0
    x264_encoder_headers( p_sys->h, &nal, &i_nal );
    for( i = 0; i < i_nal; i++ )
    {
        int i_size = p_sys->i_buffer;

        x264_nal_encode( p_sys->p_buffer, &i_size, 1, &nal[i] );

        p_enc->fmt_out.p_extra = realloc( p_enc->fmt_out.p_extra, p_enc->fmt_out.i_extra + i_size );

        memcpy( p_enc->fmt_out.p_extra + p_enc->fmt_out.i_extra,
                p_sys->p_buffer, i_size );

        p_enc->fmt_out.i_extra += i_size;
    }
#endif

    return VLC_SUCCESS;
}

/****************************************************************************
 * Encode:
 ****************************************************************************/
static block_t *Encode( encoder_t *p_enc, picture_t *p_pict )
{
    encoder_sys_t *p_sys = p_enc->p_sys;
472
    x264_picture_t pic;
473
474
    x264_nal_t *nal;
    block_t *p_block;
475
    int i_nal, i_out, i;
476

477
478
    /* init pic */
    memset( &pic, 0, sizeof( x264_picture_t ) );
479
    pic.i_pts = p_pict->date;
480
    pic.img.i_csp = X264_CSP_I420;
481
482
    pic.img.i_plane = p_pict->i_planes;
    for( i = 0; i < p_pict->i_planes; i++ )
483
    {
484
485
        pic.img.plane[i] = p_pict->p[i].p_pixels;
        pic.img.i_stride[i] = p_pict->p[i].i_pitch;
486
487
    }

488
489
490
#if X264_BUILD >= 0x0013
    x264_encoder_encode( p_sys->h, &nal, &i_nal, &pic, &pic );
#else
491
    x264_encoder_encode( p_sys->h, &nal, &i_nal, &pic );
492
#endif
493
494
495

    if( !i_nal ) return NULL;

496
497
498
499
500
501
502
503
504
505
506
    for( i = 0, i_out = 0; i < i_nal; i++ )
    {
        int i_size = p_sys->i_buffer - i_out;
        x264_nal_encode( p_sys->p_buffer + i_out, &i_size, 1, &nal[i] );

        i_out += i_size;
    }

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

507
508
509
510
511
512
    if( pic.i_type == X264_TYPE_IDR || pic.i_type == X264_TYPE_I )
        p_block->i_flags |= BLOCK_FLAG_TYPE_I;
    else if( pic.i_type == X264_TYPE_P )
        p_block->i_flags |= BLOCK_FLAG_TYPE_P;
    else if( pic.i_type == X264_TYPE_B )
        p_block->i_flags |= BLOCK_FLAG_TYPE_B;
513

514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
    /* This isn't really valid for streams with B-frames */
    p_block->i_length = I64C(1000000) *
        p_enc->fmt_in.video.i_frame_rate_base /
            p_enc->fmt_in.video.i_frame_rate;

    p_block->i_dts = p_block->i_pts = pic.i_pts;

    if( p_sys->param.i_bframe > 0 )
    {
        if( p_block->i_flags & BLOCK_FLAG_TYPE_B )
        {
            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;
        }
    }

543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
    return p_block;
}

/*****************************************************************************
 * CloseEncoder: ffmpeg encoder destruction
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    encoder_t     *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;

    x264_encoder_close( p_sys->h );
    free( p_sys->p_buffer );
    free( p_sys );
}