Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
MungData.c
/* |
File: MungData.c |
Description: Code to create & initialize data structure whose contents will be used |
during decompression operations in conjunction with our custom |
decompressor component. Our data structure include an offscreen |
gworld for decompressing frames. Also included is color clamp |
information which is passed to our decompressor component for |
performing color clamp operations on our data, and an overlay |
offscreen which is used to overlay an image on top of our frame data. |
Copyright: © Copyright 2003 Apple Computer, Inc. All rights reserved. |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under Apple’s |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Change History (most recent first): |
*/ |
#include "MungData.h" |
#include "AppBlit_Component.h" |
#include "QTUtilities.h" |
#include "Utilities.h" |
////////// |
// |
// constants |
// |
////////// |
#define BailNULL(n) if (!n) goto bail; |
#define BailError(n) if (n) goto bail; |
#define BailNil(n) if (!n) goto bail; |
#define BailErr(x) {if (x != noErr) goto bail;} |
#define bitdepth 32 |
////////// |
// |
// globals |
// |
////////// |
mungDataPtr myMungData = NULL; |
////////// |
// |
// module variables |
// |
////////// |
long mWorlds[20]; |
UInt32 mRedCount[256], mGreenCound[256], mBlueCount[256]; |
////////// |
// |
// prototypes |
// |
////////// |
static void DecompressSequencePreflight(GWorldPtr srcGWorld, |
ImageSequence *imageSeq, |
GWorldPtr destGWorld, |
Rect *srcRect); |
static void DrawRGBHistogram(mungDataRecord *theMungData); |
static void CreateEffectDescription(mungDataRecord *theMungData); |
static void CreateEffectDecompSequence(mungDataRecord *theMungData); |
static void AddGWorldDataSourceToEffectDecompSeq(mungDataRecord *theMungData); |
static void MakeEffectTimeBaseForEffect(mungDataRecord *theMungData); |
static void DrawUsingEffect(mungDataRecord *theMungData); |
////////// |
// |
// InitializeMungData |
// Create & initialize a data structure whose contents will be used |
// during decompression operations in conjunction with our custom |
// decompressor component. Our data structure include an offscreen |
// gworld for decompressing frames. Also included is color clamp information |
// which is passed to our decompressor component for performing color |
// clamp operations on our data, and an overlay offscreen which is used |
// to overlay an image on top of our frame data. |
// |
////////// |
OSErr InitializeMungData(Rect bounds, WindowPtr window, Boolean createOverlayGWorld, Boolean withClamp, Boolean withEffect) |
{ |
OSErr err = noErr; |
if(myMungData) |
{ |
DisposeMungData(); |
} |
myMungData = (mungDataPtr)NewPtrClear(sizeof(mungDataRecord)); |
if (myMungData == nil) |
{ |
err = MemError(); |
goto bail; |
} |
if (!withEffect) |
{ |
myMungData->effect = 0; |
} |
BailErr(QTNewGWorld(&(myMungData->gw),bitdepth,&bounds,0,0,0)); |
LockPixels(GetGWorldPixMap(myMungData->gw)); |
SetMungDataColorDefaults(); |
if (createOverlayGWorld) |
{ |
myMungData->selectedIndex = -1; |
BailErr(QTNewGWorld(&(myMungData->overlay),bitdepth,&bounds,0,0,0)); |
LockPixels(GetGWorldPixMap(myMungData->overlay)); |
EraseRectAndAlpha(myMungData->overlay, &bounds); |
// put the overlay into the GWorld, move the picture to the |
// bottom right of the movie |
DrawLobsterPICTtoGWorld(myMungData->overlay, &bounds); |
} |
else |
{ |
myMungData->selectedIndex = 0; |
myMungData->overlay = NULL; |
if (withClamp) |
{ |
SetCurrentClamp(0); |
} |
else |
{ |
SetCurrentClamp(-1); |
if (withEffect) |
{ |
myMungData->effect = 'fmns'; |
} |
} |
} |
myMungData->bounds = bounds; |
myMungData->window = window; |
SetRect(&bounds, 0, 0, 256*2+4, 128*3 + 20); |
BailErr(QTNewGWorld(&(myMungData->histoWorld),bitdepth,&bounds,0,0,0)); |
LockPixels(GetGWorldPixMap(myMungData->histoWorld)); |
bail: |
return err; |
} |
////////// |
// |
// DisposeMungData |
// Dispose our data structure |
// |
////////// |
OSErr DisposeMungData(void) |
{ |
OSErr err = noErr; |
if(myMungData) |
{ |
if(myMungData->drawSeq) |
{ |
CDSequenceEnd(myMungData->drawSeq); |
} |
if(myMungData->gw) |
{ |
DisposeGWorld(myMungData->gw); |
myMungData->gw = nil; |
} |
if(myMungData->overlay) |
{ |
DisposeGWorld(myMungData->overlay); |
myMungData->overlay = nil; |
} |
if(myMungData->histoWorld) |
{ |
DisposeGWorld(myMungData->histoWorld); |
myMungData->histoWorld = nil; |
} |
if (myMungData->effectTimeBase) |
{ |
DisposeTimeBase(myMungData->effectTimeBase); |
} |
if (myMungData->effectParams) |
{ |
QTDisposeAtomContainer(myMungData->effectParams); |
} |
if (myMungData->effectDesc) |
{ |
DisposeHandle((Handle)myMungData->effectDesc); |
} |
DisposePtr((Ptr)myMungData); |
myMungData = nil; |
} |
return err; |
} |
////////// |
// |
// CreateEffectDescription |
// Build an Effects Description - an atom container which |
// specifies an effect and its sources |
// |
////////// |
static void CreateEffectDescription(mungDataRecord *theMungData) |
{ |
OSType sourceType = 'srca'; |
BailErr(QTNewAtomContainer(&theMungData->effectParams)); |
BailErr(QTInsertChild(theMungData->effectParams, kParentAtomIsContainer, kEffectSourceName, 1, 0, |
sizeof(sourceType), &sourceType, nil)); |
BailErr(QTInsertChild(theMungData->effectParams, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, 0, sizeof(theMungData->effect), &theMungData->effect, nil)); |
HLockHi(theMungData->effectParams); |
bail: |
; |
} |
////////// |
// |
// CreateEffectDecompSequence |
// Create a decompression sequence for our effect |
// |
////////// |
static void CreateEffectDecompSequence(mungDataRecord *theMungData) |
{ |
ImageDescriptionHandle imageDesc = nil; |
// create definition of our effect |
BailErr(MakeImageDescriptionForEffect (theMungData->effect, &imageDesc)); |
(**imageDesc).width = theMungData->bounds.right - theMungData->bounds.left; |
(**imageDesc).height = theMungData->bounds.bottom - theMungData->bounds.top; |
// start the decompression sequence for the effect |
BailErr(DecompressSequenceBeginS(&theMungData->drawSeq, |
imageDesc, |
*(theMungData->effectParams), |
GetHandleSize(theMungData->effectParams), |
(GWorldPtr) GetWindowPort(theMungData->window), |
nil, |
&theMungData->bounds, |
nil, |
srcCopy, |
nil, |
0, |
codecNormalQuality, |
bestSpeedCodec)); |
DisposeHandle((Handle)imageDesc); |
bail: |
; |
} |
////////// |
// |
// AddGWorldDataSourceToEffectDecompSeq |
// Add our offscreen gworld as a data source to our effect |
// decompression sequence |
// |
////////// |
static void AddGWorldDataSourceToEffectDecompSeq(mungDataRecord *theMungData) |
{ |
ImageSequenceDataSource effectSource; |
OSType sourceType = 'srca'; |
// make a data source that references our offscreen |
BailErr(MakeImageDescriptionForPixMap(GetPortPixMap(theMungData->gw), |
&theMungData->effectDesc)); |
BailErr(CDSequenceNewDataSource(theMungData->drawSeq, &effectSource, sourceType, 1, |
(Handle)theMungData->effectDesc, nil, 0)); |
BailErr(CDSequenceSetSourceData(effectSource, GetPixBaseAddr(GetPortPixMap(theMungData->gw)), (**theMungData->effectDesc).dataSize)); |
bail: |
; |
} |
////////// |
// |
// MakeEffectTimeBaseForEffect |
// Create a new timebase to run our effect |
// |
////////// |
static void MakeEffectTimeBaseForEffect(mungDataRecord *theMungData) |
{ |
// make the time base to run the effect |
theMungData->effectTimeBase = NewTimeBase(); |
SetTimeBaseRate(theMungData->effectTimeBase, 0); |
BailErr(CDSequenceSetTimeBase(theMungData->drawSeq, theMungData->effectTimeBase)); |
bail: |
; |
} |
////////// |
// |
// DrawUsingEffect |
// Setup a decompression sequence for our effect, then draw. |
// We use our offscreen gworld as a data source to the effect. |
// |
////////// |
static void DrawUsingEffect(mungDataRecord *theMungData) |
{ |
ICMFrameTimeRecord frameTime = {{0}}; |
long frameNum = 0, steps = 1; |
CodecFlags ignore = 0; |
if (theMungData->drawSeq == 0) |
{ |
// build an effect decompression sequence |
CreateEffectDescription(theMungData); |
CreateEffectDecompSequence(theMungData); |
AddGWorldDataSourceToEffectDecompSeq(theMungData); |
MakeEffectTimeBaseForEffect(theMungData); |
} |
SetTimeBaseValue(theMungData->effectTimeBase, frameNum, steps); |
frameTime.value.lo = frameNum; |
frameTime.value.hi = 0; |
frameTime.scale = steps; |
frameTime.base = 0; |
frameTime.duration = steps; |
frameTime.rate = 0; |
frameTime.recordSize = sizeof(frameTime); |
frameTime.frameNumber = 1; // note: always 1, this is the SAMPLE number, not the frame within the effect! |
frameTime.flags = icmFrameTimeHasVirtualStartTimeAndDuration; |
frameTime.virtualStartTime.lo = 0; |
frameTime.virtualStartTime.hi = 0; |
frameTime.virtualDuration = steps; |
DecompressSequenceFrameWhen(theMungData->drawSeq, |
*(theMungData->effectParams), |
GetHandleSize(theMungData->effectParams), |
0, |
&ignore, |
nil, |
&frameTime); |
} |
////////// |
// |
// DecompressSequencePreflight |
// Pass a compressed sample so a codec can perform preflighting |
// before the first DecompressSequenceFrameWhen call |
// |
////////// |
static void DecompressSequencePreflight(GWorldPtr srcGWorld, |
ImageSequence *imageSeq, |
GWorldPtr destGWorld, |
Rect *srcRect) |
{ |
ImageDescriptionHandle imageDesc = nil; |
BailErr(MakeImageDescriptionForPixMap (GetGWorldPixMap(srcGWorld), &imageDesc)); |
// use our built-in decompressor to draw |
(**imageDesc).cType = kCustomDecompressorType; |
// pass a compressed sample so a codec can perform preflighting before the first DecompressSequenceFrameWhen call |
BailErr(DecompressSequenceBegin(imageSeq, |
imageDesc, |
destGWorld, |
0, |
srcRect, |
nil, |
srcCopy, |
nil, |
0, |
codecNormalQuality, |
bestSpeedCodec)); |
bail: |
if (imageDesc) |
{ |
DisposeHandle((Handle)imageDesc); |
} |
} |
////////// |
// |
// DrawRGBHistogram |
// Draw color histogram table (red, green and blue) for our image |
// |
////////// |
static void DrawRGBHistogram(mungDataRecord *theMungData) |
{ |
Rect histoRect, destRect, worldRect; |
int x, pen = 2; |
float totalPixels; |
SetGWorld(theMungData->histoWorld, nil); |
GetPortBounds(theMungData->histoWorld, &worldRect); |
EraseRect(&worldRect); |
PenSize(pen, 1); |
histoRect = theMungData->bounds; |
OffsetRect(&histoRect, histoRect.right - histoRect.left, 0); |
destRect.left = histoRect.left; |
totalPixels = -128.0 / ((histoRect.bottom - histoRect.top) * (histoRect.right - histoRect.left)) * 32.0; |
histoRect.bottom = histoRect.top + 128; |
histoRect.right = histoRect.left + 256*pen; |
OffsetRect(&histoRect, -histoRect.left, -histoRect.top); |
// red |
ClipRect(&histoRect); |
for (x = 1; x < 256; ++x) |
{ |
MoveTo(histoRect.left + x*pen, histoRect.bottom); |
ForeColor(redColor); |
Line(0, totalPixels * mRedCount[x]); |
} |
ClipRect(&worldRect); |
if (theMungData->selectedIndex == 0) |
ForeColor(magentaColor); |
else |
ForeColor(blackColor); |
MoveTo(histoRect.left + theMungData->redMin*pen-pen, histoRect.bottom); |
LineTo(histoRect.left + theMungData->redMin*pen-pen, histoRect.top); |
if (theMungData->selectedIndex == 1) |
ForeColor(magentaColor); |
else |
ForeColor(blackColor); |
MoveTo(histoRect.left + theMungData->redMax*pen+pen, histoRect.bottom); |
LineTo(histoRect.left + theMungData->redMax*pen+pen, histoRect.top); |
OffsetRect(&histoRect, 0, histoRect.bottom - histoRect.top + 10); |
// green |
ClipRect(&histoRect); |
for (x = 1; x < 256; ++x) |
{ |
MoveTo(histoRect.left + x*pen, histoRect.bottom); |
ForeColor(greenColor); |
Line(0, totalPixels * mGreenCound[x]); |
} |
ClipRect(&worldRect); |
ForeColor(blackColor); |
if (theMungData->selectedIndex == 2) |
ForeColor(magentaColor); |
else |
ForeColor(blackColor); |
MoveTo(histoRect.left + theMungData->greenMin*pen-pen, histoRect.bottom); |
LineTo(histoRect.left + theMungData->greenMin*pen-pen, histoRect.top); |
if (theMungData->selectedIndex == 3) |
ForeColor(magentaColor); |
else |
ForeColor(blackColor); |
MoveTo(histoRect.left + theMungData->greenMax*pen+pen, histoRect.bottom); |
LineTo(histoRect.left + theMungData->greenMax*pen+pen, histoRect.top); |
OffsetRect(&histoRect, 0, histoRect.bottom - histoRect.top + 10); |
// blue |
ClipRect(&histoRect); |
for (x = 1; x < 256; ++x) |
{ |
MoveTo(histoRect.left + x*pen, histoRect.bottom); |
ForeColor(blueColor); |
Line(0, totalPixels * mBlueCount[x]); |
} |
ClipRect(&worldRect); |
ForeColor(blackColor); |
if (theMungData->selectedIndex == 4) |
ForeColor(magentaColor); |
else |
ForeColor(blackColor); |
MoveTo(histoRect.left + theMungData->blueMin*pen-pen, histoRect.bottom); |
LineTo(histoRect.left + theMungData->blueMin*pen-pen, histoRect.top); |
if (theMungData->selectedIndex == 5) |
ForeColor(magentaColor); |
else |
ForeColor(blackColor); |
MoveTo(histoRect.left + theMungData->blueMax*pen+pen, histoRect.bottom); |
LineTo(histoRect.left + theMungData->blueMax*pen+pen, histoRect.top); |
PenSize(1, 1); |
SetGWorld(GetWindowPort(theMungData->window), nil); |
GetPortBounds(theMungData->histoWorld, &histoRect); |
destRect.top = histoRect.top; |
destRect.bottom = histoRect.bottom; |
destRect.left = destRect.left; |
destRect.right = destRect.left + histoRect.right - histoRect.left; |
CopyBits( |
(BitMap*)*GetGWorldPixMap(theMungData->histoWorld), |
(BitMap*)*GetGWorldPixMap(GetWindowPort(theMungData->window)), |
&histoRect, |
&destRect, |
srcCopy, nil); |
} |
////////// |
// |
// BlitOneMungData |
// Our custom blitter. This will perform a "decompress" |
// operation of the data in our offscreen gworld using |
// our custom decompressor component and draw the resulting |
// image data to the screen. |
// |
// This custom decompressor component has the ability |
// to overlay graphics on top of the data as well as |
// perform color clamping of the data. |
// |
////////// |
void BlitOneMungData(mungDataRecord *theMungData) |
{ |
static long nextDraw = 0; |
if (theMungData->effect) |
{ |
// draw using a QT Effect |
DrawUsingEffect(theMungData); |
return; |
} |
// draw using a custom built-in blitter |
// create a sequence if we do not already have one |
if (theMungData->drawSeq == 0) |
{ |
// install our custom blitter |
InstallAppBlitComponentCodec(); |
// Pass a compressed sample so a codec can perform preflighting |
// before the first DecompressSequenceFrameWhen call |
DecompressSequencePreflight(theMungData->gw, |
&theMungData->drawSeq, |
GetWindowPort(theMungData->window), |
&theMungData->bounds); |
} |
// draw the resulting (offscreen) image to the screen |
{ |
CodecFlags ignore = 0; |
// our built-in decompressor takes two GWorlds as the |
// "compressed data", plus #count array pointers, plus the |
// clamp values |
mWorlds[0] = (long)theMungData->gw; |
mWorlds[1] = (long)theMungData->overlay; |
mWorlds[2] = (long)mRedCount; |
mWorlds[3] = (long)mGreenCound; |
mWorlds[4] = (long)mBlueCount; |
mWorlds[5] = theMungData->redMin; |
mWorlds[6] = theMungData->redMax; |
mWorlds[7] = theMungData->greenMin; |
mWorlds[8] = theMungData->greenMax; |
mWorlds[9] = theMungData->blueMin; |
mWorlds[10] = theMungData->blueMax; |
BailErr(DecompressSequenceFrame(theMungData->drawSeq, |
(void*)&mWorlds,// "compressed data" = our custom data |
0, |
&ignore, |
nil)); |
// if we are in color adjustment mode, draw that to the window |
if ((TickCount() > nextDraw) && (theMungData->selectedIndex >= 0)) |
{ |
DrawRGBHistogram(theMungData); |
nextDraw = TickCount() + 5; |
} |
} |
bail: |
return; |
} |
////////// |
// |
// GetMungDataOffscreen |
// Accessor method which retrieves the current offscreen |
// used for drawing |
// |
////////// |
GWorldPtr GetMungDataOffscreen() |
{ |
return (myMungData->gw); |
} |
////////// |
// |
// SetMungDataDrawSeq |
// Accessor method to set the draw sequence |
// |
////////// |
void SetMungDataDrawSeq(ImageSequence theDrawSeq) |
{ |
myMungData->drawSeq = theDrawSeq; |
} |
////////// |
// |
// GetMungDataDrawSeq |
// Accessor method to get the draw sequence value |
// |
////////// |
ImageSequence GetMungDataDrawSeq() |
{ |
return myMungData->drawSeq; |
} |
////////// |
// |
// SetMungDataColorDefaults |
// Reset our color default values used in color |
// clamping operations |
// |
////////// |
void SetMungDataColorDefaults() |
{ |
if(myMungData) |
{ |
myMungData->redMin = 2; |
myMungData->redMax = 254; |
myMungData->greenMin = 2; |
myMungData->greenMax = 254; |
myMungData->blueMin = 2; |
myMungData->blueMax = 254; |
} |
} |
////////// |
// |
// AdjustColorClampEndpoints |
// Accessor method to set a color clamp endpoint value |
// |
////////// |
void AdjustColorClampEndpoints(short hMouseCoord) |
{ |
short hCoord = hMouseCoord; |
hCoord -= 320; |
hCoord /= 2; |
if (hCoord < 0) |
hCoord = 0; |
if (hCoord > 255) |
hCoord = 255; |
if (myMungData) |
{ |
switch (myMungData->selectedIndex) |
{ |
case 0: myMungData->redMin=hCoord; break; |
case 1: myMungData->redMax=hCoord; break; |
case 2: myMungData->greenMin=hCoord; break; |
case 3: myMungData->greenMax=hCoord; break; |
case 4: myMungData->blueMin=hCoord; break; |
case 5: myMungData->blueMax=hCoord; break; |
} |
} |
} |
////////// |
// |
// GetMungDataBoundsRect |
// Accessor method to get the bounds rect in use |
// |
////////// |
void GetMungDataBoundsRect(Rect *boundsRect) |
{ |
MacSetRect (boundsRect, |
myMungData->bounds.left, |
myMungData->bounds.top, |
myMungData->bounds.right, |
myMungData->bounds.bottom |
); |
} |
////////// |
// |
// GetMungDataWindowPort |
// Accessor method to get the window port |
// |
////////// |
CGrafPtr GetMungDataWindowPort() |
{ |
return GetWindowPort(myMungData->window); |
} |
////////// |
// |
// GetCurrentClamp |
// Accessor method to get the currently selected |
// color clamp endpoint |
// |
////////// |
long GetCurrentClamp() |
{ |
return myMungData->selectedIndex; |
} |
////////// |
// |
// SetCurrentClampEndpoint |
// Accessor method to set the current color clamp |
// endpoint value |
// |
////////// |
void SetCurrentClamp(short index) |
{ |
myMungData->selectedIndex = index; |
} |
////////// |
// |
// IncrementCurrentClamp |
// Accessor method to increment the current |
// color clamp value |
// |
////////// |
void IncrementCurrentClamp() |
{ |
switch (myMungData->selectedIndex) |
{ |
case 0: myMungData->redMin++; break; |
case 1: myMungData->redMax++; break; |
case 2: myMungData->greenMin++; break; |
case 3: myMungData->greenMax++; break; |
case 4: myMungData->blueMin++; break; |
case 5: myMungData->blueMax++; break; |
} |
} |
////////// |
// |
// DecrementCurrentClamp |
// Accessor method to decrement the current color |
// clamp value |
// |
////////// |
void DecrementCurrentClamp() |
{ |
switch (myMungData->selectedIndex) |
{ |
case 0: myMungData->redMin--; break; |
case 1: myMungData->redMax--; break; |
case 2: myMungData->greenMin--; break; |
case 3: myMungData->greenMax--; break; |
case 4: myMungData->blueMin--; break; |
case 5: myMungData->blueMax--; break; |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-06