Parent Directory
|
Revision Log
Revision 860 - (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 OpenDivX/Divx4-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 odivx_enc_dec odivx_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 <malloc.h> | ||
43 : | |||
44 : | suxen_drol | 860 | #include "divx4.h" |
45 : | Isibaar | 3 | |
46 : | #define ARG_FRAMERATE 25 | ||
47 : | #define ARG_BITRATE 900 | ||
48 : | |||
49 : | int QUALITY =5; | ||
50 : | edgomez | 851 | int QUANTI = 0; // used for fixed-quantizer encoding |
51 : | Isibaar | 3 | |
52 : | int XDIM=0; | ||
53 : | edgomez | 851 | int YDIM=0; // will be set when reading first image |
54 : | Isibaar | 3 | int filenr = 0; |
55 : | |||
56 : | edgomez | 851 | 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 | ||
59 : | Isibaar | 3 | |
60 : | edgomez | 851 | void *enchandle = NULL; // enchandle is a void*, written by encore |
61 : | const long dechandle = 0x0815; // dechandle is a unique constant!!! | ||
62 : | Isibaar | 3 | |
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 : | edgomez | 851 | fread(&dummy,1,1,handle); // should be EOF |
106 : | Isibaar | 3 | 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 status; | ||
118 : | ENC_PARAM enc_param; | ||
119 : | |||
120 : | enc_param.x_dim = XDIM; | ||
121 : | enc_param.y_dim = YDIM; | ||
122 : | edgomez | 851 | enc_param.framerate = ARG_FRAMERATE; // a float |
123 : | Isibaar | 3 | enc_param.bitrate = ARG_BITRATE*1000; |
124 : | |||
125 : | enc_param.rc_period = 2000; | ||
126 : | enc_param.rc_reaction_period = 10; | ||
127 : | enc_param.rc_reaction_ratio = 20; | ||
128 : | |||
129 : | enc_param.max_quantizer = 31; | ||
130 : | enc_param.min_quantizer = 1; | ||
131 : | |||
132 : | enc_param.quality = QUALITY; | ||
133 : | |||
134 : | edgomez | 851 | enc_param.use_bidirect = 0; // use bidirectional coding |
135 : | enc_param.deinterlace = 0; // fast deinterlace | ||
136 : | enc_param.obmc = 0; // flag to enable overlapped block motion compensation mode | ||
137 : | Isibaar | 3 | |
138 : | enc_param.max_key_interval = (int)ARG_FRAMERATE*10; | ||
139 : | edgomez | 851 | enc_param.handle = NULL; //will be filled by encore |
140 : | Isibaar | 3 | |
141 : | status = encore(enchandle, ENC_OPT_INIT, &enc_param, NULL); | ||
142 : | enchandle = enc_param.handle; | ||
143 : | |||
144 : | edgomez | 851 | // if (status) |
145 : | Isibaar | 3 | printf("Encore INIT return %d, handle=%lx\n", status, enchandle); |
146 : | |||
147 : | return status; | ||
148 : | } | ||
149 : | |||
150 : | int enc_stop() | ||
151 : | { int status; | ||
152 : | |||
153 : | status = encore(enchandle, ENC_OPT_RELEASE, NULL, NULL); | ||
154 : | edgomez | 851 | // if (status) |
155 : | Isibaar | 3 | printf("Encore RELEASE return %d\n", status); |
156 : | |||
157 : | return status; | ||
158 : | } | ||
159 : | |||
160 : | int enc_main(unsigned char* image, unsigned char* bitstream, int *streamlength) | ||
161 : | { int status; | ||
162 : | |||
163 : | ENC_FRAME enc_frame; | ||
164 : | ENC_RESULT enc_result; | ||
165 : | |||
166 : | enc_frame.image = (void *) image; | ||
167 : | enc_frame.bitstream = (void *) bitstream; | ||
168 : | edgomez | 851 | enc_frame.length = 0; // filled by encore |
169 : | enc_frame.colorspace = ENC_CSP_YV12; // input is YUV | ||
170 : | enc_frame.mvs = NULL; // unsupported | ||
171 : | Isibaar | 3 | |
172 : | if (QUANTI==0) | ||
173 : | { | ||
174 : | status = encore(enchandle, ENC_OPT_ENCODE, &enc_frame, &enc_result); | ||
175 : | } | ||
176 : | else | ||
177 : | { enc_frame.quant = QUANTI; | ||
178 : | edgomez | 851 | enc_frame.intra = -1; // let encoder decide if frame is INTER/INTRA |
179 : | Isibaar | 3 | status = encore(enchandle, ENC_OPT_ENCODE_VBR, &enc_frame, &enc_result); |
180 : | } | ||
181 : | |||
182 : | /* ENC_OPT_ENCODE is used to encode using ratecontrol alg. and bitrate from enc_init, | ||
183 : | ENC_OPT_ENCODE_VBR is used to encode with fixed quantizer and INTER/INTRA mode | ||
184 : | */ | ||
185 : | |||
186 : | *streamlength = enc_frame.length; | ||
187 : | |||
188 : | return status; | ||
189 : | } | ||
190 : | |||
191 : | |||
192 : | /*********************************************************************/ | ||
193 : | /* Routines for decoding: init encoder, frame step, release encoder */ | ||
194 : | /*********************************************************************/ | ||
195 : | |||
196 : | int dec_init() | ||
197 : | { | ||
198 : | int status; | ||
199 : | |||
200 : | DEC_PARAM dec_param; | ||
201 : | edgomez | 851 | DEC_SET dec_set; |
202 : | Isibaar | 3 | |
203 : | dec_param.x_dim = XDIM; | ||
204 : | dec_param.y_dim = YDIM; | ||
205 : | edgomez | 851 | dec_param.output_format = DEC_RGB24; // output color format, , see <decore.h> |
206 : | Isibaar | 3 | |
207 : | dec_param.time_incr = 20; | ||
208 : | |||
209 : | status = decore(dechandle, DEC_OPT_INIT, &dec_param, NULL); | ||
210 : | edgomez | 851 | // if (status) |
211 : | Isibaar | 3 | printf("Decore INIT return %d\n", status); |
212 : | |||
213 : | edgomez | 851 | // We don't do any postprocessing here... |
214 : | Isibaar | 3 | |
215 : | /* dec_set.postproc_level = 0; | ||
216 : | status = decore(dechandle, DEC_OPT_SETPP, &dec_set, NULL); | ||
217 : | if (status) | ||
218 : | printf("Decore POSTPROC %d return %d\n", dec_set.postproc_level, status); | ||
219 : | */ | ||
220 : | |||
221 : | return status; | ||
222 : | } | ||
223 : | |||
224 : | int dec_main(unsigned char *m4v_buffer, unsigned char *rgb_buffer, int m4v_size) | ||
225 : | { | ||
226 : | int status; | ||
227 : | |||
228 : | static DEC_FRAME dec_frame; | ||
229 : | static DEC_FRAME_INFO dec_frame_info; | ||
230 : | |||
231 : | dec_frame.length = m4v_size; | ||
232 : | dec_frame.bitstream = m4v_buffer; | ||
233 : | dec_frame.bmp = rgb_buffer; | ||
234 : | edgomez | 851 | dec_frame.render_flag = 1; // 0 means: skip this frame |
235 : | Isibaar | 3 | dec_frame.stride = XDIM; |
236 : | |||
237 : | status = decore(dechandle, DEC_OPT_FRAME, &dec_frame, &dec_frame_info); | ||
238 : | if (status) | ||
239 : | printf("Decore Frame status %d!\n", status); | ||
240 : | |||
241 : | return status; | ||
242 : | } | ||
243 : | |||
244 : | int dec_stop() | ||
245 : | { | ||
246 : | int status; | ||
247 : | status = decore(dechandle, DEC_OPT_RELEASE, NULL, NULL); | ||
248 : | edgomez | 851 | // if (status) |
249 : | Isibaar | 3 | printf("Decore RELEASE return %d\n", status); |
250 : | return status; | ||
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 : | edgomez | 851 | int frame_size; |
266 : | Isibaar | 3 | 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 : | yuv_buffer = (unsigned char *) malloc(XDIM*YDIM); | ||
281 : | if (!yuv_buffer) | ||
282 : | edgomez | 851 | goto free_all_memory; // goto is one of the most underestimated instructions in C !!! |
283 : | divx_buffer = (unsigned char *) malloc(XDIM*YDIM*2); // this should really be enough! | ||
284 : | Isibaar | 3 | if (!divx_buffer) |
285 : | edgomez | 851 | goto free_all_memory; // actually, every program should contain a goto |
286 : | Isibaar | 3 | |
287 : | edgomez | 851 | YDIM = YDIM*2/3; // PGM is YUV 4:2:0 format, so height is *3/2 too much |
288 : | Isibaar | 3 | |
289 : | rgb_buffer = (unsigned char *) malloc(XDIM*YDIM*4); | ||
290 : | if (!rgb_buffer) | ||
291 : | edgomez | 851 | goto free_all_memory; // the more, the better! |
292 : | Isibaar | 3 | |
293 : | /*********************************************************************/ | ||
294 : | /* DIVX PART Start */ | ||
295 : | /*********************************************************************/ | ||
296 : | |||
297 : | status = enc_init(); | ||
298 : | edgomez | 851 | // if (status) |
299 : | Isibaar | 3 | printf("Encore INIT return %d, handle=%lx\n", status, enchandle); |
300 : | |||
301 : | status = dec_init(); | ||
302 : | edgomez | 851 | // if (status) |
303 : | Isibaar | 3 | printf("Decore INIT return %d\n", status); |
304 : | |||
305 : | |||
306 : | /*********************************************************************/ | ||
307 : | /* Main loop */ | ||
308 : | /*********************************************************************/ | ||
309 : | |||
310 : | do | ||
311 : | { | ||
312 : | edgomez | 851 | status = read_pgmdata(stdin, yuv_buffer); // read PGM data (YUV-format) |
313 : | Isibaar | 3 | if (status) |
314 : | { | ||
315 : | fprintf(stderr, "PGM-Data-Error: %d\n", status); /* this should not happen */ | ||
316 : | continue; | ||
317 : | } | ||
318 : | |||
319 : | /*********************************************************************/ | ||
320 : | /* encode and decode this frame */ | ||
321 : | /*********************************************************************/ | ||
322 : | |||
323 : | status = enc_main(yuv_buffer, divx_buffer, &m4v_size); | ||
324 : | |||
325 : | printf("Frame %5d: encore-ENCODE status %d, m4v-stream length=%7d bytes\n", | ||
326 : | filenr, status, m4v_size); | ||
327 : | |||
328 : | if (save_m4v_flag) | ||
329 : | { | ||
330 : | sprintf(filename, "%s/frame%05d.m4v", filepath, filenr); | ||
331 : | filehandle = fopen(filename, "wb"); | ||
332 : | fwrite(divx_buffer, m4v_size, 1, filehandle); | ||
333 : | fclose(filehandle); | ||
334 : | } | ||
335 : | |||
336 : | status = dec_main(divx_buffer, rgb_buffer, m4v_size); | ||
337 : | if (status) | ||
338 : | printf("Frame %5d: decore status %d\n",status); | ||
339 : | |||
340 : | if (save_dec_flag) | ||
341 : | { | ||
342 : | sprintf(filename, "%s/dec%05d.ppm", filepath, filenr); | ||
343 : | filehandle=fopen(filename,"wb"); | ||
344 : | if (filehandle) | ||
345 : | { | ||
346 : | edgomez | 851 | fprintf(filehandle,"P6\n"); // rgb24 in PPM format |
347 : | Isibaar | 3 | fprintf(filehandle,"%d %d 255\n",XDIM,YDIM); |
348 : | fwrite(rgb_buffer,XDIM,YDIM*3,filehandle); | ||
349 : | fclose(filehandle); | ||
350 : | } | ||
351 : | } | ||
352 : | |||
353 : | filenr++; | ||
354 : | edgomez | 851 | status = read_pgmheader(stdin); // if it was the last PGM, stop after it |
355 : | Isibaar | 3 | if (status) |
356 : | { | ||
357 : | fprintf(stderr, "PGM-Header-Error: %d\n", status); /* normally, just end of file */ | ||
358 : | } | ||
359 : | } | ||
360 : | while (!status); | ||
361 : | |||
362 : | |||
363 : | /*********************************************************************/ | ||
364 : | /* DIVX PART Stop */ | ||
365 : | /*********************************************************************/ | ||
366 : | |||
367 : | |||
368 : | /* Stop XviD */ | ||
369 : | |||
370 : | dec_stop(); | ||
371 : | edgomez | 851 | // if (status) |
372 : | Isibaar | 3 | printf("Encore RELEASE return %d\n", status); |
373 : | |||
374 : | enc_stop(); | ||
375 : | edgomez | 851 | // if (status) |
376 : | Isibaar | 3 | printf("Decore RELEASE return %d\n", status); |
377 : | |||
378 : | free_all_memory: | ||
379 : | |||
380 : | if (rgb_buffer) | ||
381 : | free(rgb_buffer); | ||
382 : | if (divx_buffer) | ||
383 : | free(divx_buffer); | ||
384 : | if (yuv_buffer) | ||
385 : | free(yuv_buffer); | ||
386 : | |||
387 : | return 0; | ||
388 : | } |
No admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.4 |