VfW: expose option "Nth pass" (i.e. simultaneously read and update the multipass...
[x262.git] / vfw / codec.c
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
29 /* get_csp:
30  *  return a valid x264 CSP or X264_CSP_NULL if unsuported */
31 static int get_csp( BITMAPINFOHEADER *hdr )
32 {
33     int i_vlip = hdr->biHeight < 0 ? 0 : X264_CSP_VFLIP;
34
35     switch( hdr->biCompression )
36     {
37         case FOURCC_I420:
38         case FOURCC_IYUV:
39             return X264_CSP_I420;
40
41         case FOURCC_YV12:
42             return X264_CSP_YV12;
43
44         case FOURCC_YUYV:
45         case FOURCC_YUY2:
46             return X264_CSP_YUYV;
47
48         case BI_RGB:
49             if( hdr->biBitCount == 24 )
50                 return X264_CSP_BGR | i_vlip;
51             if( hdr->biBitCount == 32 )
52                 return X264_CSP_BGRA | i_vlip;
53             else
54                 return X264_CSP_NONE;
55
56         default:
57             return X264_CSP_NONE;
58     }
59 }
60
61 /* Test that we can do the compression */
62 LRESULT compress_query( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
63 {
64     BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
65     BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
66     CONFIG           *config = &codec->config;
67
68     if( get_csp( inhdr ) == X264_CSP_NONE )
69         return ICERR_BADFORMAT;
70
71     if( lpbiOutput == NULL )
72         return ICERR_OK;
73
74     if( inhdr->biWidth != outhdr->biWidth ||
75         inhdr->biHeight != outhdr->biHeight )
76         return ICERR_BADFORMAT;
77
78     /* We need x16 width/height */
79     if( inhdr->biWidth % 16 != 0 || inhdr->biHeight % 16 != 0 )
80         return ICERR_BADFORMAT;
81
82
83     if( inhdr->biCompression != mmioFOURCC( config->fcc[0], config->fcc[1],
84                                             config->fcc[2], config->fcc[3] ) )
85         return ICERR_BADFORMAT;
86
87     return ICERR_OK;
88 }
89
90 /* */
91 LRESULT compress_get_format( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
92 {
93     BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
94     BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
95     CONFIG           *config = &codec->config;
96
97     if( get_csp( inhdr ) == X264_CSP_NONE )
98         return ICERR_BADFORMAT;
99
100     if( lpbiOutput == NULL )
101         return sizeof(BITMAPINFOHEADER);
102
103     memcpy( outhdr, inhdr, sizeof( BITMAPINFOHEADER ) );
104     outhdr->biSize = sizeof( BITMAPINFOHEADER );
105     outhdr->biSizeImage = compress_get_size( codec, lpbiInput, lpbiOutput );
106     outhdr->biXPelsPerMeter = 0;
107     outhdr->biYPelsPerMeter = 0;
108     outhdr->biClrUsed = 0;
109     outhdr->biClrImportant = 0;
110     outhdr->biCompression = mmioFOURCC( config->fcc[0], config->fcc[1],
111                                         config->fcc[2], config->fcc[3] );
112
113     return ICERR_OK;
114 }
115
116 /* */
117 LRESULT compress_get_size( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
118 {
119     return 2 * lpbiOutput->bmiHeader.biWidth * lpbiOutput->bmiHeader.biHeight * 3;
120 }
121
122 /* */
123 LRESULT compress_frames_info(CODEC * codec, ICCOMPRESSFRAMES * icf )
124 {
125     codec->fincr = icf->dwScale;
126     codec->fbase = icf->dwRate;
127     return ICERR_OK;
128 }
129
130 /* */
131 LRESULT compress_begin(CODEC * codec, BITMAPINFO * lpbiInput, BITMAPINFO * lpbiOutput )
132 {
133     CONFIG *config = &codec->config;
134     x264_param_t param;
135
136     /* Destroy previous handle */
137     if( codec->h != NULL )
138     {
139         x264_encoder_close( codec->h );
140         codec->h = NULL;
141     }
142
143     /* Get default param */
144     x264_param_default( &param );
145
146     param.i_log_level = X264_LOG_NONE;
147     param.analyse.b_psnr = 0;
148     param.analyse.inter = 0;
149     param.analyse.intra = X264_ANALYSE_I4x4;
150
151     /* Set params: TODO to complete */
152     param.i_width = lpbiInput->bmiHeader.biWidth;
153     param.i_height= lpbiInput->bmiHeader.biHeight;
154
155     param.i_fps_num = codec->fbase;
156     param.i_fps_den = codec->fincr;
157
158     param.i_frame_reference = config->i_refmax;
159     param.i_keyint_min = config->i_keyint_min;
160     param.i_keyint_max = config->i_keyint_max;
161     param.b_deblocking_filter = config->b_filter;
162     param.b_cabac = config->b_cabac;
163     param.rc.f_ip_factor = 1 + (float)config->i_key_boost / 100;
164     param.rc.f_pb_factor = 1 + (float)config->i_b_red / 100;
165     param.rc.f_qcompress = (float)config->i_curve_comp / 100;
166
167     param.i_bframe = config->i_bframe;
168     param.analyse.i_subpel_refine = config->i_subpel_refine + 1; /* 0..4 -> 1..5 */
169
170     /* bframe prediction - gui goes alphabetically, so 1=SPATIAL, 2=TEMPORAL */
171     switch(config->i_direct_mv_pred) {
172         case 0: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; break;
173         case 1: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; break;
174     }
175     param.i_deblocking_filter_alphac0 = config->i_inloop_a;
176     param.i_deblocking_filter_beta = config->i_inloop_b;
177
178     if( config->b_bsub16x16 )
179         param.analyse.inter |= X264_ANALYSE_BSUB16x16;
180
181     if( config->b_psub16x16 )
182         param.analyse.inter |= X264_ANALYSE_PSUB16x16;
183     if( config->b_psub8x8 )
184         param.analyse.inter |= X264_ANALYSE_PSUB8x8;
185     if( config->b_i4x4 )
186         param.analyse.inter |= X264_ANALYSE_I4x4;
187
188     switch( config->i_encoding_type )
189     {
190         case 0: /* 1 PASS CBR */
191             param.rc.b_cbr = 1;
192             param.rc.i_bitrate = config->bitrate;
193             break;
194         case 1: /* 1 PASS CQ */
195             param.rc.i_qp_constant = config->i_qp;
196             break;
197         default:
198         case 2: /* 2 PASS */
199             param.rc.psz_stat_out = param.rc.psz_stat_in = config->stats;
200             if (config->i_pass == 1)
201             {
202                 param.rc.b_stat_write = 1;
203                 if (config->b_fast1pass)
204                 {
205                     /* adjust or turn off some flags to gain speed, if needed */
206                     if (param.analyse.i_subpel_refine > 1)
207                         param.analyse.i_subpel_refine --;
208                     if (param.analyse.i_subpel_refine > 3)
209                         param.analyse.i_subpel_refine = 3;
210                     param.i_frame_reference = (param.i_frame_reference + 1) >> 1;
211                     param.analyse.inter &= (~X264_ANALYSE_PSUB8x8);
212                     param.analyse.inter &= (~X264_ANALYSE_BSUB16x16);
213                 }
214             }    
215             else
216             {    
217                 param.rc.i_bitrate = config->i_2passbitrate;
218                 param.rc.b_stat_read = 1;
219                 param.rc.b_cbr = 1;
220                 if( config->b_updatestats )
221                     param.rc.b_stat_write = 1;
222             }
223             break;
224     }
225
226     /* Open the encoder */
227     codec->h = x264_encoder_open( &param );
228     if( codec->h == NULL )
229         return ICERR_ERROR;
230
231     return ICERR_OK;
232 }
233
234 /* */
235 LRESULT compress_end(CODEC * codec)
236 {
237     if( codec->h != NULL )
238     {
239         x264_encoder_close( codec->h );
240         codec->h = NULL;
241     }
242
243     return ICERR_OK;
244 }
245
246 /* */
247 LRESULT compress( CODEC *codec, ICCOMPRESS *icc )
248 {
249     BITMAPINFOHEADER *inhdr = icc->lpbiInput;
250     BITMAPINFOHEADER *outhdr = icc->lpbiOutput;
251
252     x264_picture_t pic;
253
254     int        i_nal;
255     x264_nal_t *nal;
256     int        i_out;
257
258     int i;
259
260     /* Init the picture */
261     memset( &pic, 0, sizeof( x264_picture_t ) );
262     pic.img.i_csp = get_csp( inhdr );
263
264     /* For now biWidth can be divided by 16 so no problem */
265     switch( pic.img.i_csp & X264_CSP_MASK )
266     {
267         case X264_CSP_I420:
268         case X264_CSP_YV12:
269             pic.img.i_plane = 3;
270             pic.img.i_stride[0] = inhdr->biWidth;
271             pic.img.i_stride[1] =
272             pic.img.i_stride[2] = inhdr->biWidth / 2;
273
274             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
275             pic.img.plane[1]    = pic.img.plane[0] + inhdr->biWidth * inhdr->biHeight;
276             pic.img.plane[2]    = pic.img.plane[1] + inhdr->biWidth * inhdr->biHeight / 4;
277             break;
278
279         case X264_CSP_YUYV:
280             pic.img.i_plane = 1;
281             pic.img.i_stride[0] = 2 * inhdr->biWidth;
282             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
283             break;
284
285         case X264_CSP_BGR:
286             pic.img.i_plane = 1;
287             pic.img.i_stride[0] = 3 * inhdr->biWidth;
288             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
289             break;
290
291         case X264_CSP_BGRA:
292             pic.img.i_plane = 1;
293             pic.img.i_stride[0] = 4 * inhdr->biWidth;
294             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
295             break;
296
297         default:
298             return ICERR_BADFORMAT;
299     }
300
301     /* encode it */
302     x264_encoder_encode( codec->h, &nal, &i_nal, &pic );
303
304     /* create bitstream, unless we're dropping it in 1st pass */
305     i_out = 0;
306
307     if (codec->config.i_encoding_type != 2 || codec->config.i_pass > 1) {
308         for( i = 0; i < i_nal; i++ ) {
309             int i_size = outhdr->biSizeImage - i_out;
310             x264_nal_encode( (uint8_t*)icc->lpOutput + i_out, &i_size, 1, &nal[i] );
311
312             i_out += i_size;
313         }
314     }
315
316     outhdr->biSizeImage = i_out;
317
318     /* Set key frame only for IDR, as they are real synch point, I frame
319        aren't always synch point (ex: with multi refs, ref marking) */
320     if( pic.i_type == X264_TYPE_IDR )
321         *icc->lpdwFlags = AVIIF_KEYFRAME;
322     else
323         *icc->lpdwFlags = 0;
324
325     return ICERR_OK;
326 }
327