Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | pj | 1 | /* |
2 | * Copyright (c) 1994 by Gregory P. Ward. |
||
3 | * All rights reserved. |
||
4 | * |
||
5 | * This file is part of the MNI front end of the Berkeley MPEG decoder. |
||
6 | * |
||
7 | * Permission to use, copy, modify, and distribute this software and its |
||
8 | * documentation for any purpose, without fee, and without written agreement is |
||
9 | * hereby granted, provided that the above copyright notice and the following |
||
10 | * two paragraphs appear in all copies of this software. |
||
11 | * |
||
12 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, |
||
13 | * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
||
14 | * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE |
||
15 | * UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF |
||
16 | * SUCH DAMAGE. |
||
17 | * |
||
18 | * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT |
||
19 | * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER |
||
21 | * IS ON AN "AS IS" BASIS, AND THE AUTHOR HAS NO OBLIGATION TO PROVIDE |
||
22 | * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||
23 | */ |
||
24 | /* |
||
25 | * Portions of this software Copyright (c) 1995 Brown University. |
||
26 | * All rights reserved. |
||
27 | * |
||
28 | * Permission to use, copy, modify, and distribute this software and its |
||
29 | * documentation for any purpose, without fee, and without written agreement |
||
30 | * is hereby granted, provided that the above copyright notice and the |
||
31 | * following two paragraphs appear in all copies of this software. |
||
32 | * |
||
33 | * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR DIRECT, |
||
34 | * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
||
35 | * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN |
||
36 | * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
37 | * |
||
38 | * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
||
39 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
||
40 | * PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" |
||
41 | * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, |
||
42 | * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||
43 | */ |
||
44 | |||
45 | /* |
||
46 | * |
||
47 | * Original C version by Greg Ward <greg@pet.mni.mcgill.ca>, |
||
48 | * reentrant C++ version by Loring Holden <lsh@cs.brown.edu> |
||
49 | * |
||
50 | * All functions that have an "MNI Header" are rewritten from the original |
||
51 | * MNI C function |
||
52 | * |
||
53 | */ |
||
54 | |||
55 | #include "ANIMmpeg.H" |
||
56 | |||
57 | // These are MPEG decoder globals but shouldn't be, really; |
||
58 | int quietFlag=1, loopFlag=1,qualityFlag=0, requireKeypressFlag=0; |
||
59 | int framerate=0,gammaCorrectFlag=0, chromaCorrectFlag=0, noDisplayFlag=0; |
||
60 | int partialFlag=0,startFrame=-1, endFrame=-1; |
||
61 | double gammaCorrect = 1.0, chromaCorrect=1.0; |
||
62 | |||
63 | int ANIMmpeg::numMovies=0; |
||
64 | |||
65 | // |
||
66 | //Constructor |
||
67 | // |
||
68 | // |
||
69 | ANIMmpeg::ANIMmpeg(const char * const inFileName) |
||
70 | : vid_stream(NULL) |
||
71 | { |
||
72 | newMovie(inFileName); |
||
73 | init(); |
||
74 | } |
||
75 | |||
76 | // |
||
77 | //Copy constructor |
||
78 | // |
||
79 | ANIMmpeg::ANIMmpeg(const ANIMmpeg& rhs) |
||
80 | : ANIMbase(rhs), |
||
81 | vid_stream(NULL) |
||
82 | { |
||
83 | newMovie(rhs.fileName); |
||
84 | init(); |
||
85 | } |
||
86 | |||
87 | // |
||
88 | // Takes in read-only string that is the the name of the new movie, |
||
89 | // if NULL, then just deallocates memory |
||
90 | // |
||
91 | void |
||
92 | ANIMmpeg::newMovie(const char * const infile) |
||
93 | { |
||
94 | int stringLength = infile==NULL ? 0 : strlen(infile); |
||
95 | #ifndef NOTHREADS |
||
96 | Boolean tmpThreaded=MultiThreaded; |
||
97 | |||
98 | // In case we're decoding in another thread... |
||
99 | if (MultiThreaded && mp_man->processor(threadNumber)->running) { |
||
100 | mp_man->processor(threadNumber)->wait_for_done(); |
||
101 | } |
||
102 | #endif |
||
103 | |||
104 | // Clean up after old movie |
||
105 | if (fileName) { |
||
106 | delete [] fileName; |
||
107 | } |
||
108 | if (filePtr) fclose(filePtr); |
||
109 | if (vid_stream) { |
||
110 | DestroyVidStream(vid_stream, NULL); |
||
111 | vid_stream=NULL; |
||
112 | } |
||
113 | if (frameBuffer) { |
||
114 | Buffer(FALSE); |
||
115 | } |
||
116 | #ifndef NOTHREADS |
||
117 | MultiThread(FALSE); |
||
118 | #endif |
||
119 | |||
120 | if (stringLength) { |
||
121 | fileName = new char[stringLength]; |
||
122 | strcpy(fileName, infile); |
||
123 | filePtr = fopen(fileName,"r"); |
||
124 | #ifndef NOTHREADS |
||
125 | MultiThread(tmpThreaded); |
||
126 | #endif |
||
127 | } |
||
128 | |||
129 | /* Initialize movie information */ |
||
130 | Height=Width=BlockHeight=BlockWidth=Depth=PixelSize=Size=BitmapPad=0; |
||
131 | PictureRate=BitRate=0; |
||
132 | } |
||
133 | |||
134 | // |
||
135 | //Initialization used by all constructors |
||
136 | // |
||
137 | // |
||
138 | void |
||
139 | ANIMmpeg::init() { |
||
140 | thread_routine=RunDecode; |
||
141 | numMovies++; |
||
142 | if (numMovies==1) { |
||
143 | /* Allocate/initialize tables used for dithering (?) */ |
||
144 | lum_values = (int *) malloc(LUM_RANGE*sizeof(int)); |
||
145 | cr_values = (int *) malloc(CR_RANGE*sizeof(int)); |
||
146 | cb_values = (int *) malloc(CB_RANGE*sizeof(int)); |
||
147 | init_tables(); /* initialize decoding stuff */ |
||
148 | InitCrop(); |
||
149 | InitDither(); /* initializes dithering structures and */ |
||
150 | /* colormap (i.e. this is where we do */ |
||
151 | /* all dither-specific stuff) */ |
||
152 | } |
||
153 | } |
||
154 | |||
155 | /* ----------------------------- MNI Header ----------------------------------- |
||
156 | @NAME : OpenMPEG |
||
157 | @INPUT : MPEGfile - pointer to a stream opened for reading, positioned |
||
158 | at the beginning of an MPEG stream |
||
159 | ImgInfo - pointer to an ImageDesc structure which will have |
||
160 | information such as frame height, width, depth |
||
161 | and size (total bytes per frame) put in it. |
||
162 | @OUTPUT : |
||
163 | @RETURNS : |
||
164 | @DESCRIPTION: Creates and initializes the variables needed to start |
||
165 | reading/decoding an MPEG stream. |
||
166 | |||
167 | This function is part of the MNI front end to the Berkeley |
||
168 | MPEG decoder, adapted from the original Berkeley code. |
||
169 | @METHOD : |
||
170 | @GLOBALS : LUM_RANGE, CR_RANGE, CB_RANGE |
||
171 | lum_values, cr_values, cb_values |
||
172 | @CALLS : GetMPEGInfo() |
||
173 | init_tables() |
||
174 | InitDither() |
||
175 | @CREATED : 94/6/16, Greg Ward (adapted from main() in the original |
||
176 | Berkeley source) |
||
177 | @MODIFIED : 95/10, Loring Holden (made reentrant and ported to C++) |
||
178 | ---------------------------------------------------------------------------- */ |
||
179 | Boolean ANIMmpeg::open() |
||
180 | { |
||
181 | Boolean okMovie; |
||
182 | /* |
||
183 | * Create the video stream and read the first chunk to get movie |
||
184 | * stats -- width and height in particular. |
||
185 | */ |
||
186 | #ifndef NOTHREADS |
||
187 | if (MultiThreaded && (mp_man->processor(threadNumber)->running)) { |
||
188 | #ifdef sol |
||
189 | fprintf(stderr,"%s: Decode running when open called\n", |
||
190 | fileName); |
||
191 | #else |
||
192 | fprintf(stderr,"%s: Decode running when open called\n",fileName); |
||
193 | #endif |
||
194 | fflush(stderr); |
||
195 | exit(2); |
||
196 | } |
||
197 | #endif |
||
198 | |||
199 | if (vid_stream==NULL) { |
||
200 | vid_stream =NewVidStream((unsigned int) BUF_LENGTH); |
||
201 | /* Initialize start time */ |
||
202 | vid_stream->realTimeStart = ReadSysClock(); |
||
203 | } else { |
||
204 | // clear_data_stream(vid_stream) already called in mpegVidRsrc |
||
205 | ResetVidStream(vid_stream); |
||
206 | allBuffered=FALSE; |
||
207 | // call buffer destructor |
||
208 | if (frameBuffer) Buffer(FALSE); |
||
209 | } |
||
210 | |||
211 | vid_stream->input = filePtr; |
||
212 | vid_stream->filename = (char *) fileName; |
||
213 | vid_stream->ditherType=FULL_COLOR_DITHER; /* default */ |
||
214 | frames=0; |
||
215 | InitStream(); |
||
216 | |||
217 | okMovie=(mpegVidRsrc(0, vid_stream, 1, NULL)!=NULL); |
||
218 | if (okMovie) { |
||
219 | GetInfo(); |
||
220 | moreFrames=TRUE; |
||
221 | } else moreFrames=FALSE; |
||
222 | |||
223 | #ifndef NOTHREADS |
||
224 | if (!allBuffered && MultiThreaded && okMovie) { |
||
225 | // Should check that nothing is running, but assume rewind has been |
||
226 | // called |
||
227 | mp_man->processor(threadNumber)->start_execute(RunDecode,this,NULL); |
||
228 | } |
||
229 | #endif |
||
230 | return okMovie; |
||
231 | |||
232 | } /* OpenMPEG () */ |
||
233 | |||
234 | |||
235 | // Destructor |
||
236 | /* ----------------------------- MNI Header ----------------------------------- |
||
237 | @NAME : CloseMPEG |
||
238 | @INPUT : (none) |
||
239 | @OUTPUT : (none) |
||
240 | @RETURNS : (void) |
||
241 | @DESCRIPTION: Frees up some of the memory allocated by OpenMPEG() (some |
||
242 | is not freed because the Berkeley code doesn't take into |
||
243 | account the fact that somebody might want to, say, free |
||
244 | up the memory it allocates... someday, I'll probably have |
||
245 | to hack into it to fix that, but not today thanks.) |
||
246 | @METHOD : |
||
247 | @GLOBALS : lum_values |
||
248 | cr_values |
||
249 | cb_values |
||
250 | @CALLS : DestroyVidStream |
||
251 | @CREATED : 94/6/27, Greg Ward |
||
252 | @MODIFIED : 95/10, Loring Holden (made reentrant and ported to C++) |
||
253 | ---------------------------------------------------------------------------- */ |
||
254 | ANIMmpeg::~ANIMmpeg() |
||
255 | { |
||
256 | newMovie(NULL); //Like we are playing a new movie, but no new |
||
257 | //allocation |
||
258 | // These stay around for the life of the program |
||
259 | // free (lum_values); |
||
260 | // free (cr_values); |
||
261 | // free (cb_values); |
||
262 | } |
||
263 | |||
264 | |||
265 | |||
266 | /* ----------------------------- MNI Header ----------------------------------- |
||
267 | @NAME : RewindMPEG |
||
268 | @INPUT : MPEGfile - the input stream where the MPEG's coming from |
||
269 | Image - image descriptor (just passed to OpenMPEG ()) |
||
270 | @OUTPUT : (none) |
||
271 | @RETURNS : (void) |
||
272 | @DESCRIPTION: Resets things so that the caller can start reading the MPEG |
||
273 | stream from the start again. Note that the caller does NOT |
||
274 | need to call OpenMPEG() again -- after a call to RewindMPEG(), |
||
275 | the next call to GetMPEGFrame() will return the first frame |
||
276 | of the MPEG. |
||
277 | @METHOD : |
||
278 | @GLOBALS : |
||
279 | @CALLS : |
||
280 | @CREATED : 94/7/20, Greg Ward |
||
281 | @MODIFIED : 95/10, Loring Holden (made reentrant and ported to C++) |
||
282 | @COMMENTS : |
||
283 | ---------------------------------------------------------------------------- */ |
||
284 | void ANIMmpeg::rewind() |
||
285 | { |
||
286 | #ifndef NOTHREADS |
||
287 | if (MultiThreaded && (mp_man->processor(threadNumber)->running)) { |
||
288 | #ifdef sol |
||
289 | fprintf(stderr,"%s: Decode running when rewind called\n", |
||
290 | fileName); |
||
291 | #else |
||
292 | fprintf(stderr,"%s: Decode running when rewind called\n",fileName); |
||
293 | #endif |
||
294 | fflush(stderr); |
||
295 | exit(2); |
||
296 | } |
||
297 | #endif |
||
298 | |||
299 | if (!allBuffered) { |
||
300 | ::rewind(filePtr); |
||
301 | open(); |
||
302 | } else { |
||
303 | // do buffering stuff here |
||
304 | } |
||
305 | } |
||
306 | |||
307 | |||
308 | |||
309 | /* ----------------------------- MNI Header ----------------------------------- |
||
310 | @NAME : GetMPEGInfo |
||
311 | @INPUT : vid_stream - a video stream that is open and has had at |
||
312 | least one call to mpegVidRsrc() performed on it |
||
313 | Info - a pointer to an ImageDesc struct in the caller's |
||
314 | space (i.e., the argument to OpenMPEG()) where |
||
315 | the image information will be copied |
||
316 | @OUTPUT : |
||
317 | @RETURNS : (void) |
||
318 | @DESCRIPTION: From the video stream, determines the width, height, pixel |
||
319 | size and depth (in bits) and total image size (in bytes) |
||
320 | for an MPEG stream. Sets the global variable Info |
||
321 | (part of the interface between wrapper.c and globals.c), |
||
322 | and then copies that struct to the user application's |
||
323 | space via the Info pointer. |
||
324 | @METHOD : |
||
325 | @GLOBALS : |
||
326 | @CALLS : |
||
327 | @CREATED : 94/6/17, Greg Ward: based on code from ExecuteDisplay() in the |
||
328 | original Berkeley source |
||
329 | @MODIFIED : 95/10, Loring Holden (made reentrant and ported to C++) |
||
330 | ---------------------------------------------------------------------------- */ |
||
331 | void ANIMmpeg::GetInfo() |
||
332 | { |
||
333 | #ifndef DISABLE_DITHER |
||
334 | switch (vid_stream->ditherType) |
||
335 | { |
||
336 | case Twox2_DITHER: |
||
337 | { |
||
338 | Height = vid_stream->v_size; |
||
339 | Width = vid_stream->h_size; |
||
340 | BlockHeight=vid_stream->mb_height; |
||
341 | BlockWidth=vid_stream->mb_width; |
||
342 | Depth = 8; |
||
343 | PixelSize = 8; |
||
344 | BitmapPad = 8; |
||
345 | break; |
||
346 | } |
||
347 | case FULL_COLOR_DITHER: |
||
348 | { |
||
349 | #endif |
||
350 | Height = vid_stream->v_size; |
||
351 | Width = vid_stream->h_size; |
||
352 | BlockHeight=vid_stream->mb_height; |
||
353 | BlockWidth=vid_stream->mb_width; |
||
354 | Depth = 24; |
||
355 | PixelSize = 32; |
||
356 | BitmapPad = 32; |
||
357 | #ifndef DISABLE_DITHER |
||
358 | break; |
||
359 | } |
||
360 | case MONO_DITHER: |
||
361 | case MONO_THRESHOLD: |
||
362 | { |
||
363 | Height = vid_stream->v_size; |
||
364 | Width = vid_stream->h_size; |
||
365 | Depth = 1; |
||
366 | PixelSize = 1; |
||
367 | BitmapPad = 8; |
||
368 | break; |
||
369 | } |
||
370 | default: /* including GRAY_DITHER and ORDERED_DITHER */ |
||
371 | { |
||
372 | Height = vid_stream->v_size; |
||
373 | Width = vid_stream->h_size; |
||
374 | Depth = 8; |
||
375 | PixelSize = 8; |
||
376 | BitmapPad = 8; |
||
377 | break; |
||
378 | } |
||
379 | } /* switch on ditherType */ |
||
380 | #endif |
||
381 | |||
382 | Size = (BlockHeight*16*BlockWidth*16*PixelSize) / 8; |
||
383 | PictureRate = vid_stream->picture_rate; |
||
384 | BitRate = vid_stream->bit_rate; |
||
385 | |||
386 | } /* GetMPEGInfo () */ |
||
387 | |||
388 | /* ----------------------------- MNI Header ----------------------------------- |
||
389 | @NAME : GetMPEGFrame |
||
390 | @INPUT : |
||
391 | @OUTPUT : Frame - the image data, converted to RGB space, is |
||
392 | copied to the area pointed to by Frame. There must be |
||
393 | enough room for the entire image; the ImageDesc |
||
394 | structure returned by OpenMPEG() will tell you just how |
||
395 | much memory this is. The format of the data depends on |
||
396 | the dithering type; for full colour dithering, there are |
||
397 | four bytes per pixel: red, green, blue, and unused. |
||
398 | (Perfect for passing to lrectwrite() or XPutImage().) |
||
399 | @RETURNS : TRUE if there are still frames left to decode |
||
400 | FALSE if we have just decoded the last frame |
||
401 | @DESCRIPTION: Part of the MNI front end to the Berkeley MPEG decoder. |
||
402 | Essentially reads, decodes, and converts to RGB space the |
||
403 | next frame in the MPEG stream opened with OpenMPEG(). |
||
404 | @METHOD : |
||
405 | @GLOBALS : |
||
406 | @CALLS : mpegVidRsrc () |
||
407 | @CREATED : 94/6/16, Greg Ward |
||
408 | @MODIFIED : 95/10, Loring Holden (made reentrant and ported to C++) |
||
409 | ---------------------------------------------------------------------------- */ |
||
410 | void *ANIMmpeg::RunDecode(void *ptr, void *) |
||
411 | { |
||
412 | ANIMmpeg *movie=(ANIMmpeg *) ptr; |
||
413 | Boolean MovieDone = FALSE; |
||
414 | int frames; |
||
415 | |||
416 | #if 0 |
||
417 | dprintf ("GetMPEGFrame: starting or continuing movie\n"); |
||
418 | #endif |
||
419 | |||
420 | frames=movie->vid_stream->totNumFrames; |
||
421 | while (!MovieDone && (frames==movie->vid_stream->totNumFrames)) |
||
422 | { |
||
423 | mpegVidRsrc(0,movie->vid_stream,0, NULL); |
||
424 | MovieDone = movie->vid_stream->film_has_ended; |
||
425 | } |
||
426 | |||
427 | return NULL; |
||
428 | |||
429 | } /* GetMPEGFrame () */ |
||
430 | |||
431 | Boolean ANIMmpeg::GetFrame(char **Frame, Boolean *newFrame) |
||
432 | { |
||
433 | void *CurrentImage; |
||
434 | int looped; |
||
435 | |||
436 | if ((vid_stream==NULL) && !open()) { |
||
437 | *newFrame=FALSE; |
||
438 | return FALSE; |
||
439 | } |
||
440 | |||
441 | if (!allBuffered) { |
||
442 | #ifndef NOTHREADS |
||
443 | if (MultiThreaded) { |
||
444 | mp_man->processor(threadNumber)->wait_for_done(); |
||
445 | } else { |
||
446 | ANIMmpeg::RunDecode(this,NULL); |
||
447 | } |
||
448 | #else |
||
449 | ANIMmpeg::RunDecode(this,NULL); |
||
450 | #endif |
||
451 | moreFrames=!vid_stream->film_has_ended; |
||
452 | CurrentImage=(void *) vid_stream->current->display; |
||
453 | if (buffering) { |
||
454 | // copy CurrentImage to the right place in the array |
||
455 | if (!frameBuffer->addToBuffer(CurrentImage)) { |
||
456 | // ran out of memory - can't buffer |
||
457 | Buffer(FALSE); |
||
458 | fflush(stdout); |
||
459 | fprintf(stderr,"%s: no more room to buffer\n",fileName); |
||
460 | fflush(stderr); |
||
461 | } else if (!moreFrames) { |
||
462 | allBuffered=TRUE; |
||
463 | moreFrames=TRUE; |
||
464 | } |
||
465 | } |
||
466 | #if 0 |
||
467 | dprintf ("\nGetMPEGFrame: just received a finished frame: ", |
||
468 | "copying from %08X to %08X\n", CurrentImage, Frame); |
||
469 | #endif |
||
470 | memcpy ((void *) *Frame, CurrentImage, Size); |
||
471 | |||
472 | if (allBuffered) { |
||
473 | int totFrames=vid_stream->totNumFrames; |
||
474 | |||
475 | DestroyVidStream(vid_stream,NULL); |
||
476 | // This is a hack in order to use PrintTimeInfo |
||
477 | // - Create a NewVidStream just to use realTimeStart |
||
478 | // - all the image information is deallocated, so we do save space |
||
479 | vid_stream =NewVidStream((unsigned int) BUF_LENGTH); |
||
480 | vid_stream->totNumFrames=totFrames; |
||
481 | /* Initialize start time */ |
||
482 | vid_stream->realTimeStart = ReadSysClock(); |
||
483 | } |
||
484 | |||
485 | } else { |
||
486 | // set moreFrames |
||
487 | moreFrames=TRUE; |
||
488 | // set CurrentImage to point to the right place in the array |
||
489 | *Frame=(char *) frameBuffer->nextBufferItem(&looped); |
||
490 | if (looped) { |
||
491 | PrintTimeInfo(vid_stream); |
||
492 | vid_stream->realTimeStart = ReadSysClock(); |
||
493 | } |
||
494 | } |
||
495 | |||
496 | #ifndef NOTHREADS |
||
497 | if (!allBuffered && MultiThreaded && moreFrames) { |
||
498 | mp_man->processor(threadNumber)->start_execute(RunDecode,this,NULL); |
||
499 | } |
||
500 | #endif |
||
501 | |||
502 | frames++; |
||
503 | *newFrame=TRUE; |
||
504 | return moreFrames; |
||
505 | } |
||
506 | |||
507 | #ifndef DISABLE_DITHER |
||
508 | /* ----------------------------- MNI Header ----------------------------------- |
||
509 | @NAME : DoDitherImage |
||
510 | @INPUT : l, Cr, Cb - pointers to the luminance, Cr, and Cb planes |
||
511 | disp - ? |
||
512 | h, w - height and width of image (?) |
||
513 | @OUTPUT : |
||
514 | @RETURNS : |
||
515 | @DESCRIPTION: Called when image needs to be dithered. Selects correct |
||
516 | dither routine based on info in ditherType. |
||
517 | @METHOD : |
||
518 | @GLOBALS : ditherType |
||
519 | @CALLS : One of the following, depending on the value of ditherType: |
||
520 | HybridDitherImage (hybrid.c) |
||
521 | HybridErrorDitherImage (hybriderr.c) |
||
522 | FS2FastDitherImage (fs2fast.c) |
||
523 | FS2DitherImage (fs2.c) |
||
524 | FS4DitherImage (fs4.c) |
||
525 | Twox2DitherImage (2x2.c) |
||
526 | ColorDitherImage (16bit.c) |
||
527 | GrayDitherImage (gray.c) |
||
528 | OrderedDitherImage (ordered.c) |
||
529 | MonoDitherImage (mono.c) |
||
530 | MonoThresholdImage (mono.c) |
||
531 | Ordered2DitherImage (ordered2.c) |
||
532 | MBOrderedDitherImage (mb_ordered.c) |
||
533 | @CREATED : (taken from the original Berkeley code) |
||
534 | @MODIFIED : |
||
535 | ---------------------------------------------------------------------------- */ |
||
536 | void |
||
537 | DoDitherImage(VidStream *vid_stream) |
||
538 | { |
||
539 | unsigned char *l=vid_stream->current->luminance, |
||
540 | *Cr=vid_stream->current->Cr, |
||
541 | *Cb=vid_stream->current->Cb, |
||
542 | *disp=vid_stream->current->display; |
||
543 | int h=(int) vid_stream->mb_height * 16; |
||
544 | int w=(int) vid_stream->mb_width * 16; |
||
545 | int ditherType=vid_stream->ditherType; |
||
546 | int matched_depth=vid_stream->matched_depth; |
||
547 | |||
548 | switch(ditherType) { |
||
549 | case HYBRID_DITHER: |
||
550 | HybridDitherImage(l, Cr, Cb, disp, h, w); |
||
551 | break; |
||
552 | |||
553 | case HYBRID2_DITHER: |
||
554 | HybridErrorDitherImage(l, Cr, Cb, disp, h, w); |
||
555 | break; |
||
556 | |||
557 | case FS2FAST_DITHER: |
||
558 | FS2FastDitherImage(l, Cr, Cb, disp, h, w); |
||
559 | break; |
||
560 | |||
561 | case FS2_DITHER: |
||
562 | FS2DitherImage(l, Cr, Cb, disp, h, w); |
||
563 | break; |
||
564 | |||
565 | case FS4_DITHER: |
||
566 | FS4DitherImage(l, Cr, Cb, disp, h, w); |
||
567 | break; |
||
568 | |||
569 | case Twox2_DITHER: |
||
570 | Twox2DitherImage(l, Cr, Cb, disp, h, w); |
||
571 | break; |
||
572 | |||
573 | case FULL_COLOR_DITHER: |
||
574 | Color32DitherImage(l, Cr, Cb, disp, h, w); |
||
575 | break; |
||
576 | |||
577 | case GRAY_DITHER: |
||
578 | GrayDitherImage(l, Cr, Cb, disp, h, w); |
||
579 | break; |
||
580 | |||
581 | case NO_DITHER: |
||
582 | break; |
||
583 | |||
584 | case PPM_DITHER: |
||
585 | Color32DitherImage(l, Cr, Cb, disp, h, w); |
||
586 | break; |
||
587 | |||
588 | case ORDERED_DITHER: |
||
589 | OrderedDitherImage(l, Cr, Cb, disp, h, w); |
||
590 | break; |
||
591 | |||
592 | case MONO_DITHER: |
||
593 | MonoDitherImage(l, Cr, Cb, disp, h, w); |
||
594 | break; |
||
595 | |||
596 | case MONO_THRESHOLD: |
||
597 | MonoThresholdImage(l, Cr, Cb, disp, h, w); |
||
598 | break; |
||
599 | |||
600 | case ORDERED2_DITHER: |
||
601 | Ordered2DitherImage(l, Cr, Cb, disp, h, w); |
||
602 | break; |
||
603 | |||
604 | case MBORDERED_DITHER: |
||
605 | MBOrderedDitherImage(l, Cr, Cb, disp, h, w, vid_stream->ditherFlags); |
||
606 | break; |
||
607 | } |
||
608 | } /* DoDitherImage () */ |
||
609 | #else |
||
610 | void |
||
611 | DoDitherImage(VidStream *vid_stream) |
||
612 | { |
||
613 | unsigned char *l=vid_stream->current->luminance, |
||
614 | *Cr=vid_stream->current->Cr, |
||
615 | *Cb=vid_stream->current->Cb, |
||
616 | *disp=vid_stream->current->display; |
||
617 | int h=(int) vid_stream->mb_height * 16; |
||
618 | int w=(int) vid_stream->mb_width * 16; |
||
619 | |||
620 | Color32DitherImage(l,Cr,Cb,disp,h,w); |
||
621 | } |
||
622 | #endif |
||
623 | |||
624 | /* ----------------------------- MNI Header ----------------------------------- |
||
625 | @NAME : InitColormap |
||
626 | @INPUT : (none) |
||
627 | @OUTPUT : *NumColors - number of entries in the newly-created colormap |
||
628 | *Map - an array of colourmap entries; each one contains a |
||
629 | red, green, and blue byte-values (0 .. 255). |
||
630 | *Map[i] gives the colour to display a pixel value i. |
||
631 | @RETURNS : (none) |
||
632 | @DESCRIPTION: Creates a colour map used for most dithering methods |
||
633 | (everything except full-colour, gray, and monochrome). |
||
634 | The colour map itself is pretty self-explanatory -- a |
||
635 | pixel with value i is to be displayed using the red, green |
||
636 | and blue values in *Map[i] after InitColormap() is done. |
||
637 | @METHOD : |
||
638 | @GLOBALS : |
||
639 | @CALLS : |
||
640 | @CREATED : 95/3/4, Greg Ward: based on InitColorDisplay(), from gdith.c |
||
641 | in the original Berkeley player |
||
642 | @MODIFIED : |
||
643 | ---------------------------------------------------------------------------- */ |
||
644 | #ifndef DISABLE_DITHER |
||
645 | static void |
||
646 | InitColormap (int *NumColors, ColormapEntry **Map) |
||
647 | { |
||
648 | int i, lum_num, cr_num, cb_num; |
||
649 | |||
650 | *NumColors = LUM_RANGE*CB_RANGE*CR_RANGE; |
||
651 | *Map = (ColormapEntry *) malloc (*NumColors * sizeof (ColormapEntry)); |
||
652 | |||
653 | for (i = 0; i < *NumColors; i++) |
||
654 | { |
||
655 | lum_num = (i / (CR_RANGE*CB_RANGE))%LUM_RANGE; |
||
656 | cr_num = (i / CB_RANGE)%CR_RANGE; |
||
657 | cb_num = i % CB_RANGE; |
||
658 | |||
659 | /* ConvertColor(lum_values[lum_num], cr_values[cr_num], cb_values[cb_num], |
||
660 | &(*Map)[i].red, &(*Map)[i].green, &(*Map)[i].blue); |
||
661 | */ |
||
662 | pixel[i] = i; |
||
663 | } |
||
664 | } |
||
665 | #endif |
||
666 | |||
667 | |||
668 | /* ----------------------------- MNI Header ----------------------------------- |
||
669 | @NAME : InitGrayColormap |
||
670 | @INPUT : (none) |
||
671 | @OUTPUT : *NumColors - number of entries in the newly-created colormap |
||
672 | *Map - an array of colourmap entries |
||
673 | @RETURNS : (none) |
||
674 | @DESCRIPTION: Creates a colour map used for gray-scale dithering, i.e. |
||
675 | the red/green/blue values are the same for any given |
||
676 | pixel value. |
||
677 | @METHOD : |
||
678 | @GLOBALS : |
||
679 | @CALLS : |
||
680 | @CREATED : 95/3/4, Greg Ward: based on InitGrayDisplay(), from gdith.c |
||
681 | in the original Berkeley player |
||
682 | @MODIFIED : |
||
683 | ---------------------------------------------------------------------------- */ |
||
684 | #ifndef DISABLE_DITHER |
||
685 | static void |
||
686 | InitGrayColormap (int *NumColors, ColormapEntry **Map) |
||
687 | { |
||
688 | int i; |
||
689 | |||
690 | *NumColors = NUM_COLORS; |
||
691 | *Map = (ColormapEntry *) malloc (*NumColors * sizeof (ColormapEntry)); |
||
692 | |||
693 | for (i = 0; i < *NumColors; i++) |
||
694 | { |
||
695 | (*Map)[i].red = (*Map)[i].green = (*Map)[i].blue = i; |
||
696 | pixel[i] = i; |
||
697 | } |
||
698 | } |
||
699 | #endif |
||
700 | |||
701 | |||
702 | /* ----------------------------- MNI Header ----------------------------------- |
||
703 | @NAME : InitDither |
||
704 | @INPUT : Image - pointer to the image descriptor for the current MPEG |
||
705 | @OUTPUT : ColormapSize, Colormap - the colour map for |
||
706 | this movie, as initialized by either InitColormap or |
||
707 | InitGrayColormap (unless the current dithering scheme |
||
708 | is full colour, in which case there is no colour map) |
||
709 | @RETURNS : (none) |
||
710 | @DESCRIPTION: Does all initialization particular to the type of dithering |
||
711 | being used. Basically, sets up the internal data structures |
||
712 | needed by the dithering code, and then sets up a colour map |
||
713 | needed to display the pixels output by the ditherers. |
||
714 | @METHOD : |
||
715 | @GLOBALS : |
||
716 | @CALLS : InitColor (for most dithering methods) |
||
717 | InitColormap (for most dithering methods) |
||
718 | InitGrayColormap (for gray-scale dithering) |
||
719 | Init(..)Dither (.. = the current dithering method) |
||
720 | @CREATED : 95/3/3, Greg Ward: taken mostly from main() in the original |
||
721 | Berkeley player |
||
722 | @MODIFIED : |
||
723 | ---------------------------------------------------------------------------- */ |
||
724 | void |
||
725 | ANIMmpeg::InitDither(unsigned long red, |
||
726 | unsigned long green, |
||
727 | unsigned long blue) |
||
728 | { |
||
729 | LUM_RANGE = 8; |
||
730 | CR_RANGE = 4; |
||
731 | CB_RANGE = 4; |
||
732 | #ifndef DISABLE_DITHER |
||
733 | switch (vid_stream->ditherType) |
||
734 | { |
||
735 | case HYBRID_DITHER: |
||
736 | InitColor (); |
||
737 | InitHybridDither (); |
||
738 | InitColormap (&ColormapSize, &Colormap); |
||
739 | break; |
||
740 | |||
741 | case HYBRID2_DITHER: |
||
742 | InitColor (); |
||
743 | InitHybridErrorDither (); |
||
744 | InitColormap (&ColormapSize, &Colormap); |
||
745 | break; |
||
746 | |||
747 | case FS4_DITHER: |
||
748 | InitColor (); |
||
749 | InitFS4Dither (); |
||
750 | InitColormap (&ColormapSize, &Colormap); |
||
751 | break; |
||
752 | |||
753 | case FS2_DITHER: |
||
754 | InitColor (); |
||
755 | InitFS2Dither (); |
||
756 | InitColormap (&ColormapSize, &Colormap); |
||
757 | break; |
||
758 | |||
759 | case FS2FAST_DITHER: |
||
760 | InitColor (); |
||
761 | InitFS2FastDither (); |
||
762 | InitColormap (&ColormapSize, &Colormap); |
||
763 | break; |
||
764 | |||
765 | case Twox2_DITHER: |
||
766 | InitColor (); |
||
767 | Init2x2Dither (); |
||
768 | InitColormap (&ColormapSize, &Colormap); |
||
769 | PostInit2x2Dither (); |
||
770 | break; |
||
771 | |||
772 | case GRAY_DITHER: |
||
773 | InitGrayColormap (&ColormapSize, &Colormap); |
||
774 | break; |
||
775 | case FULL_COLOR_DITHER: |
||
776 | #endif |
||
777 | wpixel[0]=red; |
||
778 | wpixel[1]=green; |
||
779 | wpixel[2]=blue; |
||
780 | InitColorDither(1); |
||
781 | #ifndef DISABLE_DITHER |
||
782 | break; |
||
783 | |||
784 | case NO_DITHER: |
||
785 | break; |
||
786 | |||
787 | case ORDERED_DITHER: |
||
788 | InitColor (); |
||
789 | InitOrderedDither (); |
||
790 | InitColormap (&ColormapSize, &Colormap); |
||
791 | break; |
||
792 | |||
793 | case MONO_DITHER: |
||
794 | case MONO_THRESHOLD: |
||
795 | break; |
||
796 | |||
797 | case ORDERED2_DITHER: |
||
798 | InitColor (); |
||
799 | InitColormap (&ColormapSize, &Colormap); |
||
800 | InitOrdered2Dither (); |
||
801 | break; |
||
802 | |||
803 | case MBORDERED_DITHER: |
||
804 | InitColor (); |
||
805 | InitColormap (&ColormapSize, &Colormap); |
||
806 | InitMBOrderedDither (); |
||
807 | break; |
||
808 | |||
809 | case PPM_DITHER: |
||
810 | ColormapSize = -1; |
||
811 | Colormap = NULL; |
||
812 | wpixel[0] = 0xff; |
||
813 | wpixel[1] = 0xff00; |
||
814 | wpixel[2] = 0xff0000; |
||
815 | vid_stream->matched_depth=24; |
||
816 | InitColorDither(TRUE); |
||
817 | break; |
||
818 | } |
||
819 | #endif |
||
820 | } |
||
821 | |||
822 | // |
||
823 | // |
||
824 | // |
||
825 | void |
||
826 | ANIMmpeg::InitStream() |
||
827 | { |
||
828 | if ((vid_stream->ditherType==FULL_COLOR_DITHER) || |
||
829 | (vid_stream->ditherType==PPM_DITHER)) { |
||
830 | vid_stream->matched_depth=24; |
||
831 | // InitColorDither(1); |
||
832 | } |
||
833 | } |