//////////
//
//	File:		QTStreamSplicer.c
//
//	Contains:	Code to splice a still frame onto a streamed movie.
//
//	Written by:	Dan Crow
//	Revised by: Tim Monroe
//
//	Copyright:	© 1999 by Apple Computer, Inc., all rights reserved.
//
//	Change History (most recent first):
//
//	   <6>	 	07/18/00	rtm		fixed bug in QTSplicer_SpliceImageOverStream
//	   <5>	 	03/20/00	rtm		made changes to get things running under CarbonLib
//	   <4>	 	06/02/99	rtm		further work on QTSplicer_SpliceImageOverStream
//	   <3>	 	05/28/99	rtm		added QTSplicer_SpliceImageOverStream, for sound-only streams
//	   <2>	 	05/19/99	rtm		minor tweaking for Windows version; added some comments; added ability
//									to save spliced file as self-contained
//	   <1>	 	05/18/99	rtm		first file from Dan Crow; modified to better cohere with QT SDK
//									standards (did some renaming of variables and functions, but otherwise
//									this is pretty much Dan's code)
//
//	This file defines two principal functions, QTSplicer_SpliceImageOntoStream and QTSplicer_SpliceImageOverStream.
//	QTSplicer_SpliceImageOntoStream prompts the user for a picture and a streamed movie, which is assumed to have
//	a video track. QTSplicer_SpliceImageOntoStream is designed to splice the selected picture onto the beginning of
//	the streamed movie, so that that picture appears in place of the standard QuickTime pre-preroll sequence, for a
//	user-specified duration.
//
//	QTSplicer_SpliceImageOverStream has a slightly different purpose. It prompts the user for a picture and a streamed
//	movie, which is assumed to have no video track. QTSplicer_SpliceImageOverStream is designed to splice the picture
//	over the streamed track for the entire duration of the streamed movie. You might want to do this to add a graphic
//	to a streamed radio broadcast or to a streamed music selection.
//
//////////

#include "QTStreamSplicer.h"


//////////
//
// QTSplicer_SpliceImageOntoStream
//
// Prompt the user for an image file and a streamed movie; then splice the image
// onto the front of the stream, for a specific duration; save the new spliced movie.
//
// This function contains the user interface for getting the input image and movie,
// the output spliced movie location, and the desired splicing settings. The function
// QTSplicer_CreateSplicedOntoMovie does all the nitty-gritty movie creation stuff.
//
//////////

