~ubuntu-branches/ubuntu/natty/x264/natty

« back to all changes in this revision

Viewing changes to vfw/codec.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2006-02-14 12:51:13 UTC
  • Revision ID: james.westby@ubuntu.com-20060214125113-t2vdkiqgcctz9ndd
Tags: upstream-0.cvs20060210
ImportĀ upstreamĀ versionĀ 0.cvs20060210

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * codec.c: vfw x264 encoder
 
3
 *****************************************************************************
 
4
 * Copyright (C) 2003 Laurent Aimar
 
5
 * $Id: codec.c,v 1.1 2004/06/03 19:27:09 fenrir Exp $
 
6
 *
 
7
 * Authors: Justin Clay
 
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation; either version 2 of the License, or
 
13
 * (at your option) any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 
23
 *****************************************************************************/
 
24
 
 
25
#include "x264vfw.h"
 
26
 
 
27
#include <stdio.h> /* debug only */
 
28
#include <io.h>
 
29
 
 
30
#define X264_MAX(a,b) ( (a)>(b) ? (a) : (b) )
 
31
#define X264_MIN(a,b) ( (a)<(b) ? (a) : (b) )
 
32
 
 
33
/* get_csp:
 
34
 *  return a valid x264 CSP or X264_CSP_NULL if unsuported */
 
35
static int get_csp( BITMAPINFOHEADER *hdr )
 
36
{
 
37
    switch( hdr->biCompression )
 
38
    {
 
39
        case FOURCC_I420:
 
40
        case FOURCC_IYUV:
 
41
            return X264_CSP_I420;
 
42
 
 
43
        case FOURCC_YV12:
 
44
            return X264_CSP_YV12;
 
45
 
 
46
        case FOURCC_YUYV:
 
47
        case FOURCC_YUY2:
 
48
            return X264_CSP_YUYV;
 
49
 
 
50
        case BI_RGB:
 
51
        {
 
52
            int i_vflip = hdr->biHeight < 0 ? 0 : X264_CSP_VFLIP;
 
53
 
 
54
            if( hdr->biBitCount == 24 )
 
55
                return X264_CSP_BGR | i_vflip;
 
56
            if( hdr->biBitCount == 32 )
 
57
                return X264_CSP_BGRA | i_vflip;
 
58
            else
 
59
                return X264_CSP_NONE;
 
60
        }
 
61
 
 
62
        default:
 
63
            return X264_CSP_NONE;
 
64
    }
 
65
}
 
66
 
 
67
/* Test that we can do the compression */
 
