Parent Directory | Revision Log
Revision 3 - (view) (download)
1 : | Isibaar | 3 | /************************************************************************** |
2 : | * | ||
3 : | * XVID MPEG-4 VIDEO CODEC - Example for encoding and decoding | ||
4 : | * | ||
5 : | * This program is free software; you can redistribute it and/or modify | ||
6 : | * it under the terms of the GNU General Public License as published by | ||
7 : | * the Free Software Foundation; either version 2 of the License, or | ||
8 : | * (at your option) any later version. | ||
9 : | * | ||
10 : | * This program is distributed in the hope that it will be useful, | ||
11 : | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 : | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 : | * GNU General Public License for more details. | ||
14 : | * | ||
15 : | * You should have received a copy of the GNU General Public License | ||
16 : | * along with this program; if not, write to the Free Software | ||
17 : | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 : | * | ||
19 : | *************************************************************************/ | ||
20 : | |||
21 : | /************************************************************************ | ||
22 : | * | ||
23 : | * Test routine for XviD using the XviD-API | ||
24 : | * (C) Christoph Lampert, 2002/01/19 | ||
25 : | * | ||
26 : | * A sequence of YUV pics in PGM file format is encoded and decoded | ||
27 : | * | ||
28 : | * The program is plain C and needs no libraries except for libxvidcore, | ||
29 : | * so with UN*X you simply compile by | ||
30 : | * | ||
31 : | * gcc -o xvid_enc_dec xvid_enc_dec.c -lxvidcore | ||
32 : | * | ||
33 : | * Run without parameters, then PGM input input is read from stdin. | ||
34 : | * | ||
35 : | * PGM/xvid-output is saved, if corresponding flags are set | ||
36 : | * | ||
37 : | * input data can be generated e.g. out of MPEG2 with mpeg2dec -o pgmpipe | ||
38 : | * | ||
39 : | ************************************************************************/ | ||
40 : | |||
41 : | #include <stdio.h> | ||
42 : | #include <stdint.h> | ||
43 : | #include <malloc.h> | ||
44 : | |||
45 : | #include "xvid.h" /* comes with XviD */ | ||
46 : | |||
47 : | #define ARG_FRAMERATE 25 | ||
48 : | #define ARG_BITRATE 900 | ||
49 : | |||
50 : | int QUALITY =5; | ||
51 : | |||
52 : | int XDIM=0; | ||
53 : | int YDIM=0; // will be set when reading first image | ||
54 : | int filenr = 0; | ||
55 : | |||
56 : | int save_m4v_flag = 0; // save MPEG4-bytestream? | ||
57 : | int save_dec_flag = 0; // save decompressed bytestream? | ||
58 : | char filepath[256] = "./"; // path where to save output | ||
59 : | |||
60 : | void *enchandle = NULL; | ||
61 : | void *dechandle = NULL; | ||
62 : | |||
63 : | /*********************************************************************/ | ||
64 : | /* Routines for file input/output, nothing specific to XviD */ | ||
65 : | /*********************************************************************/ | ||
66 : | |||
67 : | int read_pgmheader(FILE* handle) | ||
68 : | { int bytes,xsize,ysize,depth; | ||
69 : | char dummy[2]; | ||
70 : | |||
71 : | bytes = fread(dummy,1,2,handle); | ||
72 : | |||
73 : | if ( (bytes < 2) || (dummy[0] != 'P') || (dummy[1] != '5' )) | ||
74 : | return 1; | ||
75 : | fscanf(handle,"%d %d %d",&xsize,&ysize,&depth); | ||
76 : | if ( (xsize > 1440) || (ysize > 2880 ) || (depth != 255) ) | ||
77 : | { | ||
78 : | fprintf(stderr,"%d %d %d\n",XDIM,YDIM,depth); | ||
79 : | return 2; | ||
80 : | } | ||
81 : | if ( (XDIM==0) || (YDIM==0) ) | ||
82 : | { XDIM=xsize; | ||
83 : | YDIM=ysize; | ||
84 : | } | ||
85 : | |||
86 : | return 0; | ||
87 : | } | ||
88 : | |||
89 : | int read_pgmdata(FILE* handle, unsigned char *image) | ||
90 : | { int i; | ||
91 : | char dummy; | ||
92 : | |||
93 : | unsigned char* buff1_ptr2 = image + XDIM*YDIM; | ||
94 : | unsigned char* buff1_ptr3 = image + XDIM*YDIM + XDIM/2*YDIM/2; | ||
95 : | |||
96 : | fread(image,XDIM,YDIM,stdin); | ||
97 : | |||
98 : | for (i=0;i<YDIM/2;i++) | ||
99 : | { | ||
100 : | fread(buff1_ptr2,XDIM/2,1,stdin); | ||
101 : | buff1_ptr2 += XDIM/2; | ||
102 : | fread(buff1_ptr3,XDIM/2,1,stdin); | ||
103 : | buff1_ptr3 += XDIM/2; | ||
104 : | } | ||
105 : | fread(&dummy,1,1,handle); // should be EOF | ||
106 : | return 0; | ||
107 : | } | ||
108 : | |||
109 : | |||
110 : | /*********************************************************************/ | ||
111 : | /* Routines for encoding: init encoder, frame step, release encoder */ | ||
112 : | /*********************************************************************/ | ||
113 : | |||
114 : | #define FRAMERATE_INCR 1001 | ||
115 : | int enc_init() | ||
116 : | { | ||
117 : | int xerr; | ||
118 : | |||
119 : | XVID_INIT_PARAM xinit; | ||
120 : | XVID_ENC_PARAM xparam; | ||
121 : | |||
122 : | xinit.cpu_flags = 0; | ||
123 : | xvid_init(NULL, 0, &xinit, NULL); | ||
124 : | |||
125 : | xparam.width = XDIM; | ||
126 : | xparam.height = YDIM; | ||
127 : | if ((ARG_FRAMERATE - (int)ARG_FRAMERATE) == 0) | ||
128 : | { | ||
129 : | xparam.fincr = 1; | ||
130 : | xparam.fbase = (int)ARG_FRAMERATE; | ||
131 : | } | ||
132 : | else | ||
133 : | { | ||
134 : | xparam.fincr = FRAMERATE_INCR; | ||
135 : | xparam.fbase = (int)(FRAMERATE_INCR * ARG_FRAMERATE); | ||
136 : | } | ||
137 : | xparam.bitrate = ARG_BITRATE*1000; | ||
138 : | xparam.rc_period = 2000; | ||
139 : | xparam.rc_reaction_period = 10; | ||
140 : | xparam.rc_reaction_ratio = 20; | ||
141 : | xparam.min_quantizer = 1; | ||
142 : | xparam.max_quantizer = 31; | ||
143 : | xparam.max_key_interval = (int)ARG_FRAMERATE*10; | ||
144 : | xparam.motion_search = QUALITY; | ||
145 : | xparam.lum_masking = 0; // Luminance Masking is still under development | ||
146 : | xparam.quant_type = 0; // 0=h.263, 1=mpeg4 | ||
147 : | |||
148 : | xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xparam, NULL); | ||
149 : | enchandle=xparam.handle; | ||
150 : | |||
151 : | return xerr; | ||
152 : | } | ||
153 : | |||
154 : | int enc_stop() | ||
155 : | { int xerr; | ||
156 : | |||
157 : | xerr = xvid_encore(enchandle, XVID_ENC_DESTROY, NULL, NULL); | ||
158 : | return xerr; | ||
159 : | } | ||
160 : | |||
161 : | int enc_main(unsigned char* image, unsigned char* bitstream, int *streamlength) | ||
162 : | { int xerr; | ||
163 : | |||
164 : | XVID_ENC_FRAME xframe; | ||
165 : | XVID_ENC_STATS xstats; | ||
166 : | |||
167 : | xframe.bitstream = bitstream; | ||
168 : | xframe.length = -1; // this is written by the routine | ||
169 : | |||
170 : | xframe.image = image; | ||
171 : | xframe.colorspace = XVID_CSP_YV12; // defined in <xvid.h> | ||
172 : | |||
173 : | xframe.intra = -1; // let the codec decide between I-frame (1) and P-frame (0) | ||
174 : | xframe.quant = 0; | ||
175 : | // xframe.quant = QUANTI; // is quant != 0, use a fixed quant (and ignore bitrate) | ||
176 : | |||
177 : | |||
178 : | xerr = xvid_encore(enchandle, XVID_ENC_ENCODE, &xframe, &xstats); | ||
179 : | |||
180 : | /* enc_result->is_key_frame = xframe.intra; | ||
181 : | enc_result->quantizer = xframe.quant; | ||
182 : | enc_result->total_bits = xframe.length * 8; | ||
183 : | enc_result->motion_bits = xstats.hlength * 8; | ||
184 : | enc_result->texture_bits = enc_result->total_bits - enc_result->motion_bits; | ||
185 : | */ | ||
186 : | |||
187 : | /* This is statictical data, e.g. for 2-pass. | ||
188 : | If you are not interested in any of this, you can use NULL instead of &xstats | ||
189 : | */ | ||
190 : | |||
191 : | *streamlength = xframe.length; | ||
192 : | |||
193 : | return xerr; | ||
194 : | } | ||
195 : | |||
196 : | |||
197 : | /*********************************************************************/ | ||
198 : | /* Routines for decoding: init encoder, frame step, release encoder */ | ||
199 : | /*********************************************************************/ | ||
200 : | |||
201 : | int dec_init() | ||
202 : | { | ||
203 : | int xerr; | ||
204 : | |||
205 : | XVID_INIT_PARAM xinit; | ||
206 : | XVID_DEC_PARAM xparam; | ||
207 : | |||
208 : | xinit.cpu_flags = 0; | ||
209 : | xvid_init(NULL, 0, &xinit, NULL); | ||
210 : | xparam.width = XDIM; | ||
211 : | xparam.height = YDIM; | ||
212 : | |||
213 : | xerr = xvid_decore(NULL, XVID_DEC_CREATE, &xparam, NULL); | ||
214 : | dechandle = xparam.handle; | ||
215 : | |||
216 : | return xerr; | ||
217 : | } | ||
218 : | |||
219 : | int dec_main(unsigned char *m4v_buffer, unsigned char *rgb_buffer, int m4v_size) | ||
220 : | { | ||
221 : | int xerr; | ||
222 : | |||
223 : | XVID_DEC_FRAME xframe; | ||
224 : | |||
225 : | xframe.bitstream = m4v_buffer; | ||
226 : | xframe.length = m4v_size; | ||
227 : | xframe.image = rgb_buffer; | ||
228 : | xframe.stride = XDIM; | ||
229 : | xframe.colorspace = XVID_CSP_RGB24; // XVID_CSP_USER is fastest (no memcopy involved) | ||
230 : | |||
231 : | /* | ||
232 : | xframe.colorspace = XVID_CSP_NULL; // use this if you want to skip a frame (no output) | ||
233 : | */ | ||
234 : | |||
235 : | xerr = xvid_decore(dechandle, XVID_DEC_DECODE, &xframe, NULL); | ||
236 : | |||
237 : | return xerr; | ||
238 : | } | ||
239 : | |||
240 : | int dec_stop() | ||
241 : | { | ||
242 : | int xerr; | ||
243 : | xerr = xvid_decore(dechandle, XVID_DEC_DESTROY, NULL, NULL); | ||
244 : | |||
245 : | return xerr; | ||
246 : | } | ||
247 : | |||
248 : | |||
249 : | /*********************************************************************/ | ||
250 : | /* Main program */ | ||
251 : | /*********************************************************************/ | ||
252 : | |||
253 : | int main() | ||
254 : | { | ||
255 : | unsigned char *divx_buffer = NULL; | ||
256 : | unsigned char *yuv_buffer = NULL; | ||
257 : | unsigned char *rgb_buffer = NULL; | ||
258 : | |||
259 : | int status; | ||
260 : | int frame_size; | ||
261 : | int m4v_size; | ||
262 : | |||
263 : | char filename[256]; | ||
264 : | |||
265 : | FILE *filehandle; | ||
266 : | |||
267 : | /* read YUV in pgm format from stdin */ | ||
268 : | if (read_pgmheader(stdin)) | ||
269 : | { | ||
270 : | printf("Wrong input format, I want YUV encapsulated in PGM\n"); | ||
271 : | return 0; | ||
272 : | } | ||
273 : | |||
274 : | /* now we know the sizes, so allocate memory */ | ||
275 : | |||
276 : | yuv_buffer = (unsigned char *) malloc(XDIM*YDIM); | ||
277 : | if (!yuv_buffer) | ||
278 : | goto free_all_memory; // goto is one of the most underestimated instructions in C !!! | ||
279 : | |||
280 : | divx_buffer = (unsigned char *) malloc(XDIM*YDIM*2); // this should really be enough! | ||
281 : | if (!divx_buffer) | ||
282 : | goto free_all_memory; // actually, every program should contain at least one goto | ||
283 : | |||
284 : | YDIM = YDIM*2/3; // PGM is YUV 4:2:0 format, so real image height is *2/3 of PGM picture | ||
285 : | |||
286 : | rgb_buffer = (unsigned char *) malloc(XDIM*YDIM*4); | ||
287 : | if (!rgb_buffer) | ||
288 : | goto free_all_memory; // but the more, the better! | ||
289 : | |||
290 : | /*********************************************************************/ | ||
291 : | /* DIVX PART Start */ | ||
292 : | /*********************************************************************/ | ||
293 : | |||
294 : | status = enc_init(); | ||
295 : | // if (status) | ||
296 : | printf("Encore INIT return %d, handle=%lx\n", status, enchandle); | ||
297 : | |||
298 : | status = dec_init(); | ||
299 : | // if (status) | ||
300 : | printf("Decore INIT return %d\n", status); | ||
301 : | |||
302 : | |||
303 : | /*********************************************************************/ | ||
304 : | /* Main loop */ | ||
305 : | /*********************************************************************/ | ||
306 : | |||
307 : | do | ||
308 : | { | ||
309 : | status = read_pgmdata(stdin, yuv_buffer); // read PGM data (YUV-format) | ||
310 : | if (status) | ||
311 : | { | ||
312 : | fprintf(stderr, "Couldn't read PGM body: %d\n", status); /* this should not happen */ | ||
313 : | continue; | ||
314 : | } | ||
315 : | |||
316 : | /*********************************************************************/ | ||
317 : | /* encode and decode this frame */ | ||
318 : | /*********************************************************************/ | ||
319 : | |||
320 : | status = enc_main(yuv_buffer, divx_buffer, &m4v_size); | ||
321 : | |||
322 : | printf("Frame %5d: encore-ENCODE status %d, m4v-stream length=%7d bytes\n", | ||
323 : | filenr, status, m4v_size); | ||
324 : | |||
325 : | if (save_m4v_flag) | ||
326 : | { | ||
327 : | sprintf(filename, "%sframe%05d.m4v", filepath, filenr); | ||
328 : | filehandle = fopen(filename, "wb"); | ||
329 : | fwrite(divx_buffer, m4v_size, 1, filehandle); | ||
330 : | fclose(filehandle); | ||
331 : | } | ||
332 : | |||
333 : | status = dec_main(divx_buffer, rgb_buffer, m4v_size); | ||
334 : | if (status) | ||
335 : | printf("Frame %5d: decore status %d\n",status); | ||
336 : | |||
337 : | if (save_dec_flag) | ||
338 : | { | ||
339 : | sprintf(filename, "%sdec%05d.ppm", filepath, filenr); | ||
340 : | filehandle=fopen(filename,"wb"); | ||
341 : | if (filehandle) | ||
342 : | { | ||
343 : | fprintf(filehandle,"P6\n"); // rgb24 in PPM format | ||
344 : | fprintf(filehandle,"%d %d 255\n",XDIM,YDIM); | ||
345 : | fwrite(rgb_buffer,XDIM,YDIM*3,filehandle); | ||
346 : | fclose(filehandle); | ||
347 : | } | ||
348 : | } | ||
349 : | |||
350 : | filenr++; | ||
351 : | status = read_pgmheader(stdin); // if it was the last PGM, stop after it | ||
352 : | if (status) | ||
353 : | { | ||
354 : | fprintf(stderr, "Couldn't read next PGM header: %d\n", status); /* normally, just end of file */ | ||
355 : | } | ||
356 : | } | ||
357 : | while (!status); | ||
358 : | |||
359 : | /*********************************************************************/ | ||
360 : | /* DIVX PART Stop */ | ||
361 : | /*********************************************************************/ | ||
362 : | |||
363 : | dec_stop(); | ||
364 : | // if (status) | ||
365 : | printf("Encore RELEASE return %d\n", status); | ||
366 : | |||
367 : | enc_stop(); | ||
368 : | // if (status) | ||
369 : | printf("Decore RELEASE return %d\n", status); | ||
370 : | |||
371 : | free_all_memory: | ||
372 : | |||
373 : | if (rgb_buffer) | ||
374 : | free(rgb_buffer); | ||
375 : | if (divx_buffer) | ||
376 : | free(divx_buffer); | ||
377 : | if (yuv_buffer) | ||
378 : | free(yuv_buffer); | ||
379 : | |||
380 : | return 0; | ||
381 : | } |
No admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.4 |