home *** CD-ROM | disk | FTP | other *** search
- /*
- This is an example of am image compression codec that handles both
- compression and decompression of images as passed to it by the
- Image Compression manager. It is built as a Component Manager Component.
-
-
- The compression scheme here is 411 YUV. The image is stored as separate
- luminance and chrominance channels. For each 2x2 block of pixels in the
- source image we store 4 luminance (Y) components, 1 Y-Red component (U) and
- 1 Y-Blue (V) component. Each Y-component is stored as 6-bits, resulting in a
- savings of 2.4:1 over a 24-bit/pixel image (6*4 + 2*8)/4 = 10 bits/pixel.
-
- */
-
-
- #include <Memory.h>
- #include <Resources.h>
- #include <QuickDraw.h>
- #include <QDOffscreen.h>
- #include <OSUtils.h>
- #include <SysEqu.h>
- #include <Errors.h>
- #include <FixMath.h>
-
- #include "ImageCodec.h"
-
-
-
- /* Version information */
-
- #define EXAMPLE_CODEC_REV 1
- #define codecInterfaceVersion 1 /* high word returned in component GetVersion */
-
-
-
- /* Some useful macros and constants */
-
-
- #define R_W 0x4ccd
- #define G_W 0x970a
- #define B_W 0x1c29
- #define PIN(_n) ((_n) < 0 ? 0 : (_n) > 255 ? 255 : (_n))
-
-
- /*
- Our data structure declarations
- */
-
-
-
- /* This is the structure we use to hold data used by all instances of
- this compressor and decompressor */
-
- typedef struct {
- Handle rgbwTable; /* optional encode/decode table */
- Handle giwTable; /* another optional encode/decode table */
- CodecInfo **info; /* our cached codec info structure */
- } SharedGlobals;
-
-
- /* This is the structure we use to store our global data for each instance */
-
- typedef struct {
- SharedGlobals *sharedGlob; /* pointer to instance-shared globals */
- } Globals;
-
-
- /* Function prototypes to keep the compiler smiling. */
-
- pascal ComponentResult
- EXAMPLECODEC(ComponentParameters *params,char **storage);
-
- pascal ComponentResult
- OpenCodec(ComponentInstance self);
-
- pascal ComponentResult
- CloseCodec(Handle storage,ComponentInstance self);
-
- pascal ComponentResult
- CanDoSelector(short selector);
-
- pascal ComponentResult
- GetVersion();
-
- pascal void
- CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
-
- pascal void
- DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
-
-
-
- /************************************************************************************
- * This is the main dispatcher for our codec. All calls from the codec manager
- * will come through here, with a unique selector and corresponding parameter block.
- *
- * This routine must be first in the code segment of the codec thing.
- */
-
- pascal ComponentResult
- EXAMPLECODEC(ComponentParameters *params,char **storage)
- {
- /* If the selector is less than zero, it's a Component manager selector. */
-
- if ( params->what < 0 ) {
- switch ( params->what ) {
- case kComponentOpenSelect:
- return CallComponentFunction(params, (ComponentFunction) OpenCodec );
-
- case kComponentCloseSelect:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction) CloseCodec );
-
- case kComponentCanDoSelect:
- return CallComponentFunction(params, (ComponentFunction) CanDoSelector);
-
- case kComponentVersionSelect :
- return CallComponentFunction(params, (ComponentFunction) GetVersion);
-
- default :
- return (paramErr);
- }
- }
-
- /*
- * Here we dispatch the rest of our calls. We use the magic thing manager routine which
- * calls our subroutines with the proper parameters. The prototypes are in Image Codec.h.
- */
-
- switch ( params->what ) {
- case codecPreCompress:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDPreCompress);
-
- case codecBandCompress:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDBandCompress);
-
- case codecPreDecompress:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDPreDecompress);
-
- case codecBandDecompress:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDBandDecompress);
-
- case codecCDSequenceBusy:
- return 0; /* our codec is never asynchronously busy */
-
- case codecGetCodecInfo:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetCodecInfo);
-
- case codecGetCompressedImageSize:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetCompressedImageSize);
-
- case codecGetMaxCompressionSize:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetMaxCompressionSize);
-
- case codecGetCompressionTime:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetCompressionTime);
-
- case codecGetSimilarity:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetSimilarity);
-
- case codecTrimImage:
- return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDTrimImage);
-
- default:
- return(paramErr);
- }
- }
-
- /************************************************************************************
- * This gets called when the thing instance is opened. We allocate our storage at this
- * point. If we have shared globals, we check if they exist, and put a pointer to them
- * in our instance globals so that other calls can get to them.
- */
-
- pascal ComponentResult
- OpenCodec(ComponentInstance self)
- {
- ComponentResult result;
- Globals **glob;
-
- /*
- First we allocate shared storage. This should be a handle to any
- kind of data used by the thing instance. They should be allocated
- in the current heap.
-
- */
-
- if ( (glob = (Globals **)NewHandleClear(sizeof(Globals))) == nil ) {
- return(MemError());
- }
- SetComponentInstanceStorage(self,(Handle)glob);
-
- /* Check and initialize our shared globals */
-
- result = InitSharedTables(glob,self);
-
- return result;
- }
-
- /************************************************************************************
- * This gets called when the thing instance is opened. We allocate our shared storage at this
- * point.
-
- * If we have shared globals, we check if they exist, otherwise we allocate
- * them and set the ComponentRefCon so that other instances can use them.
- *
- * The shared globals hold our CodecInfo struct, which we read from our resource file,
- * and some tables that we use for speed. If we cant get the tables we can work without
- * them. All items in the shared globals are made purgeable when the last of our
- * instances is closed. If our component was loaded in the application heap ( because
- * there was no room in the system heap) then we keep our shared storage in the app heap.
- *
- * We keep a pointer to the shared globals in our instance globals so that other calls can get to them.
- */
-
-
- ComponentResult
- InitSharedTables(Globals **glob,ComponentInstance self)
- {
- SharedGlobals *sGlob;
- long i,j,*lp;
- char *cp;
- short resFile;
- THz saveZone;
- Boolean inAppHeap;
- OSErr result = noErr;
-
-
- saveZone = GetZone();
- inAppHeap = ( GetComponentInstanceA5(self) != 0 );
- if ( !inAppHeap )
- SetZone(SystemZone());
- if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil ) {
- if ( (sGlob = (SharedGlobals*)NewPtrClear(sizeof(SharedGlobals))) == nil ) {
- result = MemError();
- goto obail;
- }
- SetComponentRefcon((Component)self,(long)sGlob);
- }
-
- (*glob)->sharedGlob = sGlob; // keep this around where it's easy to get at
-
-
- if ( sGlob->info == nil || *(Handle)sGlob->info == nil ) {
-
- if ( sGlob->info )
- DisposHandle((Handle)sGlob->info);
-
- /* Get the CodecInfo struct which we keep in our resource fork */
-
- resFile = OpenComponentResFile((Component)self);
- if (resFile == -1) {
- result = memFullErr;
- goto obail;
- }
- sGlob->info = (CodecInfo **) Get1Resource(codecInfoResourceType,128);
- if ( sGlob->info == nil ) {
- CloseComponentResFile(resFile);
- result = ResError();
- goto obail;
- }
- LoadResource((Handle)sGlob->info);
- if ( ResError() ) {
- CloseComponentResFile(resFile);
- result = ResError();
- goto obail;
- }
- DetachResource((Handle)sGlob->info);
- CloseComponentResFile(resFile);
- }
- HNoPurge((Handle)sGlob->info);
-
- if ( sGlob->rgbwTable == nil || *sGlob->rgbwTable == nil ) {
- if ( sGlob->rgbwTable )
- ReallocHandle(sGlob->rgbwTable,3*256*sizeof(long));
- else
- sGlob->rgbwTable = NewHandleSys(3*256*sizeof(long));
-
- /* we can actual still work without these tables, so we dont bail
- if we cant get the memory for them */
-
- if ( sGlob->rgbwTable && *sGlob->rgbwTable ) {
- lp = (long *)*sGlob->rgbwTable;
- for ( i=0, j = 0; i < 256; i++, j += R_W )
- *lp++ = j;
- for ( i=0, j = 0; i < 256; i++, j += G_W )
- *lp++ = j;
- for ( i=0, j = 0; i < 256; i++, j += B_W )
- *lp++ = j;
- }
- }
- if ( sGlob->rgbwTable )
- HNoPurge(sGlob->rgbwTable); /* make sure it wont get purged while we are open */
-
- /* green inverse table */
-
- if ( sGlob->giwTable == nil || *sGlob->giwTable == nil ) {
- if ( sGlob->giwTable )
- ReallocHandle(sGlob->giwTable,256);
- else
- sGlob->giwTable = NewHandleSys(256);
-
- /* we can actual still work without these tables, so we dont bail
- if we cant get hte memory for them */
-
- if ( sGlob->giwTable && *sGlob->giwTable ) {
- for ( i=0, cp = *sGlob->giwTable ; i < 256; i++ )
- *cp++ = PIN( (i<<16) / G_W);
- }
- }
- if ( sGlob->giwTable )
- HNoPurge(sGlob->giwTable); /* make sure it wont get purged while we are open */
-
-
- obail:
-
- SetZone(saveZone);
- if ( result != noErr && sGlob != nil ) {
- if ( sGlob->rgbwTable )
- DisposHandle(sGlob->rgbwTable);
- if ( sGlob->info )
- DisposHandle((Handle)sGlob->info);
- DisposPtr((Ptr)sGlob);
- SetComponentRefcon((Component)self,(long)nil);
- }
- return(result);
- }
-
- /************************************************************************************
- * This gets called when the thing instance is closed. We need to get rid of any
- * instance storage here.
- */
-
- pascal ComponentResult
- CloseCodec(Handle storage,ComponentInstance self)
- {
- SharedGlobals *sGlob;
- long i;
- Globals **glob = (Globals **)storage;
-
- /* If we are closing our last instance
- then we make the shared global items purgeable to
- speed things up next instance.
- */
-
- if ( CountComponentInstances((Component)self) == 1) {
- if ( (sGlob=(SharedGlobals*)(*glob)->sharedGlob) != nil ) {
- if ( sGlob->rgbwTable )
- HPurge(sGlob->rgbwTable);
- if ( sGlob->giwTable )
- HPurge(sGlob->giwTable);
- if ( sGlob->info )
- HPurge((Handle)sGlob->info);
- }
- }
- if ( glob )
- DisposHandle((Handle)glob);
- return(noErr);
- }
-
-
-
- /************************************************************************************
- * Return true if we can handle the selector, otherwise false.
- */
-
- pascal ComponentResult
- CanDoSelector(short selector)
- {
- switch(selector) {
- case kComponentOpenSelect:
- case kComponentCloseSelect:
- case kComponentCanDoSelect:
- case kComponentVersionSelect :
- case codecPreCompress:
- case codecBandCompress:
- case codecPreDecompress:
- case codecBandDecompress:
- case codecCDSequenceBusy:
- case codecGetCodecInfo:
- case codecGetCompressedImageSize:
- case codecGetMaxCompressionSize:
- case codecGetCompressionTime:
- case codecGetSimilarity:
- case codecTrimImage:
- return(true);
- default:
- return (false);
- }
- }
-
-
- /************************************************************************************
- * Return the version of this component ( defines interface ) and revision level
- * of the code.
- */
-
- pascal ComponentResult
- GetVersion()
- {
- return ((codecInterfaceVersion<<16) | EXAMPLE_CODEC_REV); /* interface version in hi word, code rev in lo word */
- }
-
-
- /************************************************************************************
- * CDPreCompress gets called before an image is compressed, or whenever the source pixmap
- * pixel size changes when compressing a sequence. We return information about
- * how we can compress the image to the codec manager, so that it can fit the source data
- * to our requirements. The ImageDescriptor is already filled in, so we can use it for
- * reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we
- * use this as a reference for deciding what we can do. The other parameters return information
- * to the CodecManager about what we can do. We can also do setup here if we want to.
- */
-
- pascal long
- CDPreCompress(Handle storage,register CodecCompressParams *p)
- {
- CodecCapabilities *capabilities = p->capabilities;
-
- /*
- * First we return which depth input pixels we can deal with - based on what the
- * app has available - we can only work with 32 bit input pixels.
- */
-
- switch ( (*p->imageDescription)->depth ) {
- case 16:
- capabilities->wantedPixelSize = 32;
- break;
- default:
- return(codecConditionErr);
- break;
- }
-
- /* if the buffer gets banded, return the smallest one we can deal with */
-
- capabilities->bandMin = 2;
-
- /* if the buffer gets banded, return the increment it be should grown */
-
- capabilities->bandInc = 2;
-
-
- /*
- * If a codec needs the dimensions of the source pixmap to be of certain multiples
- * it can ask for the image to be extended out (via pixel replication) vertically
- * and/or horizontally.
- *
- * In our case, we're dealing with 2 by 2 blocks and therefore we want the image
- * height and width to both be multiples of 2. If either dimension is odd, we
- * ask it have it extended by one pixel.
- */
-
- capabilities->extendWidth = (*p->imageDescription)->width & 1;
- capabilities->extendHeight = (*p->imageDescription)->height & 1;
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal
- * band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we
- * demanded in BeginCompress.
- */
-
- pascal long
- CDBandCompress(Handle storage,register CodecCompressParams *p)
- {
- short width,height;
- Ptr cDataPtr,dataStart;
- short depth;
- Rect sRect;
- long offsetH,offsetV;
- Globals **glob = (Globals **)storage;
- register char *baseAddr;
- long numLines,numStrips;
- short rowBytes;
- long stripBytes;
- char mmuMode = 1;
- register short y;
- ImageDescription **desc = p->imageDescription;
- OSErr result = noErr;
-
- /* If there is a progress proc, give it an open call at the start of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressOpen,0,
- p->progressProcRecord.progressRefCon);
-
- width = (*desc)->width;
- height = (*desc)->height;
- depth = (*desc)->depth;
- dataStart = cDataPtr = p->data;
-
- /* figure out offset to first pixel in baseAddr from the pixelsize and bounds */
-
- rowBytes = p->srcPixMap.rowBytes & 0x3fff;
- sRect = p->srcPixMap.bounds;
- numLines = p->stopLine - p->startLine; /* number of scanlines in this band */
- numStrips = (numLines+1)>>1; /* number of strips in this band */
- stripBytes = ((width+1)>>1) * 5;
-
- /* adjust the source baseAddress to be at the beginning of the desired rect */
-
- switch ( p->srcPixMap.pixelSize ) {
- case 32:
- offsetH = sRect.left<<2;
- break;
- case 16:
- offsetH = sRect.left<<1;
- break;
- case 8:
- offsetH = sRect.left;
- break;
- default:
- result = codecErr;
- goto bail;
- }
- offsetV = sRect.top * rowBytes;
- baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV;
-
-
- /* if there is not a flush proc, adjust the pointer to the next band */
-
- if ( p->flushProcRecord.flushProc == nil )
- cDataPtr += (p->startLine>>1) * stripBytes;
- else {
- if ( p->bufferSize < stripBytes ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
-
-
- /* do the slower flush/progress case if we have too */
-
- if ( p->flushProcRecord.flushProc || p->progressProcRecord.progressProc ) {
- SharedGlobals *sg = (*glob)->sharedGlob;
-
-
- for ( y=0; y < numStrips; y++) {
- SwapMMUMode(&mmuMode);
- CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- SwapMMUMode(&mmuMode);
- baseAddr += rowBytes<<1;
- if ( p->flushProcRecord.flushProc ) {
- if ( (result=p->flushProcRecord.flushProc(cDataPtr,stripBytes,
- p->flushProcRecord.flushRefCon)) != noErr) {
- result = codecSpoolErr;
- goto bail;
- }
- } else {
- cDataPtr += stripBytes;
- }
- if (p->progressProcRecord.progressProc) {
- if ( (result=p->progressProcRecord.progressProc(codecProgressUpdatePercent,
- FixDiv(y,numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- } else {
- SharedGlobals *sg = (*glob)->sharedGlob;
- short tRowBytes = rowBytes<<1;
-
- SwapMMUMode(&mmuMode);
- for ( y=numStrips; y--; ) {
- CompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- cDataPtr += stripBytes;
- baseAddr += tRowBytes;
- }
- SwapMMUMode(&mmuMode);
- }
-
- /*
-
- return size and similarity on the last band
-
- */
-
- if ( p->conditionFlags & codecConditionLastBand ) {
- (*p->imageDescription)->dataSize = stripBytes * ((height+1)>>1); /* return the actual size of the compressed data */
- p->similarity = 0; /* we don't do frame differencing */
- }
-
- bail:
- /* If there is a progress proc, give it a close call at the end of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressClose,0,
- p->progressProcRecord.progressRefCon);
-
- return(result);
- }
-
-
-
- /************************************************************************************
- * CDPreDecompress gets called before an image is decompressed. We return information about
- * how we can decompress the image to the codec manager, so that it can fit the destination data
- * to our requirements.
- */
-
- pascal long
- CDPreDecompress(Handle storage,register CodecDecompressParams *p)
- {
- register CodecCapabilities *capabilities = p->capabilities;
- Rect dRect = p->srcRect;
-
- /* Check if the matrix is okay for us. We don't do anything fancy. */
-
- if ( !TransformRect(p->matrix,&dRect,nil) )
- return(codecConditionErr);
-
-
- /* Decide which depth compressed data we can deal with. */
-
- switch ( (*p->imageDescription)->depth ) {
- case 16:
- break;
- default:
- return(codecConditionErr);
- break;
- }
-
- /* We can deal only 32 bit pixels. */
-
- capabilities->wantedPixelSize = 32;
-
- /* The smallest possible band we can do is 2 scan lines. */
-
- capabilities->bandMin = 2;
-
- /* We can deal with 2 scan line high bands. */
-
- capabilities->bandInc = 2;
-
- /* If we needed our pixels to be aligned on some integer multiple we would set these to
- * the number of pixels we need the dest extended by. If we dont care, or we take care of
- * it ourselves we set them to zero.
- */
-
- capabilities->extendWidth = p->srcRect.right & 1;
- capabilities->extendHeight = p->srcRect.bottom & 1;
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal
- * band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we
- * demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and
- * we need to clear bits in it that correspond to any pixels in the destination we do not want to
- * change. ( We always write all pixels, so we dont care. This mode is important only for those
- * codecs that have frame differencing and don't always write all the pixels. )
- */
-
- pascal long
- CDBandDecompress(Handle storage,register CodecDecompressParams *p)
- {
- Rect dRect;
- long offsetH,offsetV;
- Globals **glob = (Globals **)storage;
- long numLines,numStrips;
- short rowBytes;
- long stripBytes;
- short width;
- register short y;
- register char *baseAddr;
- char *cDataPtr;
- char mmuMode = 1;
- OSErr result = noErr;
-
- /* Calculate the real base address based on the bounds rect. If it's not
- a linear transformation, we dont do it. */
-
- dRect = p->srcRect;
- if ( !TransformRect(p->matrix,&dRect,nil) )
- return(paramErr);
-
- /* If there is a progress proc, give it an open call at the start of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressOpen,0,
- p->progressProcRecord.progressRefCon);
-
-
- /* initialize some local variables */
-
- width = (*p->imageDescription)->width;
- rowBytes = p->dstPixMap.rowBytes;
- numLines = p->stopLine - p->startLine; /* number of scanlines in this band */
- numStrips = (numLines+1)>>1; /* number of strips in this band */
- stripBytes = ((width+1)>>1) * 5; /* number of bytes in one strip of blocks */
- cDataPtr = p->data;
-
- /* adjust the destination baseaddress to be at the beginning of the desired rect */
-
- offsetH = (dRect.left - p->dstPixMap.bounds.left);
- switch ( p->dstPixMap.pixelSize ) {
- case 32:
- offsetH <<=2; /* 1 pixel = 4 bytes */
- break;
- case 16:
- offsetH <<=1; /* 1 pixel = 2 bytes */
- break;
- case 8:
- break; /* 1 pixel = 1 byte */
- default:
- result = codecErr; /* we dont handle these cases, thow we could */
- goto bail;
- }
- offsetV = (dRect.top - p->dstPixMap.bounds.top) * rowBytes;
- baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
-
-
- /*
- * If we are skipping some data, we just skip it here. We can tell because
- * firstBandInFrame says this is the first band for a new frame, and
- * if startLine is not zero, then that many lines were clipped out.
- */
-
- if ( (p->conditionFlags & codecConditionFirstBand) && p->startLine != 0 ) {
- if ( p->dataProcRecord.dataProc ) {
- for ( y=0; y < p->startLine>>1; y++ ) {
- if ( (result=p->dataProcRecord.dataProc(&cDataPtr,stripBytes,
- p->dataProcRecord.dataRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- cDataPtr += stripBytes;
- }
- } else
- cDataPtr += (p->startLine>>1) * stripBytes;
- }
-
- /*
- * If theres a dataproc spooling the data to us, then we have to do the data
- * in whatever size chunks they want to give us, or if there is a progressProc
- * make sure to call it as we go along.
- */
-
- if ( p->dataProcRecord.dataProc || p->progressProcRecord.progressProc ) {
- SharedGlobals *sg = (*glob)->sharedGlob;
-
- for (y=0; y < numStrips; y++) {
- if (p->dataProcRecord.dataProc) {
- if ( (result=p->dataProcRecord.dataProc(&cDataPtr,stripBytes,
- p->dataProcRecord.dataRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
- SwapMMUMode(&mmuMode);
- DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- SwapMMUMode(&mmuMode);
- baseAddr += rowBytes<<1;
- cDataPtr += stripBytes;
- if (p->progressProcRecord.progressProc) {
- if ( (result=p->progressProcRecord.progressProc(codecProgressUpdatePercent,
- FixDiv(y, numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
-
-
- /*
- *
- * otherwise - do the fast case.
- *
- */
-
- } else {
- SharedGlobals *sg = (*glob)->sharedGlob;
- short tRowBytes = rowBytes<<1;
-
- SwapMMUMode(&mmuMode);
- for ( y=numStrips; y--; ) {
- DecompressStrip(cDataPtr,baseAddr,rowBytes,width,sg);
- baseAddr += tRowBytes;
- cDataPtr += stripBytes;
- }
- SwapMMUMode(&mmuMode);
- }
-
- /*
- *
- * IMPORTANT: update pointer to data in params, so when we get the next
- * band we'll be at the right place in our data.
- *
- */
-
- p->data = cDataPtr;
-
- if ( p->conditionFlags & codecConditionLastBand ) {
- /* Tie up any loose ends on the last band of the frame, if we had any */
- }
-
- bail:
- /* If there is a progress proc, give it a close call at the end of this band. */
-
- if (p->progressProcRecord.progressProc)
- p->progressProcRecord.progressProc(codecProgressClose,0,
- p->progressProcRecord.progressRefCon);
- return(result);
- }
-
-
- /************************************************************************************
- * CDGetCodecInfo allows us to return information about ourselves to the codec manager.
- *
- * There will be a tool for determining appropriate values for the accuracy, speed
- * and level information. For now we estimate with scientific wild guessing.
- *
- * The info is stored as a resource in the same file with our component.
- */
-
- pascal ComponentResult
- CDGetCodecInfo(Handle storage,CodecInfo *info)
- {
- Globals **glob = (Globals **)storage;
-
- if ( info == nil )
- return(paramErr);
- BlockMove((Ptr)*((*glob)->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo));
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetSimilarity is called, we return the percent of the compressed image A that
- * is different from compressed image B. This can be used by applications that use sequence
- * dynamics as an indicator for editing image sequences.
- *
- * If the codec cannot do a direct similarity comparison, the ICM decompresses image A and
- * do a comparison with image B. This call is provided so that a codec can save the time
- * of the intermediate decompress if it can do the comparison directly.
- */
-
- pascal ComponentResult
- CDGetSimilarity(Handle storage,PixMapHandle src,const Rect *srcRect,ImageDescriptionHandle desc,
- Ptr data,Fixed *similarity)
- {
- #pragma unused(storage,src,srcRect,desc,data,dif,refcon)
-
- /* This call is not implemented yet, which is okay, because its not used very much and is not mandatory */
-
- return(codecUnimpErr);
- }
-
-
- /************************************************************************************
- * When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed
- * data ( for one image frame).
- */
-
- pascal ComponentResult
- CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize,
- DataProcRecordPtr dataProc,long *size)
- {
- #pragma unused(storage,data,dataSize,dataProc)
-
- short width =(*desc)->width;
- short height = (*desc)->height;
-
- if ( size == nil )
- return(paramErr);
-
- /*
- * Our data has a size which is deterministic based on the image size. If it were not we
- * could encode the size in the compressed data, or figure it out by walking the
- * compressed data.
- */
-
- *size = ((width+1)/2) * 5 * ((height+1)/2);
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for
- * the given image would be in bytes.
- */
-
- pascal ComponentResult
- CDGetMaxCompressionSize(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
- CodecQ quality,long *size)
- {
- #pragma unused(storage,src,depth,quality)
-
- short width = srcRect->right - srcRect->left;
- short height = srcRect->bottom - srcRect->top;
-
- /* we always end up with a fixed size. If we did not, we would return the worst case size */
-
- *size = ((width+1)/2) * 5 * ((height+1)/2);
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDGetCompressionTime is called, we return the approximate time for compressing
- * the given image would be in milliseconds. We also return the closest actual quality
- * we can handle for the requested value.
- */
-
- pascal ComponentResult
- CDGetCompressionTime(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
- CodecQ *spatialQuality,CodecQ *temporalQuality,unsigned long *time)
- {
- #pragma unused(storage,src,srcRect,depth)
-
- if (time)
- *time = 0; /* we don't know how many msecs */
-
- if (spatialQuality)
- *spatialQuality = codecNormalQuality; /* we have only one quality level for now */
-
- if (temporalQuality)
- *temporalQuality = 0; /* we cannot do temporal compression */
-
- return(noErr);
- }
-
-
- /************************************************************************************
- * When CDTrimImage is called, we take the given compressed data and return only the portion
- * which is represented by the trimRect. We can return a little more if we have too, but we
- * need only return enough so that the image in trimRect is properly displayed. We then
- * adjust the rectangle to corresond to the same rectangle in the new trimmed data.
- */
-
- pascal ComponentResult
- CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize,
- DataProcRecordPtr dataProc,Ptr outData,long outDataSize,FlushProcRecordPtr flushProc,
- Rect *trimRect,ProgressProcRecordPtr progressProc)
- {
- #pragma unused(storage)
-
- Rect rect = *trimRect;
- char *dataP,*odP,*startP;
- short trimOffTop;
- short trimOffBottom;
- short trimOffLeft;
- short trimOffRight;
- short bytesOffLeft;
- short newHeight,newWidth;
- long size;
- short stripBytes;
- short newStripBytes;
- short i,y;
- OSErr result = noErr;
-
-
- if ( dataProc->dataProc == nil )
- dataProc = nil;
- if ( flushProc->flushProc == nil )
- flushProc = nil;
- if ( progressProc->progressProc == nil )
- progressProc = nil;
- if ( progressProc )
- progressProc->progressProc(codecProgressOpen,0,progressProc->progressRefCon);
-
- dataP = inData;
- newHeight = (*desc)->height;
- newWidth = (*desc)->width;
- stripBytes = ((newWidth+1)>>1) * 5; /* the number of bytes in a strip (2-scanlines/strip) */
-
- /* figure out how many 2x2 blocks we want to strip from each side of the image */
-
- trimOffTop = rect.top>>1;
- trimOffBottom = (newHeight - rect.bottom) >> 1;
- trimOffLeft = rect.left>>1;
- trimOffRight = (newWidth - rect.right) >> 1;
-
- /* point to the start of the first strip we are using */
-
- startP = dataP + stripBytes * trimOffTop;
-
-
- /* make the trim values pixel based */
-
- trimOffLeft <<= 1;
- trimOffTop <<= 1;
- trimOffBottom <<= 1;
- trimOffRight <<= 1;
-
- /* calculate new height and width */
-
- newHeight -= trimOffTop + trimOffBottom;
- newWidth -= trimOffLeft + trimOffRight;
-
- /* calc size in bytes of strips of the new width */
-
- newStripBytes = ((newWidth+1)>>1) * 5;
-
- /* figure number of bytes to toss at the beginning of each strip */
-
- bytesOffLeft = (trimOffLeft>>1) * 5;
-
- /* figure size of new trimmed image */
-
- size = newStripBytes * (newHeight>>1);
-
- /* make sure it's gonna fit */
-
- if ( size > outDataSize ) {
- result = codecErr;
- goto bail;
- }
-
- /* now go through the strips and copy the needed portion of each to the new data */
-
- if ( dataProc ) {
- short rightBytes = stripBytes - newStripBytes - bytesOffLeft;
- for ( y=0; y < trimOffTop; y++ ) {
- if ( (result=dataProc->dataProc(&inData,stripBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += stripBytes;
- if (progressProc ) {
- if ( (result=progressProc->progressProc(codecProgressUpdatePercent,
- FixDiv(y, (*desc)->height),progressProc->progressRefCon)) != noErr) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- for ( y=0; y < newHeight; y+= 2) {
- if ( bytesOffLeft ) {
- if ( (result=dataProc->dataProc(&inData,bytesOffLeft,dataProc->dataRefCon)) != noErr )
- goto bail;
- inData += bytesOffLeft;
- }
- if ( (result=dataProc->dataProc(&inData,newStripBytes,dataProc->dataRefCon)) != noErr )
- goto bail;
- if ( flushProc ) {
- if ( (result=flushProc->flushProc(inData,newStripBytes,flushProc->flushRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
- else {
- BlockMove(inData,outData,newStripBytes);
- outData += newStripBytes;
- }
- inData += newStripBytes;
- if ( rightBytes ) {
- if ( (result=dataProc->dataProc(&inData,rightBytes,dataProc->dataRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- inData += rightBytes;
- }
- if (progressProc) {
- if ( (result=progressProc->progressProc(codecProgressUpdatePercent,
- FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- }
- else {
- inData += stripBytes * trimOffTop;
- for ( y=0; y < newHeight; y += 2, inData += stripBytes) {
- if ( flushProc ) {
- if ( (result=flushProc->flushProc(inData + bytesOffLeft,newStripBytes,flushProc->flushRefCon)) != noErr ) {
- result = codecSpoolErr;
- goto bail;
- }
- }
- else {
- BlockMove(inData + bytesOffLeft,outData,newStripBytes);
- outData += newStripBytes;
- }
- if (progressProc ) {
- if ( (result=progressProc->progressProc(codecProgressUpdatePercent,
- FixDiv((trimOffTop + y),(*desc)->height),progressProc->progressRefCon)) != noErr ) {
- result = codecAbortErr;
- goto bail;
- }
- }
- }
- }
-
- /* adjust the rectangle to reflect our changes */
-
- trimRect->top -= trimOffTop;
- trimRect->bottom -= trimOffTop;
- trimRect->left -= trimOffLeft;
- trimRect->right -= trimOffLeft;
-
- /* return the new width and height in the image description and the size */
-
- (*desc)->height = newHeight;
- (*desc)->width = newWidth;
- (*desc)->dataSize = size;
- bail:
- if ( progressProc )
- progressProc->progressProc(codecProgressClose,0,progressProc->progressRefCon);
-
- return(result);
-
-
- }
-
-
- #ifndef HAS_ASM /* we could do this part in assembly for speed if we desired */
-
-
- #define READPIXEL(n) \
- l = *lp++; \
- r = (l>>16); \
- g = (l>>8); \
- b = l; \
- yt = (R_W*r + G_W*g + B_W*b); \
- if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
- ys[n] = yt>>16; \
- y += yt; \
- u += r; \
- v += b;
-
- #define READPIXEL_TAB(n) \
- l = *lp++; \
- r = (l>>16); \
- g = (l>>8); \
- b = l; \
- yt = (rwTable[r] + gwTable[g] + bwTable[b]); \
- if ( yt > ((256L<<16)-1) ) yt = ((256L<<16)-1); \
- ys[n] = yt>>16; \
- y += yt; \
- u += r; \
- v += b;
-
-
- pascal void
- CompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
- {
-
- register long l,*lp = (long *)baseAddr;
- register unsigned char r,g,b;
- unsigned char ys[4];
- register long y,yt;
- short u,v;
- short rowLongs = (rowBytes>>2);
-
-
-
-
- len++;
- len>>=1;
-
- if ( sg->rgbwTable && *sg->rgbwTable ) {
- long *rwTable,*gwTable,*bwTable;
-
- rwTable = (long *)*sg->rgbwTable;
- gwTable = rwTable + 256;
- bwTable = rwTable + 512;
-
- while ( len-- > 0) {
- y = u = v = 0;
- READPIXEL_TAB(0);
- READPIXEL_TAB(1);
- lp += rowLongs-2;
- READPIXEL_TAB(2);
- READPIXEL_TAB(3);
- lp -= rowLongs;
-
- y >>= 16;
- u = (u - y)>>4;
- v = (v - y)>>4;
-
- l = (long)(0xfc & (ys[0])) << 24;
- l |= (long)(0xfc & (ys[1])) << 18;
- l |= (long)(0xfc & (ys[2])) << 12;
- l |= (long)(0xfc & (ys[3])) << 6;
- l |= u & 0xff;
- *(long *)data = l;
- data += sizeof(long);
- *data++ = v;
- }
- } else {
- while ( len-- > 0) {
- y = u = v = 0;
- READPIXEL(0);
- READPIXEL(1);
- lp += rowLongs-2;
- READPIXEL(2);
- READPIXEL(3);
- lp -= rowLongs;
-
- y >>= 16;
- u = (u - y)>>4;
- v = (v - y)>>4;
-
- l = (long)(0xfc & (ys[0])) << 24;
- l |= (long)(0xfc & (ys[1])) << 18;
- l |= (long)(0xfc & (ys[2])) << 12;
- l |= (long)(0xfc & (ys[3])) << 6;
- l |= u & 0xff;
- *(long *)data = l;
- data += sizeof(long);
- *data++ = v;
- }
- }
- }
-
-
-
-
- #define WRITEPIXEL \
- r = PIN(u+y); \
- b = PIN(v+y); \
- y <<= 16; \
- y -= r * R_W; \
- y -= b * B_W; \
- g = PIN(y / G_W); \
- *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;
-
- #define WRITEPIXEL_TAB \
- r = PIN(u+y); \
- b = PIN(v+y); \
- y <<= 16; \
- y -= rwTable[r]; \
- y -= bwTable[b]; \
- g = giwTable[PIN(y>>16)]; \
- *lp++ = (long) ( (long) r <<16) | ( (long) g <<8) | b;
-
- pascal void
- DecompressStrip(char *data,char *baseAddr,short rowBytes,short len,SharedGlobals *sg)
- {
- register long y;
- register unsigned char r,g,b;
- register long l,*lp;
- long u,v;
- unsigned char ys[4];
- short rowLongs = (rowBytes>>2);
- short blen = len;
-
- lp = (long *)baseAddr;
- blen++;
- blen >>= 1;
-
- if ( sg->rgbwTable && *sg->rgbwTable && sg->giwTable && *sg->giwTable ) {
- unsigned char *giwTable;
- long *rwTable,*bwTable;
-
- giwTable = *sg->giwTable;
- rwTable = (long *)*sg->rgbwTable;
- bwTable = rwTable + 512;
- while ( blen-- > 0 ) {
- l = *(long *)data;
- data += sizeof(long);
- ys[0] = (0xfc & (l>>24));
- ys[1] = (0xfc & (l>>18));
- ys[2] = (0xfc & (l>>12));
- ys[3] = (0xfc & (l>>6));
- u = (char)l;
- v = *data++;
- u<<=2;
- v<<=2;
- y = ys[0];
- WRITEPIXEL_TAB;
- y = ys[1];
- WRITEPIXEL_TAB;
- lp += rowLongs - 2;
- y = ys[2];
- WRITEPIXEL_TAB;
- y = ys[3];
- WRITEPIXEL_TAB;
- lp -= rowLongs;
- }
- } else {
- while ( blen-- > 0 ) {
- l = *(long *)data;
- data += sizeof(long);
- ys[0] = (0xfc & (l>>24));
- ys[1] = (0xfc & (l>>18));
- ys[2] = (0xfc & (l>>12));
- ys[3] = (0xfc & (l>>6));
- u = (char)l;
- v = *data++;
- u<<=2;
- v<<=2;
- y = ys[0];
- WRITEPIXEL;
- y = ys[1];
- WRITEPIXEL;
- lp += rowLongs - 2;
- y = ys[2];
- WRITEPIXEL;
- y = ys[3];
- WRITEPIXEL;
- lp -= rowLongs;
- }
- }
- }
-
-
- #endif
-
-
-