8620912340426a2840f57a4a2df9d9c5b2e518a1
[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     static char statsfile[] = ".\\x264.stats";
136
137     /* Destroy previous handle */
138     if( codec->h != NULL )
139     {
140         x264_encoder_close( codec->h );
141         codec->h = NULL;
142     }
143
144     /* Get default param */
145     x264_param_default( &param );
146
147     param.i_log_level = X264_LOG_NONE;
148     param.analyse.b_psnr = 0;
149     param.analyse.inter = 0;
150     param.analyse.intra = X264_ANALYSE_I4x4;
151
152     /* Set params: TODO to complete */
153     param.i_width = lpbiInput->bmiHeader.biWidth;
154     param.i_height= lpbiInput->bmiHeader.biHeight;
155
156     param.i_fps_num = codec->fbase;
157     param.i_fps_den = codec->fincr;
158
159     param.i_frame_reference = config->i_refmax;
160     param.i_keyint_min = config->i_keyint_min;
161     param.i_keyint_max = config->i_keyint_max;
162     param.b_deblocking_filter = config->b_filter;
163     param.b_cabac = config->b_cabac;
164     param.rc.f_ip_factor = 1 + (float)config->i_key_boost / 100;
165     param.rc.f_pb_factor = 1 + (float)config->i_b_red / 100;
166     param.rc.f_qcompress = (float)config->i_curve_comp / 100;
167
168     param.i_bframe = config->i_bframe;
169     param.analyse.i_subpel_refine = config->i_subpel_refine + 1; /* 0..4 -> 1..5 */
170
171     /* bframe prediction - gui goes alphabetically, so 1=SPATIAL, 2=TEMPORAL */
172     switch(config->i_direct_mv_pred) {
173         case 0: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; break;
174         case 1: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; break;
175     }
176     param.i_deblocking_filter_alphac0 = config->i_inloop_a;
177     param.i_deblocking_filter_beta = config->i_inloop_b;
178
179     if( config->b_bsub16x16 )
180         param.analyse.inter |= X264_ANALYSE_BSUB16x16;
181
182     if( config->b_psub16x16 )
183         param.analyse.inter |= X264_ANALYSE_PSUB16x16;
184     if( config->b_psub8x8 )
185         param.analyse.inter |= X264_ANALYSE_PSUB8x8;
186     if( config->b_i4x4 )
187         param.analyse.inter |= X264_ANALYSE_I4x4;
188
189     switch( config->i_encoding_type )
190     {
191         case 0: /* 1 PASS CBR */
192             param.rc.b_cbr = 1;
193             param.rc.i_bitrate = config->bitrate;
194             break;
195         case 1: /* 1 PASS CQ */
196             param.rc.i_qp_constant = config->i_qp;
197             break;
198         default:
199         case 2: /* 2 PASS */
200             param.rc.psz_stat_out = param.rc.psz_stat_in = statsfile;
201             if (config->i_pass == 1)
202             {
203                 param.rc.b_stat_write = 1;
204                 if (config->b_fast1pass)
205                 {
206                     /* adjust or turn off some flags to gain speed, if needed */
207                     if (param.analyse.i_subpel_refine > 1)
208                         param.analyse.i_subpel_refine --;
209                     if (param.analyse.i_subpel_refine > 3)
210                         param.analyse.i_subpel_refine = 3;
211                     param.i_frame_reference = (param.i_frame_reference + 1) >> 1;
212                     param.analyse.inter &= (~X264_ANALYSE_PSUB8x8);
213                     param.analyse.inter &= (~X264_ANALYSE_BSUB16x16);
214                 }
215             }    
216             else
217             {    
218                 param.rc.i_bitrate = config->i_2passbitrate;
219                 param.rc.b_stat_read = 1;
220                 param.rc.b_cbr = 1;
221             }
222             break;
223     }
224
225     /* Open the encoder */
226     codec->h = x264_encoder_open( &param );
227     if( codec->h == NULL )
228         return ICERR_ERROR;
229
230     return ICERR_OK;
231 }
232
233 /* */
234 LRESULT compress_end(CODEC * codec)
235 {
236     if( codec->h != NULL )
237     {
238         x264_encoder_close( codec->h );
239         codec->h = NULL;
240     }
241
242     return ICERR_OK;
243 }
244
245 /* */
246 LRESULT compress( CODEC *codec, ICCOMPRESS *icc )
247 {
248     BITMAPINFOHEADER *inhdr = icc->lpbiInput;
249     BITMAPINFOHEADER *outhdr = icc->lpbiOutput;
250
251     x264_picture_t pic;
252
253     int        i_nal;
254     x264_nal_t *nal;
255     int        i_out;
256
257     int i;
258
259     /* Init the picture */
260     memset( &pic, 0, sizeof( x264_picture_t ) );
261     pic.img.i_csp = get_csp( inhdr );
262
263     /* For now biWidth can be divided by 16 so no problem */
264     switch( pic.img.i_csp & X264_CSP_MASK )
265     {
266         case X264_CSP_I420:
267         case X264_CSP_YV12:
268             pic.img.i_plane = 3;
269             pic.img.i_stride[0] = inhdr->biWidth;
270             pic.img.i_stride[1] =
271             pic.img.i_stride[2] = inhdr->biWidth / 2;
272
273             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
274             pic.img.plane[1]    = pic.img.plane[0] + inhdr->biWidth * inhdr->biHeight;
275             pic.img.plane[2]    = pic.img.plane[1] + inhdr->biWidth * inhdr->biHeight / 4;
276             break;
277
278         case X264_CSP_YUYV:
279             pic.img.i_plane = 1;
280             pic.img.i_stride[0] = 2 * inhdr->biWidth;
281             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
282             break;
283
284         case X264_CSP_BGR:
285             pic.img.i_plane = 1;
286             pic.img.i_stride[0] = 3 * inhdr->biWidth;
287             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
288             break;
289
290         case X264_CSP_BGRA:
291             pic.img.i_plane = 1;
292             pic.img.i_stride[0] = 4 * inhdr->biWidth;
293             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
294             break;
295
296         default:
297             return ICERR_BADFORMAT;
298     }
299
300     /* encode it */
301     x264_encoder_encode( codec->h, &nal, &i_nal, &pic );
302
303     /* create bitstream, unless we're dropping it in 1st pass */
304     i_out = 0;
305
306     if (codec->config.i_encoding_type != 2 || codec->config.i_pass > 1) {
307         for( i = 0; i < i_nal; i++ ) {
308             int i_size = outhdr->biSizeImage - i_out;
309             x264_nal_encode( (uint8_t*)icc->lpOutput + i_out, &i_size, 1, &nal[i] );
310
311             i_out += i_size;
312         }
313     }
314
315     outhdr->biSizeImage = i_out;
316
317     /* Set key frame only for IDR, as they are real synch point, I frame
318        aren't always synch point (ex: with multi refs, ref marking) */
319     if( pic.i_type == X264_TYPE_IDR )
320         *icc->lpdwFlags = AVIIF_KEYFRAME;
321     else
322         *icc->lpdwFlags = 0;
323
324     return ICERR_OK;
325 }
326