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.
QTEffects.c
////////// |
// |
// File: QTEffects.c |
// |
// Contains: QuickTime video effect support for QuickTime movies. |
// Based on existing samples QTShowEffect, MakeEffectMovie, and AddEffectSeg. |
// |
// Written by: Tim Monroe |
// |
// Copyright: © 1997-2001 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <1> 11/06/97 rtm first file; parts from QTShowEffect, MakeEffectMovie, and AddEffectSeg |
// |
// |
////////// |
////////// |
// |
// header files |
// |
////////// |
#include "QTEffects.h" |
////////// |
// |
// global variables |
// |
////////// |
QTParameterDialog gEffectsDialog = 0L; // identifier for the standard parameter dialog box |
int gNumberOfSteps = k30StepsCount; |
QTAtomContainer gEffectDesc = NULL; // effects description |
QTAtomContainer gEffectList = NULL; |
PicHandle gPosterA = NULL; |
PicHandle gPosterB = NULL; |
Movie gSrcMovies[kMaxNumSources] = {NULL, NULL, NULL}; |
Track gSrcTracks[kMaxNumSources] = {NULL, NULL, NULL}; |
UInt16 gSpecCount = 0; |
Boolean gCopyMovieMedia = false; // should we copy the movie media into the new effects movie? |
Boolean gDoneWithDialog = false; // are we done using the effects parameters dialog box? |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// High-level functions. |
// |
// These functions are called by QTApp_HandleMenu. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// QTEffects_MakeFireMovie |
// Make a movie containing the fire effect. |
// |
////////// |
void QTEffects_MakeFireMovie (void) |
{ |
FSSpec myFile; |
Boolean myIsSelected = false; |
Boolean myIsReplacing = false; |
StringPtr myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt); |
StringPtr myFileName = QTUtils_ConvertCToPascalString(kEffectsFireMovieFileName); |
Movie myMovie = NULL; |
short myMovieRefNum = kInvalidFileRefNum; |
short myResID = movieInDataForkResID; |
Track myEffectTrack = NULL; |
Media myEffectMedia = NULL; |
QTAtomContainer myEffectDesc = NULL; |
ImageDescriptionHandle mySampleDesc = NULL; |
TimeValue mySampleTime = 0; |
long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; |
OSType myType = FOUR_CHAR_CODE('none'); |
OSErr myErr = noErr; |
// ask the user for the name of the new movie file |
QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing); |
if (!myIsSelected) |
goto bail; // deal with user cancelling |
// create a movie file for the destination movie |
myErr = CreateMovieFile(&myFile, sigMoviePlayer, smSystemScript, myFlags, &myMovieRefNum, &myMovie); |
if (myErr != noErr) |
goto bail; |
// select the "no controller" movie controller |
myType = EndianU32_NtoB(myType); |
SetUserDataItem(GetMovieUserData(myMovie), &myType, sizeof(myType), kUserDataMovieControllerType, 1); |
////////// |
// |
// create the effects track |
// |
////////// |
myEffectTrack = NewMovieTrack(myMovie, IntToFixed(kDefaultTrackWidth), IntToFixed(kDefaultTrackHeight), kNoVolume); |
if (myEffectTrack == NULL) |
goto bail; |
myEffectMedia = NewTrackMedia(myEffectTrack, VideoMediaType, kOneSecond, NULL, 0); |
if (myEffectMedia == NULL) |
goto bail; |
////////// |
// |
// create the sample description |
// |
////////// |
mySampleDesc = EffectsUtils_MakeSampleDescription(kFireCodecType, kDefaultTrackWidth, kDefaultTrackHeight); |
if (mySampleDesc == NULL) |
goto bail; |
////////// |
// |
// create the effect description |
// |
////////// |
myEffectDesc = EffectsUtils_CreateEffectDescription(kFireCodecType, kSourceNoneName, kSourceNoneName, kSourceNoneName); |
if (myEffectDesc == NULL) |
goto bail; |
// add a parameter atom to the effects sample |
if (0) { |
long myRate = 11; // this one goes to 11.... |
myRate = EndianS32_NtoB(myRate); |
myErr = QTInsertChild(myEffectDesc, kParentAtomIsContainer, FOUR_CHAR_CODE('decy'), 1, 0, sizeof(myRate), &myRate, NULL); |
} |
////////// |
// |
// add the effect description as a sample to the effects track media |
// |
////////// |
myErr = BeginMediaEdits(myEffectMedia); |
if (myErr != noErr) |
goto bail; |
myErr = AddMediaSample(myEffectMedia, myEffectDesc, 0, GetHandleSize(myEffectDesc), kEffectMovieDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime); |
if (myErr != noErr) |
goto bail; |
myErr = EndMediaEdits(myEffectMedia); |
if (myErr != noErr) |
goto bail; |
myErr = InsertMediaIntoTrack(myEffectTrack, 0, mySampleTime, kEffectMovieDuration, fixed1); |
if (myErr != noErr) |
goto bail; |
AddMovieResource(myMovie, myMovieRefNum, &myResID, NULL); |
bail: |
if (myMovieRefNum != kInvalidFileRefNum) |
CloseMovieFile(myMovieRefNum); |
if (myMovie != NULL) |
DisposeMovie(myMovie); |
if (myEffectDesc != NULL) |
QTDisposeAtomContainer(myEffectDesc); |
if (mySampleDesc != NULL) |
DisposeHandle((Handle)mySampleDesc); |
free(myPrompt); |
free(myFileName); |
return; |
} |
////////// |
// |
// QTEffects_AddFilmNoiseToMovie |
// Add the film noise effect to the (first video track in the) specified movie. |
// |
////////// |
void QTEffects_AddFilmNoiseToMovie (Movie theMovie) |
{ |
ImageDescriptionHandle mySampleDesc = NULL; |
Track mySrcTrack = NULL; |
Track myTrack = NULL; |
Media myMedia = NULL; |
QTAtomContainer myInputMap = NULL; |
QTAtomContainer myEffectDesc = NULL; |
TimeValue mySampleTime; |
Fixed myWidth, myHeight; |
OSErr myErr = noErr; |
if (theMovie == NULL) |
goto bail; |
// get the first visual track in the movie |
mySrcTrack = GetMovieIndTrackType(theMovie, 1, kCharacteristicCanSendVideo, movieTrackCharacteristic | movieTrackEnabledOnly); |
if (mySrcTrack == NULL) |
goto bail; |
// get the width and height of that track |
GetTrackDimensions(mySrcTrack, &myWidth, &myHeight); |
////////// |
// |
// create the effects track |
// |
////////// |
myTrack = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume); |
if (myTrack == NULL) |
goto bail; |
myMedia = NewTrackMedia(myTrack, VideoMediaType, kOneSecond, NULL, 0); |
if (myMedia == NULL) |
goto bail; |
////////// |
// |
// create the sample description |
// |
////////// |
mySampleDesc = EffectsUtils_MakeSampleDescription(kFilmNoiseImageFilterType, FixedToInt(myWidth), FixedToInt(myHeight)); |
if (mySampleDesc == NULL) |
goto bail; |
////////// |
// |
// create the effect description |
// |
////////// |
myEffectDesc = EffectsUtils_CreateEffectDescription(kFilmNoiseImageFilterType, kSourceOneName, kSourceNoneName, kSourceNoneName); |
if (myEffectDesc == NULL) |
goto bail; |
////////// |
// |
// add the effect description as a sample to the effects track media |
// |
////////// |
myErr = BeginMediaEdits(myMedia); |
if (myErr != noErr) |
goto bail; |
myErr = AddMediaSample(myMedia, (Handle)myEffectDesc, 0, GetHandleSize((Handle)myEffectDesc), GetMediaDuration(GetTrackMedia(mySrcTrack)), (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime); |
if (myErr != noErr) |
goto bail; |
myErr = EndMediaEdits(myMedia); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create the input map and add references for the first effects track |
// |
////////// |
myErr = QTNewAtomContainer(&myInputMap); |
if (myErr != noErr) |
goto bail; |
myErr = EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myTrack, mySrcTrack, kSourceOneName); |
if (myErr != noErr) |
goto bail; |
// add the input map to the effects track |
myErr = SetMediaInputMap(myMedia, myInputMap); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// add the media to the track |
// |
////////// |
myErr = InsertMediaIntoTrack(myTrack, 0, mySampleTime, GetMediaDuration(myMedia), fixed1); |
bail: |
if (myEffectDesc != NULL) |
QTDisposeAtomContainer(myEffectDesc); |
if (mySampleDesc != NULL) |
DisposeHandle((Handle)mySampleDesc); |
if (myInputMap != NULL) |
QTDisposeAtomContainer(myInputMap); |
return; |
} |
////////// |
// |
// QTEffects_AddFilmNoiseToImage |
// Add the film noise effect to the image associated with the specified window object. |
// |
////////// |
void QTEffects_AddFilmNoiseToImage (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
GraphicsImportComponent myImporter = NULL; |
Rect myRect; |
if (theWindowObject == NULL) |
return; |
myAppData = (ApplicationDataHdl)(**theWindowObject).fAppData; |
if (myAppData == NULL) |
return; |
myImporter = (**theWindowObject).fGraphicsImporter; |
if (myImporter == NULL) |
return; |
GraphicsImportGetBoundsRect(myImporter, &myRect); |
// set up the initial state |
(**myAppData).fSampleDescription = EffectsUtils_MakeSampleDescription(kImageEffectType, myRect.right - myRect.left, myRect.bottom - myRect.top); |
(**myAppData).fEffectDescription = EffectsUtils_CreateEffectDescription(kImageEffectType, kSourceOneName, kSourceNoneName, kSourceNoneName); |
(**myAppData).fEffectType = kImageEffectType; |
(**myAppData).fEffectSequenceID = 0L; |
(**myAppData).fTimeBase = NULL; |
QTEffects_SetUpEffectSequence(theWindowObject); |
} |
////////// |
// |
// QTEffects_MakePenguinMovie |
// Make a movie that cross-fades the penguin picture in from a white initial frame. |
// |
////////// |
void QTEffects_MakePenguinMovie (void) |
{ |
ImageDescriptionHandle mySampleDesc = NULL; |
short myMovieRefNum = kInvalidFileRefNum; |
short myResID = movieInDataForkResID; |
Movie myMovie = NULL; |
Track myTrack = NULL; |
Track mySrc1Track = NULL; |
Track mySrc2Track = NULL; |
Media myMedia; |
GWorldPtr myGW1 = NULL; |
GWorldPtr myGW2 = NULL; |
FSSpec myFile; |
Boolean myIsSelected = false; |
Boolean myIsReplacing = false; |
QTAtomContainer myInputMap = NULL; |
QTAtomContainer myEffectDesc = NULL; |
TimeValue mySampleTime; |
long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; |
StringPtr myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt); |
StringPtr myFileName = QTUtils_ConvertCToPascalString(kEffectsPenguinMovieFileName); |
OSErr myErr = noErr; |
// ask the user for the name of the new movie file |
QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing); |
if (!myIsSelected) |
goto bail; // deal with user cancelling |
// create a movie file for the destination movie |
myErr = CreateMovieFile(&myFile, sigMoviePlayer, smCurrentScript, myFlags, &myMovieRefNum, &myMovie); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create the effects track |
// |
////////// |
myTrack = NewMovieTrack(myMovie, IntToFixed(kPenguinTrackWidth), IntToFixed(kPenguinTrackHeight), kNoVolume); |
if (myTrack == NULL) |
goto bail; |
myMedia = NewTrackMedia(myTrack, VideoMediaType, kOneSecond, NULL, 0); |
if (myMedia == NULL) |
goto bail; |
////////// |
// |
// create the sample description |
// |
////////// |
mySampleDesc = EffectsUtils_MakeSampleDescription(kCrossFadeTransitionType, kPenguinTrackWidth, kPenguinTrackHeight); |
if (mySampleDesc == NULL) |
goto bail; |
////////// |
// |
// create the effect description |
// |
////////// |
myEffectDesc = EffectsUtils_CreateEffectDescription(kCrossFadeTransitionType, kSourceOneName, kSourceTwoName, kSourceNoneName); |
if (myEffectDesc == NULL) |
goto bail; |
////////// |
// |
// add the video tracks of the source pictures to the effects movie |
// |
////////// |
myErr = EffectsUtils_GetPictResourceAsGWorld(kWhiteRectID, kPenguinTrackWidth, kPenguinTrackHeight, 0, &myGW1); |
if (myErr != noErr) |
goto bail; |
myErr = EffectsUtils_GetPictResourceAsGWorld(kPenguinPictID, kPenguinTrackWidth, kPenguinTrackHeight, 0, &myGW2); |
if (myErr != noErr) |
goto bail; |
// the video tracks used as sources for the effect should start at the same time as the effects track |
// and end at the same time as the effects track |
myErr = EffectsUtils_AddVideoTrackFromGWorld(&myMovie, myGW1, &mySrc1Track, 0, kEffectMovieDuration, kPenguinTrackWidth, kPenguinTrackHeight); |
if (myErr != noErr) |
goto bail; |
myErr = EffectsUtils_AddVideoTrackFromGWorld(&myMovie, myGW2, &mySrc2Track, 0, kEffectMovieDuration, kPenguinTrackWidth, kPenguinTrackHeight); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// add the effect description as a sample to the effects track media |
// |
////////// |
myErr = BeginMediaEdits(myMedia); |
if (myErr != noErr) |
goto bail; |
myErr = AddMediaSample(myMedia, (Handle)myEffectDesc, 0, GetHandleSize((Handle)myEffectDesc), kEffectMovieDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime); |
if (myErr != noErr) |
goto bail; |
myErr = EndMediaEdits(myMedia); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create the input map and add references for the first effects track |
// |
////////// |
myErr = QTNewAtomContainer(&myInputMap); |
if (myErr != noErr) |
goto bail; |
myErr = EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myTrack, mySrc1Track, kSourceOneName); |
if (myErr != noErr) |
goto bail; |
myErr = EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myTrack, mySrc2Track, kSourceTwoName); |
if (myErr != noErr) |
goto bail; |
// add the input map to the effects track |
myErr = SetMediaInputMap(myMedia, myInputMap); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// add the media to the track |
// |
////////// |
myErr = InsertMediaIntoTrack(myTrack, 0, mySampleTime, GetMediaDuration(myMedia), fixed1); |
if (myErr != noErr) |
goto bail; |
// put the movie resource into the file |
myErr = AddMovieResource(myMovie, myMovieRefNum, &myResID, NULL); |
bail: |
if (myGW1 != NULL) |
DisposeGWorld(myGW1); |
if (myGW2 != NULL) |
DisposeGWorld(myGW2); |
if (mySampleDesc != NULL) |
DisposeHandle((Handle)mySampleDesc); |
if (myMovieRefNum != kInvalidFileRefNum) |
CloseMovieFile(myMovieRefNum); |
if (myMovie != NULL) |
DisposeMovie(myMovie); |
if (myInputMap != NULL) |
QTDisposeAtomContainer(myInputMap); |
free(myPrompt); |
free(myFileName); |
return; |
} |
////////// |
// |
// QTEffects_AddEffectToMovieSegment |
// Add the specified effect to occur at the specified time and duration. |
// |
////////// |
OSErr QTEffects_AddEffectToMovieSegment (Movie theMovie, OSType theEffectType, long theNumSources, TimeValue theStartTime, TimeValue theDuration) |
{ |
Track myVidTrack1 = NULL; |
Track myVidTrack2 = NULL; |
Track mySrcTrack1 = NULL; |
Track mySrcTrack2 = NULL; |
Media mySrcMedia1 = NULL; |
Media mySrcMedia2 = NULL; |
Track myEffectTrack = NULL; |
Media myEffectMedia = NULL; |
Fixed myWidth, myHeight; |
TimeScale myTimeScale; |
TimeValue mySampleTime; |
Rect myRect; |
QTAtomContainer myInputMap = NULL; |
QTAtomContainer myEffectDesc = NULL; |
ImageDescriptionHandle mySampleDesc = NULL; |
OSType myEffectName1 = kSourceNoneName; |
OSType myEffectName2 = kSourceNoneName; |
short myLayer; |
OSErr myErr = noErr; |
// make sure we were passed a valid movie |
if (theMovie == NULL) |
return(paramErr); |
////////// |
// |
// get some information about the movie |
// |
////////// |
myTimeScale = GetMovieTimeScale(theMovie); |
GetMovieBox(theMovie, &myRect); |
myLayer = EffectsUtils_GetFrontmostTrackLayer(theMovie, VideoMediaType); |
myWidth = IntToFixed((myRect.right - myRect.left)); |
myHeight = IntToFixed((myRect.bottom - myRect.top)); |
////////// |
// |
// retrieve the original video track(s), create the effect's source track(s) and media, |
// then set the new source track(s) to reference the data in the original video track(s) |
// |
////////// |
switch (theNumSources) { |
case 2: |
myVidTrack2 = GetMovieIndTrackType(theMovie, 2, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly); |
if (myVidTrack2 == NULL) |
return(paramErr); |
mySrcTrack2 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume); |
if (mySrcTrack2 == NULL) |
return(paramErr); |
mySrcMedia2 = NewTrackMedia(mySrcTrack2, VideoMediaType, myTimeScale, NULL, 0); |
if (mySrcMedia2 == NULL) |
return(paramErr); |
#if COPY_MOVIE_MEDIA |
myErr = BeginMediaEdits(mySrcMedia2); |
if (myErr != noErr) |
return(myErr); |
#endif |
myErr = CopyTrackSettings(myVidTrack2, mySrcTrack2); |
myErr = InsertTrackSegment(myVidTrack2, mySrcTrack2, theStartTime, theDuration, theStartTime); |
if (myErr != noErr) |
return(myErr); |
#if COPY_MOVIE_MEDIA |
EndMediaEdits(mySrcMedia2); |
#endif |
myEffectName2 = kSourceTwoName; |
// note that we fall through here! |
case 1: |
myVidTrack1 = GetMovieIndTrackType(theMovie, 1, VideoMediaType, movieTrackMediaType | movieTrackEnabledOnly); |
if (myVidTrack1 == NULL) |
return(paramErr); |
mySrcTrack1 = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume); |
if (mySrcTrack1 == NULL) |
return(paramErr); |
mySrcMedia1 = NewTrackMedia(mySrcTrack1, VideoMediaType, myTimeScale, NULL, 0); |
if (mySrcMedia1 == NULL) |
return(paramErr); |
#if COPY_MOVIE_MEDIA |
myErr = BeginMediaEdits(mySrcMedia1); |
if (myErr != noErr) |
return(myErr); |
#endif |
myErr = CopyTrackSettings(myVidTrack1, mySrcTrack1); |
myErr = InsertTrackSegment(myVidTrack1, mySrcTrack1, theStartTime, theDuration, theStartTime); |
if (myErr != noErr) |
return(myErr); |
#if COPY_MOVIE_MEDIA |
EndMediaEdits(mySrcMedia1); |
#endif |
myEffectName1 = kSourceOneName; |
break; |
case 0: |
// for 0-source effects, we don't need to create a new source track |
break; |
default: |
return(paramErr); |
} |
////////// |
// |
// create the effects track and media |
// |
////////// |
myEffectTrack = NewMovieTrack(theMovie, myWidth, myHeight, kNoVolume); |
if (myEffectTrack == NULL) |
return(GetMoviesError()); |
myEffectMedia = NewTrackMedia(myEffectTrack, VideoMediaType, myTimeScale, NULL, 0); |
if (myEffectMedia == NULL) |
return(GetMoviesError()); |
// create an effect sample description |
mySampleDesc = EffectsUtils_MakeSampleDescription(theEffectType, FixedToInt(myWidth), FixedToInt(myHeight)); |
if (mySampleDesc == NULL) |
goto bail; |
// create an effect description |
myEffectDesc = EffectsUtils_CreateEffectDescription(theEffectType, myEffectName1, myEffectName2, kSourceNoneName); |
// add the effect description as a sample to the effects track media |
BeginMediaEdits(myEffectMedia); |
myErr = AddMediaSample(myEffectMedia, (Handle)myEffectDesc, 0, GetHandleSize((Handle)myEffectDesc), theDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime); |
if (myErr != noErr) |
goto bail; |
EndMediaEdits(myEffectMedia); |
// add the media sample to the effects track |
myErr = InsertMediaIntoTrack(myEffectTrack, theStartTime, mySampleTime, theDuration, fixed1); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create the input map and add references for the source track(s) |
// |
////////// |
myErr = QTNewAtomContainer(&myInputMap); |
if (myErr != noErr) |
goto bail; |
if (mySrcTrack1 != NULL) { |
myErr = EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack1, kSourceOneName); |
if (myErr != noErr) |
goto bail; |
} |
if (mySrcTrack2 != NULL) { |
myErr = EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, mySrcTrack2, kSourceTwoName); |
if (myErr != noErr) |
goto bail; |
} |
// add the input map to the effects track |
myErr = SetMediaInputMap(myEffectMedia, myInputMap); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// do any required positioning and graphics mode manipulation |
// |
////////// |
SetTrackLayer(myEffectTrack, myLayer - 1); // in front of any existing video track |
switch (theNumSources) { |
case 2: |
break; |
case 1: |
break; |
case 0: { |
RGBColor myColor; |
myColor.red = 0; // (good for fire, not so good for clouds) |
myColor.green = 0; |
myColor.blue = 0; |
MediaSetGraphicsMode(GetMediaHandler(myEffectMedia), transparent, &myColor); |
break; |
} |
} |
bail: |
if (mySampleDesc != NULL) |
DisposeHandle((Handle)mySampleDesc); |
if (myInputMap != NULL) |
QTDisposeAtomContainer(myInputMap); |
return(myErr); |
} |
////////// |
// |
// QTEffects_MakeSpriteEffectMovie |
// Create a movie with a sprite that uses an effect for its image. |
// |
////////// |
void QTEffects_MakeSpriteEffectMovie (void) |
{ |
Movie myMovie = NULL; |
Track myTrack = NULL; |
Media myMedia = NULL; |
FSSpec myFile; |
Boolean myIsSelected = false; |
Boolean myIsReplacing = false; |
StringPtr myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt); |
StringPtr myFileName = QTUtils_ConvertCToPascalString(kEffectsPenguinMovieFileName); |
long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; |
OSType myType = FOUR_CHAR_CODE('none'); |
short myMovieRefNum = kInvalidFileRefNum; |
short myResID = movieInDataForkResID; |
OSErr myErr = noErr; |
////////// |
// |
// create a new movie file |
// |
////////// |
// prompt the user for the destination file name |
QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing); |
if (!myIsSelected) |
goto bail; |
// create a movie file for the destination movie |
myErr = CreateMovieFile(&myFile, sigMoviePlayer, smSystemScript, myFlags, &myMovieRefNum, &myMovie); |
if (myErr != noErr) |
goto bail; |
// select the "no controller" movie controller |
myType = EndianU32_NtoB(myType); |
SetUserDataItem(GetMovieUserData(myMovie), &myType, sizeof(myType), kUserDataMovieControllerType, 1); |
////////// |
// |
// create the sprite track and media |
// |
////////// |
myTrack = NewMovieTrack(myMovie, IntToFixed(kPenguinTrackWidth), IntToFixed(kPenguinTrackHeight), kFullVolume); |
if (myTrack == NULL) |
goto bail; |
myMedia = NewTrackMedia(myTrack, SpriteMediaType, kSpriteMediaTimeScale, NULL, 0); |
if (myMedia == NULL) |
goto bail; |
////////// |
// |
// add the appropriate samples to the sprite media |
// |
////////// |
myErr = BeginMediaEdits(myMedia); |
if (myErr != noErr) |
goto bail; |
QTEffects_AddPenguinMovieSamplesToMedia(myMedia); |
myErr = EndMediaEdits(myMedia); |
if (myErr != noErr) |
goto bail; |
// add the media to the track |
InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1); |
////////// |
// |
// set the sprite track properties |
// |
////////// |
QTEffects_SetTrackProperties(myMedia); |
////////// |
// |
// add the movie resource to the movie file |
// |
////////// |
myErr = AddMovieResource(myMovie, myMovieRefNum, &myResID, myFile.name); |
bail: |
if (myMovieRefNum != kInvalidFileRefNum) |
CloseMovieFile(myMovieRefNum); |
if (myMovie != NULL) |
DisposeMovie(myMovie); |
free(myPrompt); |
free(myFileName); |
return; |
} |
////////// |
// |
// QTEffects_PromptUserForFilesAndMakeEffectMovie |
// Let the user select some movies, then apply the effect to them. |
// |
// If the user cancels the first file-open dialog box, there are zero sources. |
// If the user cancels the second file-open dialog box, there is one source. |
// |
////////// |
void QTEffects_PromptUserForFilesAndMakeEffectMovie (void) |
{ |
QTFrameFileFilterUPP myFileFilterUPP = NULL; |
FSSpec mySpecs[kMaxNumSources]; |
int mySpecCount; |
OSType myTypeList[] = {kQTFileTypeMovie}; |
short myNumTypes = 1; |
OSErr myErr = noErr; |
#if TARGET_OS_MAC |
myNumTypes = 0; |
#endif |
myFileFilterUPP = QTFrame_GetFileFilterUPP((ProcPtr)QTFrame_FilterFiles); |
// ask for up to kMaxNumSources movie files; |
// accept early cancels; they just mean there are fewer input movies |
mySpecCount = 0; |
while (mySpecCount < kMaxNumSources) { |
FSSpec myFSSpec; |
myTypeList[0] = MovieFileType; |
myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP); |
if (myErr != noErr) |
break; // the user doesn't want any more source movies |
// save the FSSpec from the reply information |
mySpecs[mySpecCount] = myFSSpec; |
mySpecCount++; |
} |
QTEffects_DisplayDialogForSources(mySpecs, mySpecCount); |
if (myFileFilterUPP != NULL) |
DisposeNavObjectFilterUPP(myFileFilterUPP); |
} |
//////////////////// |
// |
// QTEffects_AddRippleEffectAsSpriteImage |
// Add the ripple effect as the image override of the specified sprite image ID. |
// |
//////////////////// |
void QTEffects_AddRippleEffectAsSpriteImage (QTAtomContainer theKeySample, QTAtomID theImageID) |
{ |
ImageDescriptionHandle mySampleDesc = NULL; |
QTAtomContainer myEffectDesc = NULL; |
OSType myType = kWaterRippleCodecType; |
OSErr myErr = noErr; |
// create a sample description |
mySampleDesc = EffectsUtils_MakeSampleDescription(myType, kPenguinTrackWidth, kPenguinTrackHeight); |
if (mySampleDesc == NULL) |
goto bail; |
// create an effect description |
myEffectDesc = EffectsUtils_CreateEffectDescription(myType, kSourceNoneName, kSourceNoneName, kSourceNoneName); |
if (myEffectDesc == NULL) |
goto bail; |
SpriteUtils_AddCompressedImageToKeyFrameSample(theKeySample, mySampleDesc, GetHandleSize(myEffectDesc), *myEffectDesc, theImageID, NULL, NULL); |
bail: |
if (mySampleDesc != NULL) |
DisposeHandle((Handle)mySampleDesc); |
if (myEffectDesc != NULL) |
QTDisposeAtomContainer(myEffectDesc); |
return; |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Effects dialog utilities. |
// |
// Use these functions to work with the effects parameter dialog box. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// QTEffects_DisplayDialogForSources |
// Display the standard effects parameters dialog box for the movies passed in. |
// |
////////// |
OSErr QTEffects_DisplayDialogForSources (FSSpec *theSpecList, UInt16 theSpecCount) |
{ |
UInt16 myMovieIter; |
OSErr myErr = noErr; |
// make sure that there aren't too many sources |
if (theSpecCount > kMaxNumSources) { |
myErr = paramErr; |
goto bail; |
} |
// assign source count to a global, so QTEffects_RespondToDialogSelection has access to it |
gSpecCount = theSpecCount; |
// get the first video track from each movie file |
for (myMovieIter = 0; myMovieIter < theSpecCount; myMovieIter++) { |
short myRefNum; |
// open a movie file using the FSSpec and create a movie from that file |
myErr = OpenMovieFile(&theSpecList[myMovieIter], &myRefNum, 0); |
if (myErr != noErr) |
goto bail; |
myErr = NewMovieFromFile(&gSrcMovies[myMovieIter], myRefNum, NULL, NULL, newMovieActive, NULL); |
if (myErr != noErr) |
goto bail; |
SetMoviePlayHints(gSrcMovies[myMovieIter], hintsHighQuality, hintsHighQuality); |
// we're done with the movie file, so close it |
CloseMovieFile(myRefNum); |
// find the first video track in the source movie |
gSrcTracks[myMovieIter] = GetMovieIndTrackType(gSrcMovies[myMovieIter], 1, kCharacteristicCanSendVideo, movieTrackCharacteristic | movieTrackEnabledOnly); |
if (gSrcTracks[myMovieIter] == NULL) |
goto bail; |
} |
// ask the user to select an effect |
myErr = QTNewAtomContainer(&gEffectDesc); |
if (myErr != noErr) |
goto bail; |
myErr = QTGetEffectsList(&gEffectList, theSpecCount, theSpecCount, 0); |
if (myErr != noErr) |
goto bail; |
// create the effects parameter dialog box, so the user can select an effect |
myErr = QTCreateStandardParameterDialog(gEffectList, gEffectDesc, 0, &gEffectsDialog); |
if (myErr != noErr) |
goto bail; |
// insert poster frames into dialog |
if (gSrcTracks[0] != NULL) { |
gPosterA = GetTrackPict(gSrcTracks[0], GetMoviePosterTime(gSrcMovies[0])); |
if (gPosterA != NULL) { |
QTParamPreviewRecord myPreviewRecord; |
myPreviewRecord.sourcePicture = gPosterA; |
myPreviewRecord.sourceID = 1; |
myErr = QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &myPreviewRecord); |
} |
} |
if (gSrcTracks[1] != NULL) { |
gPosterB = GetTrackPict(gSrcTracks[1], GetMoviePosterTime(gSrcMovies[1])); |
if (gPosterB != NULL) { |
QTParamPreviewRecord myPreviewRecord; |
myPreviewRecord.sourcePicture = gPosterB; |
myPreviewRecord.sourceID = 2; |
myErr = QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &myPreviewRecord); |
} |
} |
// now, the frontmost window is the standard effects parameter dialog box; |
// on the Mac, we call QTEffects_HandleEffectsDialogEvents in our main event loop |
// to find and process events targeted at the effects parameter dialog box; on Windows, |
// we need to use a different strategy: we install a modeless dialog callback procedure |
// that is called internally by QTML |
#if TARGET_OS_WIN32 |
gDoneWithDialog = false; |
// force the dialog box to be drawn |
{ |
EventRecord myEvent = {0}; |
QTEffects_EffectsDialogCallback(&myEvent, FrontWindow(), 0); |
} |
SetModelessDialogCallbackProc(FrontWindow(), (QTModelessCallbackUPP)QTEffects_EffectsDialogCallback); |
QTMLSetWindowWndProc(FrontWindow(), QTEffects_CustomDialogWndProc); |
#endif |
bail: |
return(myErr); |
} |
////////// |
// |
// QTEffects_RespondToDialogSelection |
// If theErr is codecParameterDialogConfirm, make an effects movie. |
// If theErr is userCanceledErr, do any necessary clean up. |
// |
////////// |
static void QTEffects_RespondToDialogSelection (OSErr theErr) |
{ |
short myMovieRefNum = 0; |
short myResID = movieInDataForkResID; |
OSType myEffectCode; |
OSType mySourceName; |
Fixed myTrackWidth, myTrackHeight; |
TimeScale myMovieTimeScale = 600; |
TimeValue myEffectDuration = 0; |
TimeValue mySampleTime = 0; |
FSSpec myFile; |
Boolean myIsSelected = false; |
Boolean myIsReplacing = false; |
StringPtr myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt); |
StringPtr myFileName = QTUtils_ConvertCToPascalString(kEffectsSaveMovieFileName); |
Movie myDestMovie = NULL; |
Track myVideoTracks[kMaxNumSources]; |
Track myEffectTrack = NULL; |
Media myEffectMedia = NULL; |
UInt16 myMovieIter; |
ImageDescriptionHandle mySampleDesc = NULL; |
QTAtomContainer myInputMap = NULL; |
long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; |
OSErr myErr = noErr; |
////////// |
// |
// standard parameter box has been dismissed; first do any necessary clean-up |
// |
////////// |
gEffectsDialog = 0L; |
// we're finished with the effect list and movie posters |
if (gEffectList != NULL) |
QTDisposeAtomContainer(gEffectList); |
if (gPosterA != NULL) |
KillPicture(gPosterA); |
if (gPosterB != NULL) |
KillPicture(gPosterB); |
// if the user cancelled, bail |
if (theErr == userCanceledErr) |
goto bail; |
////////// |
// |
// add to gEffectDesc some atoms naming the sources |
// |
////////// |
if (gSpecCount >= 1) { |
mySourceName = EndianU32_NtoB(kSourceOneName); |
QTInsertChild(gEffectDesc, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(mySourceName), &mySourceName, NULL); |
} |
if (gSpecCount >= 2) { |
mySourceName = EndianU32_NtoB(kSourceTwoName); |
QTInsertChild(gEffectDesc, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(mySourceName), &mySourceName, NULL); |
} |
if (gSpecCount >= 3) { |
mySourceName = EndianU32_NtoB(kSourceThreeName); |
QTInsertChild(gEffectDesc, kParentAtomIsContainer, kEffectSourceName, 3, 0, sizeof(mySourceName), &mySourceName, NULL); |
} |
////////// |
// |
// find out what kind of effect it is |
// |
////////// |
myErr = EffectsUtils_GetTypeFromEffectDescription(gEffectDesc, &myEffectCode); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create the effects movie |
// |
////////// |
// ask the user for the name of the new movie file |
QTFrame_PutFile(myPrompt, myFileName, &myFile, &myIsSelected, &myIsReplacing); |
if (!myIsSelected) |
goto bail; // deal with user cancelling |
// create a movie file for the destination movie |
myErr = CreateMovieFile(&myFile, sigMoviePlayer, smSystemScript, myFlags, &myMovieRefNum, &myDestMovie); |
if (myErr != noErr) |
goto bail; |
// copy the user data and settings from the source to the destination movie; |
// these settings include information like user data |
if (gSpecCount > 0) |
CopyMovieSettings(gSrcMovies[0], myDestMovie); |
// convert all the movies to have a common time scale; |
// we pick the largest time scale out of all the source movies, with a minimum of 600 |
myMovieTimeScale = 600; |
for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) { |
if (myMovieTimeScale < GetMovieTimeScale(gSrcMovies[myMovieIter])) |
myMovieTimeScale = GetMovieTimeScale(gSrcMovies[myMovieIter]); |
} |
for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) { |
if (myMovieTimeScale != GetMovieTimeScale(gSrcMovies[myMovieIter])) |
SetMovieTimeScale(gSrcMovies[myMovieIter], myMovieTimeScale); |
} |
// the effect duration is the minimum of the length of the tracks |
if (gSpecCount == 0) |
myEffectDuration = myMovieTimeScale * 10; |
else |
myEffectDuration = GetTrackDuration(gSrcTracks[0]); |
for (myMovieIter = 1; myMovieIter < gSpecCount; myMovieIter++) { |
if (myEffectDuration > GetTrackDuration(gSrcTracks[myMovieIter])) |
myEffectDuration = GetTrackDuration(gSrcTracks[myMovieIter]); |
} |
// default size when there are no video tracks |
myTrackWidth = IntToFixed(kDefaultTrackWidth); |
myTrackHeight = IntToFixed(kDefaultTrackHeight); |
for (myMovieIter = 0; myMovieIter < kMaxNumSources; myMovieIter++) { |
myVideoTracks[myMovieIter] = NULL; |
} |
// make the video tracks |
for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) { |
Fixed mySrcTrackWidth, mySrcTrackHeight; |
OSType mySrcMediaType = 0; |
Media myVideoMedia; |
// myVideoTracks[n] is a clone of gSrcTracks[n] |
GetTrackDimensions(gSrcTracks[myMovieIter], &mySrcTrackWidth, &mySrcTrackHeight); |
if ((myMovieIter == 0) || (myTrackWidth < mySrcTrackWidth)) |
myTrackWidth = mySrcTrackWidth; |
if ((myMovieIter == 0) || (myTrackHeight < mySrcTrackHeight)) |
myTrackHeight = mySrcTrackHeight; |
GetMediaHandlerDescription(GetTrackMedia(gSrcTracks[myMovieIter]), &mySrcMediaType, NULL, NULL); |
myVideoTracks[myMovieIter] = NewMovieTrack(myDestMovie, mySrcTrackWidth, mySrcTrackHeight, kNoVolume); |
if (myVideoTracks[myMovieIter] == NULL) |
goto bail; |
myVideoMedia = NewTrackMedia(myVideoTracks[myMovieIter], mySrcMediaType, myMovieTimeScale, NULL, 0); |
if (myVideoMedia == NULL) |
goto bail; |
if (gCopyMovieMedia) { |
myErr = BeginMediaEdits(myVideoMedia); |
if (myErr != noErr) |
goto bail; |
} |
myErr = CopyTrackSettings(gSrcTracks[myMovieIter], myVideoTracks[myMovieIter]); |
if (myErr != noErr) |
goto bail; |
myErr = InsertTrackSegment(gSrcTracks[myMovieIter], myVideoTracks[myMovieIter], 0, myEffectDuration, 0); |
if (myErr != noErr) |
goto bail; |
if (gCopyMovieMedia) { |
myErr = EndMediaEdits(myVideoMedia); |
if (myErr != noErr) |
goto bail; |
} |
} |
////////// |
// |
// create the effects track |
// |
////////// |
// myEffectTrack is the special track that implements the effect |
myEffectTrack = NewMovieTrack(myDestMovie, myTrackWidth, myTrackHeight, kNoVolume); |
if (myEffectTrack == NULL) |
goto bail; |
myEffectMedia = NewTrackMedia(myEffectTrack, VideoMediaType, myMovieTimeScale, NULL, 0); |
if (myEffectMedia == NULL) |
goto bail; |
// create the sample description |
mySampleDesc = EffectsUtils_MakeSampleDescription(myEffectCode, FixedToInt(myTrackWidth), FixedToInt(myTrackHeight)); |
if (mySampleDesc == NULL) |
goto bail; |
////////// |
// |
// add the effects sample to the movie |
// |
////////// |
myErr = BeginMediaEdits(myEffectMedia); |
if (myErr != noErr) |
goto bail; |
myErr = AddMediaSample(myEffectMedia, gEffectDesc, 0, GetHandleSize(gEffectDesc), myEffectDuration, (SampleDescriptionHandle)mySampleDesc, 1, 0, &mySampleTime); |
if (myErr != noErr) |
goto bail; |
myErr = EndMediaEdits(myEffectMedia); |
if (myErr != noErr) |
goto bail; |
QTDisposeAtomContainer(gEffectDesc); |
DisposeHandle((Handle)mySampleDesc); |
myErr = InsertMediaIntoTrack(myEffectTrack, 0, mySampleTime, myEffectDuration, fixed1); |
if (myErr != noErr) |
goto bail; |
////////// |
// |
// create and add the input map |
// |
////////// |
myErr = QTNewAtomContainer(&myInputMap); |
if (myErr != noErr) |
goto bail; |
// first input |
if (myVideoTracks[0] != NULL) |
EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, myVideoTracks[0], kSourceOneName); |
if (myVideoTracks[1] != NULL) |
EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, myVideoTracks[1], kSourceTwoName); |
if (myVideoTracks[2] != NULL) |
EffectsUtils_AddTrackReferenceToInputMap(myInputMap, myEffectTrack, myVideoTracks[2], kSourceThreeName); |
// set the input map |
if (gSpecCount > 0) |
SetMediaInputMap(GetTrackMedia(myEffectTrack), myInputMap); |
////////// |
// |
// finish up |
// |
////////// |
myErr = AddMovieResource(myDestMovie, myMovieRefNum, &myResID, NULL); |
if (myErr != noErr) |
goto bail; |
CloseMovieFile(myMovieRefNum); |
for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) |
DisposeMovie(gSrcMovies[myMovieIter]); |
DisposeMovie(myDestMovie); |
bail: |
free(myPrompt); |
free(myFileName); |
if (myInputMap != NULL) |
QTDisposeAtomContainer(myInputMap); |
return; |
} |
#if TARGET_OS_WIN32 |
////////// |
// |
// QTEffects_EffectsDialogCallback |
// This function is called by QTML when it processes events for the standard or custom effects parameter dialog box. |
// |
////////// |
static void QTEffects_EffectsDialogCallback (EventRecord *theEvent, DialogRef theDialog, DialogItemIndex theItemHit) |
{ |
QTParamDialogEventRecord myRecord; |
myRecord.theEvent = theEvent; |
myRecord.whichDialog = theDialog; |
myRecord.itemHit = theItemHit; |
if (gEffectsDialog != 0L) { |
QTStandardParameterDialogDoAction(gEffectsDialog, pdActionModelessCallback, &myRecord); |
// see if the event is meant for the effects parameter dialog box |
QTEffects_HandleEffectsDialogEvents(theEvent, theItemHit); |
} |
} |
////////// |
// |
// QTEffects_CustomDialogWndProc |
// Handle messages for the custom effects parameters dialog box. |
// |
////////// |
LRESULT CALLBACK QTEffects_CustomDialogWndProc (HWND theWnd, UINT theMessage, UINT wParam, LONG lParam) |
{ |
EventRecord myEvent = {0}; |
if (!gDoneWithDialog && (theMessage == 0x7FFF)) |
QTEffects_EffectsDialogCallback(&myEvent, GetNativeWindowPort(theWnd), 0); |
return(DefWindowProc(theWnd, theMessage, wParam, lParam)); |
} |
#endif |
////////// |
// |
// QTEffects_HandleEffectsDialogEvents |
// Process events that might be targeted at the standard effects parameter dialog box. |
// Return true if the event was completely handled. |
// |
////////// |
Boolean QTEffects_HandleEffectsDialogEvents (EventRecord *theEvent, DialogItemIndex theItemHit) |
{ |
#pragma unused(theItemHit) |
Boolean isHandled = false; |
OSErr myErr = noErr; |
// pass the event to the standard effects parameter dialog box handler |
myErr = QTIsStandardParameterDialogEvent(theEvent, gEffectsDialog); |
// the result from QTIsStandardParameterDialogEvent tells us how to respond next |
switch (myErr) { |
case codecParameterDialogConfirm: |
case userCanceledErr: |
// the user clicked the OK or Cancel button; dismiss the dialog box and respond accordingly |
gDoneWithDialog = true; |
if (myErr == codecParameterDialogConfirm) |
QTStandardParameterDialogDoAction(gEffectsDialog, pdActionConfirmDialog, NULL); |
QTDismissStandardParameterDialog(gEffectsDialog); |
gEffectsDialog = 0L; |
QTEffects_RespondToDialogSelection(myErr); |
isHandled = true; |
break; |
case noErr: |
// the event was completely handled by QTIsStandardParameterDialogEvent |
isHandled = true; |
break; |
case featureUnsupported: |
// the event was not handled by QTIsStandardParameterDialogEvent; |
// let the event be processed normally |
isHandled = false; |
break; |
default: |
// the event was not handled by QTIsStandardParameterDialogEvent; |
// do not let the event be processed normally |
isHandled = true; |
break; |
} |
return(isHandled); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Effects-rendering utilities. |
// |
// Use these functions to render an effect into a GWorld. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// QTEffects_InitWindowData |
// Do any effects-specific initialization for the specified window. |
// |
////////// |
Handle QTEffects_InitWindowData (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
// if we already have some window data, dump it |
myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject); |
if (myAppData != NULL) |
QTEffects_DumpWindowData(theWindowObject); |
// allocate and initialize our application data |
myAppData = (ApplicationDataHdl)NewHandleClear(sizeof(ApplicationDataRecord)); |
return((Handle)myAppData); |
} |
////////// |
// |
// QTEffects_DumpWindowData |
// Do any effects-specific tear-down for the specified window. |
// |
////////// |
void QTEffects_DumpWindowData (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject); |
if (myAppData != NULL) { |
if ((**myAppData).fGWDesc != NULL) |
DisposeHandle((Handle)(**myAppData).fGWDesc); |
if ((**myAppData).fGW != NULL) |
DisposeGWorld((**myAppData).fGW); |
if ((**myAppData).fSampleDescription != NULL) |
DisposeHandle((Handle)(**myAppData).fSampleDescription); |
if ((**myAppData).fEffectDescription != NULL) |
QTDisposeAtomContainer((**myAppData).fEffectDescription); |
if ((**myAppData).fEffectSequenceID != 0L) |
CDSequenceEnd((**myAppData).fEffectSequenceID); |
if ((**myAppData).fTimeBase != NULL) |
DisposeTimeBase((**myAppData).fTimeBase); |
DisposeHandle((Handle)myAppData); |
(**theWindowObject).fAppData = NULL; |
} |
} |
////////// |
// |
// QTEffects_SetUpEffectSequence |
// Set up an effects sequence for a one-source effect. |
// |
////////// |
static OSErr QTEffects_SetUpEffectSequence (WindowObject theWindowObject) |
{ |
ApplicationDataHdl myAppData = NULL; |
ImageSequenceDataSource mySrc = 0; |
PixMapHandle mySrcPixMap = NULL; |
GraphicsImportComponent myImporter = NULL; |
Rect myRect; |
OSErr myErr = paramErr; |
myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject); |
if (myAppData == NULL) |
goto bail; |
// if an effect sequence is already set up, end it |
if ((**myAppData).fEffectSequenceID != 0L) { |
CDSequenceEnd((**myAppData).fEffectSequenceID); |
(**myAppData).fEffectSequenceID = 0L; |
} |
// if there is a timebase already set up, dispose of it |
if ((**myAppData).fTimeBase != NULL) { |
DisposeTimeBase((**myAppData).fTimeBase); |
(**myAppData).fTimeBase = NULL; |
} |
// make an effects sequence |
HLock((Handle)(**myAppData).fEffectDescription); |
// prepare the decompression sequence for playback |
myErr = DecompressSequenceBeginS( |
&(**myAppData).fEffectSequenceID, |
(**myAppData).fSampleDescription, |
#if TARGET_CPU_68K |
StripAddress(*(**myAppData).fEffectDescription), |
#else |
*(**myAppData).fEffectDescription, |
#endif |
GetHandleSize((**myAppData).fEffectDescription), |
(CGrafPtr)QTFrame_GetPortFromWindowReference((**theWindowObject).fWindow), |
NULL, |
NULL, |
NULL, |
ditherCopy, |
NULL, |
0, |
codecNormalQuality, |
NULL); |
HUnlock((Handle)(**myAppData).fEffectDescription); |
if (myErr != noErr) |
goto bail; |
// create the offscreen GWorld holding the original image data |
myImporter = (**theWindowObject).fGraphicsImporter; |
if (myImporter == NULL) |
goto bail; |
// set the size of the GWorld |
GraphicsImportGetBoundsRect(myImporter, &myRect); |
HLock((Handle)myAppData); |
// allocate a new GWorld |
myErr = QTNewGWorld(&(**myAppData).fGW, 32, &myRect, NULL, NULL, kICMTempThenAppMemory); |
if (myErr != noErr) |
goto bail; |
// lock the pixmap |
LockPixels(GetGWorldPixMap((**myAppData).fGW)); |
GraphicsImportSetGWorld(myImporter, (**myAppData).fGW, NULL); |
GraphicsImportDraw(myImporter); |
// get the pixel maps for the GWorlds |
mySrcPixMap = GetGWorldPixMap((**myAppData).fGW); |
if (mySrcPixMap == NULL) |
goto bail; |
// make the effect source |
if ((**myAppData).fGW == NULL) |
goto bail; |
myErr = MakeImageDescriptionForPixMap(mySrcPixMap, &(**myAppData).fGWDesc); |
if (myErr != noErr) |
goto bail; |
myErr = CDSequenceNewDataSource((**myAppData).fEffectSequenceID, &mySrc, kSourceOneName, 1, (Handle)(**myAppData).fGWDesc, NULL, 0); |
if (myErr != noErr) |
goto bail; |
CDSequenceSetSourceData(mySrc, GetPixBaseAddr(mySrcPixMap), (**(**myAppData).fGWDesc).dataSize); |
// create a new time base and associate it with the decompression sequence |
(**myAppData).fTimeBase = NewTimeBase(); |
myErr = GetMoviesError(); |
if (myErr != noErr) |
goto bail; |
SetTimeBaseRate((**myAppData).fTimeBase, 0); |
myErr = CDSequenceSetTimeBase((**myAppData).fEffectSequenceID, (**myAppData).fTimeBase); |
bail: |
HUnlock((Handle)myAppData); |
return(myErr); |
} |
////////// |
// |
// QTEffects_RunEffect |
// Run the effect: decompress a single step of the effect sequence. |
// |
////////// |
OSErr QTEffects_RunEffect (WindowObject theWindowObject, TimeValue theTime) |
{ |
ApplicationDataHdl myAppData = NULL; |
ICMFrameTimeRecord myFrameTime; |
OSErr myErr = paramErr; |
myAppData = (ApplicationDataHdl)QTFrame_GetAppDataFromWindowObject(theWindowObject); |
if (myAppData == NULL) |
goto bail; |
// assertions |
if (((**myAppData).fEffectDescription == NULL) || ((**myAppData).fEffectSequenceID == 0L)) |
goto bail; |
// set the timebase time to the step of the sequence to be rendered |
SetTimeBaseValue((**myAppData).fTimeBase, theTime, gNumberOfSteps); |
myFrameTime.value.hi = 0; |
myFrameTime.value.lo = theTime; |
myFrameTime.scale = gNumberOfSteps; |
myFrameTime.base = 0; |
myFrameTime.duration = gNumberOfSteps; |
myFrameTime.rate = 0; |
myFrameTime.recordSize = sizeof(myFrameTime); |
myFrameTime.frameNumber = 1; |
myFrameTime.flags = icmFrameTimeHasVirtualStartTimeAndDuration; |
myFrameTime.virtualStartTime.lo = 0; |
myFrameTime.virtualStartTime.hi = 0; |
myFrameTime.virtualDuration = gNumberOfSteps; |
HLock((Handle)(**myAppData).fEffectDescription); |
myErr = DecompressSequenceFrameWhen( |
(**myAppData).fEffectSequenceID, |
#if TARGET_CPU_68K |
StripAddress(*((Handle)(**myAppData).fEffectDescription)), |
#else |
*((Handle)(**myAppData).fEffectDescription), |
#endif |
GetHandleSize((Handle)(**myAppData).fEffectDescription), |
0, |
NULL, |
NULL, |
&myFrameTime); |
HUnlock((Handle)(**myAppData).fEffectDescription); |
bail: |
return(myErr); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
// |
// Sprite utilities. |
// |
// Use these functions to create sprite tracks. |
// |
/////////////////////////////////////////////////////////////////////////////////////////////////////////// |
////////// |
// |
// QTEffects_AddPenguinMovieSamplesToMedia |
// Build the key frame for the penguin sprite movie. |
// |
////////// |
static void QTEffects_AddPenguinMovieSamplesToMedia (Media theMedia) |
{ |
QTAtomContainer mySample = NULL; |
QTAtomContainer mySpriteData = NULL; |
RGBColor myKeyColor; |
Point myLocation; |
short isVisible, myIndex, myLayer; |
OSErr myErr = noErr; |
// create a new, empty key frame sample |
myErr = QTNewAtomContainer(&mySample); |
if (myErr != noErr) |
goto bail; |
myKeyColor.red = myKeyColor.green = myKeyColor.blue = 0xffff; // white |
// add images to the key frame sample |
SpriteUtils_AddPICTImageToKeyFrameSample(mySample, kPenguinPictID, &myKeyColor, 1, NULL, NULL); |
QTEffects_AddRippleEffectAsSpriteImage(mySample, 2); |
myErr = QTNewAtomContainer(&mySpriteData); |
if (myErr != noErr) |
goto bail; |
// the penguin sprite |
myLocation.h = 0; |
myLocation.v = 0; |
isVisible = true; |
myIndex = 1; |
myLayer = 0; |
SpriteUtils_SetSpriteData(mySpriteData, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, NULL); |
SpriteUtils_AddSpriteToSample(mySample, mySpriteData, 1); |
QTDisposeAtomContainer(mySpriteData); |
myErr = QTNewAtomContainer(&mySpriteData); |
if (myErr != noErr) |
goto bail; |
// the ripple sprite |
myLocation.h = 0; |
myLocation.v = 0; |
isVisible = true; |
myIndex = 2; |
myLayer = -1; |
SpriteUtils_SetSpriteData(mySpriteData, &myLocation, &isVisible, &myLayer, &myIndex, NULL, NULL, NULL); |
WiredUtils_AddQTEventAndActionAtoms(mySpriteData, kParentAtomIsContainer, kQTEventMouseClick, kActionSpritePassMouseToCodec, NULL); |
SpriteUtils_AddSpriteToSample(mySample, mySpriteData, 2); |
SpriteUtils_AddSpriteSampleToMedia(theMedia, mySample, kSpriteMediaFrameDurationPenguin, true, NULL); |
bail: |
if (mySample != NULL) |
QTDisposeAtomContainer(mySample); |
if (mySpriteData != NULL) |
QTDisposeAtomContainer(mySpriteData); |
} |
////////// |
// |
// QTEffects_SetTrackProperties |
// Set the track properties for the specified sample sprite movie. |
// |
////////// |
void QTEffects_SetTrackProperties (Media theMedia) |
{ |
QTAtomContainer myTrackProperties; |
RGBColor myBackgroundColor; |
Boolean hasActions; |
OSErr myErr = noErr; |
// add a background color to the sprite track |
myBackgroundColor.red = EndianU16_NtoB(0xffff); |
myBackgroundColor.green = EndianU16_NtoB(0xffff); |
myBackgroundColor.blue = EndianU16_NtoB(0xffff); |
myErr = QTNewAtomContainer(&myTrackProperties); |
if (myErr == noErr) { |
QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyBackgroundColor, 1, 1, sizeof(myBackgroundColor), &myBackgroundColor, NULL); |
// tell the movie controller that this sprite track has actions |
hasActions = true; |
QTInsertChild(myTrackProperties, 0, kSpriteTrackPropertyHasActions, 1, 1, sizeof(hasActions), &hasActions, NULL); |
SetMediaPropertyAtom(theMedia, myTrackProperties); |
QTDisposeAtomContainer(myTrackProperties); |
} |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14