#include "codec.h" //#include "libc.h" #include "Zim.h" #include "math.h" #include "ParamImSeq.h" static TagTable *image; static TagTable *newImage; static TagTable *previousImage[2]; // the ones in video ram and offscreen ram static int numQuadCels; static int whichFrame; static BOOL detail; static int onQuad; static int initRGBtab; static byte luty[256]; static byte *luti; static quadcel *qStatus; static int dxMean; static int dyMean; static int codebooksize; static int index2[256]; static int overAmount; static VQDATA **codebook2; static VQDATA norm2[256]; static int index4[256]; static VQDATA **codebook4; static VQDATA norm4[256]; static int pixelsWide; static int pixelsHigh; static int codebookmade; static BOOL used2[256]; static BOOL used4[256]; static int dimension2; static int dimension4; static int currentTotalBits; static int sizeQuickAdd[DEAD+1]; int CodecInit( ) { int i; printf("init: initing.....\n"); codebooksize = 256; codebook2 = (VQDATA **) calloc(256,sizeof(VQDATA *)); for(i=0; i < 256; i++) { codebook2[i] = (VQDATA *) calloc(16,sizeof(VQDATA)); } codebook4 = (VQDATA **) calloc(256,sizeof(VQDATA *)); for(i=0; i < 256; i++) { codebook4[i] = (VQDATA *) calloc(64,sizeof(VQDATA)); } previousImage[0] = 0; image = NULL; whichFrame = 0; qStatus = 0; luti = 0; overAmount = 0; codebookmade = 0; sizeQuickAdd[DEP] = 2; sizeQuickAdd[SLD] = 10; sizeQuickAdd[PAT] = 10; sizeQuickAdd[CCC] = 34; sizeQuickAdd[MOT] = 2; sizeQuickAdd[FCC] = 10; sizeQuickAdd[DEAD] = 0; currentTotalBits = 0; if ( RoqIsQuiet() == NO) { unlink("/LocalLibrary/RoQFiles/previousFrame.tiff"); unlink("/LocalLibrary/RoQFiles/previousPreviousFrame.tiff"); } return 1; } int CodecFree( ) { printf("free: resetting\n"); if (qStatus) free(qStatus); if (luti) free(luti); if (previousImage[0]) ZimFree(previousImage[0]); if (previousImage[1]) ZimFree(previousImage[1]); qStatus = 0; initRGBtab = 0; previousImage[0] = 0; whichFrame = 0; luti = 0; return 1; } /* Because Shellsort is a variation on Insertion Sort, it has the same * inconsistency that I noted in the InsertionSort class. Notice where I * subtract a move to compensate for calling a swap for visual purposes. */ int CodecSort( float * list ,int * intIndex ,int numElements ) { #define STRIDE_FACTOR 3 // good value for stride factor is not well-understood // 3 is a fairly good choice (Sedgewick) int c,d, stride; BOOL found; stride = 1; while (stride <= numElements) stride = stride*STRIDE_FACTOR +1; while (stride>(STRIDE_FACTOR-1)) { // loop to sort for each value of stride stride = stride / STRIDE_FACTOR; for (c = stride; c < numElements; c++){ found = NO; d = c-stride; while ((d >= 0) && !found) { // move to left until correct place if (list[d] numc) numc = numElements; onf = 0; for(x=0;x bestdistortion) j = dimension; /* abort loop */ } if (tempfloat < bestdistortion) { bestdistortion = tempfloat; bestcodeword = i; } /* if bestidistortion is 0 then the best codeword has been found */ if (bestdistortion == 0.0) i = codebooksize; } /* the best codeword has been found */ return index[bestcodeword]; } int CodecSetPreviousImage( const char* filename ,TagTable * timage) { if (previousImage[0]) { ZimFree(previousImage[0]); } if (previousImage[1]) { ZimFree(previousImage[1]); } printf("setPreviousImage:%s\n", filename); image = ZimImageTagTableFromFile(filename, "jpeg"); whichFrame=1; pixelsHigh = ZimHeight(image); pixelsWide = ZimWidth(image); printf("setPreviousImage: %dx%d\n", pixelsWide, pixelsHigh ); previousImage[0] = ZimImageTagTableNew(pixelsWide, pixelsHigh, IMVFBRGB | IMVFBALPHA); previousImage[1] = ZimImageTagTableNew(pixelsWide, pixelsHigh, IMVFBRGB | IMVFBALPHA); // memcpy( ZimData(previousImage[0]), ZimData(image), pixelsWide*pixelsHigh*4); // memcpy( ZimData(previousImage[1]), ZimData(image), pixelsWide*pixelsHigh*4); ZimFree(image); printf("setPreviousImage:done\n"); return 1; } int CodecMakePreviousImage( quadcel * pquad ) { int i, dy, dx, pluck, size, ind, renamedone, xx, yy, pWide; int x, y; byte *rgbmap, *idataA, *fccdictionary; BOOL diff; if (RoqIsQuiet() == NO) { renamedone = rename("/LocalLibrary/RoQFiles/previousFrame.tiff", "/LocalLibrary/RoQFiles/previousPreviousFrame.tiff" ); } for(i=0;i<256;i++) { used2[i] = used4[i] = NO; } pWide = pixelsWide & 0xfff0; if (!previousImage[0]) { previousImage[0] = ZimImageTagTableNew(pWide, pixelsHigh & 0xfff0, IMVFBRGB | IMVFBALPHA); previousImage[1] = ZimImageTagTableNew(pWide, pixelsHigh & 0xfff0, IMVFBRGB | IMVFBALPHA); } rgbmap = ZimData(previousImage[(whichFrame&1)]); if ((whichFrame&1) == 1) { fccdictionary = ZimData(previousImage[0]); } else { fccdictionary = ZimData(previousImage[1]); } idataA = malloc( 16*16*4 ); for(i=0;i>1)*dimension2)+(dx>>1)*(dimension2/4); if (rgbmap[pluck+0] != codebook4[ind][xx+0]) diff = YES; if (rgbmap[pluck+1] != codebook4[ind][xx+1]) diff = YES; if (rgbmap[pluck+2] != codebook4[ind][xx+2]) diff = YES; if (dimension4 == 64 && rgbmap[pluck+3] != codebook4[ind][xx+3]) diff = YES; rgbmap[pluck+0] = codebook4[ind][xx+0]; rgbmap[pluck+1] = codebook4[ind][xx+1]; rgbmap[pluck+2] = codebook4[ind][xx+2]; if (dimension4 == 64) rgbmap[pluck+3] = codebook4[ind][xx+3]; else rgbmap[pluck+3] = 255; pluck += 4; } } if (diff == NO && whichFrame) printf("drawImage: SLD just changed the same thing\n"); break; case PAT: ind = pquad[i].patten[0]; used4[ind] = YES; for( dy=0; dy> 8 ) - 128); dy = pquad[i].yat - ((pquad[i].domain & 0xff) - 128); if (ZimWidth(image) == (ZimHeight(image)*4)) dx = pquad[i].xat - ((pquad[i].domain >> 8 ) - 128)*2; // interlaced style video recognition hack if (RoqScaleable()) { dx = pquad[i].xat - ((pquad[i].domain >> 8 ) - 128)*2; dy = pquad[i].yat - ((pquad[i].domain & 0xff) - 128)*2; } // if (pquad[i].yat == 0) printf("dx = %d, dy = %d, xat = %d\n", dx, dy, pquad[i].xat); ind = (dy*pWide+dx)*4; for( dy=0; dy= lowx) && (startX+quadSize) <= (bigx) && (startY+quadSize) <= (bigy) && (startY >= lowy) && quadSize <= MAXSIZE) { qStatus[onQuad].size = quadSize; qStatus[onQuad].xat = startX; qStatus[onQuad].yat = startY; onQuad++; } if (quadSize != MINSIZE) { startSize = quadSize>>1; CodecQuadX( startX, startY, startSize); CodecQuadX( startX+startSize, startY, startSize); CodecQuadX( startX, startY+startSize, startSize); CodecQuadX( startX+startSize, startY+startSize, startSize); } return 1; } int CodecInitQStatus( ) { int i,x,y; for (i=0; ipatten[0] = best = CodecBestCodeword(tempImage, dimension4, codebook4, norm4, index4); for(y=0;y<8;y++) { for(x=0;x<8;x++) { temp = y*32+x*4; i = ((y/2)*4*(dimension2/4))+(x/2)*(dimension2/4); tempImage[temp+0] = codebook4[best][i+0]; tempImage[temp+1] = codebook4[best][i+1]; tempImage[temp+2] = codebook4[best][i+2]; if (dimension4 == 64) tempImage[temp+3] = codebook4[best][i+3]; else tempImage[temp+3] = 255; } } pquad->snr[SLD] = CodecSnr(cel, tempImage, 8); return 1; } int CodecVqData4( byte * cel , quadcel * pquad ) { byte tempImage[64]; int i, best, bpp; // if ([theRoQ makingVideo] && previousImage[0]) return 1; if (dimension4 == 64) bpp = 4; else bpp = 3; for(i=0;i<16;i++) { tempImage[i*bpp+0] = cel[i*4+0]; tempImage[i*bpp+1] = cel[i*4+1]; tempImage[i*bpp+2] = cel[i*4+2]; if (dimension4 == 64) tempImage[i*bpp+3] = cel[i*4+3]; } pquad->patten[0] = best = CodecBestCodeword(tempImage, dimension4, codebook4, norm4, index4); for(i=0;i<16;i++) { tempImage[i*4+0] = codebook4[best][i*bpp+0]; tempImage[i*4+1] = codebook4[best][i*bpp+1]; tempImage[i*4+2] = codebook4[best][i*bpp+2]; if (dimension4 == 64) tempImage[i*4+3] = codebook4[best][i*bpp+3]; else tempImage[i*4+3] = 255; } pquad->snr[PAT] = CodecSnr(cel, tempImage, 4); return 1; } int CodecVqData2( byte * cel , quadcel * pquad ) { byte tempImage[16], tempOut[64]; int i, j, best,x,y,xx,yy,bpp; if (dimension4 == 64) bpp = 4; else bpp = 3; j = 1; for(yy=0;yy<4;yy+=2) { for(xx=0;xx<4;xx+=2) { i = 0; for(y=yy;y<(yy+2);y++) { for(x=xx;x<(xx+2);x++) { tempImage[i++] = cel[y*16+x*4+0]; tempImage[i++] = cel[y*16+x*4+1]; tempImage[i++] = cel[y*16+x*4+2]; if (dimension4 == 64) tempImage[i++] = cel[y*16+x*4+3]; } } pquad->patten[j++] = best = CodecBestCodeword(tempImage, dimension2, codebook2, norm2, index2); i = 0; for(y=yy;y<(yy+2);y++) { for(x=xx;x<(xx+2);x++) { tempOut[y*16+x*4+0] = codebook2[best][i++]; tempOut[y*16+x*4+1] = codebook2[best][i++]; tempOut[y*16+x*4+2] = codebook2[best][i++]; if (dimension4 == 64) tempOut[y*16+x*4+3] = codebook2[best][i++]; else tempOut[y*16+x*4+3] = 255; } } } } pquad->snr[CCC] = CodecSnr(cel, tempOut, 4); return 1; } int CodecIRGBtab ( ) { initRGBtab++; return 1; } float CodecSnr( byte * old ,byte * new ,int size) { int i, j; float fsnr; register int ind; ind = 0; for(i=0; isnr[FCC] == 9999)) { return 1;//we already did this cell and dxMean and dyMean don't change for cells of size 4 } } if ( !previousImage[0] || dimension4 == 64) { return 1; } for(x=0; x<(size*size); x++) { fmblur0 = RMULT*bitmap[x*4+0] + GMULT*bitmap[x*4+1] + BMULT*bitmap[x*4+2]; luty[x] = fmblur0; } if (!luti) { pquad->domain = 0x8080; pquad->snr[FCC] = 9999; return 1; } ony = realy - (realy & 0xfff0); onx = realx - (realx & 0xfff0); xLen = ZimWidth(previousImage[0]); yLen = ZimHeight(previousImage[0]); ripl = xLen-size; breakHigh = 99999999; fabort = 0; lowX = lowY = -1; depthx = depthy = 1; searchY = 32; searchX = 32; if (xLen == (yLen*4)) depthx = 2; if (RoqScaleable()) depthx = depthy = 2; if (clamp) { searchX = searchY = 8; } searchX = searchX*depthx; searchY = searchY*depthy; xxMean = dxMean*depthx; yyMean = dyMean*depthy; if (((realx-xxMean)+searchX)<0 ||(((realx-xxMean)-searchX)+depthx+size)>xLen || ((realy-yyMean)+searchY)<0 || (((realy-yyMean)-searchY)+depthy+size)>yLen) { pquad->snr[FCC] = 9999; return 1; } for( sX=(((realx-xxMean)-searchX)+depthx); sX<=((realx-xxMean)+searchX) && !fabort; sX+=depthx ) { for( sY=(((realy-yyMean)-searchY)+depthy); sY<=((realy-yyMean)+searchY); sY+=depthy ) { temp1 = xLen*sY+sX; if ( sX >= 0 && (sX+size) <= xLen && sY >= 0 && (sY+size) <= yLen ) { mblur0 = 0; bitma2 = luty; scale1 = luti + temp1; for( y=0; y breakHigh) { break; } scale1 += ripl; } if (breakHigh > mblur0) { breakHigh = mblur0; lowX = sX; lowY = sY; if (breakHighdomain = (sX<<8)+sY; pquad->snr[FCC] = lowestSNR; } return 1; } int CodecConvertPlanertoPacked( ) { byte *iPlane[5], *newdata, *olddata; int x,y,index, sample; newImage = ZimImageTagTableNew(pixelsWide, pixelsHigh,IMVFBRGB | IMVFBALPHA ); newdata = ZimData(newImage); index = 0; if (ZimIsPlanar(image)) { ZimGetDataPlanes(image, iPlane); for(y=0;y ZimHeight(bitmap)) return 1; if (yend > ZimHeight(bitmap)) yend = ZimHeight(bitmap); if (xend > ZimWidth(bitmap)) xend = ZimWidth(bitmap); bpp = ZimBpp(bitmap); if (ZimIsPlanar(bitmap)) { ZimGetDataPlanes(bitmap, iPlane); for(y=startY;y0;i--) { if ( qtemp->snr[i]*quickadd[i] < wtemp ) { tstatus = i; tsnr = qtemp->snr[i]; wtemp = qtemp->snr[i]*quickadd[i]; } } if ( qtemp->mark == YES ) tstatus = MOT; CodecSetStatus(tstatus,qtemp); *snr = tsnr; return 1; } int CodecGetCurrentQuadOutputSize( quadcel * pquad ) { return (currentTotalBits >>3) +2; } int CodecComputeCurrentQuadOutputSize( quadcel * pquad ) { int totalbits, i; totalbits = 0; for( i=0; istatus == status) { return 1; } else if ((!(cel->size && cel->size < 16)) || (sizeQuickAdd[cel->status] == sizeQuickAdd[status])) { cel->status = status; return 1; } if (cel->size && cel->size < 16) { currentTotalBits += sizeQuickAdd[status] - sizeQuickAdd[cel->status] ; } cel->status = status; return 1; } int CodecSetSize( int size ,quadcel * cel ) { BOOL oldquick, newquick; oldquick = (cel->size && cel->size < 16); newquick = size && size <16; if (oldquick && !newquick) { currentTotalBits -= sizeQuickAdd[cel->status]; } if (!oldquick && newquick) { currentTotalBits += sizeQuickAdd[cel->status]; } cel->size = size; return 1; } float CodecGetCurrentRMSE( quadcel * pquad ) { int i, j; double totalbits; totalbits = 0; j = 0; for( i=0; i newsnr ) { CodecSetStatus(DEP,&pquad[lownum]); pquad[lownum].rsnr = 0; } else { CodecSetStatus(0,&pquad[lownum+nx*0+1]); CodecSetStatus(0,&pquad[lownum+nx*1+1]); CodecSetStatus(0,&pquad[lownum+nx*2+1]); CodecSetStatus(0,&pquad[lownum+nx*3+1]); CodecSetSize(0,&pquad[lownum+nx*0+1]); CodecSetSize(0,&pquad[lownum+nx*1+1]); CodecSetSize(0,&pquad[lownum+nx*2+1]); CodecSetSize(0,&pquad[lownum+nx*3+1]); } } else { lownum = -1; } return lownum; } int CodecMotMeanX( ) { return dxMean; } int CodecMotMeanY( ) { return dyMean; } int CodecSparseEncode( ) { int i, j, osize, fsize, num[DEAD+1], *ilist, onf, ong, wtype, temp; float *flist, sRMSE, numredo; byte *idataA, *idataB; osize = 8; image = RoqCurrentImage(); newImage = 0; pixelsHigh = ZimHeight(image); pixelsWide = ZimWidth(image); dimension2 = 12; dimension4 = 48; if (ParamImSeqCurrentImageHadAlpha(RoqParamImSeq()) && (RoqParamNoAlpha() == NO)) { dimension2 = 16; dimension4 = 64; } if (ZimIsPlanar(image) || ZimBpp(image)!=4) CodecConvertPlanertoPacked(); idataA = malloc( 16*16*4 ); idataB = malloc( 16*16*4 ); if (!previousImage[0]) printf("sparseEncode: sparsely encoding a %d,%d image\n", pixelsWide, pixelsHigh); CodecInitImages(); flist = calloc( (numQuadCels+1), sizeof(float) ); ilist = calloc( (numQuadCels+1), sizeof(int ) ); fsize = 56*1024; if (previousImage[0]) fsize = RoqNormalFrameSize(); else fsize = RoqFirstFrameSize(); // if (RoqHasSound() && fsize > 6000 && previousImage[0]) fsize = 6000; dxMean = dyMean = 0; if (previousImage[0]) wtype = 1; else wtype = 0; for( i=0; i> 8 ) - 128; dyMean += (qStatus[i].domain & 0xff) - 128; temp++; } } if (temp) { dxMean /= temp; dyMean /= temp; } printf("sparseEncode: dx/dy mean is %d,%d\n", dxMean, dyMean); numredo = 0; detail = NO; if (codebookmade && whichFrame>4) fsize -= 256; temp = 0; for( i=0; i 0 ) { CodecGetData(idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, image); if (osize == 8) CodecVqData8(idataA, &qStatus[i]); if (previousImage[0]) { int dx,dy; dx = (qStatus[i].domain >> 8 ) - 128 - dxMean + 8; dy = (qStatus[i].domain & 0xff) - 128 - dyMean + 8; if (dx<0||dx>15||dy<0||dy>15) { qStatus[i].snr[FCC] = 9999; temp++; CodecFvqData(idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, &qStatus[i], YES); dx = (qStatus[i].domain >> 8 ) - 128 - dxMean + 8; dy = (qStatus[i].domain & 0xff) - 128 - dyMean + 8; if ((dx<0||dx>15||dy<0||dy>15)&&qStatus[i].snr[FCC]!=9999&&qStatus[i].status==FCC) { printf("sparseEncode: something is wrong here, dx/dy is %d,%d after being clamped\n", dx, dy); printf("xat: %d\n", qStatus[i].xat); printf("yat: %d\n", qStatus[i].yat); printf("size %d\n", qStatus[i].size); printf("type: %d\n", qStatus[i].status); printf("mot: %04x\n", qStatus[i].domain); printf("motsnr: %0f\n", qStatus[i].snr[FCC]); printf("rmse: %0f\n", qStatus[i].rsnr); exit(1); } } } CodecLowestQuad(&qStatus[i], &qStatus[i].status, &qStatus[i].rsnr, wtype); if (qStatus[i].status==FCC && qStatus[i].snr[FCC]>qStatus[i].snr[SLD]) { printf("sparseEncode: something is wrong here\n"); printf("xat: %d\n", qStatus[i].xat); printf("yat: %d\n", qStatus[i].yat); printf("size %d\n", qStatus[i].size); printf("type: %d\n", qStatus[i].status); printf("mot: %04x\n", qStatus[i].domain); printf("motsnr: %0f\n", qStatus[i].snr[FCC]); printf("sldsnr: %0f\n", qStatus[i].snr[SLD]); printf("rmse: %0f\n", qStatus[i].rsnr); exit(1); } } } if (RoqIsQuiet() == NO) { printf("sparseEncode: rmse of quad0 is %f, size is %d (meant to be %d)\n", CodecGetCurrentRMSE(qStatus), CodecGetCurrentQuadOutputSize(qStatus), fsize ); printf("sparseEncode: %d outside fcc limits\n", temp); } onf = 0; for(i=0;i 0 && qStatus[ilist[ong]].mark == NO) { osize = CodecAddQuad(qStatus, ilist[ong++]); } if ( CodecGetCurrentQuadOutputSize(qStatus) < fsize) { ong = 0; while ( CodecGetCurrentQuadOutputSize(qStatus) < fsize && ong < onf && flist[ong] > 0) { i = ilist[ong++]; if (qStatus[i].mark) { detail = NO; qStatus[i].mark = NO; CodecGetData(idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, image); if (qStatus[i].size == 8) CodecVqData8(idataA, &qStatus[i]); if (qStatus[i].size == 4) CodecVqData4(idataA, &qStatus[i]); if (qStatus[i].size == 4) CodecVqData2(idataA, &qStatus[i]); if (previousImage[0]) { CodecFvqData(idataA, qStatus[i].size, qStatus[i].xat, qStatus[i].yat, &qStatus[i], YES); } CodecLowestQuad(&qStatus[i], &qStatus[i].status, &qStatus[i].rsnr, wtype); } } ong = 0; while ( CodecGetCurrentQuadOutputSize(qStatus) < fsize && ong < onf && flist[ong] > 0) { i = ilist[ong++]; detail = YES; osize = CodecAddQuad(qStatus, i); } } printf("sparseEncode: rmse of frame %d is %f, size is %d\n", whichFrame, CodecGetCurrentRMSE(qStatus), CodecGetCurrentQuadOutputSize(qStatus) ); if (RoqIsQuiet() == NO) { for(i=0;i