OSErr QTSplicer_SpliceImageOntoStream (void)
{
	FSSpec					myImageSpec;
	FSSpec					myStreamSpec;
	FSSpec					myMovieSpec;
	Movie					myMovie = NULL;
	Boolean					isScaleImage = false;
	Boolean					isSelfContained = false;
	Boolean					gotImage = false;
	Boolean					gotStream = false;
	short					myResID = movieInDataForkResID;
	short					myRefNum = 0;
	DialogPtr				myDialog = NULL;
	DialogItemIndex			myItem = 0;
	DialogItemType			myItemType;
	Handle					myItemHandle = NULL;
	Rect					myItemRect;
	long					myImageDuration;
	Str255					myDurationString;
	FSSpec					myFSSpec;
	OSType 					myTypeList[] = {kQTFileTypeMovie};
	short					myNumTypes = 1;
	QTFrameFileFilterUPP	myFileFilterUPP = NULL;
	OSErr					myErr = noErr;

#if TARGET_OS_MAC
	myNumTypes = 0;
#endif

	myFileFilterUPP = QTFrame_GetFileFilterUPP((ProcPtr)QTFrame_FilterFiles);
	
	// prompt the user for the image file to splice onto the stream
	do {
		myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP);
		if (myErr == noErr) {
			if (QTUtils_IsImageFile(&myFSSpec)) {
				myImageSpec = myFSSpec;
				gotImage = true;
			}
		} else {
			break;		// if the user cancelled
		}					
	} while (!gotImage);
	
	// prompt the user for the live stream file to splice onto the end of the created movie
	do {
		myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP);
		if (myErr == noErr) {
			if (QTSplicer_FileContainsStream(myFSSpec)) {
				myStreamSpec = myFSSpec;
				gotStream = true;
			}
		} else {
			break;		// if the user cancelled
		}
	} while (!gotStream);
	
	if (myFileFilterUPP != NULL)
		DisposeNavObjectFilterUPP(myFileFilterUPP);

	// make sure we have both an image and a stream
	if (!gotStream || !gotImage)
		goto bail;

	// get the desired splicing settings; open up the Splicer dialog box
	myDialog = GetNewDialog(kSpliceOntoDialogID, NULL, (WindowPtr)-1L);
	if (myDialog == NULL)
		goto bail;
		
	SetDialogDefaultItem(myDialog, kSpliceButtonDone);
	MacShowWindow(GetDialogWindow(myDialog));
		
	do {
		ModalDialog(NULL, &myItem);
		if ((myItem == kSpliceScaleCheckbox) || (myItem == kSelfContainedCheckbox)) {
			Boolean			myValue;
			
			GetDialogItem(myDialog, myItem, &myItemType, &myItemHandle, &myItemRect);
			myValue = (Boolean)GetControlValue((ControlHandle)myItemHandle);
			SetControlValue((ControlHandle)myItemHandle, !myValue);
		}
	} while (myItem != kSpliceButtonDone);
	
	// set the isScaleImage variable depending on the state of the kSpliceScaleCheckbox item
	GetDialogItem(myDialog, kSpliceScaleCheckbox, &myItemType, &myItemHandle, &myItemRect);
	isScaleImage = (Boolean)GetControlValue((ControlHandle)myItemHandle);
	
	// set the isSelfContained variable depending on the state of the kSelfContainedCheckbox item
	GetDialogItem(myDialog, kSelfContainedCheckbox, &myItemType, &myItemHandle, &myItemRect);
	isSelfContained = (Boolean)GetControlValue((ControlHandle)myItemHandle);
	
	// get the desired image duration from the kSpliceDuration item
	GetDialogItem(myDialog, kSpliceDuration, &myItemType, &myItemHandle, &myItemRect);
	GetDialogItemText(myItemHandle, myDurationString);
	StringToNum(myDurationString, &myImageDuration);
	
	DisposeDialog(myDialog);

	// prompt the user for the location of the output spliced movie
	{
		FSSpec				myFile;
		Boolean				myIsSelected = false;
		Boolean				myIsReplacing = false;	
		StringPtr 			myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveSplicePrompt);
		StringPtr 			myMovieFileName = QTUtils_ConvertCToPascalString(kSaveSpliceFileName);

		QTFrame_PutFile(myMoviePrompt, myMovieFileName, &myFile, &myIsSelected, &myIsReplacing);
		if (!myIsSelected)
			goto bail;				// deal with user cancelling

		if (myIsReplacing)
			DeleteMovieFile(&myFile);

		myMovieSpec = myFile;

		free(myMoviePrompt);
		free(myMovieFileName);

		// create a movie file for the destination ("spliced") movie
		myErr = CreateMovieFile(&myMovieSpec, FOUR_CHAR_CODE('TVOD'), smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &myRefNum, &myMovie);
		if (myErr != noErr)
			goto bail;
	}
	
	// now create a movie that contains the image file and the stream spliced together
	myErr = QTSplicer_CreateSplicedOntoMovie(myImageSpec, myStreamSpec, myMovie, isScaleImage, isSelfContained, myImageDuration * kOneSecond);
	if (myErr != noErr)
		goto bail;
		
	// put the movie resource into the file
	myErr = AddMovieResource(myMovie, myRefNum, &myResID, NULL);
		
bail:
	if (myRefNum != 0)
		CloseMovieFile(myRefNum);
	
	if (myMovie != NULL)
		DisposeMovie(myMovie);
	
	return(myErr);
}


//////////
//
// QTSplicer_SpliceImageOverStream
//
// Prompt the user for an image file and a streamed movie, which is a sound-only stream;
// then splice the image over the stream, for the duration of the stream; save the new spliced movie.
//
// This function contains the user interface for getting the input image and movie,
// the output spliced movie location, and the desired splicing settings. The function
// QTSplicer_CreateSplicedOverMovie does all the nitty-gritty movie creation stuff.
//
//////////

