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.
Common Files/SpriteUtilities.c
////////// |
// |
// File: SpriteUtilities.c |
// |
// Contains: Utilities for adding sprite tracks to QuickTime movies. |
// |
// Written by: Sean Allen |
// Revised by: Chris Flick and Tim Monroe |
// |
// Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <3> 03/27/98 rtm added error checking to AddPICTImageToKeyFrameSample to prevent crashes |
// if PICT resources not found |
// <2> 03/27/98 cf further fixes for Windows compiles |
// <1> 03/26/98 rtm made fixes for Windows compiles |
// |
// |
////////// |
#ifndef _SPRITEUTILITIES_ |
#include "SpriteUtilities.h" |
#endif |
#ifndef _IMAGECOMPRESSIONUTILITIES_ |
#include "ImageCompressionUtilities.h" |
#endif |
#ifndef __ENDIANUTILITIES__ |
#include "EndianUtilities.h" |
#endif |
#ifndef __RESOURCES__ |
#include <Resources.h> |
#endif |
#ifndef __QUICKTIMECOMPONENTS__ |
#include <QuickTimeComponents.h> |
#endif |
#ifndef __MEDIAHANDLERS__ |
#include <MediaHandlers.h> |
#endif |
// exception handling macros |
#define FailIf(a, e) {if (a) { err = e; goto bail; }} |
#define FailOSErr(a) {if (err = a) goto bail;} |
#define FailMemErr(a) {a; if (err = MemError()) goto bail;} |
OSErr GetImageDescription( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, ImageDescriptionHandle imageDesc ); |
OSErr SetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long groupID ); |
OSErr GetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long *groupID ); |
OSErr SetSpriteData( QTAtomContainer sprite, Point *location, short *visible, short *layer, short *imageIndex, ModifierTrackGraphicsModeRecord *graphicsMode, StringPtr spriteName, QTAtomContainer actionAtoms ) |
{ |
OSErr err = noErr; |
QTAtom propertyAtom; |
if ( location ) { |
MatrixRecord matrix; |
SetIdentityMatrix( &matrix ); |
matrix.matrix[2][0] = ((long)location->h << 16); |
matrix.matrix[2][1] = ((long)location->v << 16); |
EndianUtils_MatrixRecord_NtoB( &matrix ); |
if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyMatrix, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyMatrix, 1, 0, sizeof(MatrixRecord), &matrix, nil ) ) |
else |
FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(MatrixRecord), &matrix ) ); |
} |
if ( visible ) { |
short tempVisible = *visible; |
tempVisible = EndianS16_NtoB(tempVisible); |
if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyVisible, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyVisible, 1, 0, sizeof(short), &tempVisible, nil ) ) |
else |
FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), &tempVisible ) ); |
} |
if ( layer ) { |
short tempLayer = *layer; |
tempLayer = EndianS16_NtoB(tempLayer); |
if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyLayer, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyLayer, 1, 0, sizeof(short), &tempLayer, nil ) ) |
else |
FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), &tempLayer ) ); |
} |
if ( imageIndex ) { |
short tempImageIndex = *imageIndex; |
tempImageIndex = EndianS16_NtoB(tempImageIndex); |
if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyImageIndex, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyImageIndex, 1, 0, sizeof(short), &tempImageIndex, nil ) ) |
else |
FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), &tempImageIndex ) ); |
} |
if ( graphicsMode ) { |
ModifierTrackGraphicsModeRecord tempGraphicsMode; |
tempGraphicsMode.graphicsMode = EndianU32_NtoB(graphicsMode->graphicsMode); |
tempGraphicsMode.opColor.red = EndianU16_NtoB(graphicsMode->opColor.red); |
tempGraphicsMode.opColor.green = EndianU16_NtoB(graphicsMode->opColor.green); |
tempGraphicsMode.opColor.blue = EndianU16_NtoB(graphicsMode->opColor.blue); |
if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyGraphicsMode, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyGraphicsMode, 1, 0, sizeof(tempGraphicsMode), &tempGraphicsMode, nil ) ) |
else |
FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(tempGraphicsMode), &tempGraphicsMode ) ); |
} |
if( spriteName ) { |
QTAtom spriteNameAtom; |
if ( (spriteNameAtom = QTFindChildByIndex( sprite, 0, kSpriteNameAtomType, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( sprite, 0, kSpriteNameAtomType, 1, 0, spriteName[0]+1, spriteName, nil ) ) |
else |
FailOSErr( QTSetAtomData( sprite, spriteNameAtom, spriteName[0]+1, spriteName ) ); |
} |
if ( actionAtoms ) { |
FailOSErr( QTInsertChildren( sprite, kParentAtomIsContainer, actionAtoms ) ); |
} |
bail: |
if ( err && sprite ) |
QTRemoveChildren( sprite, 0 ); |
return err; |
} |
OSErr AddSpriteToSample( QTAtomContainer theSample, QTAtomContainer theSprite, QTAtomID spriteID ) |
{ |
OSErr err = noErr; |
QTAtom newSpriteAtom; |
FailIf ( QTFindChildByID( theSample, 0, kSpriteAtomType, spriteID, nil ), paramErr ); |
FailOSErr( QTInsertChild( theSample, 0, kSpriteAtomType, spriteID, 0, 0, nil, &newSpriteAtom ) ); // index of zero means append |
FailOSErr( QTInsertChildren( theSample, newSpriteAtom, theSprite ) ); |
bail: |
return err; |
} |
OSErr AddSpriteSampleToMedia( Media theMedia, QTAtomContainer sample, TimeValue duration, Boolean isKeyFrame, |
TimeValue *sampleTime ) |
{ |
OSErr err = noErr; |
SampleDescriptionHandle sampleDesc = nil; |
FailMemErr( sampleDesc = (SampleDescriptionHandle) NewHandleClear( sizeof(SpriteDescription ) ) ); |
FailOSErr( AddMediaSample( theMedia, (Handle) sample, 0, GetHandleSize( sample ), |
duration, sampleDesc, 1, |
(short)(isKeyFrame ? 0 : mediaSampleNotSync), sampleTime ) ); |
bail: |
if ( sampleDesc ) DisposeHandle( (Handle) sampleDesc ); |
return err; |
} |
OSErr AddCompressedSpriteSampleToMedia( Media theMedia, QTAtomContainer sample, TimeValue duration, Boolean isKeyFrame, |
OSType dataCompressorType, |
TimeValue *sampleTime ) |
{ |
OSErr err = noErr; |
SpriteDescriptionHandle sampleDesc = nil; |
Handle compressedSample = nil; |
ComponentInstance dataCompressorComponentInstance = nil; |
err = OpenADefaultComponent(DataCompressorComponentType, dataCompressorType, &dataCompressorComponentInstance); |
if( err ) goto bail; |
FailMemErr( sampleDesc = (SpriteDescriptionHandle) NewHandleClear( sizeof(SpriteDescription) ) ); |
if( dataCompressorComponentInstance != nil ) { |
UInt32 compressBufferSize, actualCompressedSize, decompressSlop = 0; |
UInt32 uncompressedSize; |
SignedByte saveState = HGetState( sample ); |
err = (OSErr)DataCodecGetCompressBufferSize( dataCompressorComponentInstance, GetHandleSize( sample ), &compressBufferSize ); |
if(err) goto bail; |
compressedSample = NewHandle( sizeof(UInt32) + compressBufferSize ); |
err = MemError(); |
if(err) goto bail; |
HLockHi( sample ); |
HLockHi( compressedSample ); |
err = (OSErr)DataCodecCompress( dataCompressorComponentInstance, *sample, |
GetHandleSize(sample), |
*compressedSample + sizeof(UInt32), // room for size at beginning |
compressBufferSize, |
&actualCompressedSize, |
&decompressSlop ); |
HSetState( sample, saveState ); |
HUnlock( compressedSample ); |
if(err) goto bail; |
SetHandleSize( compressedSample, sizeof(UInt32) + actualCompressedSize ); |
err = MemError(); |
if(err) goto bail; |
(**sampleDesc).decompressorType = EndianU32_NtoB(dataCompressorType); |
uncompressedSize = GetHandleSize(sample); |
(*(UInt32*) *compressedSample) = EndianU32_NtoB(uncompressedSize); // add uncompressed size at beginning |
FailOSErr( AddMediaSample( theMedia, (Handle) compressedSample, 0, GetHandleSize( compressedSample ), |
duration, (SampleDescriptionHandle) sampleDesc, 1, |
(short)(isKeyFrame ? 0 : mediaSampleNotSync), sampleTime ) ); |
} |
else |
{ |
FailOSErr( AddMediaSample( theMedia, (Handle) sample, 0, GetHandleSize( sample ), |
duration, (SampleDescriptionHandle) sampleDesc, 1, |
(short)(isKeyFrame ? 0 : mediaSampleNotSync), sampleTime ) ); |
} |
bail: |
if ( compressedSample ) DisposeHandle( compressedSample ); |
if ( sampleDesc ) DisposeHandle( (Handle) sampleDesc ); |
if ( dataCompressorComponentInstance ) CloseComponent( dataCompressorComponentInstance ); |
return err; |
} |
OSErr AddPICTImageToKeyFrameSample( QTAtomContainer keySample, short pictID, RGBColor *keyColor, QTAtomID id, FixedPoint *registrationPoint, StringPtr imageName ) |
{ |
OSErr err = noErr; |
PicHandle picture; |
Handle compressedPicture = NULL; |
ImageDescriptionHandle idh = NULL; |
// get picture from resource |
picture = (PicHandle) GetPicture( pictID ); |
if (picture == NULL) |
err = resNotFound; |
if(err) goto bail; |
DetachResource( (Handle)picture ); |
// convert it to image data compressed by the animation compressor |
err = RecompressPictureWithTransparency( picture, keyColor, nil, &idh, &compressedPicture ); |
if(err) goto bail; |
// add it to the keySample |
HLock( compressedPicture ); |
err = AddCompressedImageToKeyFrameSample( keySample, idh, GetHandleSize( compressedPicture ), *compressedPicture, id, registrationPoint, imageName ); |
bail: |
if ( picture ) KillPicture( picture ); |
if ( compressedPicture ) DisposeHandle( compressedPicture ); |
if ( idh ) DisposeHandle( (Handle)idh ); |
return err; |
} |
OSErr AddCompressedImageToKeyFrameSample( QTAtomContainer keySample, |
ImageDescriptionHandle idh, long dataSize, Ptr compressedDataPtr, |
QTAtomID imageID, FixedPoint *registrationPoint, StringPtr imageName ) |
{ |
OSErr err = noErr; |
Handle imageData; |
QTAtom defaultsAtom, imagesContainerAtom, imageAtom; |
ImageDescriptionHandle bigEndianImageDescription = nil; |
#if TARGET_RT_LITTLE_ENDIAN |
bigEndianImageDescription = (ImageDescriptionHandle) NewHandle(GetHandleSize((Handle)idh)); |
BlockMoveData( *idh, *bigEndianImageDescription, GetHandleSize((Handle)idh)); |
EndianUtils_ImageDescription_NtoB(bigEndianImageDescription); |
#else |
bigEndianImageDescription = idh; // already is big endian |
#endif |
// append compressed picture data to imageDescription to obtain sprite image data |
FailMemErr( imageData = NewHandle(0) ); |
FailMemErr( HandAndHand( (Handle)bigEndianImageDescription, imageData ) ); // imageData <= imageData + bigEndianImageDescription |
FailMemErr( PtrAndHand( compressedDataPtr, imageData, dataSize ) ); |
if ( (defaultsAtom = QTFindChildByIndex( keySample, 0, kSpriteSharedDataAtomType, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( keySample, 0, kSpriteSharedDataAtomType, 1, 0, 0, nil, &defaultsAtom ) ); |
if ( (imagesContainerAtom = QTFindChildByIndex( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, nil )) == 0 ) |
FailOSErr( QTInsertChild( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, 0, 0, nil, &imagesContainerAtom ) ); |
FailOSErr( QTInsertChild( keySample, imagesContainerAtom, kSpriteImageAtomType, imageID, 0, 0, nil, &imageAtom ) ); |
HLock( imageData ); |
FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageDataAtomType, 1, 0, GetHandleSize(imageData), *imageData, nil ) ); |
HUnlock( imageData ); |
if ( registrationPoint ) { |
FixedPoint tempRegistrationPoint; |
tempRegistrationPoint.x = EndianS32_NtoB(registrationPoint->x); |
tempRegistrationPoint.y = EndianS32_NtoB(registrationPoint->y); |
FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageRegistrationAtomType, 1, 0, sizeof(tempRegistrationPoint), &tempRegistrationPoint, nil ) ); |
} |
else { |
FixedPoint regPoint = { 0, 0 }; |
// Flipping {0,0} doesn't change anything so we don't flip |
FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageRegistrationAtomType, 1, 0, sizeof(regPoint), ®Point, nil ) ); |
} |
if( imageName ) { |
FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageNameAtomType, 1, 0, imageName[0], &imageName[1], nil ) ); |
} |
bail: |
#if TARGET_RT_LITTLE_ENDIAN |
if(bigEndianImageDescription) |
DisposeHandle((Handle)bigEndianImageDescription); |
#else |
// bigEndianImageDescription is still idh, so don't dispose of it |
#endif |
if ( imageData ) DisposeHandle( imageData ); |
return err; |
} |
OSErr AssignImageGroupIDsToKeyFrame( QTAtomContainer keySample ) |
{ |
OSErr err = noErr; |
QTAtom defaultsAtom, imagesContainerAtom; |
ImageDescriptionHandle firstImageDesc = nil, secondImageDesc = nil; |
short firstIndex, secondIndex, numImages; |
CodecType firstImageType, secondImageType; |
long groupID = 0, testID; |
defaultsAtom = QTFindChildByIndex( keySample, 0, kSpriteSharedDataAtomType, 1, nil ); |
if ( ! defaultsAtom ) goto bail; |
imagesContainerAtom = QTFindChildByIndex( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, nil ); |
if ( ! imagesContainerAtom ) goto bail; |
firstImageDesc = (ImageDescriptionHandle)NewHandle(0); |
if ( firstImageDesc == nil ) { err = memFullErr; goto bail; } |
secondImageDesc = (ImageDescriptionHandle)NewHandle(0); |
if ( secondImageDesc == nil ) { err = memFullErr; goto bail; } |
numImages = QTCountChildrenOfType( keySample, imagesContainerAtom, kSpriteImageAtomType ); |
for ( firstIndex = 1; firstIndex <= numImages; firstIndex++ ) { |
FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, firstIndex, 0 ) ); |
} |
for ( firstIndex = 1; firstIndex <= (numImages - 1); firstIndex++ ) { |
FailOSErr( GetImageGroupID( keySample, imagesContainerAtom, firstIndex, &testID ) ); |
if ( testID == 0 ) { |
groupID++; |
FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, firstIndex, groupID ) ); |
FailOSErr( GetImageDescription( keySample, imagesContainerAtom, firstIndex, firstImageDesc ) ); |
firstImageType = (**firstImageDesc).cType; |
for ( secondIndex = (firstIndex + 1); secondIndex <= numImages; secondIndex++ ) { |
FailOSErr( GetImageGroupID( keySample, imagesContainerAtom, secondIndex, &testID ) ); |
if ( testID == 0 ) { |
FailOSErr( GetImageDescription( keySample, imagesContainerAtom, secondIndex, secondImageDesc ) ); |
secondImageType = (**secondImageDesc).cType; |
if ( firstImageType == secondImageType ) { |
ImageSequence seqID; |
Boolean equivalent; |
FailOSErr( DecompressSequenceBegin( &seqID, firstImageDesc, nil, nil, nil, nil, |
ditherCopy, (RgnHandle)nil, 0, codecNormalQuality, anyCodec ) ); |
CDSequenceEquivalentImageDescription( seqID, secondImageDesc, &equivalent ); |
CDSequenceEnd( seqID ); |
if ( equivalent ) { |
FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, secondIndex, groupID ) ); |
} |
} |
} |
} |
} |
} |
// assign an ID to the last image |
FailOSErr( GetImageGroupID( keySample, imagesContainerAtom, numImages, &testID ) ); |
if ( testID == 0 ) { |
groupID++; |
FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, numImages, groupID ) ); |
} |
bail: |
if ( firstImageDesc ) DisposeHandle( (Handle)firstImageDesc ); |
if ( secondImageDesc ) DisposeHandle( (Handle)secondImageDesc ); |
return err; |
} |
// ¥¥¥¥ ImageDescriptionHandles are in native endianism, right? If so, we need to endian flip them before |
// they're returned from GetImageDescription. |
OSErr GetImageDescription( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, ImageDescriptionHandle imageDesc ) |
{ |
OSErr err = noErr; |
QTAtom imageAtom, imageDataAtom; |
UInt8 saveState; |
UInt32 imageDescriptionSize; |
imageAtom = QTFindChildByIndex( keySample, imagesContainerAtom, kSpriteImageAtomType, imageIndex, nil ); |
if ( imageAtom == 0 ) { err = cannotFindAtomErr; goto bail; } |
imageDataAtom = QTFindChildByIndex( keySample, imageAtom, kSpriteImageDataAtomType, 1, nil ); |
if ( imageDataAtom == 0 ) { err = cannotFindAtomErr; goto bail; } |
saveState = HGetState( (Handle)imageDesc ); |
HUnlock( (Handle)imageDesc ); |
// Copy the data (ImageDescription followed by image data) to a handle |
FailOSErr( QTCopyAtomDataToHandle( keySample, imageDataAtom, (Handle)imageDesc ) ); |
imageDescriptionSize = EndianU32_BtoN((**imageDesc).idSize); |
// Pull off anything following the image description (& its color table, if any, and |
// any image description extensions. |
SetHandleSize( (Handle)imageDesc, imageDescriptionSize ); |
#if TARGET_RT_LITTLE_ENDIAN |
EndianUtils_ImageDescription_BtoN( imageDesc ); |
#endif |
HSetState( (Handle)imageDesc, saveState ); |
err = MemError(); |
bail: |
return err; |
} |
OSErr SetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long groupID ) |
{ |
OSErr err = noErr; |
QTAtom imageAtom, imageGroupAtom; |
imageAtom = QTFindChildByIndex( keySample, imagesContainerAtom, kSpriteImageAtomType, imageIndex, nil ); |
if ( imageAtom == 0 ) { err = cannotFindAtomErr; goto bail; } |
imageGroupAtom = QTFindChildByIndex( keySample, imageAtom, kSpriteImageGroupIDAtomType, 1, nil ); |
if ( imageGroupAtom == 0 ) { |
FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageGroupIDAtomType, 1, 1, 0, nil, &imageGroupAtom ) ); |
} |
groupID = EndianU32_NtoB(groupID); |
FailOSErr( QTSetAtomData( keySample, imageGroupAtom, sizeof( groupID ), &groupID ) ); |
bail: |
return err; |
} |
OSErr GetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long *groupID ) |
{ |
OSErr err = noErr; |
QTAtom imageAtom, imageGroupAtom; |
imageAtom = QTFindChildByIndex( keySample, imagesContainerAtom, kSpriteImageAtomType, imageIndex, nil ); |
if ( imageAtom == 0 ) { err = cannotFindAtomErr; goto bail; } |
imageGroupAtom = QTFindChildByIndex( keySample, imageAtom, kSpriteImageGroupIDAtomType, 1, nil ); |
if ( ! imageGroupAtom ) |
*groupID = 0; |
else { |
FailOSErr( QTCopyAtomDataToPtr( keySample, imageGroupAtom, false, sizeof(*groupID), (Ptr)groupID, nil ) ); |
*groupID = EndianU32_BtoN(*groupID); // return native endian long |
} |
bail: |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-02-25