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 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 : | #include "encore2.h" | ||
45 : | #include "decore.h" /* these come with XviD */ | ||
46 : | |||
47 : | #define ARG_FRAMERATE 25 | ||
48 : | #define ARG_BITRATE 900 | ||
49 : | |||
50 : | int QUALITY =5; | ||
51 : | int QUANTI = 0; // used for fixed-quantizer encoding | ||
52 : | |||
53 : | int XDIM=0; | ||
54 : | int YDIM=0; // will be set when reading first image | ||
55 : | int filenr = 0; | ||
56 : | |||
57 : | int save_m4v_flag = 0; // save MPEG4-bytestream? | ||
58 : | int save_dec_flag = 0; // save decompressed bytestream? | ||
59 : | char filepath[256] = "."; // path where to save | ||
60 : | |||
61 : | void *enchandle = NULL; // enchandle is a void*, written by encore | ||
62 : | const long dechandle = 0x0815; // dechandle is a unique constant!!! | ||
63 : | |||
64 : | /*********************************************************************/ | ||
65 : | /* Routines for file input/output, nothing specific to XviD */ | ||
66 : | /*********************************************************************/ | ||
67 : | |||
68 : | int read_pgmheader(FILE* handle) | ||
69 : | { int bytes,xsize,ysize,depth; | ||
70 : | char dummy[2]; | ||
71 : | |||
72 : | bytes = fread(dummy,1,2,handle); | ||
73 : | |||
74 : | if ( (bytes < 2) || (dummy[0] != 'P') || (dummy[1] != '5' )) | ||
75 : | return 1; | ||
76 : | fscanf(handle,"%d %d %d",&xsize,&ysize,&depth); | ||
77 : | if ( (xsize > 1440) || (ysize > 2880 ) || (depth != 255) ) | ||
78 : | { | ||
79 : | fprintf(stderr,"%d %d %d\n",XDIM,YDIM,depth); | ||
80 : | return 2; | ||
81 : | } | ||
82 : | if ( (XDIM==0) || (YDIM==0) ) | ||
83 : | { XDIM=xsize; | ||
84 : | YDIM=ysize; | ||
85 : | } | ||
86 : | |||
87 : | return 0; | ||
88 : | } | ||
89 : | |||
90 : | int read_pgmdata(FILE* handle, unsigned char *image) | ||
91 : | { int i; | ||
92 : | char dummy; | ||
93 : | |||
94 : | unsigned char* buff1_ptr2 = image + XDIM*YDIM; | ||
95 : | unsigned char* buff1_ptr3 = image + XDIM*YDIM + XDIM/2*YDIM/2; | ||
96 : | |||
97 : | fread(image,XDIM,YDIM,stdin); | ||
98 : | |||
99 : | for (i=0;i<YDIM/2;i++) | ||
100 : | { | ||
101 : | fread(buff1_ptr2,XDIM/2,1,stdin); | ||
102 : | buff1_ptr2 += XDIM/2; | ||
103 : | fread(buff1_ptr3,XDIM/2,1,stdin); | ||
104 : | buff1_ptr3 += XDIM/2; | ||
105 : | } | ||
106 : | fread(&dummy,1,1,handle); // should be EOF | ||
107 : | return 0; | ||
108 : | } | ||
109 : | |||
110 : | |||
111 : | /*********************************************************************/ | ||
112 : | /* Routines for encoding: init encoder, frame step, release encoder */ | ||
113 : | /*********************************************************************/ | ||
114 : | |||
115 : | #define FRAMERATE_INCR 1001 | ||
116 : | int enc_init() | ||
117 : | { | ||
118 : | int status; | ||
119 : | ENC_PARAM enc_param; | ||
120 : | |||
121 : | enc_param.x_dim = XDIM; | ||
122 : | enc_param.y_dim = YDIM; | ||
123 : | enc_param.framerate = ARG_FRAMERATE; // a float | ||
124 : | enc_param.bitrate = ARG_BITRATE*1000; | ||
125 : | |||
126 : | enc_param.rc_period = 2000; | ||
127 : | enc_param.rc_reaction_period = 10; | ||
128 : | enc_param.rc_reaction_ratio = 20; | ||
129 : | |||
130 : | enc_param.max_quantizer = 31; | ||
131 : | enc_param.min_quantizer = 1; | ||
132 : | |||
133 : | enc_param.quality = QUALITY; | ||
134 : | |||
135 : | enc_param.use_bidirect = 0; // use bidirectional coding | ||
136 : | enc_param.deinterlace = 0; // fast deinterlace | ||
137 : | enc_param.obmc = 0; // flag to enable overlapped block motion compensation mode | ||
138 : | |||
139 : | enc_param.max_key_interval = (int)ARG_FRAMERATE*10; | ||
140 : | enc_param.handle = NULL; //will be filled by encore | ||
141 : | |||
142 : | status = encore(enchandle, ENC_OPT_INIT, &enc_param, NULL); | ||
143 : | enchandle = enc_param.handle; | ||
144 : | |||
145 : | // if (status) | ||
146 : | printf("Encore INIT return %d, handle=%lx\n", status, enchandle); | ||
147 : | |||
148 : | return status; | ||
149 : | } | ||
150 : | |||
151 : | int enc_stop() | ||
152 : | { int status; | ||
153 : | |||
154 : | status = encore(enchandle, ENC_OPT_RELEASE, NULL, NULL); | ||
155 : | // if (status) | ||
156 : | printf("Encore RELEASE return %d\n", status); | ||
157 : | |||
158 : | return status; | ||
159 : | } | ||
160 : | |||
161 : | int enc_main(unsigned char* image, unsigned char* bitstream, int *streamlength) | ||
162 : | { int status; | ||
163 : | |||
164 : | ENC_FRAME enc_frame; | ||
165 : | ENC_RESULT enc_result; | ||
166 : | |||
167 : | enc_frame.image = (void *) image; | ||
168 : | enc_frame.bitstream = (void *) bitstream; | ||
169 : | enc_frame.length = 0; // filled by encore | ||
170 : | enc_frame.colorspace = ENC_CSP_YV12; // input is YUV | ||
171 : | enc_frame.mvs = NULL; // unsupported | ||
172 : | |||
173 : | if (QUANTI==0) | ||
174 : | { | ||
175 : | status = encore(enchandle, ENC_OPT_ENCODE, &enc_frame, &enc_result); | ||
176 : | } | ||
177 : | else | ||
178 : | { enc_frame.quant = QUANTI; | ||
179 : | enc_frame.intra = -1; // let encoder decide if frame is INTER/INTRA | ||
180 : | status = encore(enchandle, ENC_OPT_ENCODE_VBR, &enc_frame, &enc_result); | ||
181 : | } | ||
182 : | |||
183 : | /* ENC_OPT_ENCODE is used to encode using ratecontrol alg. and bitrate from enc_init, | ||
184 : | ENC_OPT_ENCODE_VBR is used to encode with fixed quantizer and INTER/INTRA mode | ||
185 : | */ | ||
186 : | |||
187 : | *streamlength = enc_frame.length; | ||
188 : | |||
189 : | return status; | ||
190 : | } | ||
191 : | |||
192 : | |||
193 : | /*********************************************************************/ | ||
194 : | /* Routines for decoding: init encoder, frame step, release encoder */ | ||
195 : | /*********************************************************************/ | ||
196 : | |||
197 : | int dec_init() | ||
198 : | { | ||
199 : | int status; | ||
200 : | |||
201 : | DEC_PARAM dec_param; | ||
202 : | DEC_SET dec_set; | ||
203 : | |||
204 : | dec_param.x_dim = XDIM; | ||
205 : | dec_param.y_dim = YDIM; | ||
206 : | dec_param.output_format = DEC_RGB24; // output color format, , see <decore.h> | ||
207 : | |||
208 : | dec_param.time_incr = 20; | ||
209 : | |||
210 : | status = decore(dechandle, DEC_OPT_INIT, &dec_param, NULL); | ||
211 : | // if (status) | ||
212 : | printf("Decore INIT return %d\n", status); | ||
213 : | |||
214 : | // We don't do any postprocessing here... | ||
215 : | |||
216 : | /* dec_set.postproc_level = 0; | ||
217 : | status = decore(dechandle, DEC_OPT_SETPP, &dec_set, NULL); | ||
218 : | if (status) | ||
219 : | printf("Decore POSTPROC %d return %d\n", dec_set.postproc_level, status); | ||
220 : | */ | ||
221 : | |||
222 : | return status; | ||
223 : | } | ||
224 : | |||
225 : | int dec_main(unsigned char *m4v_buffer, unsigned char *rgb_buffer, int m4v_size) | ||
226 : | { | ||
227 : | int status; | ||
228 : | |||
229 : | static DEC_FRAME dec_frame; | ||
230 : | static DEC_FRAME_INFO dec_frame_info; | ||
231 : | |||
232 : | dec_frame.length = m4v_size; | ||
233 : | dec_frame.bitstream = m4v_buffer; | ||
234 : | dec_frame.bmp = rgb_buffer; | ||
235 : | dec_frame.render_flag = 1; // 0 means: skip this frame | ||
236 : | dec_frame.stride = XDIM; | ||
237 : | |||
238 : | status = decore(dechandle, DEC_OPT_FRAME, &dec_frame, &dec_frame_info); | ||
239 : | if (status) | ||
240 : | printf("Decore Frame status %d!\n", status); | ||
241 : | |||
242 : | return status; | ||
243 : | } | ||
244 : | |||
245 : | int dec_stop() | ||
246 : | { | ||
247 : | int status; | ||
248 : | status = decore(dechandle, DEC_OPT_RELEASE, NULL, NULL); | ||
249 : | // if (status) | ||
250 : | printf("Decore RELEASE return %d\n", status); | ||
251 : | return status; | ||
252 : | } | ||
253 : | |||
254 : | |||
255 : | /*********************************************************************/ | ||
256 : | /* Main program */ | ||
257 : | /*********************************************************************/ | ||
258 : | |||
259 : | int main() | ||
260 : | { | ||
261 : | unsigned char *divx_buffer = NULL; | ||
262 : | unsigned char *yuv_buffer = NULL; | ||
263 : | unsigned char *rgb_buffer = NULL; | ||
264 : | |||
265 : | int status; | ||
266 : | int frame_size; | ||
267 : | int m4v_size; | ||
268 : | |||
269 : | char filename[256]; | ||
270 : | |||
271 : | FILE *filehandle; | ||
272 : | |||
273 : | /* read YUV in pgm format from stdin */ | ||
274 : | if (read_pgmheader(stdin)) | ||
275 : | { | ||
276 : | printf("Wrong input format, I want YUV encapsulated in PGM\n"); | ||
277 : | return 0; | ||
278 : | } | ||
279 : | |||
280 : | /* now we know the sizes, so allocate memory */ | ||
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 : | divx_buffer = (unsigned char *) malloc(XDIM*YDIM*2); // this should really be enough! | ||
285 : | if (!divx_buffer) | ||
286 : | goto free_all_memory; // actually, every program should contain a goto | ||
287 : | |||
288 : | YDIM = YDIM*2/3; // PGM is YUV 4:2:0 format, so height is *3/2 too much | ||
289 : | |||
290 : | rgb_buffer = (unsigned char *) malloc(XDIM*YDIM*4); | ||
291 : | if (!rgb_buffer) | ||
292 : | goto free_all_memory; // the more, the better! | ||
293 : | |||
294 : | /*********************************************************************/ | ||
295 : | /* DIVX PART Start */ | ||
296 : | /*********************************************************************/ | ||
297 : | |||
298 : | status = enc_init(); | ||
299 : | // if (status) | ||
300 : | printf("Encore INIT return %d, handle=%lx\n", status, enchandle); | ||
301 : | |||
302 : | status = dec_init(); | ||
303 : | // if (status) | ||
304 : | printf("Decore INIT return %d\n", status); | ||
305 : | |||
306 : | |||
307 : | /*********************************************************************/ | ||
308 : | /* Main loop */ | ||
309 : | /*********************************************************************/ | ||
310 : | |||
311 : | do | ||
312 : | { | ||
313 : | status = read_pgmdata(stdin, yuv_buffer); // read PGM data (YUV-format) | ||
314 : | if (status) | ||
315 : | { | ||
316 : | fprintf(stderr, "PGM-Data-Error: %d\n", status); /* this should not happen */ | ||
317 : | continue; | ||
318 : | } | ||
319 : | |||
320 : | /*********************************************************************/ | ||
321 : | /* encode and decode this frame */ | ||
322 : | /*********************************************************************/ | ||
323 : | |||
324 : | status = enc_main(yuv_buffer, divx_buffer, &m4v_size); | ||
325 : | |||
326 : | printf("Frame %5d: encore-ENCODE status %d, m4v-stream length=%7d bytes\n", | ||
327 : | filenr, status, m4v_size); | ||
328 : | |||
329 : | if (save_m4v_flag) | ||
330 : | { | ||
331 : | sprintf(filename, "%s/frame%05d.m4v", filepath, filenr); | ||
332 : | filehandle = fopen(filename, "wb"); | ||
333 : | fwrite(divx_buffer, m4v_size, 1, filehandle); | ||
334 : | fclose(filehandle); | ||
335 : | } | ||
336 : | |||
337 : | status = dec_main(divx_buffer, rgb_buffer, m4v_size); | ||
338 : | if (status) | ||
339 : | printf("Frame %5d: decore status %d\n",status); | ||
340 : | |||
341 : | if (save_dec_flag) | ||
342 : | { | ||
343 : | sprintf(filename, "%s/dec%05d.ppm", filepath, filenr); | ||
344 : | filehandle=fopen(filename,"wb"); | ||
345 : | if (filehandle) | ||
346 : | { | ||
347 : | fprintf(filehandle,"P6\n"); // rgb24 in PPM format | ||
348 : | fprintf(filehandle,"%d %d 255\n",XDIM,YDIM); | ||
349 : | fwrite(rgb_buffer,XDIM,YDIM*3,filehandle); | ||
350 : | fclose(filehandle); | ||
351 : | } | ||
352 : | } | ||
353 : | |||
354 : | filenr++; | ||
355 : | status = read_pgmheader(stdin); // if it was the last PGM, stop after it | ||
356 : | if (status) | ||
357 : | { | ||
358 : | fprintf(stderr, "PGM-Header-Error: %d\n", status); /* normally, just end of file */ | ||
359 : | } | ||
360 : | } | ||
361 : | while (!status); | ||
362 : | |||
363 : | |||
364 : | /*********************************************************************/ | ||
365 : | /* DIVX PART Stop */ | ||
366 : | /*********************************************************************/ | ||
367 : | |||
368 : | |||
369 : | /* Stop XviD */ | ||
370 : | |||
371 : | dec_stop(); | ||
372 : | // if (status) | ||
373 : | printf("Encore RELEASE return %d\n", status); | ||
374 : | |||
375 : | enc_stop(); | ||
376 : | // if (status) | ||
377 : | printf("Decore RELEASE return %d\n", status); | ||
378 : | |||
379 : | free_all_memory: | ||
380 : | |||
381 : | if (rgb_buffer) | ||
382 : | free(rgb_buffer); | ||
383 : | if (divx_buffer) | ||
384 : | free(divx_buffer); | ||
385 : | if (yuv_buffer) | ||
386 : | free(yuv_buffer); | ||
387 : | |||
388 : | return 0; | ||
389 : | } |
No admin address has been configured | ViewVC Help |
Powered by ViewVC 1.0.4 |