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.
MovieStuff.c
/* |
File: MovieStuff.c |
Contains: movie handling routines |
This handles all the clever movie stuff. |
- Sets up movie windows |
- Tears down movie windows |
- handles updates and events |
- handles slaving, altering playback speed, looping etc |
Written by: Jason Hodges-Harris & Don Swatman |
Copyright: Copyright © 1995-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/17/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include <Memory.h> |
#include <TextUtils.h> |
#include <Movies.h> |
#include "MovieStuff.h" |
#include "WindStuff.h" |
//============================================== |
// CallBackInfoType |
// |
// This structure is used to store QuickTime |
// call backs and any data they require. |
// - It has a several parameters at the front, |
// then a variable size record at the end. It also |
// needs the parameters used in CallMeWhen |
// - It's size is: |
// "sizeof(CallBackInfoType) + callBackDataSize - sizeof(long)" |
// - Data should not contain the only reference |
// to other handles, as it can't dispose of them |
// - It forms a linked list. Any new items are |
// added to the front. |
// - It should be passed in the call backs |
// reference field. |
//============================================== |
struct CallBackInfoType |
{ |
struct CallBackInfoType **hNextCallBackInfo; // Next in the list |
QTCallBack actualCallBack; // the call back |
WindowPtr pParentWindow; // parent window of the movie |
long param1; // Used in "CallMeWhen" |
long param2; // Used in "CallMeWhen" |
long param3; // Used in "CallMeWhen" |
long callBackDataSize; // Size of the data attached on the end |
long callBackDataStart; // where the data starts |
}; |
typedef struct CallBackInfoType CallBackInfoType, |
*CallBackInfoPtr, **CallBackInfoHdl; |
//============================================== |
// DocMovieInfoType |
// |
// Used to hold information about a movie within |
// a window |
// - It should be attached to the windows RefCon |
//============================================== |
struct DocMovieInfoType |
{ |
FSSpec movieFileSpec; // movies File Spec |
MovieController movieControls; // standard movie controller |
Movie actualMovie; // the Movie itself! |
Boolean movieAutoClose; // True if the window closes after movie finishes |
TimeBase moviesTimeBase; |
TimeScale moviesTimeScale; |
CallBackInfoHdl hFirstCallBackData; // Handle to first item of the call back info list |
WindowPtr pSlaveWind; // WindowPtr of this movies slave |
}; |
typedef struct DocMovieInfoType DocMovieInfoType, |
*DocMovieInfoPtr, **DocMovieInfoHndl; |
//============================================== |
// Global Stuff, init and tear down |
//============================================== |
// Prototypes of functions used in UPPs |
pascal void StartMovieCB(QTCallBack myCallBack,long ref); |
pascal void AlterRate( QTCallBack myCallBack,long ref); |
pascal void AlterMasterOffset( QTCallBack myCallBack,long ref); |
// Global UPPs |
QTCallBackUPP gStartMovieCBUpp; |
QTCallBackUPP gAlterRateUpp; |
QTCallBackUPP gAlterMasterOffsetUpp; |
//---------------------------------------------- |
// InitMovieGlobals |
// |
// Init's any globals used in MovieStuff |
// i.e. the UPPs |
//---------------------------------------------- |
void InitMovieGlobals(void) |
{ |
gStartMovieCBUpp = nil; |
gAlterRateUpp = nil; |
gAlterMasterOffsetUpp = nil; |
// Create routine descriptor for "StartMovieCB" QT callback routine |
gStartMovieCBUpp = NewQTCallBackProc(StartMovieCB); |
// Create routine descriptor for "AlterRate" QT callback routine |
gAlterRateUpp = NewQTCallBackProc(AlterRate); |
// Create routine descriptor for "AlterMasterOffset" QT callback routine |
gAlterMasterOffsetUpp = NewQTCallBackProc(AlterMasterOffset); |
} |
//---------------------------------------------- |
// KillMovieGlobals |
// |
// Removes the UPPs |
//---------------------------------------------- |
void KillMovieGlobals(void) |
{ |
// Clear the Universal Proc Pointers |
// You don't need to do this as quiting the app will do it for you, |
// however, I have this thing about neatness. |
if (gStartMovieCBUpp) |
DisposeRoutineDescriptor(gStartMovieCBUpp); |
if (gAlterRateUpp) |
DisposeRoutineDescriptor(gAlterRateUpp); |
if (gAlterMasterOffsetUpp) |
DisposeRoutineDescriptor(gAlterMasterOffsetUpp); |
} |
//============================================== |
// |
// Error Reporting |
// |
//============================================== |
//---------------------------------------------- |
// Report Error |
// |
// If an error occurs, Uses DebugStr to send out |
// some text passed to it, then the error number |
//---------------------------------------------- |
void ReportError( Str255 errText, OSErr theErr ); |
void ReportError( Str255 errText, OSErr theErr ) |
{ |
Str255 errorStr; |
// Check there is an error |
if (theErr) |
{ |
// convert theErr number to text |
NumToString(theErr,errorStr); |
// if there is error text then displat it |
if (errText != "\p") |
DebugStr(errText); |
// Display error number |
DebugStr(errorStr); |
} |
} |
//---------------------------------------------- |
// GetAndReportError |
// |
// Checks GetMoviesError and reports error if |
// needed |
//---------------------------------------------- |
OSErr GetAndReportError( Str255 errText ); |
OSErr GetAndReportError( Str255 errText ) |
{ |
OSErr theErr; |
theErr = GetMoviesError(); // Get Movies error number |
ReportError( errText, theErr ); // And report it |
return(theErr); // Oh yeh, return it to the caller |
} |
//============================================== |
// |
// Call Back info stuff |
// |
// Following routines handle the CallBackInfoHdl |
// structure. |
//============================================== |
//---------------------------------------------- |
// AddNewCallBackInfo |
// |
// Creates a new "CallBackInfoHdl", intialises and |
// returns it |
// - It puts "pWindow" and "theCallBack" into the structure |
// - It appends "dataSize" bytes of data from "pDataStart" |
// on to the end of the structure |
//---------------------------------------------- |
CallBackInfoHdl AddNewCallBackInfo( WindowPtr pWindow, |
QTCallBack theCallBack, |
Ptr pDataStart, |
long dataSize, |
long param1, |
long param2, |
long param3 |
); |
CallBackInfoHdl AddNewCallBackInfo( WindowPtr pWindow, |
QTCallBack theCallBack, |
Ptr pDataStart, |
long dataSize, |
long param1, |
long param2, |
long param3 |
) |
{ |
CallBackInfoHdl hNewCBInfo = nil; // the new call back info record |
DocMovieInfoHndl hDocMovieInfo; |
long newSize; // Size of hNewCBInfo and the data added to it |
// Calculate how big the block needs to be |
newSize = sizeof(CallBackInfoType) + dataSize - sizeof(long); |
// Create the call back data item |
hNewCBInfo = (CallBackInfoHdl) NewHandle (newSize); |
// Check that we actualy did create it! |
if (hNewCBInfo) |
{ |
// Setup the structure |
(**hNewCBInfo).hNextCallBackInfo = nil; |
(**hNewCBInfo).actualCallBack = theCallBack; |
(**hNewCBInfo).pParentWindow = pWindow; |
(**hNewCBInfo).param1 = param1; |
(**hNewCBInfo).param2 = param2; |
(**hNewCBInfo).param3 = param3; |
(**hNewCBInfo).callBackDataSize = 0; |
// Add in the data (if there is any) |
if (dataSize && pDataStart) |
{ |
(**hNewCBInfo).callBackDataSize = dataSize; |
BlockMove( pDataStart, &((**hNewCBInfo).callBackDataStart), dataSize); |
} |
// Now, link it into the window data structure (attach it to the front of the chain) |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon ( pWindow ); |
(**hNewCBInfo).hNextCallBackInfo = (**hDocMovieInfo).hFirstCallBackData; |
(**hDocMovieInfo).hFirstCallBackData = hNewCBInfo; |
} |
return( hNewCBInfo ); |
} |
//---------------------------------------------- |
// RemoveCallBackInfo |
// |
// Scans down the CallBackInfoHdl chain and disposes |
// of each one |
//---------------------------------------------- |
void RemoveCallBackInfo ( CallBackInfoHdl hFirstItem ); |
void RemoveCallBackInfo ( CallBackInfoHdl hFirstItem ) |
{ |
CallBackInfoHdl hNextCBInfo; |
CallBackInfoHdl hDisposeData; |
if (hFirstItem) |
{ |
// Scan down the chain of items, disposing as we go |
hNextCBInfo = hFirstItem; |
while (hNextCBInfo) |
{ |
hDisposeData = hNextCBInfo; |
hNextCBInfo = (**hNextCBInfo).hNextCallBackInfo; |
// Dispose of the call back |
DisposeCallBack( (**hDisposeData).actualCallBack ); |
// Dispose of the call back info block |
DisposeHandle( (Handle) hDisposeData); |
} |
} |
} |
//---------------------------------------------- |
// GetDataFromCBInfo |
// |
// Extracts the data from a CallBackInfoHdl and |
// moves the data into it. Checks the stored structure |
// is smaller than requested size. Ideally they should |
// be the same size. |
//---------------------------------------------- |
Boolean GetDataFromCBInfo ( CallBackInfoHdl hCallBackInfo, |
Ptr pData, |
long maxDataSize ); |
Boolean GetDataFromCBInfo ( CallBackInfoHdl hCallBackInfo, |
Ptr pData, |
long maxDataSize ) |
{ |
Boolean isOk = false; |
// Check that we have a call back, |
// and we have some where to put the data, |
// and it's bigger than 0 |
if (hCallBackInfo && pData && maxDataSize) |
// Check the call back data is smaller than the new structure |
if ( (**hCallBackInfo).callBackDataSize <= maxDataSize) |
{ |
// Move the data to pData |
BlockMove ( &((**hCallBackInfo).callBackDataStart), |
pData, |
(**hCallBackInfo).callBackDataSize ); |
isOk = true; |
} |
return ( isOk ); |
} |
//---------------------------------------------- |
// IsMoviePlaying |
// |
// Find out if any movie is playing |
//---------------------------------------------- |
Boolean IsMoviePlaying (void) |
{ |
DocMovieInfoHndl hDocMovieInfo; // The movie we're checkings info |
Boolean movieLive = false; // set to true if there is a live window |
short windCount; |
// Scan the window list until we've found a live window |
for (windCount = 0;(windCount < kMaxWindows) && !movieLive; windCount++ ) |
// If this window is open |
if (gTheWinds[windCount]) |
{ |
// Get information about the movie |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (gTheWinds[windCount]); |
// Use IsMovieDone to see if it's still running |
if (!IsMovieDone((**hDocMovieInfo).actualMovie) ) |
movieLive = true; |
} |
return (movieLive); |
} |
//---------------------------------------------- |
// UpdateMovieWindow |
//---------------------------------------------- |
void UpdateMovieWindow ( WindowPtr pWindow ) |
{ |
// Get the movie from the ref con and update it. Easy. |
UpdateMovie( (**(DocMovieInfoHndl)GetWRefCon( pWindow )).actualMovie); |
} |
//---------------------------------------------- |
// Load a movie into memory |
// |
// Use standard file to get and load a movie |
//---------------------------------------------- |
void LoadOneMovie( DocMovieInfoHndl hDocMovieInfo ); |
void LoadOneMovie( DocMovieInfoHndl hDocMovieInfo ) |
{ |
Movie myNewMovie = nil; // The new movie |
StandardFileReply newMovieFile; // Standard File Reply about the movies file |
Str255 myMovieName; // The Movies name |
OSErr error; |
SFTypeList myTypes = {MovieFileType}; // File types we want Standard File to get |
short myMovieResFile; // Movie files ref number |
short myMovieResID = 0; // Load the first movie res |
Boolean movieChanged; // Set to true if movie was changed durring |
// loading to resolve references |
// Use standard file to get the fsSpec etc. |
StandardGetFilePreview(nil,1,myTypes,&newMovieFile); |
if (newMovieFile.sfGood) |
{ |
// Open the movie file |
error = OpenMovieFile( &newMovieFile.sfFile, &myMovieResFile, fsRdPerm); |
if (error==noErr) |
{ |
// Store the file spec |
(**hDocMovieInfo).movieFileSpec = newMovieFile.sfFile; |
// Move Movie data in to memory |
error = NewMovieFromFile( &myNewMovie, myMovieResFile, &myMovieResID, |
myMovieName, newMovieActive, &movieChanged); |
// Close the file as we succeded in opening it |
CloseMovieFile (myMovieResFile); |
} |
} |
(**hDocMovieInfo).actualMovie = myNewMovie; // Return myNewMovie |
} |
//---------------------------------------------- |
// ServiceMovieTasks |
// |
// Used to Handle the null event. You need to handle |
// this to make the movie play! |
// - First it sees if the movie controller has an event |
// - Scans the window list looking for movies |
// - If the movie has finished then close it if the |
// flags are set that way |
// - If any movies are active, then call MoviesTask |
// to make them play |
// - Finally return true if the event was handled by the |
// movie controller |
//---------------------------------------------- |
Boolean ServiceMovieTasks ( WindowPtr pWindow, const EventRecord *theEvent ) |
{ |
#pragma unused ( pWindow ) |
Boolean doneProccessing = false; // goes to true if MCIsPlayerEvent handles event |
DocMovieInfoHndl hDocMovieInfo; // Current windows movie info |
short windCount; |
Boolean needMovieTasks = false; // Goes true if there is a movie running |
Boolean moviePlaying; |
// Scan window list |
for (windCount = 0;windCount < kMaxWindows; windCount++ ) |
if (gTheWinds[windCount]) |
{ |
// Get movie information for this window |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (gTheWinds[windCount]); |
// Handle any events to this windows movie controller if it's got one |
if (!doneProccessing) |
if ((**hDocMovieInfo).movieControls) |
if (MCIsPlayerEvent((**hDocMovieInfo).movieControls, theEvent)) |
doneProccessing = true; |
// Next bit checks to see if a window has finished playing (by using |
// IsMovieDone) and closes it if auto close has been set for it |
moviePlaying = !IsMovieDone((**hDocMovieInfo).actualMovie); |
if ( (**hDocMovieInfo).movieAutoClose && (!moviePlaying) ) |
CloseOurWindow( windCount ); |
else |
if (moviePlaying) |
needMovieTasks = true; // Hey there's a movie running |
} |
// If we have an active movie, then service all movies |
if (needMovieTasks) |
MoviesTask(nil,0); |
return ( doneProccessing ); |
} |
//---------------------------------------------- |
// CloseMovieWindow |
// |
// Close a movie window and destroys associated |
// structures. If this is a Master window, |
// sets "*pSlaveWindow" to the slave WindowPtr |
//---------------------------------------------- |
OSErr CloseMovieWindow( WindowPtr pWindow, |
WindowPtr *pSlaveWindow ) |
{ |
DocMovieInfoHndl hDocMovieInfo; |
*pSlaveWindow = nil; |
// Get movie structure |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon(pWindow); |
if (hDocMovieInfo) |
{ |
// Set the slave WindowPtr |
*pSlaveWindow = (**hDocMovieInfo).pSlaveWind; |
// dispose movie |
DisposeMovie((**hDocMovieInfo).actualMovie); |
// dispose of the controller if it exists |
if ((**hDocMovieInfo).movieControls) |
DisposeMovieController ( (**hDocMovieInfo).movieControls ); |
// dispose of call back structures |
RemoveCallBackInfo ( (**hDocMovieInfo).hFirstCallBackData ); |
// dispose movie structure |
DisposeHandle( (Handle)hDocMovieInfo ); |
} |
return ( noErr ); |
} |
//---------------------------------------------- |
// OpenMovieWindow |
// |
// - Opens a movie |
// - Creates and initialises the windows movie |
// structure "DocMovieInfoHndl" |
// - Creates (if wanted) a movie controller |
// - Sizes the window to fit the movie and controller |
// - Shows the window |
//---------------------------------------------- |
OSErr OpenMovieWindow ( WindowPtr pWindow, |
Boolean doesAutoClose, |
Boolean hasControler ) |
{ |
OSErr theErr = noErr; |
DocMovieInfoHndl hDocMovieInfo = nil; // new window movie information |
Rect moviesRect; // Size of the movie |
Rect newWindRect; // New Windows rect (movie + Controllers rect) |
if (!pWindow) |
{ // Error !!!! |
DebugStr("\pHey, this window doesn't exists!!"); |
theErr = userCanceledErr; // Should be something more appropriate |
} |
else |
{ |
// allocate new movie doc structure |
hDocMovieInfo = (DocMovieInfoType**) NewHandle (sizeof(DocMovieInfoType)); |
if (hDocMovieInfo == nil) |
{ // Error !!!! |
DebugStr("\pError allocating doc handle"); |
theErr = userCanceledErr; // Should be something more appropriate |
} |
else |
{ |
// Set up the hDocMovieInfo record |
(**hDocMovieInfo).movieAutoClose = doesAutoClose; |
(**hDocMovieInfo).hFirstCallBackData = nil; |
(**hDocMovieInfo).movieControls = nil; |
(**hDocMovieInfo).actualMovie = nil; |
(**hDocMovieInfo).pSlaveWind = nil; |
// set window refcon to movie doc handle |
SetWRefCon( pWindow, (long)hDocMovieInfo ); |
SetPort(pWindow); |
// load movie refs into doc structure |
LoadOneMovie ( hDocMovieInfo ); |
if ((**hDocMovieInfo).actualMovie == nil) |
{ // Cancel button pressed or Error !!!! |
theErr = userCanceledErr; // Should be something more appropriate |
return(theErr); |
} |
else |
{ |
// get timebase from movie |
(**hDocMovieInfo).moviesTimeBase = GetMovieTimeBase((**hDocMovieInfo).actualMovie); |
theErr = GetAndReportError( "\pError!! GetMovieTimeBase"); |
// get timescale from movie |
if (!theErr) |
{ |
(**hDocMovieInfo).moviesTimeScale = GetMovieTimeScale((**hDocMovieInfo).actualMovie); |
theErr = GetAndReportError( "\pError!! Getting movie time scale"); |
} |
if (!theErr) |
if (!hasControler) |
{ |
// Don't want a controller, so just |
// Get movies rect as this is the size of the window |
GetMovieBox((**hDocMovieInfo).actualMovie, &newWindRect); |
} |
else |
{ |
// We want a movie controller so create it beneath the movie |
// Get the movies rect as this is the size we want to put it in |
GetMovieBox((**hDocMovieInfo).actualMovie, &moviesRect); |
//Create a controller and put below the movie. as moviesRect is the size of the movie, |
// the controller will fall outside the rect |
(**hDocMovieInfo).movieControls = NewMovieController ( (**hDocMovieInfo).actualMovie, |
&moviesRect, |
mcTopLeftMovie); |
if ((**hDocMovieInfo).movieControls == nil) |
{ // Failed to create controller Error !!!! |
theErr = userCanceledErr; // Should be something more appropriate |
return(theErr); |
} |
else |
{ |
// Get movieControllers rect. Because it is attached the movie, it will return |
// the controller and movies size |
theErr = MCGetControllerBoundsRect((**hDocMovieInfo).movieControls, &newWindRect); |
} |
} |
if (!theErr) |
{ |
// Size the window to fit the movie and controller |
SizeWindow( pWindow,newWindRect.right, newWindRect.bottom,true); |
} |
} |
} |
} |
return ( theErr ); |
} |
//============================================== |
// The time base call back procs |
//============================================== |
//---------------------------------------------- |
// AlterMasterOffset |
// |
// QuickTime callback used to set the SetTimeBaseValue. |
// - Can be used to make the movie loop. |
// - Takes a value in seconds in the data of |
// the CallBackInfoHdl passed in "ref" |
//---------------------------------------------- |
pascal void AlterMasterOffset(QTCallBack myCallBack,long ref) |
{ |
DocMovieInfoHndl hDocMovieInfo; |
WindowPtr pWindow; |
TimeValue newTimeValue; // Where we want to move to |
OSErr theErr; |
// Extract where we want to move to from (CallBackInfoHdl)ref |
if (GetDataFromCBInfo( ( CallBackInfoHdl)ref, |
(Ptr) &newTimeValue, sizeof ( TimeValue ) )) |
{ |
pWindow = (**(CallBackInfoHdl)ref).pParentWindow; // Get the parent window |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon ( pWindow ); // Get the movie info |
// Move our position in the movie |
SetTimeBaseValue ( (**hDocMovieInfo).moviesTimeBase, |
newTimeValue, |
(**hDocMovieInfo).moviesTimeScale); |
// Finally must reschedule the call back so that it happens again |
theErr = CallMeWhen ( myCallBack, |
gAlterMasterOffsetUpp, ref, |
(**(CallBackInfoHdl)ref).param1, |
(**(CallBackInfoHdl)ref).param2, |
(**(CallBackInfoHdl)ref).param3); |
} |
} |
//---------------------------------------------- |
// AlterRate |
// |
// QuickTime callback used to set the movies rate. |
// - Alters the speed of playback. |
// - Takes a value in the data of the CallBackInfoHdl |
// passed in "ref" |
//---------------------------------------------- |
pascal void AlterRate( QTCallBack myCallBack,long ref) |
{ |
#pragma unused ( myCallBack ) |
DocMovieInfoHndl hDocMovieInfo; |
WindowPtr pWindow; |
long newMovieRate; |
// Extract the new speed we want the movie to run at |
if (GetDataFromCBInfo ( ( CallBackInfoHdl)ref, (Ptr) &newMovieRate, sizeof ( long ) )) |
{ |
pWindow = (**(CallBackInfoHdl)ref).pParentWindow; // Get the parent window |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon ( pWindow ); // Get the movie info |
// Change the movies rate |
SetMovieRate((**hDocMovieInfo).actualMovie, newMovieRate); |
} |
return; |
} |
//---------------------------------------------- |
// StartMovieCB |
// |
// QuickTime callback used to start a movie. |
// - Takes a value (Movie) in the data of the CallBackInfoHdl |
// passed in "ref" which is the movie you want to start. |
//---------------------------------------------- |
pascal void StartMovieCB(QTCallBack myCallBack,long ref) |
{ |
#pragma unused ( myCallBack ) |
Movie movieToStart; |
if (GetDataFromCBInfo ( ( CallBackInfoHdl)ref, (Ptr) &movieToStart, sizeof ( Movie ) )) |
{ |
SetMovieRate(movieToStart,65536); |
} |
} |
//============================================== |
// Set up the various options |
//============================================== |
//---------------------------------------------- |
// SetupMovieRate |
// |
// - Sets up the call backs to change the play back speed |
// of the movie. |
// - "delayBeforeChange" gives the time in seconds when |
// the first speed change happens or a constant that |
// tells it to change at 1/3 (& 2/3) of the movies |
// duration. |
//---------------------------------------------- |
OSErr SetupMovieRate( WindowPtr pWindow, short delayBeforeChange ) |
{ |
OSErr theErr = noErr; |
QTCallBack theNewCallBack; // Call Back |
long theCallBackOffset; // When we want to change the rate |
TimeValue theMovieLen; // Length of the movie |
DocMovieInfoHndl hDocMovieInfo; // Info about the windows movie |
CallBackInfoHdl hTempCallBackInfo; // Call back information |
long newMovieRate; // What the new rate will be |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (pWindow); |
if (hDocMovieInfo != nil) |
{ |
// Set up the time base value |
SetTimeBaseValue( (**hDocMovieInfo).moviesTimeBase, |
0, |
(**hDocMovieInfo).moviesTimeScale); |
// If we're changing by a thirds, we need the movie's length |
if (delayBeforeChange == kOneThird) |
theMovieLen = GetMovieDuration((**hDocMovieInfo).actualMovie); |
// ---- First call back - slow playback rate to x2 normal ----- |
// Work out length of delay before callbacks start |
if (delayBeforeChange == kOneThird) |
theCallBackOffset = theMovieLen*0.3333; |
else |
theCallBackOffset = delayBeforeChange * (**hDocMovieInfo).moviesTimeScale; |
// Create a new call back |
theNewCallBack = NewCallBack((**hDocMovieInfo).moviesTimeBase,callBackAtTime); |
newMovieRate = 131072; // speed up rate to x2 normal |
// Put the call back into call back chain ( and append newMovieRate ) |
hTempCallBackInfo = AddNewCallBackInfo( pWindow, |
theNewCallBack, |
(Ptr)&newMovieRate, sizeof ( long ), |
triggerTimeFwd, |
theCallBackOffset, |
(**hDocMovieInfo).moviesTimeScale ); |
// Attach the call back to the movie's time structures |
theErr = CallMeWhen ( theNewCallBack, |
gAlterRateUpp, |
(long)hTempCallBackInfo, |
(**hTempCallBackInfo).param1, |
(**hTempCallBackInfo).param2, |
(**hTempCallBackInfo).param3 ); |
if (theErr) |
ReportError( "\pError !! CallMeWhen", theErr ); |
else |
{ |
// --- Second call back - slow playback rate to 1/2 normal ---- |
// Work out length of delay before callbacks start |
if (delayBeforeChange == kOneThird) |
theCallBackOffset = theMovieLen*0.6666; |
else |
theCallBackOffset = (2 * delayBeforeChange) * (**hDocMovieInfo).moviesTimeScale; |
// Create a new call back |
theNewCallBack = NewCallBack((**hDocMovieInfo).moviesTimeBase,callBackAtTime); |
newMovieRate = 32768; // speed up rate to 1/2 normal |
// Put the call back into call back chain ( and append newMovieRate ) |
hTempCallBackInfo = AddNewCallBackInfo( pWindow, |
theNewCallBack, |
(Ptr)&newMovieRate, sizeof ( long ), |
triggerTimeFwd, |
theCallBackOffset, |
(**hDocMovieInfo).moviesTimeScale ); |
// Attach the call back to the movie's time structures |
theErr = CallMeWhen ( theNewCallBack, |
gAlterRateUpp, |
(long)hTempCallBackInfo, |
(**hTempCallBackInfo).param1, |
(**hTempCallBackInfo).param2, |
(**hTempCallBackInfo).param3 ); |
if (theErr) |
ReportError( "\pError !! CallMeWhen", theErr ); |
} |
} |
return ( theErr ); |
} |
//---------------------------------------------- |
// SetupLoop |
// |
// Set up a loop in the movie. |
// - It uses call backs, to change the position of |
// the movie "loopWhen" seconds into it and moves it |
// to "loopTo" seconds |
//---------------------------------------------- |
OSErr SetupLoop ( WindowPtr pWindow, |
short loopWhen, |
short loopTo ) |
{ |
OSErr theErr = noErr; |
DocMovieInfoHndl hDocMovieInfo; // Info about the windows movie |
long callBackWhen; // When we want to start loop |
CallBackInfoHdl hTempCallBackInfo; // Call back information |
QTCallBack tempCallBack; // Call Back |
TimeValue newTimeValue; // Where we want to loop to |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (pWindow); |
// Calculate when the movie should 'jump' |
callBackWhen = loopWhen*(**hDocMovieInfo).moviesTimeScale; |
// Creates a call back |
tempCallBack = NewCallBack((**hDocMovieInfo).moviesTimeBase, callBackAtTime); |
// Set up where it's going to loop to |
newTimeValue = loopTo * (**hDocMovieInfo).moviesTimeScale; |
// Add the call back to the call back list |
hTempCallBackInfo = AddNewCallBackInfo( pWindow, |
tempCallBack, |
(Ptr) &newTimeValue, sizeof ( TimeValue ), |
triggerTimeFwd, |
callBackWhen, |
(**hDocMovieInfo).moviesTimeScale ); |
// Attach the call back to the movie's time structures |
theErr = CallMeWhen( tempCallBack, |
gAlterMasterOffsetUpp, (long)hTempCallBackInfo, |
(**hTempCallBackInfo).param1, |
(**hTempCallBackInfo).param2, |
(**hTempCallBackInfo).param3 ); |
return ( theErr ); |
} |
//---------------------------------------------- |
// SetupSlaveMovie |
// |
// This sets up the slaved movie |
// - "slaveAheadBy" sets the duration that the |
// slave will lead the master (in seconds) |
// - "slaveDelayStart" sets the duration that the |
// slave start will be delayed after the master starts |
// - If both values are set the same, the slave will start |
// n seconds behind the master and run in sync |
//---------------------------------------------- |
OSErr SetupSlaveMovie ( WindowPtr pMasterWindow, |
WindowPtr pSlaveWindow, |
short slaveAheadBy, |
short slaveDelayStart ) |
{ |
OSErr theErr = noErr; |
DocMovieInfoHndl hDocMasterInfo; // masters info |
DocMovieInfoHndl hDocSlaveInfo; // slaves info |
long slaveTimeOffset; // difference between the two movies |
long slaveStartDelay; // when we've got to start the slave |
CallBackInfoHdl hTempCallBackInfo; // Call back information |
QTCallBack tempCallBack; // call back |
Movie movieToStart; // Put into the call back |
TimeValue theMovieLen; // Length of the movie |
// Get the info about the two movies |
hDocMasterInfo = (DocMovieInfoHndl)GetWRefCon (pMasterWindow); |
hDocSlaveInfo = (DocMovieInfoHndl)GetWRefCon (pSlaveWindow); |
// Attach the slave window onto the master |
(**hDocMasterInfo).pSlaveWind = pSlaveWindow; |
// Set the master movies time base value |
SetTimeBaseValue((**hDocMasterInfo).moviesTimeBase,0,(**hDocMasterInfo).moviesTimeScale); |
// slave second movie to first |
SetMovieMasterTimeBase( (**hDocSlaveInfo).actualMovie, |
(**hDocMasterInfo).moviesTimeBase, |
nil ); |
// --- Setup the slave so it will lead the master --- |
if (slaveAheadBy != kInSync) |
{ |
// Calculate how big the offset should be |
if (slaveAheadBy == kOneThird) |
{ |
// get the movie's length |
theMovieLen = GetMovieDuration((**hDocSlaveInfo).actualMovie); |
slaveTimeOffset = theMovieLen*0.3333; |
} |
else |
slaveTimeOffset = slaveAheadBy*(**hDocMasterInfo).moviesTimeScale; |
// Set the slaves time base offset |
SetTimeBaseValue( (**hDocSlaveInfo).moviesTimeBase, |
slaveTimeOffset, |
(**hDocSlaveInfo).moviesTimeScale); |
theErr = GetAndReportError( "\pError !! - Offsetting timebase" ); |
} |
// --- Put in the call back to start the slave movie (delayed if requested )-- |
// Set up slaveStartDelay |
if (slaveDelayStart == kInSync) |
slaveStartDelay = 0; |
else |
if (slaveDelayStart == kOneThird) |
{ |
// get the movie's length |
theMovieLen = GetMovieDuration((**hDocMasterInfo).actualMovie); |
slaveStartDelay = theMovieLen*0.3333; |
} |
else |
slaveStartDelay = slaveDelayStart * (**hDocMasterInfo).moviesTimeScale; |
// Create a new call back |
tempCallBack = NewCallBack((**hDocMasterInfo).moviesTimeBase,callBackAtTime); |
// Link the call back into the chain |
movieToStart = (**hDocSlaveInfo).actualMovie; |
hTempCallBackInfo = AddNewCallBackInfo( pMasterWindow, |
tempCallBack, |
(Ptr) &movieToStart, sizeof(Movie), |
triggerTimeFwd, |
slaveStartDelay, |
(**hDocMasterInfo).moviesTimeScale ); |
// Attach the call back to the movie's time structures |
theErr = CallMeWhen ( tempCallBack, gStartMovieCBUpp, |
(long)hTempCallBackInfo, |
(**hTempCallBackInfo).param1, |
(**hTempCallBackInfo).param2, |
(**hTempCallBackInfo).param3 ); |
ReportError( "\pError!! - Creating movie start call back", theErr ); |
return ( theErr ); |
} |
//---------------------------------------------- |
// StartMovieWindow |
// |
// Start a movie in pWindow |
//---------------------------------------------- |
OSErr StartMovieWindow( WindowPtr pWindow, |
Boolean fromBegining ) |
{ |
DocMovieInfoHndl hDocMovieInfo; |
if (pWindow) |
{ |
hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (pWindow); |
// Set up the movie and start it |
if (fromBegining) |
GoToBeginningOfMovie((**hDocMovieInfo).actualMovie); |
SetMovieActive((**hDocMovieInfo).actualMovie,true); |
StartMovie((**hDocMovieInfo).actualMovie); |
} |
return( noErr ); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14