Mercurial > mplayer.hg
comparison libmpcodecs/ve_xvid.c @ 7456:dacc262f41ba
Support for XviD encoding
author | kmkaplan |
---|---|
date | Sat, 21 Sep 2002 12:34:02 +0000 |
parents | |
children | e5dacf3e6a04 |
comparison
equal
deleted
inserted
replaced
7455:3be84a4653ba | 7456:dacc262f41ba |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 | |
5 #include "../config.h" | |
6 #include "../mp_msg.h" | |
7 | |
8 #ifdef HAVE_XVID | |
9 | |
10 #include "codec-cfg.h" | |
11 #include "stream.h" | |
12 #include "demuxer.h" | |
13 #include "stheader.h" | |
14 | |
15 #include "aviwrite.h" | |
16 | |
17 #include "img_format.h" | |
18 #include "mp_image.h" | |
19 #include "vf.h" | |
20 | |
21 #include <xvid.h> | |
22 #include "xvid_vbr.h" | |
23 | |
24 #include "cfgparser.h" | |
25 | |
26 /**********************************************************************/ | |
27 /* Divx4 quality to XviD encoder motion flag presets */ | |
28 static int const divx4_motion_presets[7] = { | |
29 0, | |
30 PMV_EARLYSTOP16, | |
31 PMV_EARLYSTOP16 | PMV_ADVANCEDDIAMOND16, | |
32 PMV_EARLYSTOP16 | PMV_HALFPELREFINE16, | |
33 PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8 | PMV_HALFPELREFINE8, | |
34 PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EARLYSTOP8 | PMV_HALFPELREFINE8, | |
35 PMV_EARLYSTOP16 | PMV_HALFPELREFINE16 | PMV_EXTSEARCH16 | PMV_EARLYSTOP8 | PMV_HALFPELREFINE8 | |
36 }; | |
37 | |
38 /* Divx4 quality to general encoder flag presets */ | |
39 static int const divx4_general_presets[7] = { | |
40 0, | |
41 XVID_H263QUANT, | |
42 XVID_H263QUANT, | |
43 XVID_H263QUANT | XVID_HALFPEL, | |
44 XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL, | |
45 XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL, | |
46 XVID_H263QUANT | XVID_INTER4V | XVID_HALFPEL | |
47 }; | |
48 | |
49 struct { | |
50 int quality; | |
51 int bitrate; | |
52 int rc_reaction_delay_factor; | |
53 int rc_averaging_period; | |
54 int rc_buffer; | |
55 int max_quantizer; | |
56 int min_quantizer; | |
57 int max_key_interval; | |
58 enum { | |
59 XVID_MODE_CBR = 0, XVID_MODE_2PASS_1, XVID_MODE_2PASS_2, XVID_MODE_FIXED_QUANT, | |
60 XVID_MODE_UNSPEC = -1 | |
61 } mode; | |
62 int debug; | |
63 char *stats_file;; | |
64 int keyframe_boost; | |
65 int kfthreshold; | |
66 int kfreduction; | |
67 int min_key_interval; | |
68 int fixed_quant; | |
69 } xvidenc_param = { | |
70 sizeof(divx4_motion_presets) / sizeof(divx4_motion_presets[0]) - 1, /* quality */ | |
71 0, 0, 0, 0, 0, 0, 0, | |
72 XVID_MODE_CBR, | |
73 1, /* debug */ | |
74 NULL, /* stats_file */ | |
75 -1, -1, -1, /* keyframe_boost, kfthreshold, kfreduction */ | |
76 -1, /* min_key_interval */ | |
77 -1, /* fixed_quant */ | |
78 }; | |
79 | |
80 struct config xvidencopts_conf[] = { | |
81 { "quality", &xvidenc_param.quality, CONF_TYPE_INT, CONF_RANGE, 0, | |
82 sizeof(divx4_motion_presets) / sizeof(divx4_motion_presets[0]) - 1, NULL}, | |
83 { "br", &xvidenc_param.bitrate, CONF_TYPE_INT, 0, 0, 0, NULL}, | |
84 { "rc_reaction_delay_factor", &xvidenc_param.rc_reaction_delay_factor, CONF_TYPE_INT, 0, 0, NULL}, | |
85 { "rc_averaging_period", &xvidenc_param.rc_averaging_period, CONF_TYPE_INT, 0, 0, NULL}, | |
86 { "rc_buffer", &xvidenc_param.rc_buffer, CONF_TYPE_INT, 0, 0, NULL}, | |
87 { "max_quantizer", &xvidenc_param.max_quantizer, CONF_TYPE_INT, 0, 0, NULL}, | |
88 { "min_quantizer", &xvidenc_param.max_quantizer, CONF_TYPE_INT, 0, 0, NULL}, | |
89 { "max_key_interval", &xvidenc_param.max_key_interval, CONF_TYPE_INT, 0, 0, NULL}, | |
90 /* cbr, vbrqual, vbrquant, 2pass-1, 2pass-2-int, 2pass-2-ext */ | |
91 { "cbr", &xvidenc_param.mode, CONF_TYPE_FLAG, 0, 0, XVID_MODE_CBR, NULL}, | |
92 { "2pass-1", &xvidenc_param.mode, CONF_TYPE_FLAG, 0, 0, XVID_MODE_2PASS_1, NULL}, | |
93 { "2pass-2", &xvidenc_param.mode, CONF_TYPE_FLAG, 0, 0, XVID_MODE_2PASS_2, NULL}, | |
94 { "fixedquant", &xvidenc_param.mode, CONF_TYPE_FLAG, 0, 0, XVID_MODE_FIXED_QUANT, NULL}, | |
95 { "nodebug", &xvidenc_param.debug, CONF_TYPE_FLAG, 0, 0, 0, NULL}, | |
96 { "debug", &xvidenc_param.debug, CONF_TYPE_FLAG, 0, 0, 1, NULL}, | |
97 { "statsfile", &xvidenc_param.stats_file, CONF_TYPE_STRING, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_1/22 */ | |
98 { "keyframe_boost", &xvidenc_param.keyframe_boost, CONF_TYPE_INT, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_2 */ | |
99 { "kfthreshold", &xvidenc_param.kfthreshold, CONF_TYPE_INT, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_2 */ | |
100 { "kfreduction", &xvidenc_param.kfreduction, CONF_TYPE_INT, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_2 */ | |
101 { "min_key_interval", &xvidenc_param.max_key_interval, CONF_TYPE_INT, 0, 0, 0, NULL}, /* for XVID_MODE_2PASS_2 */ | |
102 { "fixed_quant", &xvidenc_param.fixed_quant, CONF_TYPE_INT, CONF_RANGE, 1, 31, NULL}, /* for XVID_MODE_FIXED_QUANT */ | |
103 { NULL, NULL, 0, 0, 0, 0, NULL} | |
104 }; | |
105 | |
106 struct vf_priv_s { | |
107 aviwrite_stream_t* mux; | |
108 XVID_ENC_FRAME enc_frame; | |
109 void* enc_handle; | |
110 vbr_control_t vbr_state; | |
111 FILE *hintfile; | |
112 }; | |
113 | |
114 static FILE * | |
115 get_hint_file(struct vf_instance_s* vf, unsigned char *mode) | |
116 { | |
117 if (vf->priv->hintfile == NULL) { | |
118 vf->priv->hintfile = fopen("xvid_hint_me.dat", mode); | |
119 if (vf->priv->hintfile == NULL) | |
120 perror("xvid: could not open xvid_hint_me.dat"); | |
121 } | |
122 return vf->priv->hintfile; | |
123 } | |
124 | |
125 static int | |
126 config(struct vf_instance_s* vf, | |
127 int width, int height, int d_width, int d_height, | |
128 unsigned int flags, unsigned int outfmt) | |
129 { | |
130 XVID_ENC_PARAM enc_param; | |
131 | |
132 vf->priv->mux->bih->biWidth = width; | |
133 vf->priv->mux->bih->biHeight = height; | |
134 vf->priv->mux->bih->biSizeImage = vf->priv->mux->bih->biWidth * vf->priv->mux->bih->biHeight * 3; | |
135 | |
136 memset(&enc_param, 0, sizeof(enc_param)); | |
137 enc_param.width = width; | |
138 enc_param.height = height; | |
139 enc_param.fincr = vf->priv->mux->h.dwScale; | |
140 enc_param.fbase = vf->priv->mux->h.dwRate; | |
141 enc_param.rc_bitrate = xvidenc_param.bitrate; | |
142 enc_param.rc_reaction_delay_factor = xvidenc_param.rc_reaction_delay_factor; | |
143 enc_param.rc_averaging_period = xvidenc_param.rc_averaging_period; | |
144 enc_param.rc_buffer = xvidenc_param.rc_buffer; | |
145 enc_param.max_quantizer = xvidenc_param.max_quantizer; | |
146 enc_param.min_quantizer = xvidenc_param.min_quantizer; | |
147 enc_param.max_key_interval = xvidenc_param.max_key_interval; | |
148 switch (xvid_encore(NULL, XVID_ENC_CREATE, &enc_param, NULL)) { | |
149 case XVID_ERR_FAIL: | |
150 fprintf(stderr, "xvid: encoder creation failed\n"); | |
151 return 0; | |
152 case XVID_ERR_MEMORY: | |
153 fprintf(stderr, "xvid: encoder creation failed, out of memory\n"); | |
154 return 0; | |
155 case XVID_ERR_FORMAT: | |
156 fprintf(stderr, "xvid: encoder creation failed, bad format\n"); | |
157 return 0; | |
158 } | |
159 vf->priv->enc_handle = enc_param.handle; | |
160 | |
161 vf->priv->enc_frame.general = divx4_general_presets[xvidenc_param.quality]; | |
162 vf->priv->enc_frame.motion = divx4_motion_presets[xvidenc_param.quality]; | |
163 switch (outfmt) { | |
164 case IMGFMT_YV12: | |
165 vf->priv->enc_frame.colorspace = XVID_CSP_YV12; | |
166 break; | |
167 case IMGFMT_IYUV: case IMGFMT_I420: | |
168 vf->priv->enc_frame.colorspace = XVID_CSP_I420; | |
169 break; | |
170 case IMGFMT_YUY2: | |
171 vf->priv->enc_frame.colorspace = XVID_CSP_YUY2; | |
172 break; | |
173 case IMGFMT_UYVY: | |
174 vf->priv->enc_frame.colorspace = XVID_CSP_UYVY; | |
175 break; | |
176 case IMGFMT_RGB24: case IMGFMT_BGR24: | |
177 vf->priv->enc_frame.colorspace = XVID_CSP_RGB24; | |
178 break; | |
179 default: | |
180 mp_msg(MSGT_MENCODER,MSGL_ERR,"xvid: unsupported picture format (%s)!\n", | |
181 vo_format_name(outfmt)); | |
182 return 0; | |
183 } | |
184 vf->priv->enc_frame.quant_intra_matrix = 0; | |
185 vf->priv->enc_frame.quant_inter_matrix = 0; | |
186 | |
187 vf->priv->vbr_state.debug = xvidenc_param.debug; | |
188 vbrSetDefaults(&vf->priv->vbr_state); | |
189 vf->priv->vbr_state.fps = (double)enc_param.fbase / enc_param.fincr; | |
190 if (xvidenc_param.stats_file) | |
191 vf->priv->vbr_state.filename = xvidenc_param.stats_file; | |
192 if (xvidenc_param.bitrate) | |
193 vf->priv->vbr_state.desired_bitrate = xvidenc_param.bitrate; | |
194 if (xvidenc_param.keyframe_boost) | |
195 vf->priv->vbr_state.keyframe_boost = xvidenc_param.keyframe_boost; | |
196 if (xvidenc_param.kfthreshold) | |
197 vf->priv->vbr_state.kftreshold = xvidenc_param.kfthreshold; | |
198 if (xvidenc_param.kfreduction) | |
199 vf->priv->vbr_state.kfreduction = xvidenc_param.kfreduction; | |
200 if (xvidenc_param.min_key_interval) | |
201 vf->priv->vbr_state.min_key_interval = xvidenc_param.min_key_interval; | |
202 if (xvidenc_param.max_key_interval) | |
203 vf->priv->vbr_state.max_key_interval = xvidenc_param.max_key_interval; | |
204 if (xvidenc_param.fixed_quant) | |
205 vf->priv->vbr_state.fixed_quant = xvidenc_param.fixed_quant; | |
206 switch (xvidenc_param.mode) { | |
207 case XVID_MODE_CBR: | |
208 vf->priv->vbr_state.mode = VBR_MODE_1PASS; | |
209 break; | |
210 case XVID_MODE_FIXED_QUANT: | |
211 vf->priv->vbr_state.mode = VBR_MODE_FIXED_QUANT; | |
212 break; | |
213 case XVID_MODE_2PASS_1: | |
214 vf->priv->vbr_state.mode = VBR_MODE_2PASS_1; | |
215 break; | |
216 case XVID_MODE_2PASS_2: | |
217 vf->priv->vbr_state.mode = VBR_MODE_2PASS_2; | |
218 break; | |
219 default: | |
220 abort(); | |
221 } | |
222 vbrInit(&vf->priv->vbr_state); | |
223 return 1; | |
224 } | |
225 | |
226 static void | |
227 uninit(struct vf_instance_s* vf) | |
228 { | |
229 if (vf->priv->hintfile) | |
230 fclose(vf->priv->hintfile); | |
231 vbrFinish(&vf->priv->vbr_state); | |
232 } | |
233 | |
234 static int | |
235 control(struct vf_instance_s* vf, int request, void* data) | |
236 { | |
237 return CONTROL_UNKNOWN; | |
238 } | |
239 | |
240 static int | |
241 query_format(struct vf_instance_s* vf, unsigned int fmt) | |
242 { | |
243 switch(fmt){ | |
244 case IMGFMT_YV12: case IMGFMT_IYUV: case IMGFMT_I420: | |
245 return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW; | |
246 case IMGFMT_YUY2: case IMGFMT_UYVY: | |
247 return VFCAP_CSP_SUPPORTED; | |
248 case IMGFMT_RGB24: case IMGFMT_BGR24: | |
249 return VFCAP_CSP_SUPPORTED | VFCAP_FLIPPED; | |
250 } | |
251 return 0; | |
252 } | |
253 | |
254 static int | |
255 put_image(struct vf_instance_s* vf, mp_image_t *mpi) | |
256 { | |
257 XVID_ENC_STATS enc_stats; | |
258 | |
259 vf->priv->enc_frame.bitstream = vf->priv->mux->buffer; | |
260 vf->priv->enc_frame.length = -1 /* vf->priv->mux->buffer_size */; | |
261 vf->priv->enc_frame.image = mpi->planes[0]; | |
262 vf->priv->enc_frame.quant = vbrGetQuant(&vf->priv->vbr_state); | |
263 vf->priv->enc_frame.intra = vbrGetIntra(&vf->priv->vbr_state); | |
264 #if 0 | |
265 if (xvidenc_param.mode == XVID_MODE_2PASS_1) { | |
266 vf->priv->enc_frame.hint.hintstream = hintstream; | |
267 vf->priv->enc_frame.hint.rawhints = 0; | |
268 vf->priv->enc_frame.general |= XVID_HINTEDME_GET; | |
269 } | |
270 else if (xvidenc_param.mode == XVID_MODE_2PASS_2) { | |
271 FILE *f = get_hint_file(vf, "r"); | |
272 vf->priv->enc_frame.general &= ~XVID_HINTEDME_SET; | |
273 if (f) { | |
274 int blocksize; | |
275 int read; | |
276 read = fread(&blocksize, sizeof(blocksize), 1, f); | |
277 if (read == 1) { | |
278 read = fread(hintstream, blocksize, 1, f); | |
279 if (read == blocksize) { | |
280 vf->priv->enc_frame.hint.hintstream = hintstream; | |
281 vf->priv->enc_frame.hint.rawhints = 0; | |
282 vf->priv->enc_frame.general |= XVID_HINTEDME_SET; | |
283 } | |
284 else | |
285 perror("xvid: hint file read block failure"); | |
286 } | |
287 else | |
288 perror("xvid: hint file read failure"); | |
289 } | |
290 } | |
291 #endif | |
292 switch (xvid_encore(vf->priv->enc_handle, XVID_ENC_ENCODE, &vf->priv->enc_frame, &enc_stats)) { | |
293 case XVID_ERR_OK: | |
294 break; | |
295 case XVID_ERR_MEMORY: | |
296 mp_msg(MSGT_MENCODER, MSGL_ERR, "xvid: out of memory\n"); | |
297 break; | |
298 case XVID_ERR_FORMAT: | |
299 mp_msg(MSGT_MENCODER, MSGL_ERR, "xvid: bad format\n"); | |
300 break; | |
301 default: | |
302 mp_msg(MSGT_MENCODER, MSGL_ERR, "xvid: failure\n"); | |
303 break; | |
304 } | |
305 mencoder_write_chunk(vf->priv->mux, vf->priv->enc_frame.length, vf->priv->enc_frame.intra ? 0x10 : 0); | |
306 vbrUpdate(&vf->priv->vbr_state, enc_stats.quant, vf->priv->enc_frame.intra, | |
307 enc_stats.hlength, vf->priv->enc_frame.length, enc_stats.kblks, enc_stats.mblks, enc_stats.ublks); | |
308 #if 1 | |
309 if (vf->priv->enc_frame.general & XVID_HINTEDME_GET) { | |
310 FILE *f = get_hint_file(vf, "w"); | |
311 if (f) { | |
312 unsigned int wrote; | |
313 wrote = fwrite(&vf->priv->enc_frame.hint.hintlength, sizeof(vf->priv->enc_frame.hint.hintlength), 1, f); | |
314 if (wrote == 1) { | |
315 wrote = fwrite(&vf->priv->enc_frame.hint.hintstream, vf->priv->enc_frame.hint.hintlength, 1, f); | |
316 if (wrote != 1) | |
317 perror("xvid: hint write block failure"); | |
318 } | |
319 else | |
320 perror("xvid: hint write failure"); | |
321 } | |
322 } | |
323 #endif | |
324 return 1; | |
325 } | |
326 | |
327 //===========================================================================// | |
328 | |
329 static int | |
330 vf_open(vf_instance_t *vf, char* args) | |
331 { | |
332 XVID_INIT_PARAM params = { 0, 0, 0}; | |
333 vf->config = config; | |
334 vf->control = control; | |
335 vf->uninit = uninit; | |
336 vf->query_format = query_format; | |
337 vf->put_image = put_image; | |
338 vf->priv = malloc(sizeof(struct vf_priv_s)); | |
339 memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |
340 vf->priv->mux = (aviwrite_stream_t*)args; | |
341 | |
342 vf->priv->mux->bih = malloc(sizeof(BITMAPINFOHEADER)); | |
343 vf->priv->mux->bih->biSize = sizeof(BITMAPINFOHEADER); | |
344 vf->priv->mux->bih->biWidth = 0; | |
345 vf->priv->mux->bih->biHeight = 0; | |
346 vf->priv->mux->bih->biPlanes = 1; | |
347 vf->priv->mux->bih->biBitCount = 24; | |
348 vf->priv->mux->bih->biCompression = mmioFOURCC('X','V','I','D'); | |
349 | |
350 if (xvid_init(NULL, 0, ¶ms, NULL) != XVID_ERR_OK) { | |
351 fprintf(stderr, "xvid: initialisation failure\n"); | |
352 abort(); | |
353 } | |
354 if (params.api_version != API_VERSION) { | |
355 fprintf(stderr, "xvid: XviD library API version mismatch\n" | |
356 "\texpected %d.%d, got %d.%d, you should recompile MPlayer.\n", | |
357 API_VERSION >> 16, API_VERSION & 0xff, | |
358 params.api_version >> 16, params.api_version & 0xff); | |
359 abort(); | |
360 } | |
361 | |
362 return 1; | |
363 } | |
364 | |
365 vf_info_t ve_info_xvid = { | |
366 "XviD encoder", | |
367 "xvid", | |
368 "Kim Minh Kaplan", | |
369 "for internal use by mencoder", | |
370 vf_open | |
371 }; | |
372 | |
373 //===========================================================================// | |
374 #endif |