ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/freemol/trunk/src/mpeg_encode/src/iframe.c
Revision: 22
Committed: Mon Jul 7 22:16:37 2008 UTC (11 years, 1 month ago) by wdelano
File size: 31189 byte(s)
Log Message:
initial checkin of mpeg_encode source
Line File contents
1 /*===========================================================================*
2 * iframe.c *
3 * *
4 * Procedures concerned with the I-frame encoding *
5 * *
6 * EXPORTED PROCEDURES: *
7 * GenIFrame *
8 * SetSlicesPerFrame *
9 * SetBlocksPerSlice *
10 * SetIQScale *
11 * GetIQScale *
12 * ResetIFrameStats *
13 * ShowIFrameSummary *
14 * EstimateSecondsPerIFrame *
15 * EncodeYDC *
16 * EncodeCDC *
17 * time_elapsed *
18 * *
19 *===========================================================================*/
20
21 /*
22 * Copyright (c) 1995 The Regents of the University of California.
23 * All rights reserved.
24 *
25 * Permission to use, copy, modify, and distribute this software and its
26 * documentation for any purpose, without fee, and without written agreement is
27 * hereby granted, provided that the above copyright notice and the following
28 * two paragraphs appear in all copies of this software.
29 *
30 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
31 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
32 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
33 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
36 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
38 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
39 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
40 */
41
42 /*
43 * $Header: /n/picasso/project/mpeg/mpeg_dist/mpeg_encode/RCS/iframe.c,v 1.23 1995/08/14 22:29:49 smoot Exp $
44 * $Log: iframe.c,v $
45 * Revision 1.23 1995/08/14 22:29:49 smoot
46 * changed inits in BlockComputeSNR so sgi compiler would be happy
47 *
48 * Revision 1.22 1995/08/07 21:50:51 smoot
49 * spacing
50 * simplified some code
51 * added Laplace stuff
52 * minor error check bug in alloc
53 *
54 * Revision 1.21 1995/06/21 22:24:25 smoot
55 * added CalcDistortion (TUNEing)
56 * fixed timeing stuff for ANSI
57 * fixed specifics bug
58 *
59 * Revision 1.20 1995/05/02 21:59:43 smoot
60 * fixed BlockComputeSNR bugs
61 *
62 * Revision 1.19 1995/04/24 23:02:50 smoot
63 * Fixed BlockComputeSNR for Linux and others
64 *
65 * Revision 1.18 1995/04/14 23:08:02 smoot
66 * reorganized to ease rate control experimentation
67 *
68 * Revision 1.17 1995/02/24 23:49:38 smoot
69 * added support for Specifics file version 2
70 *
71 * Revision 1.16 1995/01/30 20:02:34 smoot
72 * cleanup, killed a couple warnings
73 *
74 * Revision 1.15 1995/01/30 19:49:17 smoot
75 * cosmetic
76 *
77 * Revision 1.14 1995/01/23 02:49:34 darryl
78 * initialized variable
79 *
80 * Revision 1.13 1995/01/19 23:08:30 eyhung
81 * Changed copyrights
82 *
83 * Revision 1.12 1995/01/16 08:01:34 eyhung
84 * Added realQuiet
85 *
86 * Revision 1.11 1994/12/07 00:40:36 smoot
87 * Added seperate P and B search ranges
88 *
89 * Revision 1.10 1994/11/14 22:30:30 smoot
90 * Merged specifics and rate control
91 *
92 * Revision 1.9 1994/11/01 05:00:48 darryl
93 * with rate control changes added
94 *
95 * Revision 2.2 1994/10/31 00:06:07 darryl
96 * version before, hopefully, final changes
97 *
98 * Revision 2.1 1994/10/24 22:03:01 darryl
99 * put in preliminary experiments code
100 *
101 * Revision 2.0 1994/10/24 02:38:04 darryl
102 * will be adding the experiment stuff.
103 *
104 * Revision 1.1 1994/09/27 00:15:24 darryl
105 * Initial revision
106 *
107 * Revision 1.8 1994/03/15 00:27:11 keving
108 * nothing
109 *
110 * Revision 1.7 1993/12/22 19:19:01 keving
111 * nothing
112 *
113 * Revision 1.6 1993/07/22 22:23:43 keving
114 * nothing
115 *
116 * Revision 1.5 1993/06/30 20:06:09 keving
117 * nothing
118 *
119 * Revision 1.4 1993/06/03 21:08:08 keving
120 * nothing
121 *
122 * Revision 1.3 1993/03/04 22:24:06 keving
123 * nothing
124 *
125 * Revision 1.2 1993/02/19 18:10:02 keving
126 * nothing
127 *
128 * Revision 1.1 1993/02/18 22:56:39 keving
129 * nothing
130 *
131 *
132 */
133
134
135 /*==============*
136 * HEADER FILES *
137 *==============*/
138
139
140 #ifdef CLOCKS_PER_SEC
141 #include <times.h>
142 #else
143 #include <sys/times.h>
144 #endif
145
146 #include <sys/param.h>
147 #include "all.h"
148 #include "mtypes.h"
149 #include "frames.h"
150 #include "prototypes.h"
151 #include "mpeg.h"
152 #include "param.h"
153 #include "mheaders.h"
154 #include "fsize.h"
155 #include "parallel.h"
156 #include "postdct.h"
157 #include "rate.h"
158 #include "opts.h"
159
160 /*==================*
161 * STATIC VARIABLES *
162 *==================*/
163
164 static int lastNumBits = 0;
165 static int lastIFrame = 0;
166 static int numBlocks = 0;
167 static int numBits;
168 static int numFrames = 0;
169 static int numFrameBits = 0;
170 static int32 totalTime = 0;
171 static float totalSNR = 0.0;
172 static float totalPSNR = 0.0;
173
174 static int lengths[256] = {
175 0, 1, 2, 2, 3, 3, 3, 3, /* 0 - 7 */
176 4, 4, 4, 4, 4, 4, 4, 4, /* 8 - 15 */
177 5, 5, 5, 5, 5, 5, 5, 5, /* 16 - 31 */
178 5, 5, 5, 5, 5, 5, 5, 5,
179 6, 6, 6, 6, 6, 6, 6, 6, /* 32 - 63 */
180 6, 6, 6, 6, 6, 6, 6, 6,
181 6, 6, 6, 6, 6, 6, 6, 6,
182 6, 6, 6, 6, 6, 6, 6, 6,
183 7, 7, 7, 7, 7, 7, 7, 7, /* 64 - 127 */
184 7, 7, 7, 7, 7, 7, 7, 7,
185 7, 7, 7, 7, 7, 7, 7, 7,
186 7, 7, 7, 7, 7, 7, 7, 7,
187 7, 7, 7, 7, 7, 7, 7, 7,
188 7, 7, 7, 7, 7, 7, 7, 7,
189 7, 7, 7, 7, 7, 7, 7, 7,
190 7, 7, 7, 7, 7, 7, 7, 7,
191 8, 8, 8, 8, 8, 8, 8, 8,
192 8, 8, 8, 8, 8, 8, 8, 8,
193 8, 8, 8, 8, 8, 8, 8, 8,
194 8, 8, 8, 8, 8, 8, 8, 8,
195 8, 8, 8, 8, 8, 8, 8, 8,
196 8, 8, 8, 8, 8, 8, 8, 8,
197 8, 8, 8, 8, 8, 8, 8, 8,
198 8, 8, 8, 8, 8, 8, 8, 8,
199 8, 8, 8, 8, 8, 8, 8, 8,
200 8, 8, 8, 8, 8, 8, 8, 8,
201 8, 8, 8, 8, 8, 8, 8, 8,
202 8, 8, 8, 8, 8, 8, 8, 8,
203 8, 8, 8, 8, 8, 8, 8, 8,
204 8, 8, 8, 8, 8, 8, 8, 8,
205 8, 8, 8, 8, 8, 8, 8, 8,
206 8, 8, 8, 8, 8, 8, 8, 8
207 };
208
209
210 /*==================*
211 * GLOBAL VARIABLES *
212 *==================*/
213
214 int qscaleI;
215 int slicesPerFrame;
216 int blocksPerSlice;
217 int fCodeI, fCodeP, fCodeB;
218 boolean printSNR = FALSE;
219 boolean printMSE = FALSE;
220 boolean decodeRefFrames = FALSE;
221 Block **dct=NULL, **dctr=NULL, **dctb=NULL;
222 dct_data_type **dct_data; /* used in p/bframe.c */
223 int TIME_RATE;
224
225
226 /*=====================*
227 * EXPORTED PROCEDURES *
228 *=====================*/
229 extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum));
230
231 /*===============================*
232 * INTERNAL PROCEDURE prototypes *
233 *===============================*/
234 void AllocDctBlocks _ANSI_ARGS_((void ));
235 int SetFCodeHelper _ANSI_ARGS_((int sr));
236 void CalcDistortion _ANSI_ARGS_((MpegFrame *current, int y, int x));
237
238 int
239 SetFCodeHelper(SR)
240 int SR;
241 {
242 int range,fCode;
243
244 if ( pixelFullSearch ) {
245 range = SR;
246 } else {
247 range = SR*2;
248 }
249
250 if ( range < 256 ) {
251 if ( range < 64 ) {
252 if ( range < 32 ) {
253 fCode = 1;
254 } else {
255 fCode = 2;
256 }
257 } else {
258 if ( range < 128 ) {
259 fCode = 3;
260 } else {
261 fCode = 4;
262 }
263 }
264 } else {
265 if ( range < 1024 ) {
266 if ( range < 512 ) {
267 fCode = 5;
268 } else {
269 fCode = 6;
270 }
271 } else {
272 if ( range < 2048 ) {
273 fCode = 7;
274 } else {
275 fprintf(stderr, "ERROR: INVALID SEARCH RANGE!!!\n");
276 exit(1);
277 }
278 }
279 }
280 return fCode;
281 }
282
283 /*===========================================================================*
284 *
285 * SetFCode
286 *
287 * set the forward_f_code and backward_f_code according to the search
288 * range. Must be called AFTER pixelFullSearch and searchRange have
289 * been initialized. Irrelevant for I-frames, but computation is
290 * negligible (done only once, as well)
291 *
292 * RETURNS: nothing
293 *
294 * SIDE EFFECTS: fCodeI,fCodeP,fCodeB
295 *
296 *===========================================================================*/
297 void
298 SetFCode()
299 {
300 fCodeI = SetFCodeHelper(1); /* GenIFrame ignores value */
301 fCodeP = SetFCodeHelper(searchRangeP);
302 fCodeB = SetFCodeHelper(searchRangeB);
303 }
304
305 /*===========================================================================*
306 *
307 * SetSlicesPerFrame
308 *
309 * set the number of slices per frame
310 *
311 * RETURNS: nothing
312 *
313 * SIDE EFFECTS: slicesPerFrame
314 *
315 *===========================================================================*/
316 void
317 SetSlicesPerFrame(number)
318 int number;
319 {
320 slicesPerFrame = number;
321 }
322
323
324 /*===========================================================================*
325 *
326 * SetBlocksPerSlice
327 *
328 * set the number of blocks per slice, based on slicesPerFrame
329 *
330 * RETURNS: nothing
331 *
332 * SIDE EFFECTS: blocksPerSlice
333 *
334 *===========================================================================*/
335 void
336 SetBlocksPerSlice()
337 {
338 int totalBlocks;
339
340 totalBlocks = (Fsize_y>>4)*(Fsize_x>>4);
341
342 if ( slicesPerFrame > totalBlocks ) {
343 blocksPerSlice = 1;
344 } else {
345 blocksPerSlice = totalBlocks/slicesPerFrame;
346 }
347 }
348
349
350 /*===========================================================================*
351 *
352 * SetIQScale
353 *
354 * set the I-frame Q-scale
355 *
356 * RETURNS: nothing
357 *
358 * SIDE EFFECTS: qscaleI
359 *
360 *===========================================================================*/
361 void
362 SetIQScale(qI)
363 int qI;
364 {
365 qscaleI = qI;
366 }
367
368 /*===========================================================================*
369 *
370 * GetIQScale
371 *
372 * Get the I-frame Q-scale
373 *
374 * RETURNS: the Iframe Qscale
375 *
376 * SIDE EFFECTS: none
377 *
378 *===========================================================================*/
379 int
380 GetIQScale()
381 {
382 return qscaleI;
383 }
384
385 /*===========================================================================*
386 *
387 * GenIFrame
388 *
389 * generate an I-frame; appends result to bb
390 *
391 * RETURNS: I-frame appended to bb
392 *
393 * SIDE EFFECTS: none
394 *
395 *===========================================================================*/
396 void
397 GenIFrame(bb, current)
398 BitBucket *bb;
399 MpegFrame *current;
400 {
401 register int x, y;
402 register int index;
403 FlatBlock fb[6];
404 Block dec[6];
405 int32 y_dc_pred, cr_dc_pred, cb_dc_pred;
406 int totalBits;
407 int totalFrameBits;
408 int32 startTime, endTime;
409 float snr[3], psnr[3];
410 int mbAddress;
411 int QScale;
412 BlockMV *info; /* Not used in Iframes, but nice to pass in anyway */
413 int bitstreamMode, newQScale;
414 int rc_blockStart=0;
415
416 if (dct==NULL) AllocDctBlocks();
417 if (collect_quant) {fprintf(collect_quant_fp, "# I\n");}
418
419 /* set-up for statistics */
420 numFrames++;
421 totalFrameBits = bb->cumulativeBits;
422 if ( ( ! childProcess) && showBitRatePerFrame ) {
423 if ( lastNumBits == 0 ) {
424 lastNumBits = bb->cumulativeBits;
425 lastIFrame = current->id;
426 } else {
427 /* ASSUMES 30 FRAMES PER SECOND */
428
429 if (! realQuiet) {
430 fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
431 lastIFrame, current->id-1,
432 ((bb->cumulativeBits-lastNumBits)*30)/
433 (current->id-lastIFrame));
434 }
435
436 fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
437 lastIFrame, current->id-1,
438 ((bb->cumulativeBits-lastNumBits)*30)/
439 (current->id-lastIFrame));
440 lastNumBits = bb->cumulativeBits;
441 lastIFrame = current->id;
442 }
443 }
444
445 startTime = time_elapsed();
446
447 Frame_AllocBlocks(current);
448 BlockifyFrame(current);
449
450 DBG_PRINT(("Generating iframe\n"));
451 QScale = GetIQScale();
452 /* Allocate bits for this frame for rate control purposes */
453 bitstreamMode = getRateMode();
454 if (bitstreamMode == FIXED_RATE) {
455 targetRateControl(current);
456 }
457
458 Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCodeI);
459 /* Check for Qscale change */
460 if (specificsOn) {
461 newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info, QScale);
462 if (newQScale != -1) {
463 QScale = newQScale;
464 }
465 /* check for slice */
466 newQScale = SpecLookup(current->id, 1, 1, &info, QScale);
467 if (newQScale != -1) {
468 QScale = newQScale;
469 }
470 }
471 Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0);
472
473 if ( referenceFrame == DECODED_FRAME ) {
474 Frame_AllocDecoded(current, TRUE);
475 } else if ( printSNR ) {
476 Frame_AllocDecoded(current, FALSE);
477 }
478
479 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
480 totalBits = bb->cumulativeBits;
481 mbAddress = 0;
482
483 /* DCT the macroblocks */
484 for (y = 0; y < (Fsize_y >> 3); y += 2) {
485 for (x = 0; x < (Fsize_x >> 3); x += 2) {
486 if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n");
487 if (DoLaplace) {LaplaceCnum = 0;}
488 mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]);
489 mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]);
490 mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]);
491 mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]);
492 if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n");
493 if (DoLaplace) {LaplaceCnum = 1;}
494 mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]);
495 if (DoLaplace) {LaplaceCnum = 2;}
496 mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]);
497 }}
498
499 if (DoLaplace) {
500 extern void CalcLambdas();
501 CalcLambdas();
502 }
503
504 for (y = 0; y < (Fsize_y >> 3); y += 2) {
505 for (x = 0; x < (Fsize_x >> 3); x += 2) {
506 /* Check for Qscale change */
507 if (specificsOn) {
508 newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale);
509 if (newQScale != -1) {
510 QScale = newQScale;
511 }
512 }
513
514 /* Determine if new Qscale needed for Rate Control purposes */
515 if (bitstreamMode == FIXED_RATE) {
516 rc_blockStart = bb->cumulativeBits;
517 newQScale = needQScaleChange(qscaleI,
518 current->y_blocks[y][x],
519 current->y_blocks[y][x+1],
520 current->y_blocks[y+1][x],
521 current->y_blocks[y+1][x+1]);
522 if (newQScale > 0) {
523 QScale = newQScale;
524 }
525 }
526
527 if ( (mbAddress % blocksPerSlice == 0) && (mbAddress != 0) ) {
528 /* create a new slice */
529 if (specificsOn) {
530 /* Make sure no slice Qscale change */
531 newQScale = SpecLookup(current->id,1,mbAddress/blocksPerSlice, &info, QScale);
532 if (newQScale != -1) QScale = newQScale;
533 }
534 Mhead_GenSliceEnder(bb);
535 Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0);
536 y_dc_pred = cr_dc_pred = cb_dc_pred = 128;
537
538 GEN_I_BLOCK(I_FRAME, current, bb, 1+(x>>1), QScale);
539 } else {
540 GEN_I_BLOCK(I_FRAME, current, bb, 1, QScale);
541 }
542
543 if (WriteDistortionNumbers) {
544 CalcDistortion(current, y, x);
545 }
546
547 if ( decodeRefFrames ) {
548 /* now, reverse the DCT transform */
549 LaplaceCnum = 0;
550 for ( index = 0; index < 6; index++ ) {
551 if (!DoLaplace) {
552 Mpost_UnQuantZigBlock(fb[index], dec[index], QScale, TRUE);
553 } else {
554 if (index == 4) {LaplaceCnum = 1;}
555 if (index == 5) {LaplaceCnum = 2;}
556 Mpost_UnQuantZigBlockLaplace(fb[index], dec[index], QScale, TRUE);
557 }
558 mpeg_jrevdct((int16 *)dec[index]);
559 }
560
561 /* now, unblockify */
562 BlockToData(current->decoded_y, dec[0], y, x);
563 BlockToData(current->decoded_y, dec[1], y, x+1);
564 BlockToData(current->decoded_y, dec[2], y+1, x);
565 BlockToData(current->decoded_y, dec[3], y+1, x+1);
566 BlockToData(current->decoded_cb, dec[4], y>>1, x>>1);
567 BlockToData(current->decoded_cr, dec[5], y>>1, x>>1);
568 }
569
570 numBlocks++;
571 mbAddress++;
572 /* Rate Control */
573 if (bitstreamMode == FIXED_RATE) {
574 incMacroBlockBits(bb->cumulativeBits - rc_blockStart);
575 rc_blockStart = bb->cumulativeBits;
576 MB_RateOut(TYPE_IFRAME);
577 }
578 }
579 }
580
581 if ( printSNR ) {
582 BlockComputeSNR(current,snr,psnr);
583 totalSNR += snr[0];
584 totalPSNR += psnr[0];
585 }
586
587 if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) {
588 if ( remoteIO ) {
589 SendDecodedFrame(current);
590 } else {
591 WriteDecodedFrame(current);
592 }
593
594 /* now, tell decode server it is ready */
595 NotifyDecodeServerReady(current->id);
596 }
597
598 numBits += (bb->cumulativeBits-totalBits);
599
600 DBG_PRINT(("End of frame\n"));
601
602 Mhead_GenSliceEnder(bb);
603 /* Rate Control */
604 if (bitstreamMode == FIXED_RATE) {
605 updateRateControl(TYPE_IFRAME);
606 }
607
608 endTime = time_elapsed();
609 totalTime += (endTime-startTime);
610
611 numFrameBits += (bb->cumulativeBits-totalFrameBits);
612
613 if ( ( ! childProcess) && showBitRatePerFrame ) {
614 /* ASSUMES 30 FRAMES PER SECOND */
615 fprintf(bitRateFile, "%5d\t%8d\n", current->id,
616 30*(bb->cumulativeBits-totalFrameBits));
617 }
618
619 if ( (! childProcess) && frameSummary && (! realQuiet) ) {
620
621 /* ASSUMES 30 FRAMES PER SECOND */
622 fprintf(stdout, "FRAME %d (I): %ld seconds (%d bits/s output)\n",
623 current->id, (long)((endTime-startTime)/TIME_RATE),
624 30*(bb->cumulativeBits-totalFrameBits));
625 if ( printSNR ) {
626 fprintf(stdout, "FRAME %d: SNR: %.1f\t%.1f\t%.1f\tPSNR: %.1f\t%.1f\t%.1f\n",
627 current->id, snr[0], snr[1], snr[2],
628 psnr[0], psnr[1], psnr[2]);
629 }
630 }
631 }
632
633
634 /*===========================================================================*
635 *
636 * ResetIFrameStats
637 *
638 * reset the I-frame statistics
639 *
640 * RETURNS: nothing
641 *
642 * SIDE EFFECTS: none
643 *
644 *===========================================================================*/
645 void
646 ResetIFrameStats()
647 {
648 numBlocks = 0;
649 numBits = 0;
650 numFrames = 0;
651 numFrameBits = 0;
652 totalTime = 0;
653 }
654
655
656 /*===========================================================================*
657 *
658 * ShowIFrameSummary
659 *
660 * prints out statistics on all I-frames
661 *
662 * RETURNS: time taken for I-frames (in seconds)
663 *
664 * SIDE EFFECTS: none
665 *
666 *===========================================================================*/
667 float
668 ShowIFrameSummary(inputFrameBits, totalBits, fpointer)
669 int inputFrameBits;
670 int32 totalBits;
671 FILE *fpointer;
672 {
673 if ( numFrames == 0 ) {
674 return 0.0;
675 }
676
677 fprintf(fpointer, "-------------------------\n");
678 fprintf(fpointer, "*****I FRAME SUMMARY*****\n");
679 fprintf(fpointer, "-------------------------\n");
680
681 fprintf(fpointer, " Blocks: %5d (%6d bits) (%5d bpb)\n",
682 numBlocks, numBits, numBits/numBlocks);
683 fprintf(fpointer, " Frames: %5d (%6d bits) (%5d bpf) (%2.1f%% of total)\n",
684 numFrames, numFrameBits, numFrameBits/numFrames,
685 100.0*(float)numFrameBits/(float)totalBits);
686 fprintf(fpointer, " Compression: %3d:1 (%9.4f bpp)\n",
687 numFrames*inputFrameBits/numFrameBits,
688 24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits));
689 if ( printSNR )
690 fprintf(fpointer, " Avg Y SNR/PSNR: %.1f %.1f\n",
691 totalSNR/(float)numFrames, totalPSNR/(float)numFrames);
692 if ( totalTime == 0 ) {
693 fprintf(fpointer, " Seconds: NONE\n");
694 } else {
695 fprintf(fpointer, " Seconds: %9ld (%9.4f fps) (%9ld pps) (%9ld mps)\n",
696 (long)(totalTime/TIME_RATE),
697 (float)((float)(TIME_RATE*numFrames)/(float)totalTime),
698 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)),
699 (long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime)));
700 }
701
702 return (float)totalTime/(float)TIME_RATE;
703 }
704
705
706 /*===========================================================================*
707 *
708 * EstimateSecondsPerIFrame
709 *
710 * estimates the number of seconds required per I-frame
711 *
712 * RETURNS: seconds (floating point value)
713 *
714 * SIDE EFFECTS: none
715 *
716 *===========================================================================*/
717 float
718 EstimateSecondsPerIFrame()
719 {
720 return (float)totalTime/((float)TIME_RATE*(float)numFrames);
721 }
722
723
724 /*===========================================================================*
725 *
726 * EncodeYDC
727 *
728 * Encode the DC portion of a DCT of a luminance block
729 *
730 * RETURNS: result appended to bb
731 *
732 * SIDE EFFECTS: updates pred_term
733 *
734 *===========================================================================*/
735 void
736 EncodeYDC(dc_term, pred_term, bb)
737 int32 dc_term;
738 int32 *pred_term;
739 BitBucket *bb;
740 {
741 /* see Table B.5a -- MPEG-I doc */
742 static int codes[9] = {
743 0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e
744 };
745 static int codeLengths[9] = {
746 3, 2, 2, 3, 3, 4, 5, 6, 7
747 };
748 int ydiff, ydiff_abs;
749 int length;
750
751 ydiff = (dc_term - (*pred_term));
752 if (ydiff > 255) {
753 #ifdef BLEAH
754 fprintf(stdout, "TRUNCATED\n");
755 #endif
756 ydiff = 255;
757 } else if (ydiff < -255) {
758 #ifdef BLEAH
759 fprintf(stdout, "TRUNCATED\n");
760 #endif
761 ydiff = -255;
762 }
763
764 ydiff_abs = ABS(ydiff);
765 length = lengths[ydiff_abs];
766 Bitio_Write(bb, codes[length], codeLengths[length]);
767 if ( length != 0 ) {
768 if ( ydiff > 0 ) {
769 Bitio_Write(bb, ydiff_abs, length);
770 } else {
771 Bitio_Write(bb, ~ydiff_abs, length);
772 }
773 }
774
775 (*pred_term) += ydiff;
776 }
777
778
779 /*===========================================================================*
780 *
781 * EncodeCDC
782 *
783 * Encode the DC portion of a DCT of a chrominance block
784 *
785 * RETURNS: result appended to bb
786 *
787 * SIDE EFFECTS: updates pred_term
788 *
789 *===========================================================================*/
790 void
791 EncodeCDC(dc_term, pred_term, bb)
792 int32 dc_term;
793 int32 *pred_term;
794 BitBucket *bb;
795 {
796 /* see Table B.5b -- MPEG-I doc */
797 static int codes[9] = {
798 0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe
799 };
800 static int codeLengths[9] = {
801 2, 2, 2, 3, 4, 5, 6, 7, 8
802 };
803 int cdiff, cdiff_abs;
804 int length;
805
806 cdiff = (dc_term - (*pred_term));
807 if (cdiff > 255) {
808 #ifdef BLEAH
809 fprintf(stdout, "TRUNCATED\n");
810 #endif
811 cdiff = 255;
812 } else if (cdiff < -255) {
813 #ifdef BLEAH
814 fprintf(stdout, "TRUNCATED\n");
815 #endif
816 cdiff = -255;
817 }
818
819 cdiff_abs = ABS(cdiff);
820 length = lengths[cdiff_abs];
821 Bitio_Write(bb, codes[length], codeLengths[length]);
822 if ( length != 0 ) {
823 if ( cdiff > 0 ) {
824 Bitio_Write(bb, cdiff_abs, length);
825 } else {
826 Bitio_Write(bb, ~cdiff_abs, length);
827 }
828 }
829
830 (*pred_term) += cdiff;
831 }
832
833
834 void
835 BlockComputeSNR(current, snr, psnr)
836 MpegFrame *current;
837 float snr[];
838 float psnr[];
839 {
840 register int32 tempInt;
841 register int y, x;
842 int32 varDiff[3];
843 double ratio[3];
844 double total[3];
845 register uint8 **origY=current->orig_y, **origCr=current->orig_cr,
846 **origCb=current->orig_cb;
847 register uint8 **newY=current->decoded_y, **newCr=current->decoded_cr,
848 **newCb=current->decoded_cb;
849 static int32 **SignalY, **NoiseY;
850 static int32 **SignalCb, **NoiseCb;
851 static int32 **SignalCr, **NoiseCr;
852 static short ySize[3], xSize[3];
853 static boolean needs_init=TRUE;
854
855 /* Init */
856 if (needs_init) {
857 int ysz = (Fsize_y>>3) * sizeof(int32 *);
858 int xsz = (Fsize_x>>3);
859
860 needs_init = FALSE;
861 for (y=0; y<3; y++) {
862 varDiff[y] = ratio[y] = total[y] = 0.0;
863 }
864 ySize[0]=Fsize_y; xSize[0]=Fsize_x;
865 ySize[1]=Fsize_y>>1; xSize[1]=Fsize_x>>1;
866 ySize[2]=Fsize_y>>1; xSize[2]=Fsize_x>>1;
867 SignalY = (int32 **) malloc(ysz);
868 NoiseY = (int32 **) malloc(ysz);
869 SignalCb = (int32 **) malloc(ysz);
870 NoiseCb = (int32 **) malloc(ysz);
871 SignalCr = (int32 **) malloc(ysz);
872 NoiseCr = (int32 **) malloc(ysz);
873 if (SignalY == NULL || NoiseY == NULL || SignalCr == NULL ||
874 NoiseCb == NULL || SignalCb == NULL || NoiseCr == NULL) {
875 fprintf(stderr, "Out of memory in BlockComputeSNR\n");
876 exit(-1);
877 }
878 for (y = 0; y < ySize[0]>>3; y++) {
879 SignalY[y] = (int32 *) calloc(xsz,4);
880 SignalCr[y] = (int32 *) calloc(xsz,4);
881 SignalCb[y] = (int32 *) calloc(xsz,4);
882 NoiseY[y] = (int32 *) calloc(xsz,4);
883 NoiseCr[y] = (int32 *) calloc(xsz,4);
884 NoiseCb[y] = (int32 *) calloc(xsz,4);
885 }
886 } else {
887 for (y = 0; y < ySize[0]>>3; y++) {
888 memset((char *) &NoiseY[y][0], 0, (xSize[0]>>3) * 4);
889 memset((char *) &SignalY[y][0], 0, (xSize[0]>>3) * 4);
890 memset((char *) &NoiseCb[y][0], 0, (xSize[0]>>3) * 4);
891 memset((char *) &NoiseCr[y][0], 0, (xSize[0]>>3) * 4);
892 memset((char *) &SignalCb[y][0], 0, (xSize[0]>>3) * 4);
893 memset((char *) &SignalCr[y][0], 0, (xSize[0]>>3) * 4);
894 }
895 }
896
897 /* find all the signal and noise */
898 for (y = 0; y < ySize[0]; y++) {
899 for (x = 0; x < xSize[0]; x++) {
900 tempInt = (origY[y][x] - newY[y][x]);
901 NoiseY[y>>4][x>>4] += tempInt*tempInt;
902 total[0] += (double)abs(tempInt);
903 tempInt = origY[y][x];
904 SignalY[y>>4][x>>4] += tempInt*tempInt;
905 }}
906 for (y = 0; y < ySize[1]; y++) {
907 for (x = 0; x < xSize[1]; x ++) {
908 tempInt = (origCb[y][x] - newCb[y][x]);
909 NoiseCb[y>>3][x>>3] += tempInt*tempInt;
910 total[1] += (double)abs(tempInt);
911 tempInt = origCb[y][x];
912 SignalCb[y>>3][x>>3] += tempInt*tempInt;
913 tempInt = (origCr[y][x]-newCr[y][x]);
914 NoiseCr[y>>3][x>>3] += tempInt*tempInt;
915 total[2] += (double)abs(tempInt);
916 tempInt = origCr[y][x];
917 SignalCr[y>>3][x>>3] += tempInt*tempInt;
918 }}
919
920 /* Now sum up that noise */
921 for(y=0; y<Fsize_y>>4; y++){
922 for(x=0; x<Fsize_x>>4; x++){
923 varDiff[0] += NoiseY[y][x];
924 varDiff[1] += NoiseCb[y][x];
925 varDiff[2] += NoiseCr[y][x];
926 if (printMSE) printf("%4d ",(int)(NoiseY[y][x]/256.0));
927 }
928 if (printMSE) puts("");
929 }
930
931 /* Now look at those ratios! */
932 for(y=0; y<Fsize_y>>4; y++){
933 for(x=0; x<Fsize_x>>4; x++){
934 ratio[0] += (double)SignalY[y][x]/(double)varDiff[0];
935 ratio[1] += (double)SignalCb[y][x]/(double)varDiff[1];
936 ratio[2] += (double)SignalCr[y][x]/(double)varDiff[2];
937 }}
938
939 for (x=0; x<3; x++) {
940 snr[x] = 10.0*log10(ratio[x]);
941 psnr[x] = 20.0*log10(255.0/sqrt((double)varDiff[x]/(double)(ySize[x]*xSize[x])));
942
943 if (! realQuiet) {
944 fprintf(stdout, "Mean error[%1d]: %f\n", x, total[x]/(double)(xSize[x]*ySize[x]));
945 }
946
947 }
948 }
949
950 void
951 WriteDecodedFrame(frame)
952 MpegFrame *frame;
953 {
954 FILE *fpointer;
955 char fileName[256];
956 int width, height;
957 register int y;
958
959 /* need to save decoded frame to disk because it might be accessed
960 by another process */
961
962 width = Fsize_x;
963 height = Fsize_y;
964
965 sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id);
966
967 if (!realQuiet) {
968 fprintf(stdout, "Outputting to %s\n", fileName);
969 fflush(stdout);
970 }
971
972 fpointer = fopen(fileName, "wb");
973
974 for ( y = 0; y < height; y++ ) {
975 fwrite(frame->decoded_y[y], 1, width, fpointer);
976 }
977
978 for (y = 0; y < (height >> 1); y++) { /* U */
979 fwrite(frame->decoded_cb[y], 1, width >> 1, fpointer);
980 }
981
982 for (y = 0; y < (height >> 1); y++) { /* V */
983 fwrite(frame->decoded_cr[y], 1, width >> 1, fpointer);
984 }
985 fflush(fpointer);
986 fclose(fpointer);
987 }
988
989
990 void
991 PrintItoIBitRate(numBits, frameNum)
992 int numBits;
993 int frameNum;
994 {
995 if ( ( ! childProcess) && showBitRatePerFrame ) {
996 /* ASSUMES 30 FRAMES PER SECOND */
997
998 if (! realQuiet) {
999 fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
1000 lastIFrame, frameNum-1,
1001 ((numBits-lastNumBits)*30)/
1002 (frameNum-lastIFrame));
1003 }
1004
1005 fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n",
1006 lastIFrame, frameNum-1,
1007 ((numBits-lastNumBits)*30)/
1008 (frameNum-lastIFrame));
1009 }
1010 }
1011
1012
1013 /*===========================================================================*
1014 *
1015 * AllocDctBlocks
1016 *
1017 * allocate memory for dct blocks
1018 *
1019 * RETURNS: nothing
1020 *
1021 * SIDE EFFECTS: creates dct, dctr, dctb
1022 *
1023 *===========================================================================*/
1024 void
1025 AllocDctBlocks()
1026 {
1027 int dctx, dcty;
1028 int i;
1029
1030 dctx = Fsize_x / DCTSIZE;
1031 dcty = Fsize_y / DCTSIZE;
1032
1033 dct = (Block **) malloc(sizeof(Block *) * dcty);
1034 ERRCHK(dct, "malloc");
1035 for (i = 0; i < dcty; i++) {
1036 dct[i] = (Block *) malloc(sizeof(Block) * dctx);
1037 ERRCHK(dct[i], "malloc");
1038 }
1039
1040 dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty);
1041 ERRCHK(dct_data, "malloc");
1042 for (i = 0; i < dcty; i++) {
1043 dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx);
1044 ERRCHK(dct[i], "malloc");
1045 }
1046
1047 dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
1048 dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1));
1049 ERRCHK(dctr, "malloc");
1050 ERRCHK(dctb, "malloc");
1051 for (i = 0; i < (dcty >> 1); i++) {
1052 dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
1053 dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1));
1054 ERRCHK(dctr[i], "malloc");
1055 ERRCHK(dctb[i], "malloc");
1056 }
1057 }
1058
1059
1060 /*======================================================================*
1061 *
1062 * time_elapsed
1063 *
1064 * Handle different time systems on different machines
1065 *
1066 * RETURNS number of seconds process time used
1067 *
1068 *======================================================================*/
1069 int32 time_elapsed()
1070 {
1071 #ifdef CLOCKS_PER_SEC
1072 /* ANSI C */
1073 TIME_RATE = CLOCKS_PER_SEC;
1074 return (int32) clock();
1075 #else
1076 struct tms timeBuffer;
1077 TIME_RATE = 60;
1078 times(&timeBuffer);
1079 return timeBuffer.tms_utime + timeBuffer.tms_stime;
1080 #endif
1081 }
1082
1083
1084 void
1085 CalcDistortion(current, y, x)
1086 MpegFrame *current;
1087 int y,x;
1088 {
1089
1090 int qscale, distort=0;
1091 Block decblk;
1092 FlatBlock fblk;
1093 int datarate = 0;
1094
1095 for (qscale = 1; qscale < 32; qscale ++) {
1096 distort = 0;
1097 datarate = 0;
1098 Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE);
1099 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1100 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1101 mpeg_jrevdct((int16 *)decblk);
1102 distort += mse(current->y_blocks[y][x], decblk);
1103
1104 Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE);
1105 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1106 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1107 mpeg_jrevdct((int16 *)decblk);
1108 distort += mse(current->y_blocks[y][x+1], decblk);
1109
1110 Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE);
1111 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1112 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1113 mpeg_jrevdct((int16 *)decblk);
1114 distort += mse(current->y_blocks[y+1][x], decblk);
1115
1116 Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE);
1117 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1118 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1119 mpeg_jrevdct((int16 *)decblk);
1120 distort += mse(current->y_blocks[y+1][x+1], decblk);
1121
1122 Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE);
1123 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1124 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1125 mpeg_jrevdct((int16 *)decblk);
1126 distort += mse(current->cb_blocks[y>>1][x>>1], decblk);
1127
1128 Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE);
1129 Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE);
1130 if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk);
1131 mpeg_jrevdct((int16 *)decblk);
1132 distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk);
1133
1134 if (!collect_distortion_detailed) {
1135 fprintf(distortion_fp, "\t%d\n", distort);
1136 } else if (collect_distortion_detailed == 1) {
1137 fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate);
1138 } else {
1139 fprintf(fp_table_rate[qscale-1], "%d\n", datarate);
1140 fprintf(fp_table_dist[qscale-1], "%d\n", distort);
1141 }
1142 }
1143 }