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 |
#ifdef WIN32 |
140 |
#define CLOCKS_PER_SEC 1000 |
141 |
#else |
142 |
#ifdef CLOCKS_PER_SEC |
143 |
#include <times.h> |
144 |
#else |
145 |
#include <sys/times.h> |
146 |
#endif |
147 |
#endif |
148 |
|
149 |
#include <sys/param.h> |
150 |
#include "all.h" |
151 |
#include "mtypes.h" |
152 |
#include "frames.h" |
153 |
#include "prototypes.h" |
154 |
#include "mpeg.h" |
155 |
#include "param.h" |
156 |
#include "mheaders.h" |
157 |
#include "fsize.h" |
158 |
#include "parallel.h" |
159 |
#include "postdct.h" |
160 |
#include "rate.h" |
161 |
#include "opts.h" |
162 |
|
163 |
/*==================* |
164 |
* STATIC VARIABLES * |
165 |
*==================*/ |
166 |
|
167 |
static int lastNumBits = 0; |
168 |
static int lastIFrame = 0; |
169 |
static int numBlocks = 0; |
170 |
static int numBits; |
171 |
static int numFrames = 0; |
172 |
static int numFrameBits = 0; |
173 |
static int32 totalTime = 0; |
174 |
static float totalSNR = 0.0; |
175 |
static float totalPSNR = 0.0; |
176 |
|
177 |
static int lengths[256] = { |
178 |
0, 1, 2, 2, 3, 3, 3, 3, /* 0 - 7 */ |
179 |
4, 4, 4, 4, 4, 4, 4, 4, /* 8 - 15 */ |
180 |
5, 5, 5, 5, 5, 5, 5, 5, /* 16 - 31 */ |
181 |
5, 5, 5, 5, 5, 5, 5, 5, |
182 |
6, 6, 6, 6, 6, 6, 6, 6, /* 32 - 63 */ |
183 |
6, 6, 6, 6, 6, 6, 6, 6, |
184 |
6, 6, 6, 6, 6, 6, 6, 6, |
185 |
6, 6, 6, 6, 6, 6, 6, 6, |
186 |
7, 7, 7, 7, 7, 7, 7, 7, /* 64 - 127 */ |
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 |
7, 7, 7, 7, 7, 7, 7, 7, |
192 |
7, 7, 7, 7, 7, 7, 7, 7, |
193 |
7, 7, 7, 7, 7, 7, 7, 7, |
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 |
8, 8, 8, 8, 8, 8, 8, 8, |
208 |
8, 8, 8, 8, 8, 8, 8, 8, |
209 |
8, 8, 8, 8, 8, 8, 8, 8 |
210 |
}; |
211 |
|
212 |
|
213 |
/*==================* |
214 |
* GLOBAL VARIABLES * |
215 |
*==================*/ |
216 |
|
217 |
int qscaleI; |
218 |
int slicesPerFrame; |
219 |
int blocksPerSlice; |
220 |
int fCodeI, fCodeP, fCodeB; |
221 |
boolean printSNR = FALSE; |
222 |
boolean printMSE = FALSE; |
223 |
boolean decodeRefFrames = FALSE; |
224 |
Block **dct=NULL, **dctr=NULL, **dctb=NULL; |
225 |
dct_data_type **dct_data; /* used in p/bframe.c */ |
226 |
int TIME_RATE; |
227 |
|
228 |
|
229 |
/*=====================* |
230 |
* EXPORTED PROCEDURES * |
231 |
*=====================*/ |
232 |
extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum)); |
233 |
|
234 |
/*===============================* |
235 |
* INTERNAL PROCEDURE prototypes * |
236 |
*===============================*/ |
237 |
void AllocDctBlocks _ANSI_ARGS_((void )); |
238 |
int SetFCodeHelper _ANSI_ARGS_((int sr)); |
239 |
void CalcDistortion _ANSI_ARGS_((MpegFrame *current, int y, int x)); |
240 |
|
241 |
int |
242 |
SetFCodeHelper(SR) |
243 |
int SR; |
244 |
{ |
245 |
int range,fCode; |
246 |
|
247 |
if ( pixelFullSearch ) { |
248 |
range = SR; |
249 |
} else { |
250 |
range = SR*2; |
251 |
} |
252 |
|
253 |
if ( range < 256 ) { |
254 |
if ( range < 64 ) { |
255 |
if ( range < 32 ) { |
256 |
fCode = 1; |
257 |
} else { |
258 |
fCode = 2; |
259 |
} |
260 |
} else { |
261 |
if ( range < 128 ) { |
262 |
fCode = 3; |
263 |
} else { |
264 |
fCode = 4; |
265 |
} |
266 |
} |
267 |
} else { |
268 |
if ( range < 1024 ) { |
269 |
if ( range < 512 ) { |
270 |
fCode = 5; |
271 |
} else { |
272 |
fCode = 6; |
273 |
} |
274 |
} else { |
275 |
if ( range < 2048 ) { |
276 |
fCode = 7; |
277 |
} else { |
278 |
fprintf(stderr, "ERROR: INVALID SEARCH RANGE!!!\n"); |
279 |
exit(1); |
280 |
} |
281 |
} |
282 |
} |
283 |
return fCode; |
284 |
} |
285 |
|
286 |
/*===========================================================================* |
287 |
* |
288 |
* SetFCode |
289 |
* |
290 |
* set the forward_f_code and backward_f_code according to the search |
291 |
* range. Must be called AFTER pixelFullSearch and searchRange have |
292 |
* been initialized. Irrelevant for I-frames, but computation is |
293 |
* negligible (done only once, as well) |
294 |
* |
295 |
* RETURNS: nothing |
296 |
* |
297 |
* SIDE EFFECTS: fCodeI,fCodeP,fCodeB |
298 |
* |
299 |
*===========================================================================*/ |
300 |
void |
301 |
SetFCode() |
302 |
{ |
303 |
fCodeI = SetFCodeHelper(1); /* GenIFrame ignores value */ |
304 |
fCodeP = SetFCodeHelper(searchRangeP); |
305 |
fCodeB = SetFCodeHelper(searchRangeB); |
306 |
} |
307 |
|
308 |
/*===========================================================================* |
309 |
* |
310 |
* SetSlicesPerFrame |
311 |
* |
312 |
* set the number of slices per frame |
313 |
* |
314 |
* RETURNS: nothing |
315 |
* |
316 |
* SIDE EFFECTS: slicesPerFrame |
317 |
* |
318 |
*===========================================================================*/ |
319 |
void |
320 |
SetSlicesPerFrame(number) |
321 |
int number; |
322 |
{ |
323 |
slicesPerFrame = number; |
324 |
} |
325 |
|
326 |
|
327 |
/*===========================================================================* |
328 |
* |
329 |
* SetBlocksPerSlice |
330 |
* |
331 |
* set the number of blocks per slice, based on slicesPerFrame |
332 |
* |
333 |
* RETURNS: nothing |
334 |
* |
335 |
* SIDE EFFECTS: blocksPerSlice |
336 |
* |
337 |
*===========================================================================*/ |
338 |
void |
339 |
SetBlocksPerSlice() |
340 |
{ |
341 |
int totalBlocks; |
342 |
|
343 |
totalBlocks = (Fsize_y>>4)*(Fsize_x>>4); |
344 |
|
345 |
if ( slicesPerFrame > totalBlocks ) { |
346 |
blocksPerSlice = 1; |
347 |
} else { |
348 |
blocksPerSlice = totalBlocks/slicesPerFrame; |
349 |
} |
350 |
} |
351 |
|
352 |
|
353 |
/*===========================================================================* |
354 |
* |
355 |
* SetIQScale |
356 |
* |
357 |
* set the I-frame Q-scale |
358 |
* |
359 |
* RETURNS: nothing |
360 |
* |
361 |
* SIDE EFFECTS: qscaleI |
362 |
* |
363 |
*===========================================================================*/ |
364 |
void |
365 |
SetIQScale(qI) |
366 |
int qI; |
367 |
{ |
368 |
qscaleI = qI; |
369 |
} |
370 |
|
371 |
/*===========================================================================* |
372 |
* |
373 |
* GetIQScale |
374 |
* |
375 |
* Get the I-frame Q-scale |
376 |
* |
377 |
* RETURNS: the Iframe Qscale |
378 |
* |
379 |
* SIDE EFFECTS: none |
380 |
* |
381 |
*===========================================================================*/ |
382 |
int |
383 |
GetIQScale() |
384 |
{ |
385 |
return qscaleI; |
386 |
} |
387 |
|
388 |
/*===========================================================================* |
389 |
* |
390 |
* GenIFrame |
391 |
* |
392 |
* generate an I-frame; appends result to bb |
393 |
* |
394 |
* RETURNS: I-frame appended to bb |
395 |
* |
396 |
* SIDE EFFECTS: none |
397 |
* |
398 |
*===========================================================================*/ |
399 |
void |
400 |
GenIFrame(bb, current) |
401 |
BitBucket *bb; |
402 |
MpegFrame *current; |
403 |
{ |
404 |
register int x, y; |
405 |
register int index; |
406 |
FlatBlock fb[6]; |
407 |
Block dec[6]; |
408 |
int32 y_dc_pred, cr_dc_pred, cb_dc_pred; |
409 |
int totalBits; |
410 |
int totalFrameBits; |
411 |
int32 startTime, endTime; |
412 |
float snr[3], psnr[3]; |
413 |
int mbAddress; |
414 |
int QScale; |
415 |
BlockMV *info; /* Not used in Iframes, but nice to pass in anyway */ |
416 |
int bitstreamMode, newQScale; |
417 |
int rc_blockStart=0; |
418 |
|
419 |
if (dct==NULL) AllocDctBlocks(); |
420 |
if (collect_quant) {fprintf(collect_quant_fp, "# I\n");} |
421 |
|
422 |
/* set-up for statistics */ |
423 |
numFrames++; |
424 |
totalFrameBits = bb->cumulativeBits; |
425 |
if ( ( ! childProcess) && showBitRatePerFrame ) { |
426 |
if ( lastNumBits == 0 ) { |
427 |
lastNumBits = bb->cumulativeBits; |
428 |
lastIFrame = current->id; |
429 |
} else { |
430 |
/* ASSUMES 30 FRAMES PER SECOND */ |
431 |
|
432 |
if (! realQuiet) { |
433 |
fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n", |
434 |
lastIFrame, current->id-1, |
435 |
((bb->cumulativeBits-lastNumBits)*30)/ |
436 |
(current->id-lastIFrame)); |
437 |
} |
438 |
|
439 |
fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n", |
440 |
lastIFrame, current->id-1, |
441 |
((bb->cumulativeBits-lastNumBits)*30)/ |
442 |
(current->id-lastIFrame)); |
443 |
lastNumBits = bb->cumulativeBits; |
444 |
lastIFrame = current->id; |
445 |
} |
446 |
} |
447 |
|
448 |
startTime = time_elapsed(); |
449 |
|
450 |
Frame_AllocBlocks(current); |
451 |
BlockifyFrame(current); |
452 |
|
453 |
DBG_PRINT(("Generating iframe\n")); |
454 |
QScale = GetIQScale(); |
455 |
/* Allocate bits for this frame for rate control purposes */ |
456 |
bitstreamMode = getRateMode(); |
457 |
if (bitstreamMode == FIXED_RATE) { |
458 |
targetRateControl(current); |
459 |
} |
460 |
|
461 |
Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCodeI); |
462 |
/* Check for Qscale change */ |
463 |
if (specificsOn) { |
464 |
newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info, QScale); |
465 |
if (newQScale != -1) { |
466 |
QScale = newQScale; |
467 |
} |
468 |
/* check for slice */ |
469 |
newQScale = SpecLookup(current->id, 1, 1, &info, QScale); |
470 |
if (newQScale != -1) { |
471 |
QScale = newQScale; |
472 |
} |
473 |
} |
474 |
Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0); |
475 |
|
476 |
if ( referenceFrame == DECODED_FRAME ) { |
477 |
Frame_AllocDecoded(current, TRUE); |
478 |
} else if ( printSNR ) { |
479 |
Frame_AllocDecoded(current, FALSE); |
480 |
} |
481 |
|
482 |
y_dc_pred = cr_dc_pred = cb_dc_pred = 128; |
483 |
totalBits = bb->cumulativeBits; |
484 |
mbAddress = 0; |
485 |
|
486 |
/* DCT the macroblocks */ |
487 |
for (y = 0; y < (Fsize_y >> 3); y += 2) { |
488 |
for (x = 0; x < (Fsize_x >> 3); x += 2) { |
489 |
if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n"); |
490 |
if (DoLaplace) {LaplaceCnum = 0;} |
491 |
mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]); |
492 |
mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]); |
493 |
mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]); |
494 |
mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]); |
495 |
if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n"); |
496 |
if (DoLaplace) {LaplaceCnum = 1;} |
497 |
mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]); |
498 |
if (DoLaplace) {LaplaceCnum = 2;} |
499 |
mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]); |
500 |
}} |
501 |
|
502 |
if (DoLaplace) { |
503 |
extern void CalcLambdas(); |
504 |
CalcLambdas(); |
505 |
} |
506 |
|
507 |
for (y = 0; y < (Fsize_y >> 3); y += 2) { |
508 |
for (x = 0; x < (Fsize_x >> 3); x += 2) { |
509 |
/* Check for Qscale change */ |
510 |
if (specificsOn) { |
511 |
newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale); |
512 |
if (newQScale != -1) { |
513 |
QScale = newQScale; |
514 |
} |
515 |
} |
516 |
|
517 |
/* Determine if new Qscale needed for Rate Control purposes */ |
518 |
if (bitstreamMode == FIXED_RATE) { |
519 |
rc_blockStart = bb->cumulativeBits; |
520 |
newQScale = needQScaleChange(qscaleI, |
521 |
current->y_blocks[y][x], |
522 |
current->y_blocks[y][x+1], |
523 |
current->y_blocks[y+1][x], |
524 |
current->y_blocks[y+1][x+1]); |
525 |
if (newQScale > 0) { |
526 |
QScale = newQScale; |
527 |
} |
528 |
} |
529 |
|
530 |
if ( (mbAddress % blocksPerSlice == 0) && (mbAddress != 0) ) { |
531 |
/* create a new slice */ |
532 |
if (specificsOn) { |
533 |
/* Make sure no slice Qscale change */ |
534 |
newQScale = SpecLookup(current->id,1,mbAddress/blocksPerSlice, &info, QScale); |
535 |
if (newQScale != -1) QScale = newQScale; |
536 |
} |
537 |
Mhead_GenSliceEnder(bb); |
538 |
Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0); |
539 |
y_dc_pred = cr_dc_pred = cb_dc_pred = 128; |
540 |
|
541 |
GEN_I_BLOCK(I_FRAME, current, bb, 1+(x>>1), QScale); |
542 |
} else { |
543 |
GEN_I_BLOCK(I_FRAME, current, bb, 1, QScale); |
544 |
} |
545 |
|
546 |
if (WriteDistortionNumbers) { |
547 |
CalcDistortion(current, y, x); |
548 |
} |
549 |
|
550 |
if ( decodeRefFrames ) { |
551 |
/* now, reverse the DCT transform */ |
552 |
LaplaceCnum = 0; |
553 |
for ( index = 0; index < 6; index++ ) { |
554 |
if (!DoLaplace) { |
555 |
Mpost_UnQuantZigBlock(fb[index], dec[index], QScale, TRUE); |
556 |
} else { |
557 |
if (index == 4) {LaplaceCnum = 1;} |
558 |
if (index == 5) {LaplaceCnum = 2;} |
559 |
Mpost_UnQuantZigBlockLaplace(fb[index], dec[index], QScale, TRUE); |
560 |
} |
561 |
mpeg_jrevdct((int16 *)dec[index]); |
562 |
} |
563 |
|
564 |
/* now, unblockify */ |
565 |
BlockToData(current->decoded_y, dec[0], y, x); |
566 |
BlockToData(current->decoded_y, dec[1], y, x+1); |
567 |
BlockToData(current->decoded_y, dec[2], y+1, x); |
568 |
BlockToData(current->decoded_y, dec[3], y+1, x+1); |
569 |
BlockToData(current->decoded_cb, dec[4], y>>1, x>>1); |
570 |
BlockToData(current->decoded_cr, dec[5], y>>1, x>>1); |
571 |
} |
572 |
|
573 |
numBlocks++; |
574 |
mbAddress++; |
575 |
/* Rate Control */ |
576 |
if (bitstreamMode == FIXED_RATE) { |
577 |
incMacroBlockBits(bb->cumulativeBits - rc_blockStart); |
578 |
rc_blockStart = bb->cumulativeBits; |
579 |
MB_RateOut(TYPE_IFRAME); |
580 |
} |
581 |
} |
582 |
} |
583 |
|
584 |
if ( printSNR ) { |
585 |
BlockComputeSNR(current,snr,psnr); |
586 |
totalSNR += snr[0]; |
587 |
totalPSNR += psnr[0]; |
588 |
} |
589 |
|
590 |
if ( (referenceFrame == DECODED_FRAME) && NonLocalRefFrame(current->id) ) { |
591 |
if ( remoteIO ) { |
592 |
SendDecodedFrame(current); |
593 |
} else { |
594 |
WriteDecodedFrame(current); |
595 |
} |
596 |
|
597 |
/* now, tell decode server it is ready */ |
598 |
NotifyDecodeServerReady(current->id); |
599 |
} |
600 |
|
601 |
numBits += (bb->cumulativeBits-totalBits); |
602 |
|
603 |
DBG_PRINT(("End of frame\n")); |
604 |
|
605 |
Mhead_GenSliceEnder(bb); |
606 |
/* Rate Control */ |
607 |
if (bitstreamMode == FIXED_RATE) { |
608 |
updateRateControl(TYPE_IFRAME); |
609 |
} |
610 |
|
611 |
endTime = time_elapsed(); |
612 |
totalTime += (endTime-startTime); |
613 |
|
614 |
numFrameBits += (bb->cumulativeBits-totalFrameBits); |
615 |
|
616 |
if ( ( ! childProcess) && showBitRatePerFrame ) { |
617 |
/* ASSUMES 30 FRAMES PER SECOND */ |
618 |
fprintf(bitRateFile, "%5d\t%8d\n", current->id, |
619 |
30*(bb->cumulativeBits-totalFrameBits)); |
620 |
} |
621 |
|
622 |
if ( (! childProcess) && frameSummary && (! realQuiet) ) { |
623 |
|
624 |
/* ASSUMES 30 FRAMES PER SECOND */ |
625 |
fprintf(stdout, "FRAME %d (I): %ld seconds (%d bits/s output)\n", |
626 |
current->id, (long)((endTime-startTime)/TIME_RATE), |
627 |
30*(bb->cumulativeBits-totalFrameBits)); |
628 |
if ( printSNR ) { |
629 |
fprintf(stdout, "FRAME %d: SNR: %.1f\t%.1f\t%.1f\tPSNR: %.1f\t%.1f\t%.1f\n", |
630 |
current->id, snr[0], snr[1], snr[2], |
631 |
psnr[0], psnr[1], psnr[2]); |
632 |
} |
633 |
} |
634 |
} |
635 |
|
636 |
|
637 |
/*===========================================================================* |
638 |
* |
639 |
* ResetIFrameStats |
640 |
* |
641 |
* reset the I-frame statistics |
642 |
* |
643 |
* RETURNS: nothing |
644 |
* |
645 |
* SIDE EFFECTS: none |
646 |
* |
647 |
*===========================================================================*/ |
648 |
void |
649 |
ResetIFrameStats() |
650 |
{ |
651 |
numBlocks = 0; |
652 |
numBits = 0; |
653 |
numFrames = 0; |
654 |
numFrameBits = 0; |
655 |
totalTime = 0; |
656 |
} |
657 |
|
658 |
|
659 |
/*===========================================================================* |
660 |
* |
661 |
* ShowIFrameSummary |
662 |
* |
663 |
* prints out statistics on all I-frames |
664 |
* |
665 |
* RETURNS: time taken for I-frames (in seconds) |
666 |
* |
667 |
* SIDE EFFECTS: none |
668 |
* |
669 |
*===========================================================================*/ |
670 |
float |
671 |
ShowIFrameSummary(inputFrameBits, totalBits, fpointer) |
672 |
int inputFrameBits; |
673 |
int32 totalBits; |
674 |
FILE *fpointer; |
675 |
{ |
676 |
if ( numFrames == 0 ) { |
677 |
return 0.0; |
678 |
} |
679 |
|
680 |
fprintf(fpointer, "-------------------------\n"); |
681 |
fprintf(fpointer, "*****I FRAME SUMMARY*****\n"); |
682 |
fprintf(fpointer, "-------------------------\n"); |
683 |
|
684 |
fprintf(fpointer, " Blocks: %5d (%6d bits) (%5d bpb)\n", |
685 |
numBlocks, numBits, numBits/numBlocks); |
686 |
fprintf(fpointer, " Frames: %5d (%6d bits) (%5d bpf) (%2.1f%% of total)\n", |
687 |
numFrames, numFrameBits, numFrameBits/numFrames, |
688 |
100.0*(float)numFrameBits/(float)totalBits); |
689 |
fprintf(fpointer, " Compression: %3d:1 (%9.4f bpp)\n", |
690 |
numFrames*inputFrameBits/numFrameBits, |
691 |
24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits)); |
692 |
if ( printSNR ) |
693 |
fprintf(fpointer, " Avg Y SNR/PSNR: %.1f %.1f\n", |
694 |
totalSNR/(float)numFrames, totalPSNR/(float)numFrames); |
695 |
if ( totalTime == 0 ) { |
696 |
fprintf(fpointer, " Seconds: NONE\n"); |
697 |
} else { |
698 |
fprintf(fpointer, " Seconds: %9ld (%9.4f fps) (%9ld pps) (%9ld mps)\n", |
699 |
(long)(totalTime/TIME_RATE), |
700 |
(float)((float)(TIME_RATE*numFrames)/(float)totalTime), |
701 |
(long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(24.0*(float)totalTime)), |
702 |
(long)((float)TIME_RATE*(float)numFrames*(float)inputFrameBits/(256.0*24.0*(float)totalTime))); |
703 |
} |
704 |
|
705 |
return (float)totalTime/(float)TIME_RATE; |
706 |
} |
707 |
|
708 |
|
709 |
/*===========================================================================* |
710 |
* |
711 |
* EstimateSecondsPerIFrame |
712 |
* |
713 |
* estimates the number of seconds required per I-frame |
714 |
* |
715 |
* RETURNS: seconds (floating point value) |
716 |
* |
717 |
* SIDE EFFECTS: none |
718 |
* |
719 |
*===========================================================================*/ |
720 |
float |
721 |
EstimateSecondsPerIFrame() |
722 |
{ |
723 |
return (float)totalTime/((float)TIME_RATE*(float)numFrames); |
724 |
} |
725 |
|
726 |
|
727 |
/*===========================================================================* |
728 |
* |
729 |
* EncodeYDC |
730 |
* |
731 |
* Encode the DC portion of a DCT of a luminance block |
732 |
* |
733 |
* RETURNS: result appended to bb |
734 |
* |
735 |
* SIDE EFFECTS: updates pred_term |
736 |
* |
737 |
*===========================================================================*/ |
738 |
void |
739 |
EncodeYDC(dc_term, pred_term, bb) |
740 |
int32 dc_term; |
741 |
int32 *pred_term; |
742 |
BitBucket *bb; |
743 |
{ |
744 |
/* see Table B.5a -- MPEG-I doc */ |
745 |
static int codes[9] = { |
746 |
0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e |
747 |
}; |
748 |
static int codeLengths[9] = { |
749 |
3, 2, 2, 3, 3, 4, 5, 6, 7 |
750 |
}; |
751 |
int ydiff, ydiff_abs; |
752 |
int length; |
753 |
|
754 |
ydiff = (dc_term - (*pred_term)); |
755 |
if (ydiff > 255) { |
756 |
#ifdef BLEAH |
757 |
fprintf(stdout, "TRUNCATED\n"); |
758 |
#endif |
759 |
ydiff = 255; |
760 |
} else if (ydiff < -255) { |
761 |
#ifdef BLEAH |
762 |
fprintf(stdout, "TRUNCATED\n"); |
763 |
#endif |
764 |
ydiff = -255; |
765 |
} |
766 |
|
767 |
ydiff_abs = ABS(ydiff); |
768 |
length = lengths[ydiff_abs]; |
769 |
Bitio_Write(bb, codes[length], codeLengths[length]); |
770 |
if ( length != 0 ) { |
771 |
if ( ydiff > 0 ) { |
772 |
Bitio_Write(bb, ydiff_abs, length); |
773 |
} else { |
774 |
Bitio_Write(bb, ~ydiff_abs, length); |
775 |
} |
776 |
} |
777 |
|
778 |
(*pred_term) += ydiff; |
779 |
} |
780 |
|
781 |
|
782 |
/*===========================================================================* |
783 |
* |
784 |
* EncodeCDC |
785 |
* |
786 |
* Encode the DC portion of a DCT of a chrominance block |
787 |
* |
788 |
* RETURNS: result appended to bb |
789 |
* |
790 |
* SIDE EFFECTS: updates pred_term |
791 |
* |
792 |
*===========================================================================*/ |
793 |
void |
794 |
EncodeCDC(dc_term, pred_term, bb) |
795 |
int32 dc_term; |
796 |
int32 *pred_term; |
797 |
BitBucket *bb; |
798 |
{ |
799 |
/* see Table B.5b -- MPEG-I doc */ |
800 |
static int codes[9] = { |
801 |
0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe |
802 |
}; |
803 |
static int codeLengths[9] = { |
804 |
2, 2, 2, 3, 4, 5, 6, 7, 8 |
805 |
}; |
806 |
int cdiff, cdiff_abs; |
807 |
int length; |
808 |
|
809 |
cdiff = (dc_term - (*pred_term)); |
810 |
if (cdiff > 255) { |
811 |
#ifdef BLEAH |
812 |
fprintf(stdout, "TRUNCATED\n"); |
813 |
#endif |
814 |
cdiff = 255; |
815 |
} else if (cdiff < -255) { |
816 |
#ifdef BLEAH |
817 |
fprintf(stdout, "TRUNCATED\n"); |
818 |
#endif |
819 |
cdiff = -255; |
820 |
} |
821 |
|
822 |
cdiff_abs = ABS(cdiff); |
823 |
length = lengths[cdiff_abs]; |
824 |
Bitio_Write(bb, codes[length], codeLengths[length]); |
825 |
if ( length != 0 ) { |
826 |
if ( cdiff > 0 ) { |
827 |
Bitio_Write(bb, cdiff_abs, length); |
828 |
} else { |
829 |
Bitio_Write(bb, ~cdiff_abs, length); |
830 |
} |
831 |
} |
832 |
|
833 |
(*pred_term) += cdiff; |
834 |
} |
835 |
|
836 |
|
837 |
void |
838 |
BlockComputeSNR(current, snr, psnr) |
839 |
MpegFrame *current; |
840 |
float snr[]; |
841 |
float psnr[]; |
842 |
{ |
843 |
register int32 tempInt; |
844 |
register int y, x; |
845 |
int32 varDiff[3]; |
846 |
double ratio[3]; |
847 |
double total[3]; |
848 |
register uint8 **origY=current->orig_y, **origCr=current->orig_cr, |
849 |
**origCb=current->orig_cb; |
850 |
register uint8 **newY=current->decoded_y, **newCr=current->decoded_cr, |
851 |
**newCb=current->decoded_cb; |
852 |
static int32 **SignalY, **NoiseY; |
853 |
static int32 **SignalCb, **NoiseCb; |
854 |
static int32 **SignalCr, **NoiseCr; |
855 |
static short ySize[3], xSize[3]; |
856 |
static boolean needs_init=TRUE; |
857 |
|
858 |
/* Init */ |
859 |
if (needs_init) { |
860 |
int ysz = (Fsize_y>>3) * sizeof(int32 *); |
861 |
int xsz = (Fsize_x>>3); |
862 |
|
863 |
needs_init = FALSE; |
864 |
for (y=0; y<3; y++) { |
865 |
varDiff[y] = ratio[y] = total[y] = 0.0; |
866 |
} |
867 |
ySize[0]=Fsize_y; xSize[0]=Fsize_x; |
868 |
ySize[1]=Fsize_y>>1; xSize[1]=Fsize_x>>1; |
869 |
ySize[2]=Fsize_y>>1; xSize[2]=Fsize_x>>1; |
870 |
SignalY = (int32 **) malloc(ysz); |
871 |
NoiseY = (int32 **) malloc(ysz); |
872 |
SignalCb = (int32 **) malloc(ysz); |
873 |
NoiseCb = (int32 **) malloc(ysz); |
874 |
SignalCr = (int32 **) malloc(ysz); |
875 |
NoiseCr = (int32 **) malloc(ysz); |
876 |
if (SignalY == NULL || NoiseY == NULL || SignalCr == NULL || |
877 |
NoiseCb == NULL || SignalCb == NULL || NoiseCr == NULL) { |
878 |
fprintf(stderr, "Out of memory in BlockComputeSNR\n"); |
879 |
exit(-1); |
880 |
} |
881 |
for (y = 0; y < ySize[0]>>3; y++) { |
882 |
SignalY[y] = (int32 *) calloc(xsz,4); |
883 |
SignalCr[y] = (int32 *) calloc(xsz,4); |
884 |
SignalCb[y] = (int32 *) calloc(xsz,4); |
885 |
NoiseY[y] = (int32 *) calloc(xsz,4); |
886 |
NoiseCr[y] = (int32 *) calloc(xsz,4); |
887 |
NoiseCb[y] = (int32 *) calloc(xsz,4); |
888 |
} |
889 |
} else { |
890 |
for (y = 0; y < ySize[0]>>3; y++) { |
891 |
memset((char *) &NoiseY[y][0], 0, (xSize[0]>>3) * 4); |
892 |
memset((char *) &SignalY[y][0], 0, (xSize[0]>>3) * 4); |
893 |
memset((char *) &NoiseCb[y][0], 0, (xSize[0]>>3) * 4); |
894 |
memset((char *) &NoiseCr[y][0], 0, (xSize[0]>>3) * 4); |
895 |
memset((char *) &SignalCb[y][0], 0, (xSize[0]>>3) * 4); |
896 |
memset((char *) &SignalCr[y][0], 0, (xSize[0]>>3) * 4); |
897 |
} |
898 |
} |
899 |
|
900 |
/* find all the signal and noise */ |
901 |
for (y = 0; y < ySize[0]; y++) { |
902 |
for (x = 0; x < xSize[0]; x++) { |
903 |
tempInt = (origY[y][x] - newY[y][x]); |
904 |
NoiseY[y>>4][x>>4] += tempInt*tempInt; |
905 |
total[0] += (double)abs(tempInt); |
906 |
tempInt = origY[y][x]; |
907 |
SignalY[y>>4][x>>4] += tempInt*tempInt; |
908 |
}} |
909 |
for (y = 0; y < ySize[1]; y++) { |
910 |
for (x = 0; x < xSize[1]; x ++) { |
911 |
tempInt = (origCb[y][x] - newCb[y][x]); |
912 |
NoiseCb[y>>3][x>>3] += tempInt*tempInt; |
913 |
total[1] += (double)abs(tempInt); |
914 |
tempInt = origCb[y][x]; |
915 |
SignalCb[y>>3][x>>3] += tempInt*tempInt; |
916 |
tempInt = (origCr[y][x]-newCr[y][x]); |
917 |
NoiseCr[y>>3][x>>3] += tempInt*tempInt; |
918 |
total[2] += (double)abs(tempInt); |
919 |
tempInt = origCr[y][x]; |
920 |
SignalCr[y>>3][x>>3] += tempInt*tempInt; |
921 |
}} |
922 |
|
923 |
/* Now sum up that noise */ |
924 |
for(y=0; y<Fsize_y>>4; y++){ |
925 |
for(x=0; x<Fsize_x>>4; x++){ |
926 |
varDiff[0] += NoiseY[y][x]; |
927 |
varDiff[1] += NoiseCb[y][x]; |
928 |
varDiff[2] += NoiseCr[y][x]; |
929 |
if (printMSE) printf("%4d ",(int)(NoiseY[y][x]/256.0)); |
930 |
} |
931 |
if (printMSE) puts(""); |
932 |
} |
933 |
|
934 |
/* Now look at those ratios! */ |
935 |
for(y=0; y<Fsize_y>>4; y++){ |
936 |
for(x=0; x<Fsize_x>>4; x++){ |
937 |
ratio[0] += (double)SignalY[y][x]/(double)varDiff[0]; |
938 |
ratio[1] += (double)SignalCb[y][x]/(double)varDiff[1]; |
939 |
ratio[2] += (double)SignalCr[y][x]/(double)varDiff[2]; |
940 |
}} |
941 |
|
942 |
for (x=0; x<3; x++) { |
943 |
snr[x] = 10.0*log10(ratio[x]); |
944 |
psnr[x] = 20.0*log10(255.0/sqrt((double)varDiff[x]/(double)(ySize[x]*xSize[x]))); |
945 |
|
946 |
if (! realQuiet) { |
947 |
fprintf(stdout, "Mean error[%1d]: %f\n", x, total[x]/(double)(xSize[x]*ySize[x])); |
948 |
} |
949 |
|
950 |
} |
951 |
} |
952 |
|
953 |
void |
954 |
WriteDecodedFrame(frame) |
955 |
MpegFrame *frame; |
956 |
{ |
957 |
FILE *fpointer; |
958 |
char fileName[256]; |
959 |
int width, height; |
960 |
register int y; |
961 |
|
962 |
/* need to save decoded frame to disk because it might be accessed |
963 |
by another process */ |
964 |
|
965 |
width = Fsize_x; |
966 |
height = Fsize_y; |
967 |
|
968 |
sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id); |
969 |
|
970 |
if (!realQuiet) { |
971 |
fprintf(stdout, "Outputting to %s\n", fileName); |
972 |
fflush(stdout); |
973 |
} |
974 |
|
975 |
fpointer = fopen(fileName, "wb"); |
976 |
|
977 |
for ( y = 0; y < height; y++ ) { |
978 |
fwrite(frame->decoded_y[y], 1, width, fpointer); |
979 |
} |
980 |
|
981 |
for (y = 0; y < (height >> 1); y++) { /* U */ |
982 |
fwrite(frame->decoded_cb[y], 1, width >> 1, fpointer); |
983 |
} |
984 |
|
985 |
for (y = 0; y < (height >> 1); y++) { /* V */ |
986 |
fwrite(frame->decoded_cr[y], 1, width >> 1, fpointer); |
987 |
} |
988 |
fflush(fpointer); |
989 |
fclose(fpointer); |
990 |
} |
991 |
|
992 |
|
993 |
void |
994 |
PrintItoIBitRate(numBits, frameNum) |
995 |
int numBits; |
996 |
int frameNum; |
997 |
{ |
998 |
if ( ( ! childProcess) && showBitRatePerFrame ) { |
999 |
/* ASSUMES 30 FRAMES PER SECOND */ |
1000 |
|
1001 |
if (! realQuiet) { |
1002 |
fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n", |
1003 |
lastIFrame, frameNum-1, |
1004 |
((numBits-lastNumBits)*30)/ |
1005 |
(frameNum-lastIFrame)); |
1006 |
} |
1007 |
|
1008 |
fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n", |
1009 |
lastIFrame, frameNum-1, |
1010 |
((numBits-lastNumBits)*30)/ |
1011 |
(frameNum-lastIFrame)); |
1012 |
} |
1013 |
} |
1014 |
|
1015 |
|
1016 |
/*===========================================================================* |
1017 |
* |
1018 |
* AllocDctBlocks |
1019 |
* |
1020 |
* allocate memory for dct blocks |
1021 |
* |
1022 |
* RETURNS: nothing |
1023 |
* |
1024 |
* SIDE EFFECTS: creates dct, dctr, dctb |
1025 |
* |
1026 |
*===========================================================================*/ |
1027 |
void |
1028 |
AllocDctBlocks() |
1029 |
{ |
1030 |
int dctx, dcty; |
1031 |
int i; |
1032 |
|
1033 |
dctx = Fsize_x / DCTSIZE; |
1034 |
dcty = Fsize_y / DCTSIZE; |
1035 |
|
1036 |
dct = (Block **) malloc(sizeof(Block *) * dcty); |
1037 |
ERRCHK(dct, "malloc"); |
1038 |
for (i = 0; i < dcty; i++) { |
1039 |
dct[i] = (Block *) malloc(sizeof(Block) * dctx); |
1040 |
ERRCHK(dct[i], "malloc"); |
1041 |
} |
1042 |
|
1043 |
dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty); |
1044 |
ERRCHK(dct_data, "malloc"); |
1045 |
for (i = 0; i < dcty; i++) { |
1046 |
dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx); |
1047 |
ERRCHK(dct[i], "malloc"); |
1048 |
} |
1049 |
|
1050 |
dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1)); |
1051 |
dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1)); |
1052 |
ERRCHK(dctr, "malloc"); |
1053 |
ERRCHK(dctb, "malloc"); |
1054 |
for (i = 0; i < (dcty >> 1); i++) { |
1055 |
dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1)); |
1056 |
dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1)); |
1057 |
ERRCHK(dctr[i], "malloc"); |
1058 |
ERRCHK(dctb[i], "malloc"); |
1059 |
} |
1060 |
} |
1061 |
|
1062 |
|
1063 |
/*======================================================================* |
1064 |
* |
1065 |
* time_elapsed |
1066 |
* |
1067 |
* Handle different time systems on different machines |
1068 |
* |
1069 |
* RETURNS number of seconds process time used |
1070 |
* |
1071 |
*======================================================================*/ |
1072 |
int32 time_elapsed() |
1073 |
{ |
1074 |
#ifdef CLOCKS_PER_SEC |
1075 |
/* ANSI C */ |
1076 |
TIME_RATE = CLOCKS_PER_SEC; |
1077 |
return (int32) clock(); |
1078 |
#else |
1079 |
struct tms timeBuffer; |
1080 |
TIME_RATE = 60; |
1081 |
times(&timeBuffer); |
1082 |
return timeBuffer.tms_utime + timeBuffer.tms_stime; |
1083 |
#endif |
1084 |
} |
1085 |
|
1086 |
|
1087 |
void |
1088 |
CalcDistortion(current, y, x) |
1089 |
MpegFrame *current; |
1090 |
int y,x; |
1091 |
{ |
1092 |
|
1093 |
int qscale, distort=0; |
1094 |
Block decblk; |
1095 |
FlatBlock fblk; |
1096 |
int datarate = 0; |
1097 |
|
1098 |
for (qscale = 1; qscale < 32; qscale ++) { |
1099 |
distort = 0; |
1100 |
datarate = 0; |
1101 |
Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE); |
1102 |
Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); |
1103 |
if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); |
1104 |
mpeg_jrevdct((int16 *)decblk); |
1105 |
distort += mse(current->y_blocks[y][x], decblk); |
1106 |
|
1107 |
Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE); |
1108 |
Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); |
1109 |
if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); |
1110 |
mpeg_jrevdct((int16 *)decblk); |
1111 |
distort += mse(current->y_blocks[y][x+1], decblk); |
1112 |
|
1113 |
Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE); |
1114 |
Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); |
1115 |
if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); |
1116 |
mpeg_jrevdct((int16 *)decblk); |
1117 |
distort += mse(current->y_blocks[y+1][x], decblk); |
1118 |
|
1119 |
Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE); |
1120 |
Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); |
1121 |
if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); |
1122 |
mpeg_jrevdct((int16 *)decblk); |
1123 |
distort += mse(current->y_blocks[y+1][x+1], decblk); |
1124 |
|
1125 |
Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE); |
1126 |
Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); |
1127 |
if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); |
1128 |
mpeg_jrevdct((int16 *)decblk); |
1129 |
distort += mse(current->cb_blocks[y>>1][x>>1], decblk); |
1130 |
|
1131 |
Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE); |
1132 |
Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); |
1133 |
if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); |
1134 |
mpeg_jrevdct((int16 *)decblk); |
1135 |
distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk); |
1136 |
|
1137 |
if (!collect_distortion_detailed) { |
1138 |
fprintf(distortion_fp, "\t%d\n", distort); |
1139 |
} else if (collect_distortion_detailed == 1) { |
1140 |
fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate); |
1141 |
} else { |
1142 |
fprintf(fp_table_rate[qscale-1], "%d\n", datarate); |
1143 |
fprintf(fp_table_dist[qscale-1], "%d\n", distort); |
1144 |
} |
1145 |
} |
1146 |
} |