diff options
Diffstat (limited to 'converter/ppm/ppmtompeg/iframe.c')
-rw-r--r-- | converter/ppm/ppmtompeg/iframe.c | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/converter/ppm/ppmtompeg/iframe.c b/converter/ppm/ppmtompeg/iframe.c new file mode 100644 index 00000000..cb6d4683 --- /dev/null +++ b/converter/ppm/ppmtompeg/iframe.c @@ -0,0 +1,1062 @@ +/*===========================================================================* + * iframe.c * + * * + * Procedures concerned with the I-frame encoding * + * * + * EXPORTED PROCEDURES: * + * GenIFrame * + * SetSlicesPerFrame * + * SetBlocksPerSlice * + * SetIQScale * + * GetIQScale * + * ResetIFrameStats * + * ShowIFrameSummary * + * EstimateSecondsPerIFrame * + * 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 * + *==============*/ + + +#ifdef CLOCKS_PER_SEC +#include <times.h> +#else +#include <sys/times.h> +#endif + +#include <sys/types.h> +#include <sys/param.h> +#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" + +/*==================* + * 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; +Block **dct=NULL, **dctr=NULL, **dctb=NULL; +dct_data_type **dct_data; /* used in p/bframe.c */ +int TIME_RATE; + + +/*=====================* + * EXPORTED PROCEDURES * + *=====================*/ +extern void PrintItoIBitRate _ANSI_ARGS_((int numBits, int frameNum)); + +/*===============================* + * INTERNAL PROCEDURE prototypes * + *===============================*/ +void AllocDctBlocks(void ); +int SetFCodeHelper (int sr); +void CalcDistortion (MpegFrame *current, int y, int x); + +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; +} + + + +/*===========================================================================* + * + * 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))); + } + } +} + + + +/*===========================================================================* + * + * EstimateSecondsPerIFrame + * + * estimates the number of seconds required per I-frame + * + * RETURNS: seconds (floating point value) + * + * SIDE EFFECTS: none + * + *===========================================================================*/ +float +EstimateSecondsPerIFrame() +{ + return (float)totalTime/((float)TIME_RATE*(float)numFrames); +} + + +/*===========================================================================* + * + * 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<Fsize_y>>4; y++){ + for(x=0; x<Fsize_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<Fsize_y>>4; y++){ + for(x=0; x<Fsize_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)); + } +} + + + +/*===========================================================================* + * + * AllocDctBlocks + * + * allocate memory for dct blocks + * + * RETURNS: nothing + * + * SIDE EFFECTS: creates dct, dctr, dctb + * + *===========================================================================*/ +void +AllocDctBlocks(void) { + int dctx, dcty; + int i; + + dctx = Fsize_x / DCTSIZE; + dcty = Fsize_y / DCTSIZE; + + dct = (Block **) malloc(sizeof(Block *) * dcty); + ERRCHK(dct, "malloc"); + for (i = 0; i < dcty; i++) { + dct[i] = (Block *) malloc(sizeof(Block) * dctx); + ERRCHK(dct[i], "malloc"); + } + + dct_data = (dct_data_type **) malloc(sizeof(dct_data_type *) * dcty); + ERRCHK(dct_data, "malloc"); + for (i = 0; i < dcty; i++) { + dct_data[i] = (dct_data_type *) malloc(sizeof(dct_data_type) * dctx); + ERRCHK(dct[i], "malloc"); + } + + dctr = (Block **) malloc(sizeof(Block *) * (dcty >> 1)); + dctb = (Block **) malloc(sizeof(Block *) * (dcty >> 1)); + ERRCHK(dctr, "malloc"); + ERRCHK(dctb, "malloc"); + for (i = 0; i < (dcty >> 1); i++) { + dctr[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1)); + dctb[i] = (Block *) malloc(sizeof(Block) * (dctx >> 1)); + ERRCHK(dctr[i], "malloc"); + ERRCHK(dctb[i], "malloc"); + } +} + + + +/*======================================================================* + * + * 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 +} + + + +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); + } + } +} + + + + |