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 $
8 * Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
27 #include <stdio.h> /* debug only */
30 * return a valid x264 CSP or X264_CSP_NULL if unsuported */
31 static int get_csp( BITMAPINFOHEADER *hdr )
33 int i_vlip = hdr->biHeight < 0 ? 0 : X264_CSP_VFLIP;
35 switch( hdr->biCompression )
49 if( hdr->biBitCount == 24 )
50 return X264_CSP_BGR | i_vlip;
51 if( hdr->biBitCount == 32 )
52 return X264_CSP_BGRA | i_vlip;
61 /* Test that we can do the compression */
62 LRESULT compress_query( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
64 BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
65 BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
66 CONFIG *config = &codec->config;
68 if( get_csp( inhdr ) == X264_CSP_NONE )
69 return ICERR_BADFORMAT;
71 if( lpbiOutput == NULL )
74 if( inhdr->biWidth != outhdr->biWidth ||
75 inhdr->biHeight != outhdr->biHeight )
76 return ICERR_BADFORMAT;
78 /* We need x16 width/height */
79 if( inhdr->biWidth % 16 != 0 || inhdr->biHeight % 16 != 0 )
80 return ICERR_BADFORMAT;
83 if( inhdr->biCompression != mmioFOURCC( config->fcc[0], config->fcc[1],
84 config->fcc[2], config->fcc[3] ) )
85 return ICERR_BADFORMAT;
91 LRESULT compress_get_format( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
93 BITMAPINFOHEADER *inhdr = &lpbiInput->bmiHeader;
94 BITMAPINFOHEADER *outhdr = &lpbiOutput->bmiHeader;
95 CONFIG *config = &codec->config;
97 if( get_csp( inhdr ) == X264_CSP_NONE )
98 return ICERR_BADFORMAT;
100 if( lpbiOutput == NULL )
101 return sizeof(BITMAPINFOHEADER);
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] );
117 LRESULT compress_get_size( CODEC *codec, BITMAPINFO *lpbiInput, BITMAPINFO *lpbiOutput )
119 return 2 * lpbiOutput->bmiHeader.biWidth * lpbiOutput->bmiHeader.biHeight * 3;
123 LRESULT compress_frames_info(CODEC * codec, ICCOMPRESSFRAMES * icf )
125 codec->fincr = icf->dwScale;
126 codec->fbase = icf->dwRate;
131 LRESULT compress_begin(CODEC * codec, BITMAPINFO * lpbiInput, BITMAPINFO * lpbiOutput )
133 CONFIG *config = &codec->config;
135 static char statsfile[] = ".\\x264.stats";
137 /* Destroy previous handle */
138 if( codec->h != NULL )
140 x264_encoder_close( codec->h );
144 /* Get default param */
145 x264_param_default( ¶m );
147 param.i_log_level = X264_LOG_NONE;
148 param.analyse.b_psnr = 0;
149 param.analyse.inter = param.analyse.intra = 0;
151 /* Set params: TODO to complete */
152 param.i_width = lpbiInput->bmiHeader.biWidth;
153 param.i_height= lpbiInput->bmiHeader.biHeight;
155 param.i_fps_num = codec->fbase;
156 param.i_fps_den = codec->fincr;
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;
164 param.i_bframe = config->i_bframe;
165 param.analyse.i_subpel_refine = config->i_subpel_refine + 1; /* 0..4 -> 1..5 */
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;
173 param.i_deblocking_filter_alphac0 = config->i_inloop_a;
174 param.i_deblocking_filter_beta = config->i_inloop_b;
176 if( config->b_bsub16x16 )
177 param.analyse.inter |= X264_ANALYSE_BSUB16x16;
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;
188 switch( config->i_encoding_type )
190 case 0: /* 1 PASS CBR */
192 param.rc.i_bitrate = config->bitrate;
194 case 1: /* 1 PASS CQ */
195 param.rc.i_qp_constant = config->i_qp;
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;
203 param.rc.i_bitrate = config->i_2passbitrate;
204 param.rc.b_stat_read = 1;
210 /* Open the encoder */
211 codec->h = x264_encoder_open( ¶m );
212 if( codec->h == NULL )
219 LRESULT compress_end(CODEC * codec)
221 if( codec->h != NULL )
223 x264_encoder_close( codec->h );
231 LRESULT compress( CODEC *codec, ICCOMPRESS *icc )
233 BITMAPINFOHEADER *inhdr = icc->lpbiInput;
234 BITMAPINFOHEADER *outhdr = icc->lpbiOutput;
244 /* Init the picture */
245 memset( &pic, 0, sizeof( x264_picture_t ) );
246 pic.img.i_csp = get_csp( inhdr );
248 /* For now biWidth can be divided by 16 so no problem */
249 switch( pic.img.i_csp & X264_CSP_MASK )
254 pic.img.i_stride[0] = inhdr->biWidth;
255 pic.img.i_stride[1] =
256 pic.img.i_stride[2] = inhdr->biWidth / 2;
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;
265 pic.img.i_stride[0] = 2 * inhdr->biWidth;
266 pic.img.plane[0] = (uint8_t*)icc->lpInput;
271 pic.img.i_stride[0] = 3 * inhdr->biWidth;
272 pic.img.plane[0] = (uint8_t*)icc->lpInput;
277 pic.img.i_stride[0] = 4 * inhdr->biWidth;
278 pic.img.plane[0] = (uint8_t*)icc->lpInput;
282 return ICERR_BADFORMAT;
286 x264_encoder_encode( codec->h, &nal, &i_nal, &pic );
288 /* create bitstream, unless we're dropping it in 1st pass */
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] );
300 outhdr->biSizeImage = i_out;
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;