68
LRESULT compress_query( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
 
69
{
 
70
    BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
 
71
    BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
 
72
    CONFIG           *config = &codec->config;
 
73
 
 
74
    if( get_csp( inhdr ) == X264_CSP_NONE )
 
75
        return ICERR_BADFORMAT;
 
76
 
 
77
    if( lpbiOutput == NULL )
 
78
        return ICERR_OK;
 
79
 
 
80
    if( inhdr->biWidth != outhdr->biWidth ||
 
81
        inhdr->biHeight != outhdr->biHeight )
 
82
        return ICERR_BADFORMAT;
 
83
 
 
84
    /* We need x16 width/height */
 
85
    if( inhdr->biWidth % 16 != 0 || inhdr->biHeight % 16 != 0 )
 
86
        return ICERR_BADFORMAT;
 
87
 
 
88
 
 
89
    if( inhdr->biCompression != mmioFOURCC( config->fcc[0], config->fcc[1],
 
90
                                            config->fcc[2], config->fcc[3] ) )
 
91
        return ICERR_BADFORMAT;
 
92
 
 
93
    return ICERR_OK;
 
94
}
 
95
 
 
96
/* */
 
97
LRESULT compress_get_format( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
 
98
{
 
99
    BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
 
100
    BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
 
101
    CONFIG           *config = &codec->config;
 
102
 
 
103
    if( get_csp( inhdr ) == X264_CSP_NONE )
 
104
        return ICERR_BADFORMAT;
 
105
 
 
106
    if( lpbiOutput == NULL )
 
107
        return sizeof(BITMAPINFOHEADER);
 
108
 
 
109
    memcpy( outhdr, inhdr, sizeof( BITMAPINFOHEADER ) );
 
110
    outhdr->biSize = sizeof( BITMAPINFOHEADER );
 
111
    outhdr->biSizeImage = compress_get_size( codec, lpbiInput, lpbiOutput );
 
112
    outhdr->biXPelsPerMeter = 0;
 
113
    outhdr->biYPelsPerMeter = 0;
 
114
    outhdr->biClrUsed = 0;
 
115
    outhdr->biClrImportant = 0;
 
116
    outhdr->biCompression = mmioFOURCC( config->fcc[0], config->fcc[1],
 
117
                                        config->fcc[2], config->fcc[3] );
 
118
 
 
119
    return ICERR_OK;
 
120
}
 
121
 
 
122
/* */
 
123
LRESULT compress_get_size( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
 
124
{
 
125
    return 2 * lpbiOutput->bmiHeader.biWidth * lpbiOutput->bmiHeader.biHeight * 3;
 
126
}
 
127
 
 
128
/* */
 
129
LRESULT compress_frames_info(CODEC * codec, ICCOMPRESSFRAMES * icf )
 
130
{
 
131
    codec->fincr = icf->dwScale;
 
132
    codec->fbase = icf->dwRate;
 
133
    codec->config.i_frame_total = icf->lFrameCount;
 
134
    return ICERR_OK;
 
135
}
 
136
 
 
137
static void x264_log_vfw( void *p_private, int i_level, const char *psz_fmt, va_list arg )
 
138
{
 
139
    char error_msg[1024];
 
140
    int idx;
 
141
    HWND *hCons = p_private;
 
142
 
 
143
    vsprintf( error_msg, psz_fmt, arg );
 
144
 
 
145
    /* strip final linefeeds (required) */
 
146
    idx=strlen( error_msg ) - 1;
 
147
    while( idx >= 0 && error_msg[idx] == '\n' )
 
148
        error_msg[idx--] = 0;
 
149
 
 
150
    if(!( *hCons ) ) {
 
151
        *hCons = CreateDialog( g_hInst, MAKEINTRESOURCE( IDD_ERRCONSOLE ), NULL,
 
152
                 callback_err_console );
 
153
        //ShowWindow( *hCons, SW_SHOW );
 
154
    }
 
155
    idx = SendDlgItemMessage( *hCons, IDC_CONSOLE, LB_ADDSTRING, 0, ( LPARAM )error_msg );
 
156
 
 
157
    /* make sure that the last item added is visible (autoscroll) */
 
158
    if( idx >= 0 )
 
159
        SendDlgItemMessage( *hCons, IDC_CONSOLE, LB_SETTOPINDEX, ( WPARAM )idx, 0 );
 
160
 
 
161
}
 
162
 
 
163
static void statsfilename_renumber( char *dest, char *src, int i_pass )
 
164
{
 
165
    char *last_dot = strrchr( src, '.' );
 
166
    char *last_slash = X264_MAX( strrchr( src, '/' ), strrchr( src, '\\' ) );
 
167
    char pass_str[5];
 
168
 
 
169
    sprintf( pass_str, "-%i", i_pass );
 
170
    strcpy( dest, src );
 
171
    if( last_slash < last_dot ) {
 
172
        dest[ last_dot - src ] = 0;
 
173
        strcat( dest, pass_str );
 
174
        strcat( dest, last_dot );
 
175
    }
 
176
    else
 
177
    {
 
178
        strcat( dest, pass_str );
 
179
    }
 
180
}
 
181
 
 
182
/* */
 
183
LRESULT compress_begin(CODEC * codec, BITMAPINFO * lpbiInput, BITMAPINFO * lpbiOutput )
 
184
{
 
185
    CONFIG *config = &codec->config;
 
186
    x264_param_t param;
 
187
    int pass_number;
 
188
 
 
189
    /* Destroy previous handle */
 
190
    if( codec->h != NULL )
 
191
    {
 
192
        x264_encoder_close( codec->h );
 
193
        codec->h = NULL;
 
194
    }
 
195
 
 
196
    /* Get default param */
 
197
    x264_param_default( &param );
 
198
 
 
199
    param.rc.psz_stat_out = malloc (MAX_PATH);
 
200
    param.rc.psz_stat_in = malloc (MAX_PATH);
 
201
    param.i_threads = config->i_threads;
 
202
 
 
203
    param.i_log_level = config->i_log_level - 1;
 
204
    param.pf_log = x264_log_vfw;
 
205
    param.p_log_private = malloc( sizeof( HWND ) );
 
206
    *( ( HWND * )param.p_log_private ) = NULL; /* error console window handle */
 
207
    codec->hCons = ( HWND * )param.p_log_private;
 
208
 
 
209
    param.analyse.b_psnr = 0;
 
210
 
 
211
    /* Set params: TODO to complete */
 
212
    param.i_width = lpbiInput->bmiHeader.biWidth;
 
213
    param.i_height= lpbiInput->bmiHeader.biHeight;
 
214
 
 
215
    param.i_fps_num = codec->fbase;
 
216
    param.i_fps_den = codec->fincr;
 
217
    param.i_frame_total = config->i_frame_total;
 
218
 
 
219
    param.i_frame_reference = config->i_refmax;
 
220
    param.i_keyint_min = config->i_keyint_min;
 
221
    param.i_keyint_max = config->i_keyint_max;
 
222
    param.i_scenecut_threshold = config->i_scenecut_threshold;
 
223
    param.rc.i_qp_min = config->i_qp_min;
 
224
    param.rc.i_qp_max = config->i_qp_max;
 
225
    param.rc.i_qp_step = config->i_qp_step;
 
226
    param.b_deblocking_filter = config->b_filter;
 
227
    param.b_cabac = config->b_cabac;
 
228
    param.analyse.b_chroma_me = config->b_chroma_me;
 
229
    param.rc.f_ip_factor = 1 + (float)config->i_key_boost / 100;
 
230
    param.rc.f_pb_factor = 1 + (float)config->i_b_red / 100;
 
231
    param.rc.f_qcompress = (float)config->i_curve_comp / 100;
 
232
    param.vui.i_sar_width = config->i_sar_width;
 
233
    param.vui.i_sar_height = config->i_sar_height;
 
234
 
 
235
    param.i_bframe = config->i_bframe;
 
236
    if( config->i_bframe > 1 && config->b_b_wpred)
 
237
        param.analyse.b_weighted_bipred = 1;
 
238
    if( config->i_bframe > 1 && config->b_b_refs)
 
239
        param.b_bframe_pyramid = 1;
 
240
    param.b_bframe_adaptive = config->b_bframe_adaptive;
 
241
    param.i_bframe_bias = config->i_bframe_bias;
 
242
    param.analyse.i_subpel_refine = config->i_subpel_refine + 1; /* 0..4 -> 1..5 */
 
243
    param.analyse.i_me_method = config->i_me_method;
 
244
    param.analyse.i_me_range = config->i_me_range;
 
245
 
 
246
    /* bframe prediction - gui goes alphabetically, so 1=SPATIAL, 2=TEMPORAL */
 
247
    switch(config->i_direct_mv_pred) {
 
248
        case 0: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; break;
 
249
        case 1: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; break;
 
250
    }
 
251
    param.i_deblocking_filter_alphac0 = config->i_inloop_a;
 
252
    param.i_deblocking_filter_beta = config->i_inloop_b;
 
253
    param.analyse.inter = 0;
 
254
    if( config->b_bsub16x16 )
 
255
        param.analyse.inter |= X264_ANALYSE_BSUB16x16;
 
256
    if( config->b_psub16x16 )
 
257
    {
 
258
        param.analyse.inter |= X264_ANALYSE_PSUB16x16;
 
259
        if( config->b_psub8x8 )
 
260
            param.analyse.inter |= X264_ANALYSE_PSUB8x8;
 
261
    }
 
262
    if( config->b_i4x4 )
 
263
        param.analyse.inter |= X264_ANALYSE_I4x4;
 
264
    if( config->b_i8x8 )
 
265
        param.analyse.inter |= X264_ANALYSE_I8x8;
 
266
    param.analyse.b_transform_8x8 = config->b_dct8x8;
 
267
    if( config->b_mixedref )
 
268
        param.analyse.b_mixed_references = 1;
 
269
 
 
270
 
 
271
    switch( config->i_encoding_type )
 
272
    {
 
273
        case 0: /* 1 PASS ABR */
 
274
            param.rc.b_cbr = 1;
 
275
            param.rc.i_bitrate = config->bitrate;
 
276
            break;
 
277
        case 1: /* 1 PASS CQ */
 
278
            param.rc.i_qp_constant = config->i_qp;
 
279
            break;
 
280
        default:
 
281
        case 2: /* 2 PASS */
 
282
        {
 
283
            for( pass_number = 1; pass_number < 99; pass_number++ )
 
284
            {
 
285
                FILE *f;
 
286
                statsfilename_renumber( param.rc.psz_stat_out, config->stats, pass_number );
 
287
                if( ( f = fopen( param.rc.psz_stat_out, "r" ) ) != NULL )
 
288
                {
 
289
                    fclose( f );
 
290
                    if( config->i_pass == 1 )
 
291
                        unlink( param.rc.psz_stat_out );
 
292
                }
 
293
                else break;
 
294
            }
 
295
 
 
296
            if( config->i_pass > pass_number )
 
297
            {
 
298
                /* missing 1st pass statsfile */
 
299
                free( param.rc.psz_stat_out );
 
300
                free( param.rc.psz_stat_in );
 
301
                return ICERR_ERROR;
 
302
            }
 
303
 
 
304
            param.rc.i_bitrate = config->i_2passbitrate;
 
305
            param.rc.b_cbr = 1;
 
306
 
 
307
            if( config->i_pass == 1 )
 
308
            {
 
309
                statsfilename_renumber( param.rc.psz_stat_out, config->stats, 1 );
 
310
                param.rc.b_stat_write = 1;
 
311
                param.rc.f_rate_tolerance = 4;
 
312
                if( config->b_fast1pass )
 
313
                {
 
314
                    /* adjust or turn off some flags to gain speed, if needed */
 
315
                    param.analyse.i_subpel_refine = X264_MAX( X264_MIN( 3, param.analyse.i_subpel_refine - 1 ), 1 );
 
316
                    param.i_frame_reference = ( param.i_frame_reference + 1 ) >> 1;
 
317
                    param.analyse.inter &= ( ~X264_ANALYSE_PSUB8x8 );
 
318
                    param.analyse.inter &= ( ~X264_ANALYSE_BSUB16x16 );
 
319
                }
 
320
            }
 
321
            else
 
322
            {
 
323
                statsfilename_renumber( param.rc.psz_stat_in, config->stats, pass_number - 1 );
 
324
                param.rc.b_stat_read = 1;
 
325
                if( config->b_updatestats )
 
326
                    param.rc.b_stat_write = 1;
 
327
                param.rc.f_rate_tolerance = 1;
 
328
            }
 
329
 
 
330
            break;
 
331
        }
 
332
    }
 
333
 
 
334
    /* Open the encoder */
 
335
    codec->h = x264_encoder_open( &param );
 
336
 
 
337
    free( param.rc.psz_stat_out );
 
338
    free( param.rc.psz_stat_in );
 
339
 
 
340
    if( codec->h == NULL )
 
341
        return ICERR_ERROR;
 
342
 
 
343
    return ICERR_OK;
 
344
}
 
345
 
 
346
/* */
 
347
LRESULT compress_end(CODEC * codec)
 
348
{
 
349
    if( codec->h != NULL )
 
350
    {
 
351
        x264_encoder_close( codec->h );
 
352
        codec->h = NULL;
 
353
    }
 
354
 
 
355
    free( codec->hCons );
 
356
    codec->hCons = NULL;
 
357
    return ICERR_OK;
 
358
}
 
359
 
 
360
/* */
 
361
LRESULT compress( CODEC *codec, ICCOMPRESS *icc )
 
362
{
 
363
    BITMAPINFOHEADER *inhdr = icc->lpbiInput;
 
364
    BITMAPINFOHEADER *outhdr = icc->lpbiOutput;
 
365
 
 
366
    x264_picture_t pic;
 
367
 
 
368
    int        i_nal;
 
369
    x264_nal_t *nal;
 
370
    int        i_out;
 
371
 
 
372
    int i;
 
373
 
 
374
    /* Init the picture */
 
375
    memset( &pic, 0, sizeof( x264_picture_t ) );
 
376
    pic.img.i_csp = get_csp( inhdr );
 
377
 
 
378
    /* For now biWidth can be divided by 16 so no problem */
 
379
    switch( pic.img.i_csp & X264_CSP_MASK )
 
380
    {
 
381
        case X264_CSP_I420:
 
382
        case X264_CSP_YV12:
 
383
            pic.img.i_plane = 3;
 
384
            pic.img.i_stride[0] = inhdr->biWidth;
 
385
            pic.img.i_stride[1] =
 
386
            pic.img.i_stride[2] = inhdr->biWidth / 2;
 
387
 
 
388
            pic.img.plane[0]    = (uint8_t*)icc->lpInput;
 
389
            pic.img.plane[1]    = pic.img.plane[0] + inhdr->biWidth * inhdr->biHeight;
 
390
            pic.img.plane[2]    = pic.img.plane[1] + inhdr->biWidth * inhdr->biHeight / 4;
 
391
            break;
 
392
 
 
393
        case X264_CSP_YUYV:
 
394
            pic.img.i_plane = 1;
 
395
            pic.img.i_stride[0] = 2 * inhdr->biWidth;
 
396
            pic.img.plane[0]    = (uint8_t*)icc->lpInput;
 
397
            break;
 
398
 
 
399
        case X264_CSP_BGR:
 
400
            pic.img.i_plane = 1;
 
401
            pic.img.i_stride[0] = 3 * inhdr->biWidth;
 
402
            pic.img.plane[0]    = (uint8_t*)icc->lpInput;
 
403
            break;
 
404
 
 
405
        case X264_CSP_BGRA:
 
406
            pic.img.i_plane = 1;
 
407
            pic.img.i_stride[0] = 4 * inhdr->biWidth;
 
408
            pic.img.plane[0]    = (uint8_t*)icc->lpInput;
 
409
            break;
 
410
 
 
411
        default:
 
412
            return ICERR_BADFORMAT;
 
413
    }
 
414
 
 
415
    /* encode it */
 
416
    x264_encoder_encode( codec->h, &nal, &i_nal, &pic, &pic );
 
417
 
 
418
    /* create bitstream, unless we're dropping it in 1st pass */
 
419
    i_out = 0;
 
420
 
 
421
    if( codec->config.i_encoding_type != 2 || codec->config.i_pass > 1 ) {
 
422
        for( i = 0; i < i_nal; i++ ) {
 
423
            int i_size = outhdr->biSizeImage - i_out;
 
424
            x264_nal_encode( (uint8_t*)icc->lpOutput + i_out, &i_size, 1, &nal[i] );
 
425
 
 
426
            i_out += i_size;
 
427
        }
 
428
    }
 
429
 
 
430
    outhdr->biSizeImage = i_out;
 
431
 
 
432
    /* Set key frame only for IDR, as they are real synch point, I frame
 
433
       aren't always synch point (ex: with multi refs, ref marking) */
 
434
    if( pic.i_type == X264_TYPE_IDR )
 
435
        *icc->lpdwFlags = AVIIF_KEYFRAME;
 
436
    else
 
437
        *icc->lpdwFlags = 0;
 
438
 
 
439
    return ICERR_OK;
 
440
}
 
441