OSErr QTSplicer_SpliceImageOverStream (void)
{
	FSSpec					myImageSpec;
	FSSpec					myStreamSpec;
	FSSpec					myMovieSpec;
	Movie					myMovie = NULL;
	Boolean					isScaleImage = false;
	Boolean					isSelfContained = false;
	Boolean					gotImage = false;
	Boolean					gotStream = false;
	short					myResID = movieInDataForkResID;
	short					myRefNum = 0;
	DialogPtr				myDialog = NULL;
	DialogItemIndex			myItem = 0;
	DialogItemType			myItemType;
	Handle					myItemHandle = NULL;
	Rect					myItemRect;
	long					myImageHeight;
	long					myImageWidth;
	Str255					myHeightString;
	Str255					myWidthString;
	FSSpec					myFSSpec;
	OSType 					myTypeList[] = {kQTFileTypeMovie};
	short					myNumTypes = 1;
	QTFrameFileFilterUPP	myFileFilterUPP = NULL;
	OSErr					myErr = noErr;

#if TARGET_OS_MAC
	myNumTypes = 0;
#endif

	myFileFilterUPP = QTFrame_GetFileFilterUPP((ProcPtr)QTFrame_FilterFiles);
	
	// prompt the user for the image file to splice onto the stream
	do {
		myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP);
		if (myErr == noErr) {
			if (QTUtils_IsImageFile(&myFSSpec)) {
				myImageSpec = myFSSpec;
				gotImage = true;
			}
		} else {
			break;		// if the user cancelled
		}					
	} while (!gotImage);
	
	// prompt the user for the live stream file to splice under the image file
	do {
		myErr = QTFrame_GetOneFileWithPreview(myNumTypes, (QTFrameTypeListPtr)myTypeList, &myFSSpec, myFileFilterUPP);
		if (myErr == noErr) {
			if (QTSplicer_FileContainsStream(myFSSpec)) {
				myStreamSpec = myFSSpec;
				gotStream = true;
			}
		} else {
			break;		// if the user cancelled
		}					
	} while (!gotStream);
		
	// make sure we have both an image and a stream
	if (!gotStream || !gotImage)
		goto bail;

	// get the desired splicing settings; open up the Splicer dialog box
	myDialog = GetNewDialog(kSpliceOverDialogID, NULL, (WindowPtr)-1L);
	if (myDialog == NULL)
		goto bail;
		
	SetDialogDefaultItem(myDialog, kSpliceButtonDone);
	MacShowWindow(GetDialogWindow(myDialog));
		
	do {
		ModalDialog(NULL, &myItem);
		if ((myItem == kSpliceScaleCheckbox) || (myItem == kSelfContainedCheckbox)) {
			Boolean			myValue;
			
			GetDialogItem(myDialog, myItem, &myItemType, &myItemHandle, &myItemRect);
			myValue = (Boolean)GetControlValue((ControlHandle)myItemHandle);
			SetControlValue((ControlHandle)myItemHandle, !myValue);
		}
	} while (myItem != kSpliceButtonDone);
	
	// set the isScaleImage variable depending on the state of the kSpliceScaleCheckbox item
	GetDialogItem(myDialog, kSpliceScaleCheckbox, &myItemType, &myItemHandle, &myItemRect);
	isScaleImage = (Boolean)GetControlValue((ControlHandle)myItemHandle);
	
	// set the isSelfContained variable depending on the state of the kSelfContainedCheckbox item
	GetDialogItem(myDialog, kSelfContainedCheckbox, &myItemType, &myItemHandle, &myItemRect);
	isSelfContained = (Boolean)GetControlValue((ControlHandle)myItemHandle);
	
	if (isScaleImage) {
		// get the desired image width from the kSpliceWidth item
		GetDialogItem(myDialog, kSpliceWidth, &myItemType, &myItemHandle, &myItemRect);
		GetDialogItemText(myItemHandle, myWidthString);
		StringToNum(myWidthString, &myImageWidth);
		
		// get the desired image height from the kSpliceHeight item
		GetDialogItem(myDialog, kSpliceHeight, &myItemType, &myItemHandle, &myItemRect);
		GetDialogItemText(myItemHandle, myHeightString);
		StringToNum(myHeightString, &myImageHeight);
	}
	
	DisposeDialog(myDialog);

	// prompt the user for the location of the output spliced movie
	{
		FSSpec				myFile;
		Boolean				myIsSelected = false;
		Boolean				myIsReplacing = false;	
		StringPtr 			myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveSplicePrompt);
		StringPtr 			myMovieFileName = QTUtils_ConvertCToPascalString(kSaveSpliceFileName);

		QTFrame_PutFile(myMoviePrompt, myMovieFileName, &myFile, &myIsSelected, &myIsReplacing);
		if (!myIsSelected)
			goto bail;				// deal with user cancelling

		if (myIsReplacing)
			DeleteMovieFile(&myFile);

		myMovieSpec = myFile;

		free(myMoviePrompt);
		free(myMovieFileName);

		// create a movie file for the destination ("spliced") movie
		myErr = CreateMovieFile(&myMovieSpec, FOUR_CHAR_CODE('TVOD'), smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &myRefNum, &myMovie);
		if (myErr != noErr)
			goto bail;
	}
	
	// now create a movie that contains the image file and the stream spliced together
	myErr = QTSplicer_CreateSplicedOverMovie(myImageSpec, myStreamSpec, myMovie, isScaleImage, isSelfContained, myImageHeight, myImageWidth);
	if (myErr != noErr)
		goto bail;
		
	// put the movie resource into the file
	myErr = AddMovieResource(myMovie, myRefNum, &myResID, NULL);
		
