#include "roq.h" #include "codec.h" #include "ParamImSeq.h" #include "Param.h" #include "Zim.h" #include static Param *param; static FILE *RoQFile; static TagTable *image; static int numQuadCels; static int quietMode; static int lastFrame; static char roqOutfile[MAXPATHLEN]; static char currentFile[MAXPATHLEN]; static int numberOfFrames; static int previousSize; static byte *codes; static BOOL dataStuff; static ParamImSeq *imgSeq; typedef struct { int format; int rate; int width; int channels; int samples; int dataofs; // chunk starts this many bytes from file start } wavinfo_t; int RoqWrite16Word( word * aWord ,FILE * stream ) { byte a, b; a = *aWord & 0xff; b = *aWord >> 8; fputc( a, stream ); fputc( b, stream ); return 1; } int RoqWrite32Word( unsigned int * aWord ,FILE * stream ) { byte a, b, c, d; a = *aWord & 0xff; b = (*aWord >> 8) & 0xff; c = (*aWord >> 16) & 0xff; d = (*aWord >> 24) & 0xff; fputc( a, stream ); fputc( b, stream ); fputc( c, stream ); fputc( d, stream ); return 1; } /* =============================================================================== WAV loading =============================================================================== */ byte *data_p; byte *iff_end; byte *last_chunk; byte *iff_data; int iff_chunk_len; wavinfo_t info; byte *snddata; short GetLittleShort(void) { short val = 0; val = *data_p; val = val + (*(data_p+1)<<8); data_p += 2; return val; } int GetLittleLong(void) { int val = 0; val = *data_p; val = val + (*(data_p+1)<<8); val = val + (*(data_p+2)<<16); val = val + (*(data_p+3)<<24); data_p += 4; return val; } void FindNextChunk(char *name) { while (1) { data_p=last_chunk; if (data_p >= iff_end) { // didn't find the chunk data_p = NULL; return; } data_p += 4; iff_chunk_len = GetLittleLong(); if (iff_chunk_len < 0) { data_p = NULL; return; } data_p -= 8; last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); if (!strncmp((char *)data_p, name, 4)) return; } } void FindChunk(char *name) { last_chunk = iff_data; FindNextChunk (name); } void DumpChunks(void) { char str[5]; str[4] = 0; data_p=iff_data; do { memcpy (str, data_p, 4); data_p += 4; iff_chunk_len = GetLittleLong(); printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); data_p += (iff_chunk_len + 1) & ~1; } while (data_p < iff_end); } /* ============ GetWavinfo ============ */ wavinfo_t GetWavinfo (const char *name, byte *wav, int wavlength) { wavinfo_t info; int samples; memset (&info, 0, sizeof(info)); if (!wav) return info; iff_data = wav; iff_end = wav + wavlength; // find "RIFF" chunk FindChunk("RIFF"); if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4))) { printf("Missing RIFF/WAVE chunks\n"); return info; } // get "fmt " chunk iff_data = data_p + 12; // DumpChunks (); FindChunk("fmt "); if (!data_p) { printf("Missing fmt chunk\n"); return info; } data_p += 8; info.format = GetLittleShort(); info.channels = GetLittleShort(); info.rate = GetLittleLong(); data_p += 4+2; info.width = GetLittleShort() / 8; if (info.format != 1) { printf("Microsoft PCM format only\n"); return info; } // find data chunk FindChunk("data"); if (!data_p) { printf("Missing data chunk\n"); return info; } data_p += 4; samples = GetLittleLong () / info.width; if (info.samples) { if (samples < info.samples) printf ("Sound %s has a bad loop length", name); } else info.samples = samples; info.dataofs = data_p - wav; return info; } ParamImSeq * RoqParamImSeq() { return imgSeq; } int RoqInit( ) { image = NULL; quietMode = NO; previousSize = 0; lastFrame = NO; codes = malloc( 4*1024 ); dataStuff=NO; return 1; } int RoqFree( ) { free( codes ); if (image) { ZimFree(image); } return 1; } int RoqEncodeQuietly( BOOL which ) { quietMode = which; return 1; } BOOL RoqIsQuiet( ) { return quietMode; } BOOL RoqIsLastFrame( ) { return lastFrame; } BOOL RoqScaleable( ) { return ParamIsScaleable(param); } BOOL RoqParamNoAlpha( ) { return ParamNoAlpha(param); } double RoqCurrentFade() { return ParamImSeqCurrentFade(imgSeq); } BOOL RoqMakingVideo( ) { return ParamTimecode(param); } BOOL RoqSearchType( ) { return ParamSearchType(param); } BOOL RoqHasSound( ) { return ParamHasSound(param); } int RoqPreviousFrameSize( ) { return previousSize; } int RoqFirstFrameSize( ) { return ParamFirstframesize(param); } int RoqNormalFrameSize( ) { return ParamNormalframesize(param); } char * RoqCurrentFilename( ) { return currentFile; } int FS_ReadFile( const char *filename, byte **data) { FILE* file; int size; file = fopen(filename,"rb"); if (!file) return 0; fseek (file, 0, SEEK_END); size = ftell (file); fseek (file, 0, SEEK_SET); *data = malloc(size); fread(*data, size, 1, file); fclose(file); return size; } #define ZA_SOUND_MONO 0x1020 #define ZA_SOUND_STEREO 0x1021 int EncodeSound(int onFrame) { static int soundOffset = 0; static short lastFlagsR = 0; static short lastFlagsL = 0; static short sqrTable[256]; int size, i, z; word direct; short left, right, *audio; if (onFrame == 1) { for (z=0;z<128;z++) { sqrTable[z] = (short)(z*z); sqrTable[z+128] = (short)(-sqrTable[z]); } } if ((soundOffset*info.channels) == info.samples) return 0; if (info.channels == 2) { direct = ZA_SOUND_STEREO; } else { direct = ZA_SOUND_MONO; } RoqWrite16Word(&direct, RoQFile); size = ((info.rate/30)+1) & (~1); if (onFrame == 1) { size = size*8; } if ((soundOffset+size)*info.channels > info.samples) { size = (info.samples - (soundOffset*info.channels))/info.channels; } i = size*info.channels; RoqWrite32Word(&i, RoQFile); printf("encodeSound: %d bytes to sound\n", i); if (info.channels == 2) { direct = (lastFlagsL & 0xff00) | ((lastFlagsR & 0xff00)>>8); } else { direct = lastFlagsL; } RoqWrite16Word(&direct, RoQFile); audio = (short *)(&snddata[info.dataofs]); for(i=0;i 127) left = 127; if (audio[soundOffset*2+0] - lastFlagsL < 0) left += 128; fputc(left, RoQFile); lastFlagsL = lastFlagsL + sqrTable[left ]; right = (short)sqrt(abs(audio[soundOffset*2+1] - lastFlagsR)); if (right > 127) right= 127; if (audio[soundOffset*2+1] - lastFlagsR < 0) right+= 128; fputc(right, RoQFile); lastFlagsR = lastFlagsR + sqrTable[right]; } else { left = (short)sqrt(abs(audio[soundOffset] - lastFlagsL)); if (left > 127) left = 127; if (audio[soundOffset] - lastFlagsL < 0) left += 128; fputc(left, RoQFile); lastFlagsL = lastFlagsL + sqrTable[left]; } soundOffset++; if ((soundOffset*info.channels) == info.samples) { break; } } if (info.channels == 2) { lastFlagsR &= 0xff00; lastFlagsL &= 0xff00; } return 1; } int RoqEncodeStream( Param * paramInputFile ) { int onFrame; TagTable *img; int size; onFrame = 1; CodecInit(); param = paramInputFile; numberOfFrames = ParamNumberOfFrames(param); printf("Encoding a total of %d frames (not including mpeg frames)\n", numberOfFrames); if (ParamNoAlpha(param)==YES) printf("encodeStream: eluding alpha\n"); snddata = NULL; if (ParamHasSound(param)==YES) { // load it in size = FS_ReadFile( ParamSoundFilename(param), &snddata ); if ( !snddata ) { printf("encodeStream: sound file not found"); return 0; } info = GetWavinfo( ParamSoundFilename(param), snddata, size ); } imgSeq = ParamImSeqNew(param); img = NULL; while( ParamImSeqMoreFrames(imgSeq) ) { if (ParamHasSound(param)==YES) { EncodeSound(onFrame); } if (img != NULL) { ZimFree(img); } img = ParamImSeqNextImage(imgSeq); strcpy(currentFile, ParamImSeqCurrentImageFilename(imgSeq)); RoqLoadAndDisplayImage(img); // if (onFrame==1 && (ParamImSeqCurrentImageHadAlpha(imgSeq)==NO || ParamNoAlpha(param)==YES) && !RoqMakingVideo() && !RoqScaleable()) { // RoqWriteLossless(); // } else { CodecSparseEncode(); // } onFrame++; } if (numberOfFrames != 1) { // if (ParamImSeqCurrentImageHadAlpha(imgSeq) && ParamNoAlpha(param)==NO) { lastFrame = YES; CodecSparseEncode(); // } else { // lastFrame = YES; // RoqWriteLossless(); // } } if (snddata) { free(snddata); } return 1; } long int RoqSizeFile( FILE * ftosize ) { long int fat, fend; fat = ftell(ftosize); fseek( ftosize, 0, SEEK_END ); fend = ftell(ftosize); fseek( ftosize, fat, SEEK_SET); return (fend); } int RoqWriteLossless( ) { word direct; unsigned int j; char tempFile[MAXPATHLEN]; FILE *ftemp; byte *buffer; int res, mess; if (!dataStuff) { RoqInitRoQPatterns(); dataStuff=YES; } direct = RoQ_QUAD_JPEG; RoqWrite16Word(&direct,RoQFile); sprintf(tempFile, "%s.jpg",ParamRoqTempFilename(param)); ZimWriteJFIF(image, tempFile, ParamJpegQuality(param)); ftemp = fopen(tempFile, "rb"); if (!ftemp) { fprintf(stderr, "Could not open temp file\n"); exit(1); } j = RoqSizeFile(ftemp); printf("writeLossless: writing %d bytes to RoQ_QUAD_JPEG\n", j); RoqWrite32Word(&j, RoQFile); direct = 0; // flags RoqWrite16Word( &direct, RoQFile); buffer = malloc( 16384 ); do { res = fread( buffer, 1, 16384, ftemp); mess = fwrite( buffer, 1, res, RoQFile ); if (res != mess) { fprintf(stderr, "Could not write to output stream\n"); exit(1); } } while ( res == 16384 ); free( buffer ); fclose(ftemp); if (!lastFrame) { CodecSetPreviousImage(tempFile, image); } unlink( tempFile ); fflush( RoQFile ); return 1; } int RoqInitRoQFile( const char * RoQFilename, const int iFPS ) { word i; static finit = 0; if (!finit) { finit++; printf("initRoQFile: %s\n", RoQFilename); RoQFile = fopen( RoQFilename, "wb" ); #ifdef S_ISUID chmod(RoQFilename, S_IREAD|S_IWRITE|S_ISUID|S_ISGID|0070|0007 ); #else chmod(RoQFilename, S_IREAD|S_IWRITE|0070|0007 ); #endif if (!RoQFile) { fprintf(stderr,"Unable to open output file %s.\n", RoQFilename); exit(1); } i = RoQ_ID; RoqWrite16Word(&i, RoQFile); i = 0xffff; RoqWrite16Word(&i, RoQFile); RoqWrite16Word(&i, RoQFile); i = iFPS; // framerate RoqWrite16Word(&i, RoQFile); fflush( RoQFile ); } strcpy( roqOutfile, RoQFilename ); return 1; } int RoqInitRoQPatterns( ) { int j; word direct; int pixelsWide; int pixelsHigh; pixelsWide = ZimWidth(image); pixelsHigh = ZimHeight(image); direct = RoQ_QUAD_INFO; RoqWrite16Word( &direct, RoQFile); j = 8; RoqWrite32Word(&j, RoQFile); printf("initRoQPatterns: outputting %d bytes to RoQ_INFO\n", j); direct = ParamImSeqCurrentImageHadAlpha(imgSeq); if (RoqParamNoAlpha() == YES) direct = 0; RoqWrite16Word( &direct, RoQFile); direct = pixelsWide; RoqWrite16Word( &direct, RoQFile); direct = pixelsHigh; RoqWrite16Word( &direct, RoQFile); direct = 8; RoqWrite16Word( &direct, RoQFile); direct = 4; RoqWrite16Word( &direct, RoQFile); fflush( RoQFile ); return 1; } int RoqCloseRoQFile( ) { fflush( RoQFile ); printf("closeRoQFile: closing RoQ file\n"); fclose( RoQFile ); return 1; } int RoqWriteHangFrame( ) { int j; word direct; printf("*******************************************************************\n"); direct = RoQ_QUAD_HANG; RoqWrite16Word( &direct, RoQFile); j = 0; RoqWrite32Word(&j, RoQFile); direct = 0; RoqWrite16Word( &direct, RoQFile); return 1; } int RoqWriteCodeBookToStream( byte * codebook , int csize , word cflags ) { int j; word direct; if (!csize) { printf("writeCodeBook: NO VQ DATA!!!!\n"); return 1; } direct = RoQ_QUAD_CODEBOOK; RoqWrite16Word( &direct, RoQFile); j = csize; RoqWrite32Word(&j, RoQFile); printf("writeCodeBook: outputting %d bytes to RoQ_QUAD_CODEBOOK\n", j); direct = cflags; RoqWrite16Word( &direct, RoQFile); fwrite( codebook, j, 1, RoQFile); fflush( RoQFile ); return 1; } int RoqWriteCodeBook( byte * codebook ) { memcpy( codes, codebook, 4096 ); return 1; } int RoqWriteFrame( quadcel * pquad ) { word action, direct; int onCCC, onAction, i, j, code; byte *cccList; BOOL *use2, *use4; int dx,dy,dxMean,dyMean,index2[256],index4[256], dimension; cccList = malloc( numQuadCels * 8); // maximum length use2 = malloc(256*sizeof(BOOL)); use4 = malloc(256*sizeof(BOOL)); for(i=0;i<256;i++) { use2[i] = NO; use4[i] = NO; } action = 0; j = onAction = 0; onCCC = 2; // onAction going to go at zero dxMean = CodecMotMeanX(); dyMean = CodecMotMeanY(); if (ParamImSeqCurrentImageHadAlpha(imgSeq)) dimension = 10; else dimension = 6; for (i=0; i> 8 )) - 128 - dxMean + 8; dy = ((pquad[i].domain & 0xff)) - 128 - dyMean + 8; if (dx>15 || dx<0 || dy>15 || dy<0 ) { printf("writeFrame: FCC error %d,%d mean %d,%d at %d,%d,%d rmse %f\n", dx,dy, dxMean, dyMean,pquad[i].xat,pquad[i].yat,pquad[i].size, pquad[i].snr[FCC] ); exit(1); } cccList[onCCC++] = (dx<<4)+dy; break; case PAT: code = 2; cccList[onCCC++] = index4[pquad[i].patten[0]]; break; case CCC: code = 3; cccList[onCCC++] = index2[pquad[i].patten[1]]; cccList[onCCC++] = index2[pquad[i].patten[2]]; cccList[onCCC++] = index2[pquad[i].patten[3]]; cccList[onCCC++] = index2[pquad[i].patten[4]]; break; case DEAD: fprintf(stderr,"dead cels in picture\n"); break; } if (code == -1) { fprintf(stderr, "writeFrame: an error occurred writing the frame\n"); exit(2); } action = (action<<2)|code; j++; if (j == 8) { j = 0; cccList[onAction+0] = (action & 0xff); cccList[onAction+1] = ((action >> 8) & 0xff); onAction = onCCC; onCCC += 2; } } } if (j) { action <<= ((8-j)*2); cccList[onAction+0] = (action & 0xff); cccList[onAction+1] = ((action >> 8) & 0xff); } direct = RoQ_QUAD_VQ; RoqWrite16Word(&direct, RoQFile); j = onCCC; RoqWrite32Word(&j, RoQFile); direct = dyMean; direct &= 0xff; direct += (dxMean<<8); // flags RoqWrite16Word(&direct, RoQFile); printf("writeFrame: outputting %d bytes to RoQ_QUAD_VQ\n", j); previousSize = j; fwrite( cccList, onCCC, 1, RoQFile ); fflush( RoQFile ); free( cccList ); free( use2 ); free( use4 ); return 1; } int RoqWritePuzzleFrame( quadcel * pquad ) { return 1; } // // load a frame, create a window (if neccesary) and display the frame // int RoqLoadAndDisplayImage(TagTable *newimage ) { // unsigned char *imageData; // static BOOL cleared = NO; int pixelsWide; int pixelsHigh; pixelsWide = ZimWidth(newimage); pixelsHigh = ZimHeight(newimage); if (pixelsWide == 800 && pixelsHigh == 600) { printf("resizing %dx%d - ", pixelsWide, pixelsHigh); ZimResize(newimage, 512, 512); } else if (pixelsWide == 640 && pixelsHigh == 480) { printf("resizing %dx%d - ", pixelsWide, pixelsHigh); ZimResize(newimage, 512, 256); } image = newimage; pixelsWide = ZimWidth(image); pixelsHigh = ZimHeight(image); numQuadCels = ((pixelsWide & 0xfff0)*( pixelsHigh & 0xfff0))/(MINSIZE*MINSIZE); numQuadCels += numQuadCels/4 + numQuadCels/16; if (!quietMode) printf("loadAndDisplayImage: %dx%d\n", pixelsWide, pixelsHigh); return 1; } TagTable * RoqCurrentImage( ) { return image; } int RoqNumberOfFrames ( ) { return numberOfFrames; }