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.
MakeEffectSlideShow.c
////////// |
// |
// File: MakeEffectSlideShow.c |
// |
// Contains: QuickTime video effect support for QuickTime movies and still images. |
// |
// Written by: Tim Monroe |
// Based (heavily!) on the MakeEffectSlideShow code written by Sam Bushell. |
// |
// Copyright: © 1997-1999 by Apple Computer, Inc., all rights reserved. |
// |
// Change History (most recent first): |
// |
// <8> 03/20/00 rtm made changes to get things running under CarbonLib |
// <7> 03/03/99 rtm added support for MakeImageDescriptionForEffect (QT 4.0 and later) |
// <6> 03/12/98 rtm added global flag gDoneWithDialog to fix Windows dialog box problems |
// <5> 02/28/98 rtm revised event/message handling following QTShowEffect.c |
// <4> 08/01/98 rtm sync'ed with latest code from Sam: reworked QTEffects_GetFirstVideoTrackInMovie |
// to use GetMovieIndTrackType |
// <3> 11/24/97 rtm reworked event-loop processing: changed QTEffects_DoMakeEffectSlideShowMovieForFiles into |
// QTEffects_DisplayDialogForSources and QTEffects_RespondToDialogSelection |
// <2> 11/21/97 rtm further work |
// <1> 11/06/97 rtm first file; integrated existing code with shell framework; |
// added endian macros where appropriate |
// |
// This application takes the video tracks from two or more movies, asks |
// the user to select a 2-source effect, and makes a slide show movie |
// which uses the effect to switch from one video track to the next. |
// |
// Short video tracks are scaled up to a minimum length, and we can import |
// all sorts of graphical image formats as movies, so you can use this to |
// generate a slide show movie from still images -- or even a collection |
// of stills and movies. |
// |
// Try it out: drag a bunch of JPEG files of the same size onto the application icon. |
// Alternatively, launch the application and then choose them from the Test... menu. |
// |
////////// |
// header files |
#include "MakeEffectSlideShow.h" |
// global variables |
QTParameterDialog gEffectsDialog = 0L; |
QTAtomContainer gEffectSample = 0; // effects sample |
QTAtomContainer gEffectList = 0; |
PicHandle gPosterA = NULL; |
PicHandle gPosterB = NULL; |
Movie gSrcMovies[kMaxNumSources]; |
Track gSrcTracks[kMaxNumSources]; |
UInt16 gSpecCount = 0; |
FSSpec gSpecList[kMaxNumSources]; |
Boolean gDoneWithDialog = false; // are we done using the effects parameters dialog box? |
////////// |
// |
// QTEffects_GetFirstVideoTrackInMovie |
// Return, through the theTrack parameter, the first video track in the specified movie. |
// |
// Actually, we look for the first track that has the kCharacteristicCanSendVideo characteristic, |
// so we can apply effects to MPEG or QD3D tracks as well. |
// |
// If no such track is found, return invalidTrack as the function result. |
// |
////////// |
OSErr QTEffects_GetFirstVideoTrackInMovie (Movie theMovie, Track *theTrack) |
{ |
*theTrack = GetMovieIndTrackType(theMovie, 1, kCharacteristicCanSendVideo, movieTrackCharacteristic | movieTrackEnabledOnly); |
if (*theTrack == NULL) |
return(invalidTrack); |
return(noErr); |
} |
////////// |
// |
// QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile |
// Get the poster picture for the first video track in the specified movie file. |
// |
////////// |
PicHandle QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile (FSSpec *theSpec) |
{ |
PicHandle myPict = NULL; |
Movie myMovie = NULL; |
Track myTrack = NULL; |
short myRefNum = 0; |
OSErr myErr = noErr; |
myErr = OpenMovieFile(theSpec, &myRefNum, fsRdPerm); |
BailError(myErr); |
myErr = NewMovieFromFile(&myMovie, myRefNum, NULL, NULL, 0, NULL); |
BailError(myErr); |
SetMoviePlayHints(myMovie, hintsHighQuality, hintsHighQuality); |
myErr = CloseMovieFile(myRefNum); |
BailError(myErr); |
myErr = QTEffects_GetFirstVideoTrackInMovie(myMovie, &myTrack); |
BailNil(myTrack); |
myPict = GetTrackPict(myTrack, GetMoviePosterTime(myMovie)); |
bail: |
if (myMovie != NULL) |
DisposeMovie(myMovie); |
return(myPict); |
} |
////////// |
// |
// QTEffects_CopyPortionOfTrackToTrack |
// Extract a portion of the source track and copy it to the destination track. |
// |
// The parameter theSourcePortions is formed by OR-ing any of the portion constants. |
// For example, to copy the start and middle portions, set theSourcePortions to (eStartPortion | eMiddlePortion). |
// |
// We assume that the track time scale is kTimeScale; we also assume that the track has been scaled |
// so that it is at least kMinimumDuration long. |
// |
////////// |
OSErr QTEffects_CopyPortionOfTrackToTrack (Track theSourceTrack, UInt16 theSourcePortions, Track theDestTrack, TimeValue theDestStartTime, TimeValue *theDestDuration) |
{ |
TimeValue mySourceTrackDuration; |
TimeValue mySourceSegmentStart, mySourceSegmentEnd, mySourceSegmentDuration; |
OSErr myErr = noErr; |
mySourceTrackDuration = GetTrackDuration(theSourceTrack); |
if (theSourcePortions & eStartPortion) |
mySourceSegmentStart = 0; |
else if (theSourcePortions & eMiddlePortion) |
mySourceSegmentStart = kEffectDuration; |
else |
mySourceSegmentStart = mySourceTrackDuration - kEffectDuration; |
if (theSourcePortions & eFinishPortion) |
mySourceSegmentEnd = mySourceTrackDuration; |
else if (theSourcePortions & eMiddlePortion) |
mySourceSegmentEnd = mySourceTrackDuration - kEffectDuration; |
else |
mySourceSegmentEnd = kEffectDuration; |
mySourceSegmentDuration = mySourceSegmentEnd - mySourceSegmentStart; |
myErr = InsertTrackSegment( theSourceTrack, |
theDestTrack, |
mySourceSegmentStart, |
mySourceSegmentDuration, |
theDestStartTime); |
*theDestDuration = mySourceSegmentDuration; |
return(myErr); |
} |
////////// |
// |
// QTEffects_DisplayDialogForSources |
// Display the standard effects parameters dialog box for the movies passed in. |
// |
////////// |
OSErr QTEffects_DisplayDialogForSources (FSSpec *theSpecList, UInt16 theSpecCount) |
{ |
OSErr myErr = noErr; |
// make sure that there are enough sources: you can't make an omelette without enough eggs |
if (theSpecCount < 2) { |
myErr = paramErr; |
goto bail; |
} |
// assign source count to a global, so QTEffects_RespondToDialogSelection has access to it |
gSpecCount = theSpecCount; |
// get a poster frame for the first two movies |
if (theSpecCount >= 1) |
gPosterA = QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile(&theSpecList[0]); |
if (theSpecCount >= 2) |
gPosterB = QTEffects_GetPosterPictFromFirstVideoTrackInMovieFile(&theSpecList[1]); |
// ask the user to select a two-source effect |
myErr = QTNewAtomContainer(&gEffectSample); |
BailError(myErr); |
myErr = QTGetEffectsList(&gEffectList, 2, 2, 0); // min == max == 2 |
BailError(myErr); |
myErr = QTCreateStandardParameterDialog(gEffectList, gEffectSample, 0, &gEffectsDialog); |
BailError(myErr); |
// insert poster frames into dialog |
if (gPosterA != NULL) { |
QTParamPreviewRecord pr; |
pr.sourcePicture = gPosterA; |
pr.sourceID = 1; |
QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &pr); |
} |
if (gPosterB != NULL) { |
QTParamPreviewRecord pr; |
pr.sourcePicture = gPosterB; |
pr.sourceID = 2; |
QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &pr); |
} |
// 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. |
// |
// Construct a movie that links a sequence of image or movie files together with real-time effects. |
// That is, show the first image or movie, transition (fade or whatever) to the second, show the second, |
// transition to the third, and so forth. |
// |
// We use NewMovieFromFile, which will use movie importers or graphics importers as appropriate, |
// so each file we open may end up as either. |
// |
// If a movie has only one sample in its first video track, we assume it's a still image, |
// and use several copies of that sample with different lengths. This is flawed, since the sample |
// could be a tweened 3DMF movie. |
// |
////////// |
void QTEffects_RespondToDialogSelection (OSErr theErr) |
{ |
Boolean myDialogWasCancelled = false; |
short myResID = movieInDataForkResID; |
UInt16 myMovieIter; |
short mySrcMovieRefNum = 0; |
Movie myPrevSrcMovie = NULL; |
Track myPrevSrcTrack = NULL; |
Movie myNextSrcMovie = NULL; |
Track myNextSrcTrack = NULL; |
short myDestMovieRefNum = 0; |
FSSpec myFile; |
Boolean myIsSelected = false; |
Boolean myIsReplacing = false; |
StringPtr myPrompt = QTUtils_ConvertCToPascalString(kEffectsSaveMoviePrompt); |
StringPtr myFileName = QTUtils_ConvertCToPascalString(kEffectsSaveMovieFileName); |
Movie myDestMovie = NULL; |
Fixed myDestMovieWidth, myDestMovieHeight; |
ImageDescriptionHandle myDesc = NULL; |
Track videoTrackFX, videoTrackA, videoTrackB; |
Media videoMediaFX, videoMediaA, videoMediaB; |
TimeValue myCurrentDuration = 0; |
TimeValue myReturnedDuration; |
Boolean isFirstTransition = true; |
TimeValue myMediaTransitionDuration; |
TimeValue myMediaFXStartTime, myMediaFXDuration; |
OSType myEffectCode; |
long myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; |
long myLong; |
OSErr myErr = noErr; |
// standard parameter box has been dismissed, so remember that fact |
gEffectsDialog = 0L; |
myDialogWasCancelled = (theErr == userCanceledErr); |
// we're finished with the effect list and movie posters |
QTDisposeAtomContainer(gEffectList); |
if (gPosterA != NULL) |
KillPicture(gPosterA); |
if (gPosterB != NULL) |
KillPicture(gPosterB); |
// when the sign says stop, then stop |
if (myDialogWasCancelled) |
goto bail; |
// add atoms naming the sources to gEffectSample |
myLong = EndianU32_NtoB(kSourceOneName); |
QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myLong), &myLong, NULL); |
myLong = EndianU32_NtoB(kSourceTwoName); |
QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myLong), &myLong, NULL); |
// extract the 'what' atom to find out what kind of effect it is |
{ |
QTAtom myEffectAtom; |
QTAtomID myEffectAtomID; |
long myEffectCodeSize; |
Ptr myEffectCodePtr; |
myEffectAtom = QTFindChildByIndex(gEffectSample, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, &myEffectAtomID); |
myErr = QTLockContainer(gEffectSample); |
BailError(myErr); |
myErr = QTGetAtomDataPtr(gEffectSample, myEffectAtom, &myEffectCodeSize, &myEffectCodePtr); |
BailError(myErr); |
if (myEffectCodeSize != sizeof(OSType)) { |
myErr = paramErr; |
goto bail; |
} |
myEffectCode = *(OSType *)myEffectCodePtr; // "tsk" |
myEffectCode = EndianU32_BtoN(myEffectCode); // because the data is read from an atom container |
myErr = QTUnlockContainer(gEffectSample); |
BailError(myErr); |
} |
// 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, FOUR_CHAR_CODE('TVOD'), 0, myFlags, &myDestMovieRefNum, &myDestMovie); |
BailError(myErr); |
// open the first file as a movie; call the first movie myPrevSrcMovie |
myErr = OpenMovieFile(&gSpecList[0], &mySrcMovieRefNum, fsRdPerm); |
BailError(myErr); |
myErr = NewMovieFromFile(&myPrevSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL); |
BailError(myErr); |
myErr = CloseMovieFile(mySrcMovieRefNum); |
BailError(myErr); |
// if the movie is shorter than kMinimumDuration, scale it to that length |
SetMovieTimeScale(myPrevSrcMovie, kTimeScale); |
myErr = QTEffects_GetFirstVideoTrackInMovie(myPrevSrcMovie, &myPrevSrcTrack); |
BailNil(myPrevSrcTrack); |
if (GetTrackDuration(myPrevSrcTrack) < kMinimumDuration) { |
myErr = ScaleTrackSegment(myPrevSrcTrack, 0, GetTrackDuration(myPrevSrcTrack), kMinimumDuration); |
BailError(myErr); |
} |
// find out how big the first movie is; we'll use it as the size of all our tracks |
GetTrackDimensions(myPrevSrcTrack, &myDestMovieWidth, &myDestMovieHeight); |
#if USES_MAKE_IMAGE_DESC_FOR_EFFECT |
// create a new sample description for the effect, |
// which is just an image description specifying the effect and its dimensions |
myErr = MakeImageDescriptionForEffect(myEffectCode, &myDesc); |
if (myErr != noErr) |
BailError(myErr); |
#else |
// create a new sample description for the effect, |
// which is just an image description specifying the effect and its dimensions |
myDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription)); |
BailNil(myDesc); |
(**myDesc).idSize = sizeof(ImageDescription); |
(**myDesc).cType = myEffectCode; |
(**myDesc).hRes = 72L << 16; |
(**myDesc).vRes = 72L << 16; |
(**myDesc).dataSize = 0L; |
(**myDesc).frameCount = 1; |
(**myDesc).depth = 0; |
(**myDesc).clutID = -1; |
#endif |
// fill in the fields of the sample description |
(**myDesc).vendor = kAppleManufacturer; |
(**myDesc).temporalQuality = codecNormalQuality; |
(**myDesc).spatialQuality = codecNormalQuality; |
(**myDesc).width = FixRound(myDestMovieWidth); |
(**myDesc).height = FixRound(myDestMovieHeight); |
// add three video tracks to the destination movie: |
// - videoTrackFX is where the effects and stills live; it's user-visible. |
// - videoTrackA is where the "source A"s for effects live; it's hidden by the input map |
// - videoTrackB is where the "source B"s for effects live; it's hidden by the input map |
videoTrackFX = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0); |
BailNil(videoTrackFX); |
videoMediaFX = NewTrackMedia(videoTrackFX, VideoMediaType, kTimeScale, NULL, 0); |
BailNil(videoMediaFX); |
myErr = BeginMediaEdits(videoMediaFX); |
BailError(myErr); |
videoTrackA = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0); |
BailNil(videoTrackA); |
videoMediaA = NewTrackMedia(videoTrackA, VideoMediaType, kTimeScale, NULL, 0); |
BailNil(videoMediaA); |
videoTrackB = NewMovieTrack(myDestMovie, myDestMovieWidth, myDestMovieHeight, 0); |
BailNil(videoTrackB); |
videoMediaB = NewTrackMedia(videoTrackB, VideoMediaType, kTimeScale, NULL, 0); |
BailNil(videoMediaB); |
// create the input map |
{ |
long myRefIndex1, myRefIndex2; |
QTAtomContainer myInputMap; |
QTAtom myInputAtom; |
OSType myInputType; |
QTNewAtomContainer(&myInputMap); |
// first input |
if (videoTrackA) { |
AddTrackReference(videoTrackFX, videoTrackA, kTrackModifierReference, &myRefIndex1); |
QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex1, 0, 0, NULL, &myInputAtom); |
myInputType = EndianU32_NtoB(kTrackModifierTypeImage); |
QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL); |
myLong = EndianU32_NtoB(kSourceOneName); |
QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL); |
} |
// second input |
if (videoTrackB) { |
AddTrackReference(videoTrackFX, videoTrackB, kTrackModifierReference, &myRefIndex2); |
QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex2, 0, 0, NULL, &myInputAtom); |
myInputType = EndianU32_NtoB(kTrackModifierTypeImage); |
QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL); |
myLong = EndianU32_NtoB(kSourceTwoName); |
QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL); |
} |
// set that map |
SetMediaInputMap(GetTrackMedia(videoTrackFX), myInputMap); |
QTDisposeAtomContainer(myInputMap); |
} |
myCurrentDuration = 0; |
#if MAKE_STILL_SECTIONS |
// copy the first sample of the first video track of the first movie to videoTrackFX, with duration kStillDuration. |
myErr = CopyPortionOfTrackToTrack(myPrevSrcTrack, eStartPortion + eMiddlePortion, videoTrackFX, myCurrentDuration, &myReturnedDuration); |
BailError(myErr); |
myCurrentDuration += myReturnedDuration; |
#endif |
// now process any remaining files |
myMovieIter = 1; |
while (myMovieIter < gSpecCount) { |
// open the next file as a movie; call it nextSourceMovie |
myErr = OpenMovieFile(&gSpecList[myMovieIter], &mySrcMovieRefNum, fsRdPerm); |
BailError(myErr); |
myErr = NewMovieFromFile(&myNextSrcMovie, mySrcMovieRefNum, NULL, NULL, 0, NULL); |
BailError(myErr); |
// we're done with the movie file, so close it |
myErr = CloseMovieFile(mySrcMovieRefNum); |
BailError(myErr); |
// if the movie is shorter than kMinimumDuration, scale it to that length |
SetMovieTimeScale(myNextSrcMovie, kTimeScale); |
myErr = QTEffects_GetFirstVideoTrackInMovie(myNextSrcMovie, &myNextSrcTrack); |
BailNil(myNextSrcTrack); |
if (GetTrackDuration(myNextSrcTrack) < kMinimumDuration) { |
myErr = ScaleTrackSegment(myNextSrcTrack, 0, GetTrackDuration(myNextSrcTrack), kMinimumDuration); |
BailError(myErr); |
} |
// create a transition effect from the previous source movie's first video sample to the next source movie's first video sample |
// (the effect should have duration kEffectDuration); |
// this involves adding one sample to each of the three video tracks: |
// sample from previous source movie -> videoTrackA |
myErr = QTEffects_CopyPortionOfTrackToTrack(myPrevSrcTrack, eFinishPortion, videoTrackA, myCurrentDuration, &myReturnedDuration); |
BailError(myErr); |
// sample from next source movie -> videoTrackB |
myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eStartPortion, videoTrackB, myCurrentDuration, &myReturnedDuration); |
BailError(myErr); |
// effect sample -> videoTrackFX |
if (isFirstTransition) { |
myMediaTransitionDuration = myReturnedDuration; |
myMediaFXStartTime = GetMediaDuration(videoMediaFX); |
myErr = AddMediaSample(videoMediaFX, gEffectSample, 0, GetHandleSize(gEffectSample), myMediaTransitionDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL); |
BailError(myErr); |
myMediaFXDuration = GetMediaDuration(videoMediaFX) - myMediaFXStartTime; |
isFirstTransition = false; |
} |
myErr = InsertMediaIntoTrack(videoTrackFX, myCurrentDuration, myMediaFXStartTime, myMediaFXDuration, FixRatio(myReturnedDuration, myMediaTransitionDuration)); |
BailError(myErr); |
myCurrentDuration += myReturnedDuration; |
#if MAKE_STILL_SECTIONS |
// copy the first video sample of myNextSrcMovie to videoTrackFX, with duration kStillDuration. |
myErr = QTEffects_CopyPortionOfTrackToTrack(myNextSrcTrack, eMiddlePortion + (myMovieIter + 1 == theSpecCount) ? eFinishPortion : 0, videoTrackFX, myCurrentDuration, &myReturnedDuration); |
BailError(myErr); |
myCurrentDuration += myReturnedDuration; |
#endif // MAKE_STILL_SECTIONS |
// dispose of previous source movie. |
DisposeMovie(myPrevSrcMovie); |
myPrevSrcMovie = myNextSrcMovie; |
myPrevSrcTrack = myNextSrcTrack; |
myNextSrcMovie = NULL; |
myNextSrcTrack = NULL; |
myMovieIter++; |
} // while |
myErr = EndMediaEdits(videoMediaFX); |
BailError(myErr); |
myErr = AddMovieResource(myDestMovie, myDestMovieRefNum, &myResID, "\pMovie 1"); |
BailError(myErr); |
CloseMovieFile(myDestMovieRefNum); |
if (myPrevSrcMovie != NULL) |
DisposeMovie(myPrevSrcMovie); |
DisposeMovie(myDestMovie); |
bail: |
free(myPrompt); |
free(myFileName); |
QTDisposeAtomContainer(gEffectSample); |
DisposeHandle((Handle)myDesc); |
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; |
// |
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) |
{ |
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; |
QTDismissStandardParameterDialog(gEffectsDialog); |
QTEffects_RespondToDialogSelection(myErr); |
gEffectsDialog = 0L; |
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); |
} |
////////// |
// |
// QTEffects_PromptUserForFilesAndMakeEffect |
// 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_PromptUserForFilesAndMakeEffect (void) |
{ |
QTFrameFileFilterUPP myFileFilterUPP = NULL; |
int mySpecCount = 0; |
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 |
gSpecList[mySpecCount] = myFSSpec; |
mySpecCount++; |
} |
QTEffects_DisplayDialogForSources(gSpecList, mySpecCount); |
if (myFileFilterUPP != NULL) |
DisposeNavObjectFilterUPP(myFileFilterUPP); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-02-25