bail:
	if (myRefNum != 0)
		CloseMovieFile(myRefNum);
	
	if (myMovie != NULL)
		DisposeMovie(myMovie);
	
	return(myErr);
}


//////////
//
// QTSplicer_CreateSplicedOntoMovie
//
// Create a movie file that contains the specified movie, with the specified image
// spliced onto the front for the specified duration.
//
//////////

OSErr QTSplicer_CreateSplicedOntoMovie (FSSpec theImageSpec, FSSpec theMovieSpec, Movie theSplicedMovie, Boolean isScaleImage, Boolean isSelfContained, long theImageDuration)
{
	short						myRefNum = kInvalidFileRefNum;
	short						myResID = 0;
	Movie						myMovie = NULL;
	MovieController				mySplicedController = NULL;
	Rect						myStreamBox, myImageRect;
	GraphicsImportComponent		myImporter = NULL;
	GWorldPtr					myImageGWorld = NULL;
	ComponentResult				myErr = noErr;
				
	// open the streamed movie file
	myErr = OpenMovieFile(&theMovieSpec, &myRefNum, fsRdPerm);
	if (myErr != noErr)
		goto bail;

	myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
	if (myErr != noErr)
		goto bail;
	
	// find out the size of the streamed movie
	GetMovieBox(myMovie, &myStreamBox);
	
	// get a graphics importer for the image file
	myErr = GetGraphicsImporterForFile(&theImageSpec, &myImporter);
	if (myErr != noErr)
		goto bail;
				
	// get the size of the image
	if (isScaleImage) {
		myImageRect = myStreamBox;
		MacOffsetRect(&myImageRect, -myStreamBox.left, -myStreamBox.top);
	} else {
		GraphicsImportGetBoundsRect(myImporter, &myImageRect);
	}

	// allocate a new GWorld to draw the image into
	myErr = QTNewGWorld(&myImageGWorld, 32, &myImageRect, NULL, NULL, kICMTempThenAppMemory);
	if (myErr != noErr) {
		if (myImporter != NULL)
			CloseComponent(myImporter);
		goto bail;
	}
	
	// draw the picture into the GWorld
	GraphicsImportSetGWorld(myImporter, myImageGWorld, NULL);
	GraphicsImportSetBoundsRect(myImporter, &myImageRect);
	GraphicsImportDraw(myImporter);
	
	// close the graphics importer component
	if (myImporter != NULL)
		CloseComponent(myImporter);
	
	// create a controller for the spliced movie
	mySplicedController = NewMovieController(theSplicedMovie, &myStreamBox, 0);
	
	// make sure we can edit this movie
	MCEnableEditing(mySplicedController, true);
		
	// paste the still image into the spliced movie as a new video track
	myErr = QTSplicer_AddVideoTrackFromGWorld(&theSplicedMovie, myImageGWorld, myImageRect.right - myImageRect.left, myImageRect.bottom - myImageRect.top, theImageDuration);
	if (myErr != noErr)
		goto bail;

	// go to the end of the spliced movie; this jumps past the first track,
	// which we have just pasted into the spliced movie.
	QTSplicer_SetCurrentTime(mySplicedController, GetMovieDuration(theSplicedMovie));

	if (isSelfContained) {
		Track			mySrcTrack = NULL;
		Track			myDstTrack = NULL;
		Media			myDstMedia = NULL;
		Fixed			myWidth, myHeight;
		
		mySrcTrack = GetMovieIndTrackType(myMovie, 1, kQTSStreamMediaType, movieTrackMediaType);
		if (mySrcTrack == NULL)
			goto bail;
		
		GetTrackDimensions(mySrcTrack, &myWidth, &myHeight);
		
		myDstTrack = NewMovieTrack(theSplicedMovie, myWidth, myHeight, kNoVolume);
		if (myDstTrack == NULL)
			goto bail;
		
		myDstMedia = NewTrackMedia(myDstTrack, kQTSStreamMediaType, GetMovieTimeScale(theSplicedMovie), NULL, 0);
		if (myDstTrack == NULL)
			goto bail;
		
		myErr = BeginMediaEdits(myDstMedia);
		if (myErr != noErr)
			goto bail;
		
		myErr = CopyTrackSettings(mySrcTrack, myDstTrack);
		if (myErr != noErr)
			goto bail;
		
		myErr = InsertTrackSegment(mySrcTrack, myDstTrack, 0, (0x7FFFFFFF - GetMovieDuration(theSplicedMovie)), GetMovieDuration(theSplicedMovie));
		if (myErr != noErr)
			goto bail;
		
		myErr = EndMediaEdits(myDstMedia);
		if (myErr != noErr)
			goto bail;
	} else {
		// insert the streamed movie after the image track
		myErr = InsertMovieSegment(myMovie, theSplicedMovie, 0, (0x7FFFFFFF - GetMovieDuration(theSplicedMovie)), GetMovieDuration(theSplicedMovie));
		if (myErr != noErr)
			goto bail;
	}
	
	// select none on the resulting movie
	QTSplicer_SetSelectionTimes(mySplicedController, 0, 0);
	
	// go to the start of the spliced movie
	QTSplicer_SetCurrentTime(mySplicedController, 0);
	
bail:
	if (myRefNum != 0)
		CloseMovieFile(myRefNum);

	if (myImageGWorld != NULL) {
		DisposeGWorld(myImageGWorld);
		myImageGWorld = NULL;
	}
	
	if (mySplicedController != NULL) {
		DisposeMovieController(mySplicedController);
	}
	
	return(myErr);
}


