/*===========================================================================* * iframe.c * * * * Procedures concerned with the I-frame encoding * * * * EXPORTED PROCEDURES: * * GenIFrame * * SetSlicesPerFrame * * SetBlocksPerSlice * * SetIQScale * * GetIQScale * * ResetIFrameStats * * ShowIFrameSummary * * EncodeYDC * * EncodeCDC * * time_elapsed * * * *===========================================================================*/ /* * Copyright (c) 1995 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice and the following * two paragraphs appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ /*==============* * HEADER FILES * *==============*/ #include /* Defines CLOCKS_PER_SEC, if this system has clock() */ #ifndef CLOCKS_PER_SEC /* System doesn't have clock(); we assume it has times() instead */ #include #endif #include #include #include "all.h" #include "mtypes.h" #include "frames.h" #include "prototypes.h" #include "block.h" #include "mpeg.h" #include "param.h" #include "mheaders.h" #include "fsize.h" #include "parallel.h" #include "postdct.h" #include "rate.h" #include "specifics.h" #include "opts.h" #include "iframe.h" /*==================* * STATIC VARIABLES * *==================*/ static int lastNumBits = 0; static int lastIFrame = 0; static int numBlocks = 0; static int numBits; static int numFrames = 0; static int numFrameBits = 0; static int32 totalTime = 0; static float totalSNR = 0.0; static float totalPSNR = 0.0; static int lengths[256] = { 0, 1, 2, 2, 3, 3, 3, 3, /* 0 - 7 */ 4, 4, 4, 4, 4, 4, 4, 4, /* 8 - 15 */ 5, 5, 5, 5, 5, 5, 5, 5, /* 16 - 31 */ 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, /* 32 - 63 */ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, /* 64 - 127 */ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; /*==================* * GLOBAL VARIABLES * *==================*/ int qscaleI; int slicesPerFrame; int blocksPerSlice; int fCodeI, fCodeP, fCodeB; boolean printSNR = FALSE; boolean printMSE = FALSE; boolean decodeRefFrames = FALSE; int TIME_RATE; static int SetFCodeHelper(int const SR) { int range,fCode; if ( pixelFullSearch ) { range = SR; } else { range = SR*2; } if ( range < 256 ) { if ( range < 64 ) { if ( range < 32 ) { fCode = 1; } else { fCode = 2; } } else { if ( range < 128 ) { fCode = 3; } else { fCode = 4; } } } else { if ( range < 1024 ) { if ( range < 512 ) { fCode = 5; } else { fCode = 6; } } else { if ( range < 2048 ) { fCode = 7; } else { fprintf(stderr, "ERROR: INVALID SEARCH RANGE!!!\n"); exit(1); } } } return fCode; } /*===========================================================================* * * SetFCode * * set the forward_f_code and backward_f_code according to the search * range. Must be called AFTER pixelFullSearch and searchRange have * been initialized. Irrelevant for I-frames, but computation is * negligible (done only once, as well) * * RETURNS: nothing * * SIDE EFFECTS: fCodeI,fCodeP,fCodeB * *===========================================================================*/ void SetFCode(void) { fCodeI = SetFCodeHelper(1); /* GenIFrame ignores value */ fCodeP = SetFCodeHelper(searchRangeP); fCodeB = SetFCodeHelper(searchRangeB); } /*===========================================================================* * * SetSlicesPerFrame * * set the number of slices per frame * * RETURNS: nothing * * SIDE EFFECTS: slicesPerFrame * *===========================================================================*/ void SetSlicesPerFrame(int const number) { slicesPerFrame = number; } /*===========================================================================* * * SetBlocksPerSlice * * set the number of blocks per slice, based on slicesPerFrame * * RETURNS: nothing * * SIDE EFFECTS: blocksPerSlice * *===========================================================================*/ void SetBlocksPerSlice(void) { int totalBlocks; totalBlocks = (Fsize_y>>4)*(Fsize_x>>4); if ( slicesPerFrame > totalBlocks ) { blocksPerSlice = 1; } else { blocksPerSlice = totalBlocks/slicesPerFrame; } } /*===========================================================================* * * SetIQScale * * set the I-frame Q-scale * * RETURNS: nothing * * SIDE EFFECTS: qscaleI * *===========================================================================*/ void SetIQScale(int const qI) { qscaleI = qI; } /*===========================================================================* * * GetIQScale * * Get the I-frame Q-scale * * RETURNS: the Iframe Qscale * * SIDE EFFECTS: none * *===========================================================================*/ int GetIQScale(void) { return qscaleI; } static void CalcDistortion(MpegFrame * const current, int const y, int const x) { int qscale, distort=0; Block decblk; FlatBlock fblk; int datarate = 0; for (qscale = 1; qscale < 32; qscale ++) { distort = 0; datarate = 0; Mpost_QuantZigBlock(dct[y][x], fblk, qscale, TRUE); Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); mpeg_jrevdct((int16 *)decblk); distort += mse(current->y_blocks[y][x], decblk); Mpost_QuantZigBlock(dct[y][x+1], fblk, qscale, TRUE); Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); mpeg_jrevdct((int16 *)decblk); distort += mse(current->y_blocks[y][x+1], decblk); Mpost_QuantZigBlock(dct[y+1][x], fblk, qscale, TRUE); Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); mpeg_jrevdct((int16 *)decblk); distort += mse(current->y_blocks[y+1][x], decblk); Mpost_QuantZigBlock(dct[y+1][x+1], fblk, qscale, TRUE); Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); mpeg_jrevdct((int16 *)decblk); distort += mse(current->y_blocks[y+1][x+1], decblk); Mpost_QuantZigBlock(dctb[y >> 1][x >> 1], fblk, qscale, TRUE); Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); mpeg_jrevdct((int16 *)decblk); distort += mse(current->cb_blocks[y>>1][x>>1], decblk); Mpost_QuantZigBlock(dctr[y >> 1][x >> 1], fblk, qscale, TRUE); Mpost_UnQuantZigBlock(fblk, decblk, qscale, TRUE); if (collect_distortion_detailed) datarate += CalcRLEHuffLength(fblk); mpeg_jrevdct((int16 *)decblk); distort += mse(current->cr_blocks[y >> 1][x >> 1], decblk); if (!collect_distortion_detailed) { fprintf(distortion_fp, "\t%d\n", distort); } else if (collect_distortion_detailed == 1) { fprintf(distortion_fp, "\t%d\t%d\n", distort, datarate); } else { fprintf(fp_table_rate[qscale-1], "%d\n", datarate); fprintf(fp_table_dist[qscale-1], "%d\n", distort); } } } /*===========================================================================* * * GenIFrame * * generate an I-frame; appends result to bb * * RETURNS: I-frame appended to bb * * SIDE EFFECTS: none * *===========================================================================*/ void GenIFrame(BitBucket * const bb, MpegFrame * const current) { int x, y; int index; FlatBlock fb[6]; Block dec[6]; int32 y_dc_pred, cr_dc_pred, cb_dc_pred; int totalBits; int totalFrameBits; int32 startTime, endTime; float snr[3], psnr[3]; int mbAddress; int QScale; BlockMV *info; /* Not used in Iframes, but nice to pass in anyway */ int bitstreamMode, newQScale; int rc_blockStart=0; if (dct==NULL) AllocDctBlocks(); if (collect_quant) {fprintf(collect_quant_fp, "# I\n");} /* set-up for statistics */ numFrames++; totalFrameBits = bb->cumulativeBits; if ( showBitRatePerFrame ) { if ( lastNumBits == 0 ) { lastNumBits = bb->cumulativeBits; lastIFrame = current->id; } else { /* ASSUMES 30 FRAMES PER SECOND */ if (! realQuiet) { fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n", lastIFrame, current->id-1, ((bb->cumulativeBits-lastNumBits)*30)/ (current->id-lastIFrame)); } fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n", lastIFrame, current->id-1, ((bb->cumulativeBits-lastNumBits)*30)/ (current->id-lastIFrame)); lastNumBits = bb->cumulativeBits; lastIFrame = current->id; } } startTime = time_elapsed(); Frame_AllocBlocks(current); BlockifyFrame(current); DBG_PRINT(("Generating iframe\n")); QScale = GetIQScale(); /* Allocate bits for this frame for rate control purposes */ bitstreamMode = getRateMode(); if (bitstreamMode == FIXED_RATE) { targetRateControl(current); } Mhead_GenPictureHeader(bb, I_FRAME, current->id, fCodeI); /* Check for Qscale change */ if (specificsOn) { newQScale = SpecLookup(current->id, 0, 0 /* junk */, &info, QScale); if (newQScale != -1) { QScale = newQScale; } /* check for slice */ newQScale = SpecLookup(current->id, 1, 1, &info, QScale); if (newQScale != -1) { QScale = newQScale; } } Mhead_GenSliceHeader(bb, 1, QScale, NULL, 0); if ( referenceFrame == DECODED_FRAME ) { Frame_AllocDecoded(current, TRUE); } else if ( printSNR ) { Frame_AllocDecoded(current, FALSE); } y_dc_pred = cr_dc_pred = cb_dc_pred = 128; totalBits = bb->cumulativeBits; mbAddress = 0; /* DCT the macroblocks */ for (y = 0; y < (Fsize_y >> 3); y += 2) { for (x = 0; x < (Fsize_x >> 3); x += 2) { if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "l\n"); if (DoLaplace) {LaplaceCnum = 0;} mp_fwd_dct_block2(current->y_blocks[y][x], dct[y][x]); mp_fwd_dct_block2(current->y_blocks[y][x+1], dct[y][x+1]); mp_fwd_dct_block2(current->y_blocks[y+1][x], dct[y+1][x]); mp_fwd_dct_block2(current->y_blocks[y+1][x+1], dct[y+1][x+1]); if (collect_quant && (collect_quant_detailed & 1)) fprintf(collect_quant_fp, "c\n"); if (DoLaplace) {LaplaceCnum = 1;} mp_fwd_dct_block2(current->cb_blocks[y>>1][x>>1], dctb[y>>1][x>>1]); if (DoLaplace) {LaplaceCnum = 2;} mp_fwd_dct_block2(current->cr_blocks[y>>1][x>>1], dctr[y>>1][x>>1]); } } if (DoLaplace) CalcLambdas(); for (y = 0; y < (Fsize_y >> 3); y += 2) { for (x = 0; x < (Fsize_x >> 3); x += 2) { /* Check for Qscale change */ if (specificsOn) { newQScale = SpecLookup(current->id, 2, mbAddress, &info, QScale); if (newQScale != -1) { QScale = newQScale; } } /* Determine if new Qscale needed for Rate Control purposes */ if (bitstreamMode == FIXED_RATE) { rc_blockStart = bb->cumulativeBits; newQScale = needQScaleChange(qscaleI, current->y_blocks[y][x], current->y_blocks[y][x+1], current->y_blocks[y+1][x], current->y_blocks[y+1][x+1]); if (newQScale > 0) { QScale = newQScale; } } if ( (mbAddress % blocksPerSlice == 0) && (mbAddress != 0) ) { /* create a new slice */ if (specificsOn) { /* Make sure no slice Qscale change */ newQScale = SpecLookup(current->id, 1, mbAddress/blocksPerSlice, &info, QScale); if (newQScale != -1) QScale = newQScale; } Mhead_GenSliceEnder(bb); Mhead_GenSliceHeader(bb, 1+(y>>1), QScale, NULL, 0); y_dc_pred = cr_dc_pred = cb_dc_pred = 128; GEN_I_BLOCK(I_FRAME, current, bb, 1+(x>>1), QScale); } else { GEN_I_BLOCK(I_FRAME, current, bb, 1, QScale); } if (WriteDistortionNumbers) { CalcDistortion(current, y, x); } if ( decodeRefFrames ) { /* now, reverse the DCT transform */ LaplaceCnum = 0; for ( index = 0; index < 6; index++ ) { if (!DoLaplace) { Mpost_UnQuantZigBlock(fb[index], dec[index], QScale, TRUE); } else { if (index == 4) {LaplaceCnum = 1;} if (index == 5) {LaplaceCnum = 2;} Mpost_UnQuantZigBlockLaplace(fb[index], dec[index], QScale, TRUE); } mpeg_jrevdct((int16 *)dec[index]); } /* now, unblockify */ BlockToData(current->decoded_y, dec[0], y, x); BlockToData(current->decoded_y, dec[1], y, x+1); BlockToData(current->decoded_y, dec[2], y+1, x); BlockToData(current->decoded_y, dec[3], y+1, x+1); BlockToData(current->decoded_cb, dec[4], y>>1, x>>1); BlockToData(current->decoded_cr, dec[5], y>>1, x>>1); } numBlocks++; mbAddress++; /* Rate Control */ if (bitstreamMode == FIXED_RATE) { incMacroBlockBits(bb->cumulativeBits - rc_blockStart); rc_blockStart = bb->cumulativeBits; MB_RateOut(TYPE_IFRAME); } } } if ( printSNR ) { BlockComputeSNR(current,snr,psnr); totalSNR += snr[0]; totalPSNR += psnr[0]; } numBits += (bb->cumulativeBits-totalBits); DBG_PRINT(("End of frame\n")); Mhead_GenSliceEnder(bb); /* Rate Control */ if (bitstreamMode == FIXED_RATE) { updateRateControl(TYPE_IFRAME); } endTime = time_elapsed(); totalTime += (endTime-startTime); numFrameBits += (bb->cumulativeBits-totalFrameBits); if ( showBitRatePerFrame ) { /* ASSUMES 30 FRAMES PER SECOND */ fprintf(bitRateFile, "%5d\t%8d\n", current->id, 30*(bb->cumulativeBits-totalFrameBits)); } if ( frameSummary && !realQuiet ) { /* ASSUMES 30 FRAMES PER SECOND */ fprintf(stdout, "FRAME %d (I): %ld seconds (%d bits/s output)\n", current->id, (long)((endTime-startTime)/TIME_RATE), 30*(bb->cumulativeBits-totalFrameBits)); if ( printSNR ) { fprintf(stdout, "FRAME %d: SNR: %.1f\t%.1f\t%.1f\t" "PSNR: %.1f\t%.1f\t%.1f\n", current->id, snr[0], snr[1], snr[2], psnr[0], psnr[1], psnr[2]); } } } /*===========================================================================* * * ResetIFrameStats * * reset the I-frame statistics * * RETURNS: nothing * * SIDE EFFECTS: none * *===========================================================================*/ void ResetIFrameStats(void) { numBlocks = 0; numBits = 0; numFrames = 0; numFrameBits = 0; totalTime = 0; } float IFrameTotalTime(void) { return (float)totalTime/(float)TIME_RATE; } void ShowIFrameSummary(unsigned int const inputFrameBits, unsigned int const totalBits, FILE * const fpointer) { /*---------------------------------------------------------------------------- Print out statistics on all I frames. -----------------------------------------------------------------------------*/ if (numFrames > 0) { fprintf(fpointer, "-------------------------\n"); fprintf(fpointer, "*****I FRAME SUMMARY*****\n"); fprintf(fpointer, "-------------------------\n"); fprintf(fpointer, " Blocks: %5d (%6d bits) (%5d bpb)\n", numBlocks, numBits, numBits/numBlocks); fprintf(fpointer, " Frames: %5d (%6d bits) (%5d bpf)" "(%2.1f%% of total)\n", numFrames, numFrameBits, numFrameBits/numFrames, 100.0*(float)numFrameBits/(float)totalBits); fprintf(fpointer, " Compression: %3d:1 (%9.4f bpp)\n", numFrames*inputFrameBits/numFrameBits, 24.0*(float)numFrameBits/(float)(numFrames*inputFrameBits)); if ( printSNR ) fprintf(fpointer, " Avg Y SNR/PSNR: %.1f %.1f\n", totalSNR/(float)numFrames, totalPSNR/(float)numFrames); if ( totalTime == 0 ) { fprintf(fpointer, " Seconds: NONE\n"); } else { fprintf(fpointer, " Seconds: %9ld (%9.4f fps) (%9ld pps) " "(%9ld mps)\n", (long)(totalTime/TIME_RATE), (float)((float)(TIME_RATE*numFrames)/(float)totalTime), (long)((float)TIME_RATE * (float)numFrames * (float)inputFrameBits/(24.0*(float)totalTime)), (long)((float)TIME_RATE*(float)numFrames * (float)inputFrameBits/(256.0*24.0 * (float)totalTime))); } } } /*===========================================================================* * * EncodeYDC * * Encode the DC portion of a DCT of a luminance block * * RETURNS: result appended to bb * * SIDE EFFECTS: updates pred_term * *===========================================================================*/ void EncodeYDC(int32 const dc_term, int32 * const pred_term, BitBucket * const bb) { /* see Table B.5a -- MPEG-I doc */ static int codes[9] = { 0x4, 0x0, 0x1, 0x5, 0x6, 0xe, 0x1e, 0x3e, 0x7e }; static int codeLengths[9] = { 3, 2, 2, 3, 3, 4, 5, 6, 7 }; int ydiff, ydiff_abs; int length; ydiff = (dc_term - (*pred_term)); if (ydiff > 255) { #ifdef BLEAH fprintf(stdout, "TRUNCATED\n"); #endif ydiff = 255; } else if (ydiff < -255) { #ifdef BLEAH fprintf(stdout, "TRUNCATED\n"); #endif ydiff = -255; } ydiff_abs = ABS(ydiff); length = lengths[ydiff_abs]; Bitio_Write(bb, codes[length], codeLengths[length]); if ( length != 0 ) { if ( ydiff > 0 ) { Bitio_Write(bb, ydiff_abs, length); } else { Bitio_Write(bb, ~ydiff_abs, length); } } (*pred_term) += ydiff; } /*===========================================================================* * * EncodeCDC * * Encode the DC portion of a DCT of a chrominance block * * RETURNS: result appended to bb * * SIDE EFFECTS: updates pred_term * *===========================================================================*/ void EncodeCDC(int32 const dc_term, int32 * const pred_term, BitBucket * const bb) { /* see Table B.5b -- MPEG-I doc */ static int codes[9] = { 0x0, 0x1, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe }; static int codeLengths[9] = { 2, 2, 2, 3, 4, 5, 6, 7, 8 }; int cdiff, cdiff_abs; int length; cdiff = (dc_term - (*pred_term)); if (cdiff > 255) { #ifdef BLEAH fprintf(stdout, "TRUNCATED\n"); #endif cdiff = 255; } else if (cdiff < -255) { #ifdef BLEAH fprintf(stdout, "TRUNCATED\n"); #endif cdiff = -255; } cdiff_abs = ABS(cdiff); length = lengths[cdiff_abs]; Bitio_Write(bb, codes[length], codeLengths[length]); if ( length != 0 ) { if ( cdiff > 0 ) { Bitio_Write(bb, cdiff_abs, length); } else { Bitio_Write(bb, ~cdiff_abs, length); } } (*pred_term) += cdiff; } void BlockComputeSNR(MpegFrame * const current, float * const snr, float * const psnr) { int32 tempInt; int y, x; int32 varDiff[3]; double ratio[3]; double total[3]; uint8 **origY=current->orig_y, **origCr=current->orig_cr, **origCb=current->orig_cb; uint8 **newY=current->decoded_y, **newCr=current->decoded_cr, **newCb=current->decoded_cb; static int32 **SignalY, **NoiseY; static int32 **SignalCb, **NoiseCb; static int32 **SignalCr, **NoiseCr; static short ySize[3], xSize[3]; static boolean needs_init=TRUE; /* Init */ if (needs_init) { int ysz = (Fsize_y>>3) * sizeof(int32 *); int xsz = (Fsize_x>>3); needs_init = FALSE; for (y=0; y<3; y++) { varDiff[y] = ratio[y] = total[y] = 0.0; } ySize[0]=Fsize_y; xSize[0]=Fsize_x; ySize[1]=Fsize_y>>1; xSize[1]=Fsize_x>>1; ySize[2]=Fsize_y>>1; xSize[2]=Fsize_x>>1; SignalY = (int32 **) malloc(ysz); NoiseY = (int32 **) malloc(ysz); SignalCb = (int32 **) malloc(ysz); NoiseCb = (int32 **) malloc(ysz); SignalCr = (int32 **) malloc(ysz); NoiseCr = (int32 **) malloc(ysz); if (SignalY == NULL || NoiseY == NULL || SignalCr == NULL || NoiseCb == NULL || SignalCb == NULL || NoiseCr == NULL) { fprintf(stderr, "Out of memory in BlockComputeSNR\n"); exit(-1); } for (y = 0; y < ySize[0]>>3; y++) { SignalY[y] = (int32 *) calloc(xsz,4); SignalCr[y] = (int32 *) calloc(xsz,4); SignalCb[y] = (int32 *) calloc(xsz,4); NoiseY[y] = (int32 *) calloc(xsz,4); NoiseCr[y] = (int32 *) calloc(xsz,4); NoiseCb[y] = (int32 *) calloc(xsz,4); } } else { for (y = 0; y < ySize[0]>>3; y++) { memset((char *) &NoiseY[y][0], 0, (xSize[0]>>3) * 4); memset((char *) &SignalY[y][0], 0, (xSize[0]>>3) * 4); memset((char *) &NoiseCb[y][0], 0, (xSize[0]>>3) * 4); memset((char *) &NoiseCr[y][0], 0, (xSize[0]>>3) * 4); memset((char *) &SignalCb[y][0], 0, (xSize[0]>>3) * 4); memset((char *) &SignalCr[y][0], 0, (xSize[0]>>3) * 4); } } /* find all the signal and noise */ for (y = 0; y < ySize[0]; y++) { for (x = 0; x < xSize[0]; x++) { tempInt = (origY[y][x] - newY[y][x]); NoiseY[y>>4][x>>4] += tempInt*tempInt; total[0] += (double)abs(tempInt); tempInt = origY[y][x]; SignalY[y>>4][x>>4] += tempInt*tempInt; }} for (y = 0; y < ySize[1]; y++) { for (x = 0; x < xSize[1]; x ++) { tempInt = (origCb[y][x] - newCb[y][x]); NoiseCb[y>>3][x>>3] += tempInt*tempInt; total[1] += (double)abs(tempInt); tempInt = origCb[y][x]; SignalCb[y>>3][x>>3] += tempInt*tempInt; tempInt = (origCr[y][x]-newCr[y][x]); NoiseCr[y>>3][x>>3] += tempInt*tempInt; total[2] += (double)abs(tempInt); tempInt = origCr[y][x]; SignalCr[y>>3][x>>3] += tempInt*tempInt; }} /* Now sum up that noise */ for(y=0; y>4; y++){ for(x=0; x>4; x++){ varDiff[0] += NoiseY[y][x]; varDiff[1] += NoiseCb[y][x]; varDiff[2] += NoiseCr[y][x]; if (printMSE) printf("%4d ",(int)(NoiseY[y][x]/256.0)); } if (printMSE) puts(""); } /* Now look at those ratios! */ for(y=0; y>4; y++){ for(x=0; x>4; x++){ ratio[0] += (double)SignalY[y][x]/(double)varDiff[0]; ratio[1] += (double)SignalCb[y][x]/(double)varDiff[1]; ratio[2] += (double)SignalCr[y][x]/(double)varDiff[2]; }} for (x=0; x<3; x++) { snr[x] = 10.0 * log10(ratio[x]); psnr[x] = 20.0 * log10(255.0/sqrt((double)varDiff[x]/ (double)(ySize[x]*xSize[x]))); if (! realQuiet) { fprintf(stdout, "Mean error[%1d]: %f\n", x, total[x] / (double)(xSize[x] * ySize[x])); } } } void WriteDecodedFrame(MpegFrame * const frame) { FILE * fpointer; char fileName[256]; int width, height; int y; /* need to save decoded frame to disk because it might be accessed by another process */ width = Fsize_x; height = Fsize_y; sprintf(fileName, "%s.decoded.%d", outputFileName, frame->id); if (!realQuiet) { fprintf(stdout, "Outputting to %s\n", fileName); fflush(stdout); } fpointer = fopen(fileName, "wb"); for ( y = 0; y < height; y++ ) { fwrite(frame->decoded_y[y], 1, width, fpointer); } for (y = 0; y < (height >> 1); y++) { /* U */ fwrite(frame->decoded_cb[y], 1, width >> 1, fpointer); } for (y = 0; y < (height >> 1); y++) { /* V */ fwrite(frame->decoded_cr[y], 1, width >> 1, fpointer); } fflush(fpointer); fclose(fpointer); } void PrintItoIBitRate(int const numBits, int const frameNum) { if ( showBitRatePerFrame ) { /* ASSUMES 30 FRAMES PER SECOND */ if (! realQuiet) { fprintf(stdout, "I-to-I (frames %5d to %5d) bitrate: %8d\n", lastIFrame, frameNum-1, ((numBits-lastNumBits)*30)/ (frameNum-lastIFrame)); } fprintf(bitRateFile, "I-to-I (frames %5d to %5d) bitrate: %8d\n", lastIFrame, frameNum-1, ((numBits-lastNumBits)*30)/ (frameNum-lastIFrame)); } } /*======================================================================* * * time_elapsed * * Handle different time systems on different machines * * RETURNS number of seconds process time used * *======================================================================*/ int32 time_elapsed(void) { #ifdef CLOCKS_PER_SEC /* ANSI C */ TIME_RATE = CLOCKS_PER_SEC; return (int32) clock(); #else struct tms timeBuffer; TIME_RATE = 60; times(&timeBuffer); return timeBuffer.tms_utime + timeBuffer.tms_stime; #endif }