]> git.sesse.net Git - x264/blob - vfw/codec.c
updated VfW interface by Radek Czyz
[x264] / 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 = param.analyse.intra = 0;
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_idrframe = config->i_idrframe;
160     param.i_iframe   = config->i_iframe;
161     param.b_deblocking_filter = config->b_filter;
162     param.b_cabac = config->b_cabac;
163
164     param.i_bframe = config->i_bframe;
165     param.analyse.i_subpel_refine = config->i_subpel_refine + 1; /* 0..4 -> 1..5 */
166
167     /* bframe prediction - gui goes alphabetically, so 0=NONE, 1=SPATIAL, 2=TEMPORAL */
168     switch(config->i_direct_mv_pred) {
169         case 0: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_NONE; break;
170         case 1: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_SPATIAL; break;
171         case 2: param.analyse.i_direct_mv_pred = X264_DIRECT_PRED_TEMPORAL; break;
172     }
173     param.i_deblocking_filter_alphac0 = config->i_inloop_a;
174     param.i_deblocking_filter_beta = config->i_inloop_b;
175
176     if( config->b_bsub16x16 )
177         param.analyse.inter |= X264_ANALYSE_BSUB16x16;
178
179     if( config->b_psub16x16 )
180         param.analyse.inter |= X264_ANALYSE_PSUB16x16;
181     if( config->b_psub8x8 )
182         param.analyse.inter |= X264_ANALYSE_PSUB8x8;
183     if( config->b_i4x4 ) {
184         param.analyse.intra |= X264_ANALYSE_I4x4;
185         param.analyse.inter |= X264_ANALYSE_I4x4;
186     }
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 = ".\\x264.stats";
200             if (config->i_pass == 1)
201                 param.rc.b_stat_write = 1;
202             else {    
203                 param.rc.i_bitrate = config->i_2passbitrate;
204                 param.rc.b_stat_read = 1;
205                 param.rc.b_cbr = 1;
206             }
207             break;
208     }
209
210     /* Open the encoder */
211     codec->h = x264_encoder_open( &param );
212     if( codec->h == NULL )
213         return ICERR_ERROR;
214
215     return ICERR_OK;
216 }
217
218 /* */
219 LRESULT compress_end(CODEC * codec)
220 {
221     if( codec->h != NULL )
222     {
223         x264_encoder_close( codec->h );
224         codec->h = NULL;
225     }
226
227     return ICERR_OK;
228 }
229
230 /* */
231 LRESULT compress( CODEC *codec, ICCOMPRESS *icc )
232 {
233     BITMAPINFOHEADER *inhdr = icc->lpbiInput;
234     BITMAPINFOHEADER *outhdr = icc->lpbiOutput;
235
236     x264_picture_t pic;
237
238     int        i_nal;
239     x264_nal_t *nal;
240     int        i_out;
241
242     int i;
243
244     /* Init the picture */
245     memset( &pic, 0, sizeof( x264_picture_t ) );
246     pic.img.i_csp = get_csp( inhdr );
247
248     /* For now biWidth can be divided by 16 so no problem */
249     switch( pic.img.i_csp & X264_CSP_MASK )
250     {
251         case X264_CSP_I420:
252         case X264_CSP_YV12:
253             pic.img.i_plane = 3;
254             pic.img.i_stride[0] = inhdr->biWidth;
255             pic.img.i_stride[1] =
256             pic.img.i_stride[2] = inhdr->biWidth / 2;
257
258             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
259             pic.img.plane[1]    = pic.img.plane[0] + inhdr->biWidth * inhdr->biHeight;
260             pic.img.plane[2]    = pic.img.plane[1] + inhdr->biWidth * inhdr->biHeight / 4;
261             break;
262
263         case X264_CSP_YUYV:
264             pic.img.i_plane = 1;
265             pic.img.i_stride[0] = 2 * inhdr->biWidth;
266             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
267             break;
268
269         case X264_CSP_BGR:
270             pic.img.i_plane = 1;
271             pic.img.i_stride[0] = 3 * inhdr->biWidth;
272             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
273             break;
274
275         case X264_CSP_BGRA:
276             pic.img.i_plane = 1;
277             pic.img.i_stride[0] = 4 * inhdr->biWidth;
278             pic.img.plane[0]    = (uint8_t*)icc->lpInput;
279             break;
280
281         default:
282             return ICERR_BADFORMAT;
283     }
284
285     /* encode it */
286     x264_encoder_encode( codec->h, &nal, &i_nal, &pic );
287
288     /* create bitstream, unless we're dropping it in 1st pass */
289     i_out = 0;
290
291     if (codec->config.i_encoding_type != 2 || codec->config.i_pass > 1) {
292         for( i = 0; i < i_nal; i++ ) {
293             int i_size = outhdr->biSizeImage - i_out;
294             x264_nal_encode( (uint8_t*)icc->lpOutput + i_out, &i_size, 1, &nal[i] );
295
296             i_out += i_size;
297         }
298     }
299
300     outhdr->biSizeImage = i_out;
301
302     /* Set key frame only for IDR, as they are real synch point, I frame
303        aren't always synch point (ex: with multi refs, ref marking) */
304     if( pic.i_type == X264_TYPE_IDR )
305         *icc->lpdwFlags = AVIIF_KEYFRAME;
306     else
307         *icc->lpdwFlags = 0;
308
309     return ICERR_OK;
310 }
311