//////////
//
// QTSplicer_CreateSplicedOverMovie
//
// Create a movie file that contains the specified movie, with the specified image as the video track.
//
//////////

OSErr QTSplicer_CreateSplicedOverMovie (FSSpec theImageSpec, FSSpec theMovieSpec, Movie theSplicedMovie, Boolean isScaleImage, Boolean isSelfContained, long theImageHeight, long theImageWidth)
{
	short						myRefNum = kInvalidFileRefNum;
	short						myResID = 0;
	Movie						myMovie = NULL;
	MovieController				mySplicedController = NULL;
	Rect						myImageRect;
	GraphicsImportComponent		myImporter = NULL;
	GWorldPtr					myImageGWorld = NULL;
	Track						mySrcTrack = NULL;
	Track						myDstTrack = NULL;
	Media						myDstMedia = NULL;
	Fixed						myWidth, myHeight;
	ComponentResult				myErr = noErr;
				
	// open the streamed movie file
	myErr = OpenMovieFile(&theMovieSpec, &myRefNum, fsRdPerm);
	if (myErr != noErr)
		goto bail;

	myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
	if (myErr != noErr)
		goto bail;
	
	// get a graphics importer for the image file
	myErr = GetGraphicsImporterForFile(&theImageSpec, &myImporter);
	if (myErr != noErr)
		goto bail;
				
	// get the size of the image
	if (isScaleImage) {
		myImageRect.top = 0;
		myImageRect.left = 0;
		myImageRect.bottom = (short)theImageHeight;
		myImageRect.right = (short)theImageWidth;
	} else {
		GraphicsImportGetBoundsRect(myImporter, &myImageRect);
	}

	// allocate a new GWorld to draw the image into
	myErr = QTNewGWorld(&myImageGWorld, 32, &myImageRect, NULL, NULL, kICMTempThenAppMemory);
	if (myErr != noErr) {
		if (myImporter != NULL)
			CloseComponent(myImporter);
		goto bail;
	}
	
	// draw the picture into the GWorld
	GraphicsImportSetGWorld(myImporter, myImageGWorld, NULL);
	GraphicsImportSetBoundsRect(myImporter, &myImageRect);
	GraphicsImportDraw(myImporter);
	
	// close the graphics importer component
	if (myImporter != NULL)
		CloseComponent(myImporter);
	
	// create a controller for the spliced movie
	mySplicedController = NewMovieController(theSplicedMovie, &myImageRect, 0);
	
	// make sure we can edit this movie
	MCEnableEditing(mySplicedController, true);
		
	// paste the still image into the spliced movie as a new video track
	myErr = QTSplicer_AddVideoTrackFromGWorld(&theSplicedMovie, myImageGWorld, myImageRect.right - myImageRect.left, myImageRect.bottom - myImageRect.top, GetMovieDuration(myMovie));
	if (myErr != noErr)
		goto bail;
			
	//////////
	//
	// copy over the streamed track
	//
	//////////
	
	mySrcTrack = GetMovieIndTrackType(myMovie, 1, kQTSStreamMediaType, movieTrackMediaType);
	if (mySrcTrack == NULL)
		goto bail;
	
	GetTrackDimensions(mySrcTrack, &myWidth, &myHeight);
	
	myDstTrack = NewMovieTrack(theSplicedMovie, myWidth, myHeight, kNoVolume);
	if (myDstTrack == NULL)
		goto bail;
	
	myDstMedia = NewTrackMedia(myDstTrack, kQTSStreamMediaType, GetMovieTimeScale(theSplicedMovie), NULL, 0);
	if (myDstTrack == NULL)
		goto bail;
	
	if (isSelfContained)
		BeginMediaEdits(myDstMedia);
	
	myErr = CopyTrackSettings(mySrcTrack, myDstTrack);
	if (myErr != noErr)
		goto bail;
	
	myErr = InsertTrackSegment(mySrcTrack, myDstTrack, 0, GetMovieDuration(myMovie), 0);
	if (myErr != noErr)
		goto bail;
	
	if (isSelfContained)
		EndMediaEdits(myDstMedia);
	
	// select none on the resulting movie
	QTSplicer_SetSelectionTimes(mySplicedController, 0, 0);
	
	// go to the start of the spliced movie
	QTSplicer_SetCurrentTime(mySplicedController, 0);
	
bail:
	if (myRefNum != 0)
		CloseMovieFile(myRefNum);

	if (myImageGWorld != NULL) {
		DisposeGWorld(myImageGWorld);
		myImageGWorld = NULL;
	}
	
	if (mySplicedController != NULL) {
		DisposeMovieController(mySplicedController);
	}
	
	return(myErr);
}


