Mercurial > mplayer.hg
comparison libmpcodecs/ve_x264.c @ 13166:d198f255bee9
x264 encoder support. Original patch send by Bernhard Rosenkraenzer <bero at arklinux dot org>, modifications by Loren Merritt <lorenm at u.washington dot edu>, Jeff Clagg <snacky at ikaruga.co dot uk> and me
author | iive |
---|---|
date | Fri, 27 Aug 2004 20:43:05 +0000 |
parents | |
children | f26d2c9aec04 |
comparison
equal
deleted
inserted
replaced
13165:3925db29cf1e | 13166:d198f255bee9 |
---|---|
1 /***************************************************************************** | |
2 * | |
3 * - H.264 encoder for mencoder using x264 - | |
4 * | |
5 * Copyright (C) 2004 LINUX4MEDIA GmbH | |
6 * Copyright (C) 2004 Ark Linux | |
7 * | |
8 * Written by Bernhard Rosenkraenzer <bero@arklinux.org> | |
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 version 2 as | |
12 * published by the Free Software Foundation, or if, and only if, | |
13 * version 2 is ruled invalid in a court of law, any later version | |
14 * of the GNU General Public License published by the Free Software | |
15 * Foundation. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU General Public License | |
23 * along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
25 * | |
26 *****************************************************************************/ | |
27 | |
28 #include <stdio.h> | |
29 #include <stdlib.h> | |
30 #include <string.h> | |
31 #include <errno.h> | |
32 #include <stdint.h> | |
33 | |
34 #include "../config.h" | |
35 #include "../mp_msg.h" | |
36 | |
37 #ifdef HAVE_X264 | |
38 | |
39 #include "m_option.h" | |
40 #include "codec-cfg.h" | |
41 #include "stream.h" | |
42 #include "demuxer.h" | |
43 #include "stheader.h" | |
44 | |
45 #include "muxer.h" | |
46 | |
47 #include "img_format.h" | |
48 #include "mp_image.h" | |
49 #include "vf.h" | |
50 | |
51 #include <x264.h> | |
52 | |
53 typedef struct _h264_module_t { | |
54 muxer_stream_t *mux; | |
55 x264_param_t param; | |
56 x264_t * x264; | |
57 x264_picture_t pic; | |
58 } h264_module_t; | |
59 | |
60 extern char* passtmpfile; | |
61 | |
62 static int bitrate = -1; | |
63 static int qp_constant = 26; | |
64 static int frame_ref = 1; | |
65 static int iframe = 60; | |
66 static int idrframe = 2; | |
67 static int bframe = 0; | |
68 static int deblock = 1; | |
69 static int deblockalpha = 0; | |
70 static int deblockbeta = 0; | |
71 static int cabac = 0; | |
72 static int cabacidc = -1; | |
73 static int fullinter = 0; | |
74 static float ip_factor = 2.0; | |
75 static float pb_factor = 2.0; | |
76 static int rc_buffer_size = -1; | |
77 static int rc_init_buffer = -1; | |
78 static int rc_sens = 4; | |
79 static int qp_min = 10; | |
80 static int qp_max = 51; | |
81 static int qp_step = 1; | |
82 static int pass = 0; | |
83 static float qcomp = 0.6; | |
84 static float qblur = 0.5; | |
85 static char *rc_eq = "(tex^qComp)*(avgTex^(1-qComp))"; | |
86 static int psnr = 0; | |
87 static int log_level = 2; | |
88 | |
89 m_option_t x264encopts_conf[] = { | |
90 {"bitrate", &bitrate, CONF_TYPE_INT, CONF_RANGE, 0, 24000000, NULL}, | |
91 {"qp_constant", &qp_constant, CONF_TYPE_INT, CONF_RANGE, 1, 51, NULL}, | |
92 {"frameref", &frame_ref, CONF_TYPE_INT, CONF_RANGE, 1, 100, NULL}, | |
93 {"iframe", &iframe, CONF_TYPE_INT, CONF_RANGE, 1, 24000000, NULL}, | |
94 {"idrframe", &idrframe, CONF_TYPE_INT, CONF_RANGE, 1, 24000000, NULL}, | |
95 {"bframe", &bframe, CONF_TYPE_INT, CONF_RANGE, 0, 10, NULL}, | |
96 {"deblock", &deblock, CONF_TYPE_INT, CONF_RANGE, 0, 1, NULL}, | |
97 {"deblockalpha", &deblockalpha, CONF_TYPE_INT, CONF_RANGE, -6, 6, NULL}, | |
98 {"deblockbeta", &deblockbeta, CONF_TYPE_INT, CONF_RANGE, -6, 6, NULL}, | |
99 {"cabac", &cabac, CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
100 {"cabacidc", &cabacidc, CONF_TYPE_INT, CONF_RANGE, -1, 2, NULL}, | |
101 {"fullinter", &fullinter, CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
102 {"ip_factor", &ip_factor, CONF_TYPE_FLOAT, CONF_RANGE, -10.0, 10.0, NULL}, | |
103 {"pb_factor", &pb_factor, CONF_TYPE_FLOAT, CONF_RANGE, -10.0, 10.0, NULL}, | |
104 {"rc_buffer_size", &rc_buffer_size, CONF_TYPE_INT, CONF_RANGE, 0, 24000000, NULL}, | |
105 {"rc_init_buffer", &rc_init_buffer, CONF_TYPE_INT, CONF_RANGE, 0, 24000000, NULL}, | |
106 {"rc_sens", &rc_sens, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, | |
107 {"qp_min", &qp_min, CONF_TYPE_INT, CONF_RANGE, 1, 51, NULL}, | |
108 {"qp_max", &qp_max, CONF_TYPE_INT, CONF_RANGE, 1, 51, NULL}, | |
109 {"qp_step", &qp_step, CONF_TYPE_INT, CONF_RANGE, 0, 50, NULL}, | |
110 {"pass", &pass, CONF_TYPE_INT, CONF_RANGE, 1, 3, NULL}, | |
111 {"rc_eq", &rc_eq, CONF_TYPE_STRING, 0, 0, 0, NULL}, | |
112 {"qcomp", &qcomp, CONF_TYPE_FLOAT, CONF_RANGE, 0, 1, NULL}, | |
113 {"qblur", &qblur, CONF_TYPE_FLOAT, CONF_RANGE, 0, 99, NULL}, | |
114 {"psnr", &psnr, CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
115 {"log", &log_level, CONF_TYPE_INT, CONF_RANGE, -1, 3, NULL}, | |
116 {NULL, NULL, 0, 0, 0, 0, NULL} | |
117 }; | |
118 | |
119 | |
120 static int config(struct vf_instance_s* vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) { | |
121 h264_module_t *mod=(h264_module_t*)vf->priv; | |
122 mod->mux->bih->biWidth = width; | |
123 mod->mux->bih->biHeight = height; | |
124 mod->mux->aspect = (float)d_width/d_height; | |
125 | |
126 x264_param_default(&mod->param); | |
127 mod->param.i_frame_reference = frame_ref; | |
128 mod->param.i_idrframe = idrframe; | |
129 mod->param.i_iframe = iframe; | |
130 mod->param.i_bframe = bframe; | |
131 mod->param.b_deblocking_filter = deblock; | |
132 mod->param.i_deblocking_filter_alphac0 = deblockalpha; | |
133 mod->param.i_deblocking_filter_beta = deblockbeta; | |
134 mod->param.b_cabac = cabac; | |
135 mod->param.i_cabac_init_idc = cabacidc; | |
136 mod->param.i_qp_constant = qp_constant; | |
137 if(qp_min > qp_constant) | |
138 qp_min = qp_constant; | |
139 if(qp_max < qp_constant) | |
140 qp_max = qp_constant; | |
141 mod->param.i_qp_min = qp_min; | |
142 mod->param.i_qp_max = qp_max; | |
143 mod->param.i_qp_step = qp_step; | |
144 #if 0 | |
145 mod->param.i_pass = pass; | |
146 mod->param.s_rc_eq = rc_eq; | |
147 mod->param.f_qcompress = qcomp; | |
148 mod->param.f_qblur = qblur; | |
149 mod->param.s_2pass_file_out = passtmpfile; | |
150 mod->param.s_2pass_file_in = passtmpfile; | |
151 if((pass & 2) && bitrate <= 0) | |
152 { | |
153 mp_msg(MSGT_MENCODER, MSGL_ERR, | |
154 "2 pass encoding enabled, but no bitrate specified.\n"); | |
155 return 0; | |
156 } | |
157 #endif | |
158 if(bitrate > 0) { | |
159 if(rc_buffer_size <= 0) | |
160 rc_buffer_size = bitrate; | |
161 if(rc_init_buffer < 0) | |
162 rc_init_buffer = rc_buffer_size/4; | |
163 mod->param.b_cbr = 1; | |
164 mod->param.i_bitrate = bitrate; | |
165 mod->param.i_rc_buffer_size = rc_buffer_size; | |
166 mod->param.i_rc_init_buffer = rc_init_buffer; | |
167 mod->param.i_rc_sens = rc_sens; | |
168 } | |
169 if(fullinter) | |
170 mod->param.analyse.inter = X264_ANALYSE_I4x4 | X264_ANALYSE_PSUB16x16 | X264_ANALYSE_PSUB8x8; | |
171 mod->param.f_ip_factor = ip_factor; | |
172 mod->param.f_pb_factor = pb_factor; | |
173 | |
174 mod->param.i_width = width; | |
175 mod->param.i_height = height; | |
176 mod->param.i_fps_num = mod->mux->h.dwRate; | |
177 mod->param.i_fps_den = mod->mux->h.dwScale; | |
178 mod->param.analyse.b_psnr = psnr; | |
179 mod->param.i_log_level = log_level; | |
180 | |
181 switch(outfmt) { | |
182 case IMGFMT_I420: | |
183 mod->param.i_csp = X264_CSP_I420; | |
184 mod->mux->bih->biSizeImage = width * height * 3; | |
185 break; | |
186 case IMGFMT_YV12: | |
187 mod->param.i_csp = X264_CSP_YV12; | |
188 mod->mux->bih->biSizeImage = width * height * 3; | |
189 break; | |
190 case IMGFMT_422P: | |
191 mod->param.i_csp = X264_CSP_I422; | |
192 mod->mux->bih->biSizeImage = width * height * 3; | |
193 break; | |
194 case IMGFMT_444P: | |
195 mod->param.i_csp = X264_CSP_I444; | |
196 mod->mux->bih->biSizeImage = width * height * 3; | |
197 break; | |
198 case IMGFMT_YVYU: | |
199 mod->param.i_csp = X264_CSP_YUYV; | |
200 mod->mux->bih->biSizeImage = width * height * 3; | |
201 break; | |
202 case IMGFMT_RGB: | |
203 mod->param.i_csp = X264_CSP_RGB; | |
204 mod->mux->bih->biSizeImage = width * height * 3; | |
205 break; | |
206 case IMGFMT_BGR: | |
207 mod->param.i_csp = X264_CSP_BGR; | |
208 mod->mux->bih->biSizeImage = width * height * 3; | |
209 break; | |
210 case IMGFMT_BGR32: | |
211 mod->param.i_csp = X264_CSP_BGRA; | |
212 mod->mux->bih->biSizeImage = width * height * 4; | |
213 break; | |
214 default: | |
215 mp_msg(MSGT_MENCODER, MSGL_ERR, "Wrong colorspace.\n"); | |
216 return 0; | |
217 } | |
218 | |
219 mod->x264 = x264_encoder_open(&mod->param); | |
220 if(!mod->x264) { | |
221 mp_msg(MSGT_MENCODER, MSGL_ERR, "x264_encoder_open failed.\n"); | |
222 return 0; | |
223 } | |
224 | |
225 x264_picture_alloc(&mod->pic, mod->param.i_csp, mod->param.i_width, mod->param.i_height); | |
226 return 1; | |
227 } | |
228 | |
229 static int control(struct vf_instance_s* vf, int request, void *data) | |
230 { | |
231 return CONTROL_UNKNOWN; | |
232 } | |
233 | |
234 static int query_format(struct vf_instance_s* vf, unsigned int fmt) | |
235 { | |
236 switch(fmt) { | |
237 case IMGFMT_I420: | |
238 return (VFCAP_CSP_SUPPORTED|VFCAP_CSP_SUPPORTED_BY_HW); | |
239 case IMGFMT_YV12: | |
240 case IMGFMT_422P: | |
241 case IMGFMT_444P: | |
242 case IMGFMT_YVYU: | |
243 case IMGFMT_RGB: | |
244 case IMGFMT_BGR: | |
245 case IMGFMT_BGR32: | |
246 /* 2004/08/05: There seems to be some, but not complete, | |
247 support for these colorspaces in X264. Better to stay | |
248 on the safe side for now. */ | |
249 return 0; /* VFCAP_CSP_SUPPORTED */ | |
250 } | |
251 return 0; | |
252 } | |
253 | |
254 static int put_image(struct vf_instance_s *vf, mp_image_t *mpi) | |
255 { | |
256 h264_module_t *mod=(h264_module_t*)vf->priv; | |
257 int i_nal; | |
258 x264_nal_t *nal; | |
259 int i; | |
260 | |
261 int csp=mod->pic.img.i_csp; | |
262 memset(&mod->pic, 0, sizeof(x264_picture_t)); | |
263 mod->pic.img.i_csp=csp; | |
264 mod->pic.img.i_plane=3; | |
265 for(i=0; i<4; i++) { | |
266 mod->pic.img.plane[i] = mpi->planes[i]; | |
267 mod->pic.img.i_stride[i] = mpi->stride[i]; | |
268 } | |
269 | |
270 mod->pic.i_type = X264_TYPE_AUTO; | |
271 if(x264_encoder_encode(mod->x264, &nal, &i_nal, &mod->pic) < 0) { | |
272 mp_msg(MSGT_MENCODER, MSGL_ERR, "x264_encoder_encode failed\n"); | |
273 return 0; | |
274 } | |
275 | |
276 int i_size = 0; | |
277 for(i=0; i < i_nal; i++) { | |
278 int i_data = mod->mux->buffer_size - i_size; | |
279 i_size += x264_nal_encode(mod->mux->buffer + i_size, &i_data, 1, &nal[i]); | |
280 } | |
281 if(i_size>0) { | |
282 muxer_write_chunk(mod->mux, i_size, (mod->pic.i_type == X264_TYPE_I)?0x10:0); | |
283 } | |
284 return 1; | |
285 } | |
286 | |
287 static void uninit(struct vf_instance_s *vf) | |
288 { | |
289 // FIXME: flush delayed frames | |
290 h264_module_t *mod=(h264_module_t*)vf->priv; | |
291 x264_encoder_close(mod->x264); | |
292 //x264_picture_clean(&mod->pic); | |
293 } | |
294 | |
295 static int vf_open(vf_instance_t *vf, char *args) { | |
296 vf->config = config; | |
297 vf->control = control; | |
298 vf->query_format = query_format; | |
299 vf->put_image = put_image; | |
300 vf->uninit = uninit; | |
301 vf->priv = malloc(sizeof(h264_module_t)); | |
302 | |
303 h264_module_t *mod=(h264_module_t*)vf->priv; | |
304 mod->mux = (muxer_stream_t*)args; | |
305 mod->mux->bih = malloc(sizeof(BITMAPINFOHEADER)); | |
306 memset(mod->mux->bih, 0, sizeof(BITMAPINFOHEADER)); | |
307 mod->mux->bih->biSize = sizeof(BITMAPINFOHEADER); | |
308 mod->mux->bih->biPlanes = 1; | |
309 mod->mux->bih->biBitCount = 24; | |
310 mod->mux->bih->biCompression = mmioFOURCC('h', '2', '6', '4'); | |
311 | |
312 return 1; | |
313 } | |
314 | |
315 vf_info_t ve_info_x264 = { | |
316 "H.264 encoder", | |
317 "x264", | |
318 "Bernhard Rosenkraenzer <bero@arklinux.org>", | |
319 "(C) 2004 LINUX4MEDIA GmbH; (C) 2004 Ark Linux", | |
320 vf_open | |
321 }; | |
322 #endif |