Parent Directory | Revision Log
Revision 50 -
(view)
(download)
Original Path: trunk/xvidcore/examples/xvid_enc_dec.c
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 XDIM=0; | ||
51 : | int YDIM=0; // will be set when reading first image | ||
52 : | int filenr = 0; | ||
53 : | |||
54 : | int save_m4v_flag = 0; // save MPEG4-bytestream? | ||
55 : | int save_dec_flag = 0; // save decompressed bytestream? | ||
56 : | char filepath[256] = "./"; // path where to save output | ||
57 : | |||
58 : | void *enchandle = NULL; | ||
59 : | void *dechandle = NULL; | ||
60 : | |||
61 : | /*********************************************************************/ | ||
62 : | /* Routines for file input/output, nothing specific to XviD */ | ||
63 : | /*********************************************************************/ | ||
64 : | |||
65 : | int read_pgmheader(FILE* handle) | ||
66 : | { int bytes,xsize,ysize,depth; | ||
67 : | char dummy[2]; | ||
68 : | |||
69 : | bytes = fread(dummy,1,2,handle); | ||
70 : | |||
71 : | if ( (bytes < 2) || (dummy[0] != 'P') || (dummy[1] != '5' )) | ||
72 : | return 1; | ||
73 : | fscanf(handle,"%d %d %d",&xsize,&ysize,&depth); | ||
74 : | if ( (xsize > 1440) || (ysize > 2880 ) || (depth != 255) ) | ||
75 : | { | ||
76 : | fprintf(stderr,"%d %d %d\n",XDIM,YDIM,depth); | ||
77 : | return 2; | ||
78 : | } | ||
79 : | if ( (XDIM==0) || (YDIM==0) ) | ||
80 : | { XDIM=xsize; | ||
81 : | YDIM=ysize; | ||
82 : | } | ||
83 : | |||
84 : | return 0; | ||
85 : | } | ||
86 : | |||
87 : | int read_pgmdata(FILE* handle, unsigned char *image) | ||
88 : | { int i; | ||
89 : | char dummy; | ||
90 : | |||
91 : | unsigned char* buff1_ptr2 = image + XDIM*YDIM; | ||
92 : | unsigned char* buff1_ptr3 = image + XDIM*YDIM + XDIM/2*YDIM/2; | ||
93 : | |||
94 : | fread(image,XDIM,YDIM,stdin); | ||
95 : | |||
96 : | for (i=0;i<YDIM/2;i++) | ||
97 : | { | ||
98 : | fread(buff1_ptr2,XDIM/2,1,stdin); | ||
99 : | buff1_ptr2 += XDIM/2; | ||
100 : | fread(buff1_ptr3,XDIM/2,1,stdin); | ||
101 : | buff1_ptr3 += XDIM/2; | ||
102 : | } | ||
103 : | fread(&dummy,1,1,handle); // should be EOF | ||
104 : | return 0; | ||
105 : | } | ||
106 : | |||
107 : | |||
108 : | /*********************************************************************/ | ||
109 : | /* Routines for encoding: init encoder, frame step, release encoder */ | ||
110 : | /*********************************************************************/ | ||
111 : | |||
112 : | #define FRAMERATE_INCR 1001 | ||
113 : | int enc_init() | ||
114 : | { | ||
115 : | int xerr; | ||
116 : | |||
117 : | XVID_INIT_PARAM xinit; | ||
118 : | XVID_ENC_PARAM xparam; | ||
119 : | |||
120 : | xinit.cpu_flags = 0; | ||
121 : | xvid_init(NULL, 0, &xinit, NULL); | ||
122 : | |||
123 : | xparam.width = XDIM; | ||
124 : | xparam.height = YDIM; | ||
125 : | if ((ARG_FRAMERATE - (int)ARG_FRAMERATE) == 0) | ||
126 : | { | ||
127 : | xparam.fincr = 1; | ||
128 : | xparam.fbase = (int)ARG_FRAMERATE; | ||
129 : | } | ||
130 : | else | ||
131 : | { | ||
132 : | xparam.fincr = FRAMERATE_INCR; | ||
133 : | xparam.fbase = (int)(FRAMERATE_INCR * ARG_FRAMERATE); | ||
134 : | } | ||
135 : | xparam.bitrate = ARG_BITRATE*1000; | ||
136 : | Isibaar | 50 | xparam.rc_buffersize = 2048000; // amount of data you have to buffer for continous |
137 : | // playback in a streaming app (in bytes) | ||
138 : | xparam.min_quantizer = 2; | ||
139 : | Isibaar | 3 | xparam.max_quantizer = 31; |
140 : | xparam.max_key_interval = (int)ARG_FRAMERATE*10; | ||
141 : | |||
142 : | xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xparam, NULL); | ||
143 : | enchandle=xparam.handle; | ||
144 : | |||
145 : | return xerr; | ||
146 : | } | ||
147 : | |||
148 : | int enc_stop() | ||
149 : | { int xerr; | ||
150 : | |||
151 : | xerr = xvid_encore(enchandle, XVID_ENC_DESTROY, NULL, NULL); | ||
152 : | return xerr; | ||
153 : | } | ||
154 : | |||
155 : | int enc_main(unsigned char* image, unsigned char* bitstream, int *streamlength) | ||
156 : | { int xerr; | ||
157 : | |||
158 : | XVID_ENC_FRAME xframe; | ||
159 : | XVID_ENC_STATS xstats; | ||
160 : | |||
161 : | Isibaar | 50 | // general features |
162 : | xframe.general = XVID_H263QUANT; // we use h.263 quantisation | ||
163 : | // xframe.general = XVID_MPEGQUANT; // MPEG quantization | ||
164 : | |||
165 : | xframe.general |= XVID_HALFPEL; // halfpel precision | ||
166 : | xframe.general |= XVID_INTER4V; // four motion vector mode | ||
167 : | |||
168 : | // motion estimation (pmvfast) settings | ||
169 : | xframe.motion = PMV_HALFPELREFINE16 | PMV_EARLYSTOP16 | | ||
170 : | PMV_HALFPELDIAMOND8 | PMV_EARLYSTOP8; | ||
171 : | |||
172 : | Isibaar | 3 | xframe.bitstream = bitstream; |
173 : | xframe.length = -1; // this is written by the routine | ||
174 : | |||
175 : | xframe.image = image; | ||
176 : | Isibaar | 50 | xframe.colorspace = XVID_CSP_YV12; // defined in <xvid.h> |
177 : | Isibaar | 3 | |
178 : | Isibaar | 50 | xframe.intra = -1; // let the codec decide between I-frame (1) and P-frame (0) |
179 : | Isibaar | 3 | xframe.quant = 0; |
180 : | // xframe.quant = QUANTI; // is quant != 0, use a fixed quant (and ignore bitrate) | ||
181 : | |||
182 : | |||
183 : | xerr = xvid_encore(enchandle, XVID_ENC_ENCODE, &xframe, &xstats); | ||
184 : | |||
185 : | /* enc_result->is_key_frame = xframe.intra; | ||
186 : | enc_result->quantizer = xframe.quant; | ||
187 : | enc_result->total_bits = xframe.length * 8; | ||
188 : | enc_result->motion_bits = xstats.hlength * 8; | ||
189 : | enc_result->texture_bits = enc_result->total_bits - enc_result->motion_bits; | ||
190 : | */ | ||
191 : | |||
192 : | /* This is statictical data, e.g. for 2-pass. | ||
193 : | If you are not interested in any of this, you can use NULL instead of &xstats | ||
194 : | */ | ||
195 : | |||
196 : | *streamlength = xframe.length; | ||
197 : | |||
198 : | return xerr; | ||
199 : | } | ||
200 : | |||
201 : | |||
202 : | /*********************************************************************/ | ||
203 : | /* Routines for decoding: init encoder, frame step, release encoder */ | ||
204 : | /*********************************************************************/ | ||
205 : | |||
206 : | int dec_init() | ||
207 : | { | ||
208 : | int xerr; | ||
209 : | |||
210 : | XVID_INIT_PARAM xinit; | ||
211 : | XVID_DEC_PARAM xparam; | ||
212 : | |||
213 : | xinit.cpu_flags = 0; | ||
214 : | xvid_init(NULL, 0, &xinit, NULL); | ||
215 : | xparam.width = XDIM; | ||
216 : | xparam.height = YDIM; | ||
217 : | |||
218 : | xerr = xvid_decore(NULL, XVID_DEC_CREATE, &xparam, NULL); | ||
219 : | dechandle = xparam.handle; | ||
220 : | |||
221 : | return xerr; | ||
222 : | } | ||
223 : | |||
224 : | int dec_main(unsigned char *m4v_buffer, unsigned char *rgb_buffer, int m4v_size) | ||
225 : | { | ||
226 : | int xerr; | ||
227 : | |||
228 : | XVID_DEC_FRAME xframe; | ||
229 : | |||
230 : | xframe.bitstream = m4v_buffer; | ||
231 : | xframe.length = m4v_size; | ||
232 : | xframe.image = rgb_buffer; | ||
233 : | xframe.stride = XDIM; | ||
234 : | xframe.colorspace = XVID_CSP_RGB24; // XVID_CSP_USER is fastest (no memcopy involved) | ||
235 : | |||
236 : | /* | ||
237 : | xframe.colorspace = XVID_CSP_NULL; // use this if you want to skip a frame (no output) | ||
238 : | */ | ||
239 : | |||
240 : | xerr = xvid_decore(dechandle, XVID_DEC_DECODE, &xframe, NULL); | ||
241 : | |||
242 : | return xerr; | ||
243 : | } | ||
244 : | |||
245 : | int dec_stop() | ||
246 : | { | ||
247 : | int xerr; | ||
248 : | xerr = xvid_decore(dechandle, XVID_DEC_DESTROY, NULL, NULL); | ||
249 : | |||
250 : | return xerr; | ||
251 : | } | ||
252 : | |||
253 : | |||
254 : | /*********************************************************************/ | ||
255 : | /* Main program */ | ||
256 : | /*********************************************************************/ | ||
257 : | |||
258 : | int main() | ||
259 : | { | ||
260 : | unsigned char *divx_buffer = NULL; | ||
261 : | unsigned char *yuv_buffer = NULL; | ||
262 : | unsigned char *rgb_buffer = NULL; | ||
263 : | |||
264 : | int status; | ||
265 : | int frame_size; | ||
266 : | int m4v_size; | ||
267 : | |||
268 : | char filename[256]; | ||
269 : | |||
270 : | FILE *filehandle; | ||
271 : | |||
272 : | /* read YUV in pgm format from stdin */ | ||
273 : | if (read_pgmheader(stdin)) | ||
274 : | { | ||
275 : | printf("Wrong input format, I want YUV encapsulated in PGM\n"); | ||
276 : | return 0; | ||
277 : | } | ||
278 : | |||
279 : | /* now we know the sizes, so allocate memory */ | ||
280 : | |||
281 : | yuv_buffer = (unsigned char *) malloc(XDIM*YDIM); | ||
282 : | if (!yuv_buffer) | ||
283 : | goto free_all_memory; // goto is one of the most underestimated instructions in C !!! | ||
284 : | |||
285 : | divx_buffer = (unsigned char *) malloc(XDIM*YDIM*2); // this should really be enough! | ||
286 : | if (!divx_buffer) | ||
287 : | goto free_all_memory; // actually, every program should contain at least one goto | ||
288 : | |||
289 : | YDIM = YDIM*2/3; // PGM is YUV 4:2:0 format, so real image height is *2/3 of PGM picture | ||
290 : | |||
291 : | rgb_buffer = (unsigned char *) malloc(XDIM*YDIM*4); | ||
292 : | if (!rgb_buffer) | ||
293 : | goto free_all_memory; // but the more, the better! | ||
294 : | |||
295 : | /*********************************************************************/ | ||
296 : | /* DIVX PART Start */ | ||
297 : | /*********************************************************************/ | ||
298 : | |||
299 : | status = enc_init(); | ||
300 : | // if (status) | ||
301 : | printf("Encore INIT return %d, handle=%lx\n", status, enchandle); | ||
302 : | |||
303 : | status = dec_init(); | ||
304 : | // if (status) | ||
305 : | printf("Decore INIT return %d\n", status); | ||
306 : | |||
307 : | |||
308 : | /*********************************************************************/ | ||
309 : | /* Main loop */ | ||
310 : | /*********************************************************************/ | ||
311 : | |||
312 : | do | ||
313 : | { | ||
314 : | status = read_pgmdata(stdin, yuv_buffer); // read PGM data (YUV-format) | ||
315 : | if (status) | ||
316 : | { | ||
317 : | fprintf(stderr, "Couldn't read PGM body: %d\n", status); /* this should not happen */ | ||
318 : | continue; | ||
319 : | } | ||
320 : | |||
321 : | /*********************************************************************/ | ||
322 : | /* encode and decode this frame */ | ||
323 : | /*********************************************************************/ | ||
324 : | |||
325 : | status = enc_main(yuv_buffer, divx_buffer, &m4v_size); | ||
326 : | |||
327 : | printf("Frame %5d: encore-ENCODE status %d, m4v-stream length=%7d bytes\n", | ||
328 : | filenr, status, m4v_size); | ||
329 : | |||
330 : | if (save_m4v_flag) | ||
331 : | { | ||
332 : | sprintf(filename, "%sframe%05d.m4v", filepath, filenr); | ||
333 : | filehandle = fopen(filename, "wb"); | ||
334 : | fwrite(divx_buffer, m4v_size, 1, filehandle); | ||
335 : | fclose(filehandle); | ||
336 : | } | ||
337 : | |||
338 : | status = dec_main(divx_buffer, rgb_buffer, m4v_size); | ||
339 : | if (status) | ||
340 : | printf("Frame %5d: decore status %d\n",status); | ||
341 : | |||
342 : | if (save_dec_flag) | ||
343 : | { | ||
344 : | sprintf(filename, "%sdec%05d.ppm", filepath, filenr); | ||
345 : | filehandle=fopen(filename,"wb"); | ||
346 : | if (filehandle) | ||
347 : | { | ||
348 : | fprintf(filehandle,"P6\n"); // rgb24 in PPM format | ||
349 : | fprintf(filehandle,"%d %d 255\n",XDIM,YDIM); | ||
350 : | fwrite(rgb_buffer,XDIM,YDIM*3,filehandle); | ||
351 : | fclose(filehandle); | ||
352 : | } | ||
353 : | } | ||
354 : | |||
355 : | filenr++; | ||
356 : | status = read_pgmheader(stdin); // if it was the last PGM, stop after it | ||
357 : | if (status) | ||
358 : | { | ||
359 : | fprintf(stderr, "Couldn't read next PGM header: %d\n", status); /* normally, just end of file */ | ||
360 : | } | ||
361 : | } | ||
362 : | while (!status); | ||
363 : | |||
364 : | /*********************************************************************/ | ||
365 : | /* DIVX PART Stop */ | ||
366 : | /*********************************************************************/ | ||
367 : | |||
368 : | dec_stop(); | ||
369 : | // if (status) | ||
370 : | printf("Encore RELEASE return %d\n", status); | ||
371 : | |||
372 : | enc_stop(); | ||
373 : | // if (status) | ||
374 : | printf("Decore RELEASE return %d\n", status); | ||
375 : | |||
376 : | free_all_memory: | ||
377 : | |||
378 : | if (rgb_buffer) | ||
379 : | free(rgb_buffer); | ||
380 : | if (divx_buffer) | ||
381 : | free(divx_buffer); | ||
382 : | if (yuv_buffer) | ||
383 : | free(yuv_buffer); | ||
384 : | |||
385 : | return 0; | ||
386 : | } |
No admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.4 |