//////////
//
// QTSplicer_FileContainsStream
//
// Determine whether the specified movie file contains a streaming track.
//
// Returns true iff the file is a movie file that has at least one streaming
// track in it, false otherwise.
//
//////////

Boolean QTSplicer_FileContainsStream (FSSpec theMovieFile)
{
	short		myRefNum = 0;
	short		myResID = 0;
	Movie		myMovie = NULL;
	Boolean		myResult = false;
	OSErr		myErr = noErr;

	myErr = OpenMovieFile(&theMovieFile, &myRefNum, fsRdPerm);
	if (myErr != noErr)
		goto bail;
		
	myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
	if (myErr != noErr)
		goto bail;
	
	if (GetMovieIndTrackType(myMovie, 1, kQTSStreamMediaType, movieTrackMediaType) != NULL)
		myResult = true;
	
bail:
	if (myRefNum != 0)
		CloseMovieFile(myRefNum);

	return(myResult);
}


//////////
//
// QTSplicer_SetSelectionTimes
//
// Set the movie selection to the specified times.
//
//////////

OSErr QTSplicer_SetSelectionTimes (MovieController theController, TimeValue theTime1, TimeValue theTime2)
{
	TimeRecord 			myTimeRecord;
	Movie				myMovie = MCGetMovie(theController);
	ComponentResult		myErr = noErr;
	
	myTimeRecord.value.hi = 0;
	myTimeRecord.value.lo = theTime1;
	myTimeRecord.base = 0;
	myTimeRecord.scale = GetMovieTimeScale(myMovie);
	myErr = MCDoAction(theController, mcActionSetSelectionBegin, &myTimeRecord);
	if (myErr != noErr)
		goto done;
	
	myTimeRecord.value.lo = theTime2 - theTime1;

	myErr = MCDoAction(theController, mcActionSetSelectionDuration, &myTimeRecord);
	
done:
	return((OSErr)myErr);
}


