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.
DTSQTUtilities.c
/* |
File: DTSQTUtilities.c |
Contains: QuickTime functions. |
Written by: |
Copyright: Copyright © 1994-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): |
7/28/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
// INCLUDES |
#include "DTSQTUtilities.h" |
// MOVIE TOOLBOX FUNCTIONS |
/*______________________________________________________________________ |
QTUIsQuickTimeInstalled - Test if QuickTime is installed. |
pascal Boolean QTUIsQuickTimeInstalled(void) |
DESCRIPTION |
InitQuickTime will test if QuickTime is present. We are not interested in the QuickTime |
version. |
ISSUES |
You could combine this function with the QTUGetQTVersion so you could also fetch the |
version level of QT at the same time. |
*/ |
pascal Boolean QTUIsQuickTimeInstalled(void) |
{ |
OSErr anErr = noErr; |
long qtVersion; |
anErr = Gestalt(gestaltQuickTime, &qtVersion); DebugAssert(anErr == noErr); |
if (anErr != noErr) |
return false; // no QT present |
else |
return true; |
} |
/*______________________________________________________________________ |
QTUIsQuickTimeCFMInstalled - Test if the QuickTime CFM libraries are installed and in the |
right place. |
pascal Boolean QTUIsQuickTimeCFMInstalled(void) |
DESCRIPTION |
QTUIsQuickTimeCFMInstalled will test if the CFM QuickTime libraries are present (QuickTime |
PowerPlug, for instance), and if the libraries are still present (this because the libraries are |
registered once when Gestalt finds then during runtime, and the end user might delete these, |
or move them to another location later)(. |
*/ |
#ifdef powerc |
pascal Boolean QTUIsQuickTimeCFMInstalled(void) |
{ |
OSErr anErr = noErr; |
long qtFeatures = 0L; |
// Test if the library is registered. |
anErr = Gestalt(gestaltQuickTimeFeatures, &qtFeatures); DebugAssert(anErr == noErr); |
if (!( (anErr == noErr) && (qtFeatures & (1 << gestaltPPCQuickTimeLibPresent)) )) // not true |
return false; |
// Test if a function is available (the library is not moved from the Extension folder), this is the |
// trick to be used concerning testing if a function is available via CFM. |
if ( ! CompressImage ) |
return false; |
else |
return true; |
} |
#endif // powerc |
/*______________________________________________________________________ |
QTUGetQTVersion - Return the current QuickTime version number. |
pascal long QTUGetQTVersion() |
DESCRIPTION |
QTUGetQTVersion is a simple function that will return the current QuickTime version number, |
and if QuickTime is not installed it will return 0L. The high order word defines the version number, |
for instance 0x0161 defines version 1.6.1. |
You could also directly assign a boolean value stating if a certain version is true by using this |
kind of an expression: |
Boolean gHasQT2.0 = (( QTUGetQTVersion() >> 16) & 0xFFFF) >= 0x200; |
EXAMPLE |
if( (QTUGetQTVersion() >> 16) < 0x150 ) return; // need to work with QT 1.5 or higher. |
*/ |
pascal long QTUGetQTVersion() |
{ |
long version = 0L; |
if(Gestalt(gestaltQuickTime, &version) == noErr) |
return version; |
else |
return 0L; |
} |
/*______________________________________________________________________ |
QTUAreQuickTimeMusicInstrumentsPresent - Test if the Musical Instruments Extension is |
installed. |
pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void) |
DESCRIPTION |
QTUAreQuickTimeMusicInstrumentsPresent tests if the QuickTime Musical Instruments |
extension (actually a component) is registered. If this is not the case, then most likely |
the extension was never placed into the extension folder, and the end user should be |
informed about this. |
*/ |
pascal Boolean QTUAreQuickTimeMusicInstrumentsPresent(void) |
{ |
ComponentDescription aCD; |
aCD.componentType = 'inst'; |
aCD.componentSubType = 'ss '; |
aCD.componentManufacturer = 'appl'; |
if(FindNextComponent((Component)0, &aCD) != NULL) |
return true; |
else |
return false; |
} |
/*______________________________________________________________________ |
QTUPrerollMovie - Preroll the movie before you start the movie. |
pascal OSErr QTUPrerollMovie(Movie theMovie) |
theMovie the destination movie for this operation |
DESCRIPTION |
QTUPrerollMovie will get the movie time, duration and preferred rate, and Preroll the movie |
based on this information. Note that StartMovie already does a PrerollMovie so in that case this |
is not needed, this is also true of the standard controller that handles the start of movie |
when the keyboard or mouse is used. |
*/ |
pascal OSErr QTUPrerollMovie(Movie theMovie) |
{ |
OSErr anErr = noErr; |
TimeValue aTimeValue; |
TimeValue aMovieDur; |
Fixed aPreferredRate; |
aTimeValue = GetMovieTime(theMovie, NULL); |
aMovieDur = GetMovieDuration(theMovie); |
aPreferredRate = GetMoviePreferredRate(theMovie); |
if(aTimeValue == aMovieDur) aTimeValue = 0; |
anErr = PrerollMovie(theMovie, aTimeValue, aPreferredRate); DebugAssert(anErr == noErr); |
return anErr; |
} |
pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock); |
/*______________________________________________________________________ |
QTUGetMovie - Get a Movie from a specific file. |
pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID) |
theFSSpec the specific FSSpec used, if NULL the system will use a standard dialog |
box for the end user to select a file |
theRefNum this is the specific file ref num we want to use later |
theResID this is the specific resource ID we want to use later |
DESCRIPTION |
QTUGetMovie will get a movie resource out from a specified file, if the FSSpec is not provided |
then the function will use a StandardGetFilePreview to select the movie. |
*/ |
pascal Movie QTUGetMovie(FSSpec *theFSSpec, short *theRefNum, short *theResID) |
{ |
OSErr anErr = noErr; |
SFTypeList aTypeList = {MovieFileType, 0, 0, 0}; |
StandardFileReply aReply; |
Movie aMovie = NULL; |
// If we are provided with an FSSpec then use it, otherwise do a standardgetfile dialog box and |
// ask the end user to get it. |
if(theFSSpec == NULL || theFSSpec->vRefNum == 0) |
{ |
StandardGetFilePreview( NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply); |
if(! aReply.sfGood) |
return NULL; |
*theFSSpec = aReply.sfFile; |
} |
// We should have now a usable FSSpec, just double check this once again before continuing. |
DebugAssert(theFSSpec != NULL); if(theFSSpec == NULL) return NULL; |
anErr = OpenMovieFile(theFSSpec, theRefNum, fsRdPerm); DebugAssert(anErr == noErr); |
// Note we define fsRdPerm, you could use another flag if needed. |
if(anErr == noErr) |
{ |
Str255 aMovieName; |
Boolean wasChanged; |
*theResID = 0; // want first movie |
anErr = NewMovieFromFile(&aMovie, *theRefNum, theResID, |
aMovieName, newMovieActive, &wasChanged); |
DebugAssert(anErr == noErr); |
CloseMovieFile(*theRefNum); |
} |
if(anErr != noErr) |
return NULL; |
else |
return aMovie; |
} |
/*______________________________________________________________________ |
QTUSimpleGetMovie - Get a Movie from a specific file (simpler version) |
pascal OSErr QTUSimpleGetMovie(Movie *theMovie) |
theMovie will contain the selected movie when function exits. |
DESCRIPTION |
QTUSimpleGetMovie is a simplified version of getting a movie from a file, no need for |
returning refnums, res IDs of keeping track of FSSpecs (compared with QTUGetMovie) |
*/ |
pascal OSErr QTUSimpleGetMovie(Movie *theMovie) |
{ |
OSErr anErr = noErr; |
SFTypeList aTypeList = {MovieFileType, 0, 0, 0}; |
short resFile = 0; |
short resID = 0; |
StandardFileReply aReply; |
Str255 movieName; |
Boolean wasChanged; |
StandardGetFilePreview(NewFileFilterProc(QTUFileFilter), 1, aTypeList, &aReply); |
if(aReply.sfGood) |
{ |
anErr = OpenMovieFile(&aReply.sfFile, &resFile, fsRdPerm); DebugAssert(anErr == noErr); |
if(anErr == noErr) |
{ |
anErr = NewMovieFromFile(theMovie, resFile, &resID, movieName, newMovieActive, &wasChanged); |
DebugAssert(anErr == noErr); |
CloseMovieFile(resFile); |
} |
} |
return anErr; |
} |
/*______________________________________________________________________ |
QTUFileFilter - Skeleton file filter to be used with various MovieToolbox standard dialog utilities. |
pascal Boolean QTUFileFilter(ParmBlkPtr theParamBlock) |
theParamBlock specifies a particular ParmBlockPtr |
DESCRIPTION |
QTUFileFilter is a skeleton file filter to be used with various MovieToolbox standard dialog utilities |
The function will return a boolean false if it encounters any errors from the Movie toolbox. |
*/ |
pascal Boolean QTUFileFilter(ParmBlkPtr /*theParamBlock */) |
{ |
return false; |
} |
/*______________________________________________________________________ |
QTUSaveMovie - Save and flatten a movie resource into a file. |
pascal OSErr QTUSaveMovie(Movie theMovie) |
theMovie defines the movie to be saved into a file |
DESCRIPTION |
QTUSaveMovie will provide a user dialog asking for a file name, and will then save the movie |
into this file. Note that this function will also automatically flatten the movie so that it's |
self-contained, and also make it cross-platform (by adding any possible resource forks to |
the end of the data fork. The default name of the movie is also NEWMOVIE.MOV, this reflects |
the way movie file names should be named for cross-platform support (Windows). The default |
creator type is also 'TVOD' so that MoviePlayer will be the default application that opens the |
movie file. If there's an existing movie file with the same name, it will be deleted. |
*/ |
pascal OSErr QTUSaveMovie(Movie theMovie) |
{ |
OSErr anErr = noErr; |
StandardFileReply anSFReply; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
StandardPutFile("\pSave Movie as:" , "\pNEWMOVIE.MOV", &anSFReply); |
if(anSFReply.sfGood) |
{ |
FlattenMovieData(theMovie, flattenAddMovieToDataFork, &anSFReply.sfFile, |
'TVOD', smSystemScript, createMovieFileDeleteCurFile ); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
} |
return anErr; |
} |
/*______________________________________________________________________ |
QTUFlattenMovieFile - Flatten a movie into a specified file. |
pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile) |
theMovie defines the movie to be flattened |
theFile defines the target file |
DESCRIPTION |
FlattenMovie file will take an existing movie, flatten it into a temp file, and then move the |
contents of the temp file into the specified FSSpec. This because there are cases where we |
can't flatten a movie in place. We will use TickCount as a temp file name. |
Note that we need to dispose the movie inside this function? Why? Well, the file is open as |
long as there's a pointer to it from the movie resource. And we need to delete the original |
movie file as part of the operation of swapping the files. |
*/ |
pascal OSErr QTUFlattenMovieFile(Movie theMovie, FSSpec *theFile) |
{ |
OSErr anErr = noErr; |
FSSpec tempFile; |
Str255 tempFileName; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
// Create the needed temp file. |
NumToString(TickCount(), tempFileName); |
anErr = FSMakeFSSpec(theFile->vRefNum, theFile->parID, tempFileName, &tempFile); |
if(anErr != fnfErr) return anErr; |
// Flatten the movie. |
FlattenMovie(theMovie, flattenAddMovieToDataFork, &tempFile, 'TVOD', smSystemScript, |
createMovieFileDeleteCurFile, 0, NULL); |
anErr = GetMoviesError(); |
if(anErr != noErr) |
{ |
FSpDelete(&tempFile); // remove the temp file |
return anErr; |
} |
DisposeMovie(theMovie); |
anErr = FSpDelete(theFile); ReturnIfError(anErr); |
anErr = FSpRename(&tempFile, theFile->name); ReturnIfError(anErr); |
return anErr; |
} |
// TRACKS AND MEDIA |
/*______________________________________________________________________ |
QTUMediaTypeInTrack - Check if a particular media type is present in the movie. |
pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType) |
theMovie movie to be tested about the media type |
theMediaType media type we want to test about |
DESCRIPTION |
QTUMediaTypeInTrack could be used to scan if a possible media type is present in the movie |
(video,sound, other media types). |
*/ |
pascal Boolean QTUMediaTypeInTrack(Movie theMovie, OSType theMediaType) |
{ |
Track aTrack = NULL; |
long aTrackCount = 0; |
long index; |
OSType aMediaType; |
Boolean haveMediaType = false; |
aTrackCount = GetMovieTrackCount(theMovie); |
if(aTrackCount == 0) |
return false; // no tracks in movie |
for(index = 1; index <= aTrackCount; index++) |
{ |
aTrack = GetMovieIndTrack(theMovie, index); |
GetMediaHandlerDescription( GetTrackMedia(aTrack), &aMediaType, NULL, NULL); |
haveMediaType = ( aMediaType == theMediaType); |
if(haveMediaType == true) |
return true; |
} |
return false; // didn't find the media type track in the movie |
} |
/*______________________________________________________________________ |
QTUGetTrackRect - Get the Rect of a specified track. |
pascal Rect QTUGetTrackRect(Track theTrack) |
theTrack track we are interested in concerning the rect information |
DESCRIPTION |
QTUMediaTypeInTrack will take a (visual) track and return the track's Rect boundaries that |
could be used later for various calculations of the visual track geometries. Note that |
this Rect is meaningful with video tracks (and any other tracks that have geometrical |
dimensions, otherwise this function will return a rect with zero values. |
*/ |
pascal OSErr QTUGetTrackRect(Track theTrack, Rect *theRect) |
{ |
OSErr anErr = noErr; |
Fixed aTrackHeight; |
Fixed aTrackWidth; |
theRect->top = 0; theRect->left = 0; theRect->bottom = 0; theRect->right = 0; |
DebugAssert(theTrack != NULL); |
if(theTrack == NULL) |
return invalidTrack; |
GetTrackDimensions(theTrack, &aTrackHeight, &aTrackWidth); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) |
return anErr; |
theRect->right = Fix2Long(aTrackWidth); |
theRect->bottom = Fix2Long(aTrackHeight); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUGetVideoMediaPixelDepth - Return the pixel depth of the video media (sample). |
pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index) |
theMedia visual media we want to test concerning pixel depths |
index index into the media sample we are interested in |
DESCRIPTION |
QTUGetVideoMediaPixelDepth will take a specified video media and an index into the media |
samples, and look up the pixel depth for the video sample. |
*/ |
pascal short QTUGetVideoMediaPixelDepth(Media theMedia,short index) |
{ |
OSErr anErr = noErr; |
short aPixelDepth; |
SampleDescriptionHandle anImageDesc = NULL; |
OSType mediaType; |
DebugAssert(theMedia != NULL); |
DebugAssert(index > 0); |
// Test if we are indeed dealing with video media. |
GetMediaHandlerDescription(theMedia, &mediaType, NULL, NULL); |
if(mediaType != VideoMediaType) |
return 0; |
anImageDesc = (SampleDescriptionHandle)NewHandle(sizeof(Handle)); DebugAssert(anImageDesc != NULL); |
if(anImageDesc == NULL) |
return 0; |
GetMediaSampleDescription(theMedia, index, anImageDesc); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
aPixelDepth = (* (ImageDescriptionHandle)anImageDesc)->depth; |
DisposeHandle((Handle)anImageDesc); |
return aPixelDepth; |
} |
/*______________________________________________________________________ |
QTUCountMediaSamples - Count the amount of known media samples in a movie. |
pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType) |
theMovie the movie with the track(tracks). |
theMediaType the type of media we are interested in (video, sound and so on) |
DESCRIPTION |
QTUCountMediaSamples will take a specified movie and a media type, and calculate the amount |
of samples of this particular type. It could be used to find the total amount of video frames in a |
movie, or sound samples and so on. |
Note that if the movie is long, it will take a long time to go through all the samples, especially |
in the case of sound samples. |
EXAMPLE: |
nFrames = QTUCountMediaSamples(aSourceMovie, VideoMediaType); |
ISSUES |
This function could be modified to count other types of samples by changing the flags definitions |
(nextTimeSyncSample for key frames and so on). |
*/ |
pascal long QTUCountMediaSamples(Movie theMovie, OSType theMediaType) |
{ |
long numFrames = 0; |
short flags = nextTimeMediaSample + nextTimeEdgeOK; |
TimeValue aDuration = 0; |
TimeValue theTime = 0; |
GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration); |
if(theTime == -1) return numFrames; |
flags = nextTimeMediaSample; // Don't include the nudge after the first interesting time. |
while(theTime != -1) // When the returned time equals -1, then there were no more interesting times. |
{ |
numFrames++; |
GetMovieNextInterestingTime(theMovie, flags, 1, &theMediaType, theTime, 0, &theTime, &aDuration); |
} |
return numFrames; |
} |
/*______________________________________________________________________ |
QTUGetDurationOfFirstMovieSample - Return the time value of the first sample of a certain |
media type. |
pascal TimeValue QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType) |
theMovie the movie with the media track |
theMediaType specified media type (VideoMediaType, SoundMediaType and so on) |
DESCRIPTION |
QTUGetDurationOfFirstMovieSample returns the duration of the first sample of a certain media |
in the movie. If there is no such sample, the duration is 0. |
This function could be used in known cases where all the samples are assumed to be of the same |
duration. For instance in such cases the frame count could be calculated as: |
framecount = |
GetMovieDuration(theMovie)/QTUGetDurationofFirstMovieSample(theMovie, VideoMediaType); |
*/ |
pascal TimeValue QTUGetDurationOfFirstMovieSample(Movie theMovie, OSType theMediaType) |
{ |
OSErr anErr = noErr; |
TimeValue interestingDuration = 0; |
short timeFlags = nextTimeMediaSample+nextTimeEdgeOK; |
GetMovieNextInterestingTime(theMovie, timeFlags, (TimeValue)1, &theMediaType, 0, |
fixed1, NULL, &interestingDuration); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
return interestingDuration; |
} |
/*______________________________________________________________________ |
QTUCountMaxSoundRate - Calculate the max sound data rate of a possible sound track |
in the movie. |
pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate) |
theMovie the movie with the sound track(tracks). |
theMaxSoundRate the final returned value |
DESCRIPTION |
QTUCountMaxSoundRate (taken from the ConvertToMovieJr file) is a simple function that tries |
to figure out the maximum sound track rate. This is done by looking at all of the sound tracks |
in the source movie, and using the one with the highest sample rate (11khz, 22khz and so on), |
This number could then be used for calculating the maximum data rate by extracting the sound rate and |
this way we get a loose estimation how much is left for the video data rate. |
This is just an approximation, and a better function should take into account non-overlapping |
sound tracks, stereo sound data rates, compressed sound tracks and so on. |
*/ |
pascal OSErr QTUCountMaxSoundRate(Movie theMovie,long *theMaxSoundRate) |
{ |
OSErr anErr = noErr; |
short index, trackCount; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
*theMaxSoundRate = 0; // just for security we place this value in here |
trackCount = GetMovieTrackCount(theMovie); |
for(index = 1; index <= trackCount; index++) |
{ |
OSType aTrackType; |
Track aTrack = NULL; |
Media aMedia = NULL; |
aTrack = GetMovieIndTrack(theMovie, index); DebugAssert(aTrack != NULL); |
aMedia = GetTrackMedia(aTrack); DebugAssert(aMedia != NULL); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0); |
if(aTrackType == SoundMediaType) |
{ |
long aRate; |
SampleDescriptionHandle aDesc = NULL; |
aDesc = (SampleDescriptionHandle)NewHandle(sizeof(SampleDescription)); DebugAssert(aDesc != NULL); |
GetMediaSampleDescription(aMedia, 1, aDesc); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) |
{ |
DisposeHandle((Handle)aDesc); |
continue; |
} |
aRate = (*(SoundDescriptionHandle)aDesc)->sampleRate >> 16; |
if(aRate > *theMaxSoundRate) |
*theMaxSoundRate = aRate; |
} |
} |
return anErr; |
} |
/*______________________________________________________________________ |
QTUGetMovieFrameCount - Return the amount of frames in the movie based on frame rate estimate. |
pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate) |
theMovie the movie we want to calculate the frame count for. |
theFrameRate the expected frame rate of the movie |
DESCRIPTION |
QTUGetMovieFrameCount is a simple operation that takes into account the duration of the movie, |
the time scale and a suggested frame rate, and based on this will calculate the |
amount of frames needed in the movie. We assume that the frame rate will be uniform in the movie. |
*/ |
pascal long QTUGetMovieFrameCount(Movie theMovie, long theFrameRate) |
{ |
long frameCount, duration, timescale; |
float exactFrames; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
duration = GetMovieDuration(theMovie); |
timescale = GetMovieTimeScale(theMovie); |
exactFrames = (float)duration * theFrameRate; |
frameCount = exactFrames / timescale / 65536; |
if(frameCount == 0) |
frameCount = 1; // we got to have at least one frame |
return frameCount; |
} |
/*______________________________________________________________________ |
QTUCopySoundTracks - Copy any sound track from the source movie to the destination movie. |
pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie) |
aSourceMovie movie from which to copy the sound tracks |
aDestinationMovie movie to which we will copy the sound tracks. |
DESCRIPTION |
QTUCopySoundTracks will take any sound tracks from the source movie, and copy these over to the |
destination movie. The destination movie might have no sound track, or then these tracks are |
added to the existing sound tracks. |
*/ |
pascal OSErr QTUCopySoundTracks(Movie theSrcMovie, Movie theDestMovie) |
{ |
OSErr anErr = noErr; |
long trackCount, index; |
DebugAssert(theSrcMovie != NULL); if(theSrcMovie == NULL) return invalidMovie; |
DebugAssert(theDestMovie != NULL); if(theDestMovie == NULL) return invalidMovie; |
trackCount = GetMovieTrackCount(theSrcMovie); |
// Loop through each track, look for sound tracks. |
for(index = 1; index <= trackCount; index++) |
{ |
OSType aTrackType; |
Track aSrcTrack, aDestTrack; |
Media aSrcMedia, aDestMedia; |
aSrcTrack = GetMovieIndTrack(theSrcMovie, index); // get next track and media |
aSrcMedia = GetTrackMedia(aSrcTrack); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
// try to find sound tracks/media |
GetMediaHandlerDescription(aSrcMedia, &aTrackType, 0, 0); |
if(aTrackType == SoundMediaType) |
{ |
// Create the track for the sound media. |
aDestTrack = NewMovieTrack(theDestMovie, 0, 0, GetTrackVolume(aSrcTrack)); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
// Create a media for the sound track and prepare this media for editing. |
aDestMedia = NewTrackMedia(aDestTrack, SoundMediaType, GetMediaTimeScale(aSrcMedia), 0, 0); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
anErr = BeginMediaEdits(aDestMedia); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
// Insert the new track into the destination movie starting at time zero and |
// lasting for the entire duration of the movie. |
InsertTrackSegment(aSrcTrack, aDestTrack, 0 , GetTrackDuration(aSrcTrack), 0); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
// We've done editing the media |
EndMediaEdits(aDestMedia); |
} |
} |
return anErr; |
} |
/*______________________________________________________________________ |
QTUPrintMoviePICT - Print the existing movie frame pict. |
pascal Boolean QTUPrintMoviePICTr(Movie theMovie, short x, short y, long PICTUsed) |
theMovie movie that has the poster |
x,y starting point coordinates where to place the poster on paper |
DESCRIPTION |
QTUPrintMoviePICT is a simple function showing how to print movie posters. |
ISSUES |
Note that in a real application we should put the PrStlDialog code into the Print SetupÉ menu |
function. The reason it's inside this function is that we use this code for quick testing of |
printing. |
*/ |
pascal OSErr QTUPrintMoviePICT(Movie theMovie, short x, short y, long PICTUsed) |
{ |
OSErr anErr = noErr; |
PicHandle aPictHandle = NULL; |
THPrint aTHPrint = NULL; |
GrafPtr aSavedPort; |
TPPrPort aPrintPort; |
Boolean aResult; |
Boolean isPrinting = false; |
Rect aPictRect; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
GetPort(&aSavedPort); |
// Get the PICT to be printed, either the poster pict or the current frame pict. |
switch(PICTUsed) |
{ |
case kPrintFrame: |
aPictHandle = GetMoviePict(theMovie, GetMovieTime(theMovie, 0L)); |
break; |
case kPrintPoster: |
aPictHandle = GetMoviePosterPict(theMovie); |
break; |
default: |
DebugAssert("Should not happen, incorrect constant used"); goto Closure; |
} |
if(aPictHandle == NULL) goto Closure; |
// Get the Print record. |
aTHPrint = (THPrint) NewHandleClear(sizeof(TPrint)); DebugAssert(aTHPrint != NULL); |
if(aTHPrint == NULL) goto Closure; |
PrOpen(); isPrinting = true; |
anErr = PrError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
PrintDefault(aTHPrint); |
// Move this to Print SetupÉif you want to make this look really cool. |
aResult = PrStlDialog(aTHPrint); DebugAssert(aResult == true); |
if(!aResult) goto Closure; |
aResult = PrJobDialog(aTHPrint); DebugAssert(aResult == true); |
if(!aResult) goto Closure; |
aPrintPort = PrOpenDoc(aTHPrint, NULL, NULL); DebugAssert(aPrintPort != NULL); |
PrOpenPage(aPrintPort, NULL); |
anErr = PrError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
// Print at x,y position |
aPictRect = (*aPictHandle)->picFrame; |
OffsetRect(&aPictRect, x - aPictRect.left, y - aPictRect.top); |
DrawPicture(aPictHandle, &aPictRect); |
// If you want to do additional drawing, do it here. |
PrClosePage(aPrintPort); |
PrCloseDoc(aPrintPort); |
anErr = PrError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
if(( *aTHPrint)->prJob.bJDocLoop == bSpoolLoop) |
PrPicFile(aTHPrint, NULL, NULL, NULL, NULL); |
// Our closure handling. |
Closure: |
SetPort(aSavedPort); |
if(isPrinting) PrClose(); |
if(aPictHandle) KillPicture(aPictHandle); |
if(aTHPrint) DisposeHandle((Handle)aTHPrint); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUCalculateMovieMemorySize - Calculate how much memory a movie takes in the app heap. |
pascal OSErr QTUCalculateMovieMemorySize(Movie theMovie, long *theSize) |
theMovie movie we want to know the size of in the current application heap |
theSize pointer to a long that will contain the movie size in bytes |
DESCRIPTION |
QTUCalculateMovieMemorySize will return the amount of bytes it is allocating as a handle |
in the current application heap, if there's not enough space for a temp handle, or if anything |
else fails, the function will return 0L in theSize (and the OSErr). |
ISSUES |
Note that possible movie controllers associated with the movie and other constructs will eat up |
memory. What you could do is to do a MacsBug HT before the movie or movies are opened, |
check the amount of free space, and HT after the movies are opened, figure out the movie sizes |
using the function below, and calculate the delta from these values. |
*/ |
pascal OSErr QTUCalculateMovieMemorySize(Movie theMovie, long *theSize) |
{ |
OSErr anErr = noErr; |
Handle tempHandle = NULL; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
*theSize = 0L; |
tempHandle = NewHandle(sizeof(Movie)); DebugAssert(tempHandle != NULL); |
anErr = MemError(); DebugAssert(anErr == noErr); |
if(anErr != noErr || tempHandle == NULL) goto Closure; |
anErr = PutMovieIntoHandle(theMovie, tempHandle); DebugAssert(anErr == noErr); |
if(anErr == noErr) |
*theSize = GetHandleSize(tempHandle); |
Closure: |
if(tempHandle != NULL) DisposeHandle(tempHandle); |
return anErr; |
} |
/*______________________________________________________________________ |
QTULoadWholeMovieToRAM - Load the entire active segment (movie) into RAM |
pascal OSErr QTULoadWholeMovieToRAM(Movie theMovie) |
theMovie movie we want to know the size of in the current application heap. |
DESCRIPTION |
QTULoadWholeMovieToRAM is an example of how to load movie information into RAM. In |
this case we will load the entire movie, or in other words all the active segments. |
ISSUES |
The most likely error returned from this function is due to lack of memory. You could |
also fine tune this function by loading partial data based on time or track specifications. |
Loading whole movies is OK if the movies are small, have few tracks with little info (text |
tracks, music tracks and so on), there's a certain performance need why it makes sense |
to keep the movie in RAM (looping, other issues), and in general if you know why it's needed. |
*/ |
pascal OSErr QTULoadWholeMovieToRAM(Movie theMovie) |
{ |
OSErr anErr = noErr; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
GoToBeginningOfMovie(theMovie); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if (anErr != noErr) return anErr; |
anErr = LoadMovieIntoRam(theMovie, GetMovieTime(theMovie, NULL), GetMovieDuration(theMovie), 0); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUPlayMovieSound - Play the movie sound track using the Sound Manager. |
pascal OSErr QTUPlayMovieSound(Movie theMovie) |
theMovie movie wherefrom we extract the sound resource |
DESCRIPTION |
QTUPlayMovieSound is an example of how to extract the 'snd ' sound resource from the |
first sound track in a movie, and play this track back using the Sound Manager. This |
sound resource could also be retrieved, or otherwised used in other instances. Note that |
this function is more of an example of how to retrieve sound from a movie; you might |
want to control the start point, duration, and sound track extracted. |
*/ |
pascal OSErr QTUPlayMovieSound(Movie theMovie) |
{ |
OSErr anErr = noErr; |
Handle tempHandle = NewHandle(1); |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return invalidMovie; |
// Extract first sound track. |
anErr = PutMovieIntoTypedHandle(theMovie, (Track)0, 'snd ', tempHandle, 0, GetMovieDuration(theMovie), |
0, (ComponentInstance)0); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
anErr = MemError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
// Play sound resource async. |
anErr = SndPlay(0L, (SndListHandle)tempHandle, true); DebugAssert(anErr == noErr); |
Closure: |
if(tempHandle) DisposeHandle(tempHandle); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUDrawVideoFrameAtTime - Display a movie video frame at specified movie time. |
pascal OSErr QTUDrawVideoFrameAtTime(Movie theMovie, TimeValue atTime) |
theMovie movie we are using |
atTime time value in the movie for the video frame we want to display |
DESCRIPTION |
QTUDrawVideoFrameAtTime will display a specific video sample (or frame) at a specified time. |
In other words if we want to draw a frame at time point 600, the nearest video frame |
corresponding to this time value will be shown. |
We assume that the movie is properly set, and is using a correct portRect or GWorld. |
*/ |
pascal OSErr QTUDrawVideoFrameAtTime(Movie theMovie, TimeValue atTime) |
{ |
TimeValue totalTime; |
OSErr anErr = noErr; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) return paramErr; |
totalTime = GetMovieDuration(theMovie); |
if(atTime > totalTime) return paramErr; |
if(atTime == 0L) { |
GoToBeginningOfMovie(theMovie); anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr) goto Closure; |
} |
else { |
SetMovieTimeValue(theMovie, atTime); anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr) goto Closure; |
} |
anErr = UpdateMovie(theMovie); DebugAssert(anErr == noErr); |
if(anErr) goto Closure; |
MoviesTask(theMovie, 0L); anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
Closure: |
return anErr; |
} |
/*______________________________________________________________________ |
QTUScrollToNextVideoSample - Scroll offscreen from one video sample to the next. |
pascal OSErr QTUScrollToNextVideoSample(Movie theMovie, TimeValue fromTimePoint, TimeValue toTimePoint) |
fromTimePoint starting time value of the first video sample (frame) |
toTimePoint end time value for the second video sample (frame) |
DESCRIPTION |
QTUScrollToNextVideoSample will scroll from one video sample to the other one using offscreen |
GWorlds where the effect is created. |
We assume that the movie is properly set, and that the movie will use a proper portRect or GWorld. |
CREDITS |
Presto Studios for the core idea and some of the code below. |
*/ |
pascal OSErr QTUScrollToNextVideoSample(Movie theMovie, TimeValue fromTimePoint, TimeValue toTimePoint) |
{ |
OSErr anErr = noErr; |
GWorldPtr frameGWorld1 = NULL; |
GWorldPtr frameGWorld2 = NULL; |
PixMapHandle pixMap1 = NULL; |
PixMapHandle pixMap2 = NULL; |
CGrafPtr aSavedPort, moviePort; |
GDHandle aSavedGDevice, movieGDevice; |
CTabHandle colorTable; |
short screenDepth = 0; |
short screenSize = 0; |
Rect movieRect, sourceRect, destinationRect; |
RgnHandle scrollRegion = NULL; |
RgnHandle clipRegion = NULL; |
short nSteps; |
DebugAssert(theMovie != NULL); if(theMovie == NULL) goto Closure; |
//¥ Store away current portrect and Gdevice, get pixel sizes and color table for GWorld creation purposes. |
GetGWorld(&aSavedPort, &aSavedGDevice); |
GetMovieGWorld(theMovie, &moviePort, &movieGDevice); |
screenDepth = (**(**aSavedGDevice).gdPMap).pixelSize; |
colorTable = (**(**aSavedGDevice).gdPMap).pmTable; |
//¥ Adjust the movie box. |
GetMovieBox(theMovie, &movieRect); // If you want to offset by 10,10: OffsetRect(&movieRect, 10 -movieRect.left, 10 - movieRect.top); |
SetMovieBox(theMovie, &movieRect); |
//¥ Create two GWorlds for dual screen writing and possible scrolling transition effects. Lock down pixmaps. |
anErr = NewGWorld(&frameGWorld1, screenDepth, &movieRect, colorTable, NULL, 0); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
anErr = NewGWorld(&frameGWorld2, screenDepth, &movieRect, colorTable, NULL, 0); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
pixMap1 = GetGWorldPixMap(frameGWorld1); if(!LockPixels(pixMap1)) goto Closure; |
pixMap2 = GetGWorldPixMap(frameGWorld2); if(!LockPixels(pixMap2)) goto Closure; |
//¥ Draw first video sample (frame) to GWorld number 1. |
SetMovieGWorld(theMovie, frameGWorld1, GetGWorldDevice(frameGWorld1)); |
SetMovieTimeValue(theMovie, fromTimePoint); |
UpdateMovie(theMovie); MoviesTask(theMovie, 0); |
//¥ Draw second video sample (frame) to GWorld number 2. |
SetMovieGWorld(theMovie, frameGWorld2, GetGWorldDevice(frameGWorld2)); |
SetMovieTimeValue(theMovie, toTimePoint); |
UpdateMovie(theMovie); MoviesTask(theMovie, 0); |
//¥ Create scroll region and store away the current clip region. |
scrollRegion = NewRgn(); DebugAssert(scrollRegion != NULL); |
if(scrollRegion == NULL) goto Closure; |
clipRegion = NewRgn(); DebugAssert(clipRegion != NULL); |
if(clipRegion == NULL) goto Closure; |
GetClip(clipRegion); ClipRect(&movieRect); |
//¥ Create the scroll effect. |
screenSize = movieRect.right - movieRect.left; |
for(nSteps = 10; nSteps <= screenSize; nSteps += 10) { |
SetGWorld( frameGWorld1, NULL); |
ScrollRect(&movieRect, -10, 0, scrollRegion); |
SetRect(&sourceRect, movieRect.left, movieRect.top, |
movieRect.left + nSteps, movieRect.bottom); |
SetRect(&destinationRect, movieRect.right - nSteps, |
movieRect.top, movieRect.right, movieRect.bottom); |
CopyBits( (BitMap *) *pixMap2, (BitMap *) *pixMap1, &sourceRect, &destinationRect, |
srcCopy, NULL ); // blit from frameGWorld2 to frameGWorld1 |
DebugAssert(QDError() == noErr); |
SetGWorld(aSavedPort, aSavedGDevice); |
CopyBits( (BitMap *) *pixMap1, (BitMap *) &aSavedPort->portPixMap, &movieRect, |
&movieRect, srcCopy, NULL ); // blit from frameGWorld1 to screen pixmap |
DebugAssert(QDError() == noErr); |
} |
//¥ Unlock pixels, restore the original clip region. |
UnlockPixels(pixMap1); UnlockPixels(pixMap2); |
SetClip(clipRegion); |
//¥ Closure. Clean up if we have handles. |
Closure: |
if(frameGWorld1 != NULL) DisposeGWorld(frameGWorld1); |
if(frameGWorld2 != NULL) DisposeGWorld(frameGWorld2); |
if(scrollRegion != NULL) DisposeRgn(scrollRegion); |
if(clipRegion != NULL) DisposeRgn(clipRegion); |
SetMovieGWorld(theMovie, moviePort, movieGDevice); |
SetGWorld(aSavedPort, aSavedGDevice); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUGetStartPointOfFirstVideoSample - Get time value of first sample in the movie. |
TimeValue QTUGetStartPointOfFirstVideoSample(Movie theMovie) |
theMovie movie we are interested in |
startPoint will contain the value of the start point, if the function fails it will contain |
-1. |
DESCRIPTION |
QTUGetStartPointOfFirstVideoSample will return the time value of the first video sample found in the |
movie in the startPoint parameter. If the function fails, startPoint will contain -1 and the OSErr is |
also returned. |
*/ |
pascal OSErr QTUGetStartPointOfFirstVideoSample(Movie theMovie, TimeValue *startPoint) |
{ |
OSErr anErr = noErr; |
OSType media = VideoMediaType; |
*startPoint = -1; |
GetMovieNextInterestingTime(theMovie, nextTimeMediaSample+nextTimeEdgeOK, (TimeValue)1, &media, 0, |
fixed1, startPoint, NULL); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
return anErr; |
} |
// IMAGE COMPRESSION MANAGER |
/*______________________________________________________________________ |
QTUHasCodecLossLessQuality - Test if a specific codec has a lossless mode in a specific bit depth. |
Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth) |
theCodec specifies the Codec Type ('jpeg, 'rle ' and so on). |
thePixelDepth specifies the bit depth (8, 24, 30 and so on). See NIM:QuickTime, page |
3-70 for more details. |
DESCRIPTION |
QTUHasCodecLossLessQuality will test if a specific codec has a lossless spatial compression |
quality at a certain bit depth. Note that we are not testing the temporal compression qualities. |
EXAMPLE OF USE: |
if(QTUHasCodecLossLessQuality('jpeg', 32)) |
printf("JPEG has lossless spatial compression\n"); |
else |
printf("JPEG has NOT lossless spatial compression\n"); |
*/ |
Boolean QTUHasCodecLossLessQuality(CodecType theCodec, short thePixelDepth) |
{ |
OSErr anErr = noErr; |
CodecQ aSpatialQuality = codecLosslessQuality; |
anErr = GetCompressionTime(NULL, NULL, thePixelDepth, theCodec, anyCodec, &aSpatialQuality, |
NULL, NULL); DebugAssert(anErr == noErr); |
if(aSpatialQuality == codecLosslessQuality) // still the same? |
return true; |
else |
return false; |
} |
// MOVIE CONTROLLER FUNCTIONS |
/*______________________________________________________________________ |
QTUPlayMovieWithMC - Play a specific movie when using movie controllers. |
pascal OSErr QTUPlayMovieWithMC( MovieController mc) |
mc specified movie controller to be used |
DESCRIPTION |
Playmovie will start a movie using a moviecontroller and a specified movie. Note that it also |
does a preroll of the movie for performance reasons. |
*/ |
pascal OSErr QTUPlayMovieWithMC(MovieController mc) |
{ |
// Play normal speed forward, taking into account the possibility |
// of a movie with a nonstandard PreferredRate. |
OSErr anErr = noErr; |
Fixed aRate; |
Movie aMovie; |
aMovie = MCGetMovie(mc); |
aRate= GetMoviePreferredRate(aMovie); |
anErr = QTUPrerollMovie(aMovie); // Important: Preroll the movie here. |
DebugAssert(anErr == noErr); |
if(anErr == noErr) |
{ |
MCDoAction(mc, mcActionPlay, (void *)aRate); // note last value |
} |
return anErr; |
} |
/*______________________________________________________________________ |
QTUDoIgnoreMCDrags - Disable Drag and Drop facilities of the movie controller environment. |
pascal OSErr QTUDoIgnoreMCDrags(MovieController mc) |
mc is the specified moviecontroller to be used |
DESCRIPTION |
QTUDoIgnoreMCDrags will ensure that the Drag and Drop functionality is not handled within |
the movie specified by the movie controller. |
ISSUES |
Note that this is a workaround in QT 2.0 (test for QT 2.0 or higher if you want to use |
the drag-and-drop support in QT), and this function might not be needed in later QT versions. |
*/ |
pascal OSErr QTUDoIgnoreMCDrags(MovieController mc) |
{ |
OSErr anErr = noErr; |
GWorldPtr aTempGWorld; |
Rect aTempRect = {0, 0, 20, 20}; |
CGrafPtr aPort; |
// First create a 1-bit small 20x20 offscreen. |
anErr = NewGWorld( &aTempGWorld, 1, &aTempRect, NULL, NULL, 0L ); |
DebugAssert(anErr == noErr); |
if (anErr != noErr) |
{ |
aPort = MCGetControllerPort(mc); // get the current port |
MCSetControllerPort(mc, (CGrafPtr)aTempGWorld ); // set mc port to new offscreen |
MCDoAction(mc, mcActionSetDragEnabled, (void *)false); // don't want dragging |
MCSetControllerPort(mc, aPort); // restore mc port |
DisposeGWorld(aTempGWorld); // dispose offscreen |
} |
return anErr; |
} |
/*______________________________________________________________________ |
QTUPointInMC - Test if a point is placed in the movie controller rect area or not. |
pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where) |
mc is the specified moviecontroller to be used |
theWindow window used for testing for the hit point |
where hit point |
DESCRIPTION |
QTUPointInMC is a simple test to check where the mouse was clicked inside the window |
with a movie controller, returns true of the mouse click was inside the movie controller |
rect. See Peter Hoddie's article in develop# 18 for more details (code is from him as well). |
*/ |
pascal Boolean QTUPointInMC(MovieController mc, WindowRef theWindow, Point where) |
{ |
RgnHandle aRegion; |
Boolean result = false; |
aRegion = MCGetWindowRgn(mc, theWindow); |
DebugAssert(aRegion != NULL); |
if(aRegion != NULL) |
{ |
result = PtInRgn(where, aRegion); |
DisposeRgn(aRegion); |
} |
return result; |
} |
/*______________________________________________________________________ |
QTUSelectAllMovie - Select the whole movie time duration with the controller. |
pascal OSErr QTUSelectAllMovie(MovieController mc) |
mc is the specified moviecontroller to be used |
DESCRIPTION |
QTUSelectAllMovie is an example how to select the whole movie duration using the movie |
controller, this function could be used for Select All menu entries and similar cases. |
*/ |
pascal OSErr QTUSelectAllMovie(MovieController mc) |
{ |
OSErr anErr = noErr; |
TimeRecord aTimeRecord; |
Movie aMovie = NULL; |
DebugAssert(mc != NULL); |
if(mc == NULL) return paramErr; |
aMovie = MCGetMovie(mc); DebugAssert(aMovie != NULL); |
if(aMovie == NULL) return paramErr; |
aTimeRecord.value.hi = 0; |
aTimeRecord.value.lo = 0; |
aTimeRecord.base = 0; |
aTimeRecord.scale = GetMovieTimeScale(aMovie); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
anErr = MCDoAction(mc, mcActionSetSelectionBegin, &aTimeRecord); |
DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
aTimeRecord.value.lo = GetMovieDuration(aMovie); |
anErr = GetMoviesError(); DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
anErr = MCDoAction(mc, mcActionSetSelectionDuration, &aTimeRecord); |
DebugAssert(anErr == noErr); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUResizeMCActionFilter - Example of a movie controller filter that will resize the window |
where the movie is placed when the controllers themself change. |
pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void *params, long refCon) |
mc specified moviecontroller to be used. |
action the action for the mc action filter |
params parameters passed with the action |
refCon additional long word that could be used for all kinds of purposes |
DESCRIPTION |
QTUResizeMCActionFilter is an example of how to create a nice movie controller filter that |
will handle resizing of the window with the movie, and this will happen every time the controllers |
themselves change. It's also an example of how to write other kinds of movie controller filters. |
*/ |
pascal Boolean QTUResizeMCActionFilter(MovieController mc, short action, void* /*params*/ , long refCon) |
{ |
Rect aMovieBounds; |
switch(action) |
{ |
case mcActionControllerSizeChanged: |
MCGetControllerBoundsRect(mc, &aMovieBounds); |
SizeWindow((WindowPtr) refCon, aMovieBounds.right - aMovieBounds.left, |
aMovieBounds.bottom - aMovieBounds.top, true); |
break; |
} |
return false; |
} |
/*______________________________________________________________________ |
QTUResizeMCWindow - Resize a window to either normal size, double size or half of the movie rect size. |
pascal Boolean QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize) |
mc specified moviecontroller to be used |
theWindow window that will be resized |
theMovieSize constant that defines what default size we are interested in, kNormalSize, kHalfSize, kDoubleSize |
originalSize the original size of the movie, we need to keep track of this one in order to handle the |
ambient new sizes (half, double, normal). |
DESCRIPTION |
QTUResizeMCWindow is an example of a function how to resize the movie window with the controllers. |
The most common cases is half size, normal size or double size. But nothing hinders to add more sizes |
into this function. Note that if the movie window is doubled, we will get pixel-doubling by the QuickTime |
engine. |
*/ |
pascal OSErr QTUResizeMCWindow(MovieController mc, WindowPtr theWindow, long theMovieSize, Rect originalSize) |
{ |
OSErr anErr = noErr; |
Rect aMovieBounds; |
GrafPtr aSavedPort; |
DebugAssert(mc != NULL); if(mc == NULL) return paramErr; |
DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr; |
GetPort(&aSavedPort); |
SetPort((GrafPtr)theWindow); |
aMovieBounds.top = 0; aMovieBounds.left = 0; |
switch(theMovieSize) |
{ |
case kNormalMovieSize: |
MCSetControllerBoundsRect(mc, &originalSize); |
SizeWindow(theWindow, originalSize.right, originalSize.bottom, true); |
break; |
case kHalfMovieSize: |
aMovieBounds.right = (originalSize.right - originalSize.left) / 2; |
aMovieBounds.bottom = (originalSize.bottom - originalSize.top) / 2; |
MCSetControllerBoundsRect(mc, &aMovieBounds); |
SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true); |
break; |
case kDoubleMovieSize: |
aMovieBounds.right = (originalSize.right - originalSize.left) * 2; |
aMovieBounds.bottom = (originalSize.bottom - originalSize.top) * 2; |
MCSetControllerBoundsRect(mc, &aMovieBounds); |
SizeWindow(theWindow, aMovieBounds.right, aMovieBounds.bottom, true); |
break; |
default: |
SetPort(aSavedPort); |
anErr = paramErr; |
} |
SetPort(aSavedPort); |
return anErr; |
} |
/*______________________________________________________________________ |
QTUResizeMCWindow -Change the movie rate using the movie controller. |
pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate) |
mc specified moviecontroller to be used |
theRate new rate value, we are using specific constants, see the eQTUMovieRates enum |
in the DTSQTUtilities.h file concerning the values. |
DESCRIPTION |
QTUMCSetMovieRate will use an existing movie controller and change the rate. This is a very |
simple function, but we do have a list of constants that shows the various values that could be used |
(eQTUMovieRates, DTSQTUtilities.h), and also it shows that if the rate changes from 0 to something |
else, then we need to preroll the movie. The Apple MM Tuner will make sure the movie is prerolled, |
but we can't assume that every Mac has this extension installed, that's why it's still very important |
to preroll. |
ISSUES |
Note that movies have stored preferred rates, so if you want to compensate for this factor you need |
to read in this value as well before setting a double or half speed value. |
*/ |
pascal OSErr QTUMCSetMovieRate(MovieController mc, long theRate) |
{ |
OSErr anErr = noErr; |
Fixed aRate; |
DebugAssert(mc != NULL); |
if(mc == NULL) |
{ |
anErr = paramErr; goto Closure; |
} |
// Test if the playrate changes from 0 to a non-zero value, if so then preroll the movie. |
MCDoAction(mc, mcActionGetPlayRate, &aRate); |
if( (aRate == 0) && (theRate != 0) ) |
{ |
anErr = QTUPrerollMovie(MCGetMovie(mc)); // we are using the DTSQTUtilities function |
DebugAssert(anErr == noErr); |
if(anErr != noErr) return anErr; |
} |
anErr = MCDoAction(mc, mcActionPlay, (Ptr) theRate); DebugAssert(anErr == noErr); |
Closure: |
return anErr; |
} |
// SEQUENCE GRABBER FUNCTIONS |
/*______________________________________________________________________ |
QTUCreateSequenceGrabber - Create an instance of a sequence grabber for specified window. |
pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow) |
theWindow window where the sequence grabber will operate |
DESCRIPTION |
QTUCreateSequenceGrabber will try to open the default sequence grabber component and |
make sure this component will work in the GWorld of a specified window. |
If we don't find a suitable sequence grabber, or if we encounter problems, we will return NULL. |
*/ |
pascal SeqGrabComponent QTUCreateSequenceGrabber(WindowPtr theWindow) |
{ |
OSErr anErr = noErr; |
SeqGrabComponent s = NULL; |
DebugAssert(theWindow != NULL); if(theWindow == NULL) goto Closure; |
s = OpenDefaultComponent(SeqGrabComponentType, 0); |
if(s) // we got a valid one |
{ |
anErr = SGInitialize(s); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
anErr = SGSetGWorld(s, (CGrafPtr)theWindow, NULL); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
} |
return s; |
Closure: |
return NULL; |
} |
/*______________________________________________________________________ |
QTUCreateSGGrabChannels - Create SG channels, video and audio. |
pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage, |
SGChannel *theVideoChannel, SGChannel *theSoundChannel) |
s current active sequence grabber component instance |
theBounds the size of the video channel sequence grabber area |
theUsage any additional flags for the video SG |
theVideoChannel pointer to the video channel we will receive |
theSoundChannel pointer to the audio channel we will receive |
DESCRIPTION |
QTUCreateSGGrabChannels will create video and audio SG channels (SGChannels) using the specified |
default SG component. |
ISSUES |
We will terminate whenever we can't properly create a channel (sound, audio), if you still want to |
retrieve a valid channel (let's say the sound one is OK while the we can't open an audio one), you |
could slightly rewrite this code. |
*/ |
pascal OSErr QTUCreateSGGrabChannels(SeqGrabComponent s, const Rect *theBounds, long theUsage, |
SGChannel *theVideoChannel, SGChannel *theSoundChannel) |
{ |
OSErr anErr = noErr; |
long sgUsage = seqGrabPreview; // default at least this flag |
DebugAssert(s != NULL); if(s == NULL) return badSGChannel; |
sgUsage |= theUsage; // add any other usage flag info now |
// Create Video Channel. |
anErr = SGNewChannel(s, VideoMediaType, theVideoChannel); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto FailureHandling; |
anErr = SGSetChannelBounds(*theVideoChannel, theBounds); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto FailureHandling; |
anErr = SGSetChannelUsage(*theVideoChannel, sgUsage); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto FailureHandling; |
// Create Sound Channel. |
anErr = SGNewChannel(s, SoundMediaType, theSoundChannel); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto FailureHandling; |
anErr = SGSetChannelUsage(*theSoundChannel, sgUsage); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto FailureHandling; |
return anErr; |
FailureHandling: |
SGDisposeChannel(s, *theVideoChannel); *theVideoChannel = NULL; |
SGDisposeChannel(s, *theSoundChannel); *theSoundChannel = NULL; |
return anErr; |
} |
/*______________________________________________________________________ |
QTUDoesVDIGReceiveVideo - Test if vdig receives a live incoming video signal. |
pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s) |
s our sequence grabber component instance |
DESCRIPTION |
QTUDoesVDIGReceiveVideo test if the currently active vdig is receiving an incoming, live |
video signal. We assume that all well behaved vdigs set the digiInSignalLock flag. |
*/ |
pascal Boolean QTUDoesVDIGReceiveVideo(SeqGrabComponent s) |
{ |
OSErr anErr = noErr; |
long inputFlags, outFlags; |
DebugAssert(s != NULL); if(s == NULL) goto Closure; |
anErr = VDGetCurrentFlags(s, &inputFlags, &outFlags); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
if(inputFlags & digiInSignalLock) |
return true; |
Closure: |
return false; |
} |
/*______________________________________________________________________ |
QTUChangeSGWindowSize - Change window size of the video sequence grabber window. |
pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, |
WindowPtr theWindow, long width, long height) |
s our sequence grabber component instance |
videoChannel the specified (currently used) video channel |
theWindow window used for the digitizing sequence |
width new width of the digitizer rect |
height new height of the digitizer rect |
DESCRIPTION |
QTUChangeSGWindowSize shows how to change the window size for the current digitizing sequence |
taking place in the window. This is more of an example function as there might be other issues |
to be taken into account (such as preference settings and similar issues) while changing the |
bounds of the digitizing rect. |
*/ |
pascal OSErr QTUChangeSGWindowSize(SeqGrabComponent s, SGChannel videoChannel, WindowPtr theWindow, long width, long height) |
{ |
OSErr anErr = noErr; |
DebugAssert(theWindow != NULL); if(theWindow == NULL) return paramErr; |
DebugAssert(s != NULL); if(s == NULL) return badSGChannel; |
DebugAssert(videoChannel != NULL); if(videoChannel == NULL) return badSGChannel; |
anErr = SGPause(s, true); DebugAssert(anErr == noErr); if(anErr != noErr) goto Closure; |
SizeWindow(theWindow, width, height, false); |
anErr = SGSetChannelBounds(videoChannel, &theWindow->portRect); DebugAssert(anErr == noErr); |
if(anErr != noErr) goto Closure; |
anErr = SGPause(s, false); DebugAssert(anErr == noErr); |
Closure: |
return anErr; |
} |
// COMPONENT FUNCTIONS |
/*______________________________________________________________________ |
QTUDoGetComponent - Get a specific component based on component type and component sub-type. |
pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent) |
theComponentType the component type we are interested in |
theSpecificComponent the specific component sub-type we are interested int |
DESCRIPTION |
QTUDoGetComponent will get a specific component based on the component type and sub-type. We have |
special code for particular components (for instance movieImporttype and movieExporttype), so |
if we specify such types, the function will narrow down the search further for the right components. |
The specificComponent is just the special component we want to search for, if the component type is |
NULL, then the Specific component is the one and only we are interested in. Note that we don't care |
about the manufacturer information in this function. |
If we don't find a suitable component we will return NULL. |
*/ |
pascal Component QTUDoGetComponent(OSType theComponentType, OSType theSpecificComponent) |
{ |
ComponentDescription aCD; |
Component aComponent = NULL; |
aCD.componentType = theComponentType; |
aCD.componentSubType = theSpecificComponent; |
aCD.componentManufacturer = 0; |
// The following code is inserted for special handling of some known cases. |
if(theComponentType == MovieImportType) |
{ |
aCD.componentFlags = canMovieImportFiles; |
aCD.componentFlagsMask = canMovieImportFiles; |
} |
else if(theComponentType == MovieExportType) |
{ |
aCD.componentFlags = canMovieExportFiles; |
aCD.componentFlagsMask = canMovieExportFiles; |
} |
// OK, get the component. |
aComponent = FindNextComponent((Component)0, &aCD); |
return aComponent; |
} |
/*______________________________________________________________________ |
QTUHasComponentType -Query for a specific component based on component type and |
component sub-type. |
pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent) |
theComponentType the component type we are interested in |
theSpecificComponent the specific component sub-type we are interested int |
DESCRIPTION |
QTUDoGetComponent will query for a specific component based on the component type and sub-type. |
We have special code for particular components (for instance movieImporttype and movieExporttype), |
so if we query for such types, the function will narrow down the search further for the right |
components. |
The specificComponent is just the special component we want to search for, if the component |
type is NULL, then the Specific component is the one and only we are interested in. Note that we |
don't care about the manufacturer information in this function. |
If we don't find a suitable component we will return false, otherwise we will return true. |
*/ |
pascal Boolean QTUHasComponentType(OSType theComponentType, OSType theSpecificComponent) |
{ |
ComponentDescription aCD; |
aCD.componentType = theComponentType; |
aCD.componentSubType = theSpecificComponent; |
aCD.componentManufacturer = 0; |
if(theComponentType == MovieImportType) |
{ |
aCD.componentFlags = canMovieImportFiles; |
aCD.componentFlagsMask = canMovieImportFiles; |
} |
else if(theComponentType == MovieExportType) |
{ |
aCD.componentFlags = canMovieExportFiles; |
aCD.componentFlagsMask = canMovieExportFiles; |
} |
if(FindNextComponent((Component)0, &aCD) != NULL) |
return true; |
else |
return false; |
} |
//______________________________________________________________________ |
// T H E E N D |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14