//////////
//
// QTSplicer_SetCurrentTime
//
// Set the movie current time to the specified time.
//
//////////

OSErr QTSplicer_SetCurrentTime (MovieController theController, TimeValue theTime)
{
	TimeRecord 			myTimeRecord;
	Movie				myMovie = MCGetMovie(theController);
	ComponentResult		myErr = noErr;
	
	myTimeRecord.value.hi = 0;
	myTimeRecord.value.lo = theTime;
	myTimeRecord.base = GetMovieTimeBase(myMovie);
	myTimeRecord.scale = GetMovieTimeScale(myMovie);
	myErr = MCDoAction(theController, mcActionGoToTime, &myTimeRecord);

	return((OSErr)myErr);
}


//////////
//
// QTSplicer_AddVideoTrackFromGWorld
//
// Add to the specified movie a video track, using the image in the specified GWorld.
//
//////////

OSErr QTSplicer_AddVideoTrackFromGWorld (Movie *theMovie, GWorldPtr theGW, short theWidth, short theHeight, long theImageDuration)
{
	Track						myTrack = NULL;
	Media						myMedia = NULL;
	ImageDescriptionHandle		myDesc = NULL;
	Rect						myRect;
	long						mySize;
	Handle						myData = NULL;
	Ptr							myDataPtr = NULL;
	PixMapHandle				myDstPixMap = NULL;
	OSErr						myErr = noErr;
	
	// create a video track in the movie
	myTrack = NewMovieTrack(*theMovie, FixRatio(theWidth, 1), FixRatio(theHeight, 1), kNoVolume);
	myMedia = NewTrackMedia(myTrack, VideoMediaType, kOneSecond, NULL, 0);
	
	myRect.top = 0;
	myRect.left = 0;
	myRect.right = theWidth;
	myRect.bottom = theHeight;
	
	// begin editing the new track
	BeginMediaEdits(myMedia);

	// create a new image description; CompressImage will fill in the fields of this structure
	myDesc = (ImageDescriptionHandle)NewHandle(4);
	
	myDstPixMap = GetGWorldPixMap(theGW);
	LockPixels(myDstPixMap);
	
	myErr = GetMaxCompressionSize(myDstPixMap, &myRect, 0, codecNormalQuality, kAnimationCodecType, anyCodec, &mySize);
	if (myErr != noErr)
		goto bail;
		
	myData = NewHandle(mySize);
	if (myData == NULL)
		goto bail;
		
	HLockHi(myData);
#if TARGET_CPU_68K
	myDataPtr = StripAddress(*myData);
#else
	myDataPtr = *myData;
#endif
	
	myErr = CompressImage(myDstPixMap, &myRect, codecNormalQuality, kAnimationCodecType, myDesc, myDataPtr);
	if (myErr != noErr)
		goto bail;
		
	myErr = AddMediaSample(myMedia, myData, 0, (**myDesc).dataSize, theImageDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL);
	if (myErr != noErr)
		goto bail;

	myErr = EndMediaEdits(myMedia);
	if (myErr != noErr)
		goto bail;

	myErr = InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
	
bail:
	if (myData != NULL) {
		HUnlock(myData);
		DisposeHandle(myData);
	}

	if (myDesc != NULL)
		DisposeHandle((Handle)myDesc);
		
	if (myDstPixMap != NULL)
		UnlockPixels(myDstPixMap);
	
	return(myErr);
}
