TweetFollow Us on Twitter

Jan 00 QTToolkit

Volume Number: 16 (2000)
Issue Number: 1
Column Tag: QuickTime Toolkit

QuickTime Toolkit

by Tim Monroe

Using Movie Controllers for QuickTime Movie Playback and Editing

The State of the Art

It's been almost ten years since Apple introduced QuickTime, its software architecture for creating and playing back multimedia content. In that time, QuickTime has progressed from a Mac-only tool for playing movies roughly the size of postage stamps into the de facto standard on Macintosh and Windows computers for the creation, delivery, and playback of digital media, including video, sound, music, 3D graphics, virtual reality, sprite animation, and more. The range of abilities that QuickTime has gained over the years is truly staggering. It now supports real-time streaming of audio and video over the Internet and LANs, a full-featured video effects and transitions architecture, vector drawing capabilities, and the ability to associate actions to sprites, text, hot spots in QuickTime VR movies, and 3D objects.

It's high time, then, that MacTech should begin to devote some regular space to discussing QuickTime from a programmer's point of view, and this is the first of a series of articles that will focus on using the QuickTime application programming interfaces to create and play back digital media. Given the wide range of capabilities provided by the QuickTime APIs, you can guess that there will be no shortage of topics for us to investigate over the coming months and years. Admittedly, QuickTime can perhaps be a bit overwhelming if you try to understand it all at once. So we'll adopt a fairly leisurely approach and try to dissect the QuickTime architecture a little bit at a time, starting with its high-level interfaces and then gradually working down to lower-level capabilities to add to our knowledge of the entire architecture. Eventually, we'll be creating QuickTime files and writing custom QuickTime components just like the pros.

In this article, we'll learn how to open and display QuickTime movies, and how to manage the user's interactions with those movies (such as starting and pausing movies, zooming in and out in QuickTime VR movies, and similar operations). This is a relatively simple task, and it's one that involves adding a fairly small amount of code to a basic working application. So, to really earn our money today, we're going to complicate things. In addition to showing how to support basic movie playback and editing in a Macintosh application, we're also going to show how to do it in an application that runs on Microsoft Windows. In other words, we want the code we write here to compile and execute both on the Macintosh operating system and on the major flavors of the Windows operating system (to wit: Windows 95, Windows 98, and Windows NT).

Now this might sound like heresy, especially for a publication like MacTech whose mission is to report on and facilitate software development for Macintosh computers. But it's really just as consistent with MacTech's mission as its regular coverage of the Internet or of Java and other cross-platform languages and tools. Moreover, it's fair to say that the cross-platform parity exhibited by the QuickTime application programming interfaces since version 3.0 is largely responsible for QuickTime's recent explosion in popularity and is crucial for its continued success. So, everything we're going to do in these articles will be completely cross-platform.

In point of fact, however, once you learn to pay attention to a few recurring issues like the endianness of multi-byte data, writing QuickTime code that is compatible with multiple platforms really isn't so hard. Indeed, part of the reason that QuickTime runs so well on Windows is that a good bit of the Macintosh programming concepts (including handles, resources, and file system specifications) were implemented on Windows as part of the QuickTime Media Layer. The hardest part of getting your QuickTime code to run on Windows may simply be creating a basic application shell or framework to hold that code. Accordingly, we'll spend a good bit of time in this article discussing just that issue.

Movie Controllers

Before we start looking at our source code, however, let's take a minute to make clear what it is that we want to achieve. For the moment, we'll be content to build an application that can open and display QuickTime movies in windows on the screen. The Windows version of our basic application will have a "frame window" that contains a menu bar and within which we can open and display one or more movie windows. Figure 1 shows the appearance of the application's frame window before the user has opened any QuickTime movies.

Figure 1.The frame window of the Windows application

A movie window will contain all the standard window parts (in particular, a title bar and close box), the movie itself, and a special set of controls called the movie controller bar. Figure 2 shows a typical Macintosh movie window, and Figure 3 shows a Windows version of the same movie window. Both of these windows show the standard movie controller bar along the bottom edge of the window.

Figure 2.A movie window on the Macintosh.

Figure 3.A movie window on Windows.

The movie controller bar allows the user to control the playback of the movie and to navigate within it. For instance, the user can use the fast-forward button to play the movie forward at an accelerated rate. Or, the user can drag the position thumb to set the current location in the movie.

Some kinds of QuickTime movies use a different movie controller bar. For instance, QuickTime VR movies are not typically played frame-by-frame in a linear fashion. For these movies, you'll see the movie controller bar shown in Figure 4, which contains controls that allow the user to zoom in and out and to perform other operations on the movie.

Figure 4.The movie controller bar for a QuickTime VR movie.

The movie controller bar is created and managed by a software component called a movie controller component (or, more briefly, a movie controller). Now here's the really fun part: once you've opened a QuickTime movie (using a few simple QuickTime functions), you can call a couple more functions to create and attach a movie controller to your movie. Thereafter, the movie controller (and not your application) draws the movie controller bar and manages all events associated with the movie. Your application doesn't need to know how to jump to a new location in the movie or how to start and stop the movie playback. It simply needs to pass any events it receives to the movie controller component before acting on them itself. The movie controller intercepts any events that apply to it and reacts to them appropriately.

So, the first lesson we need to take to heart is this: we can get all the basic movie playback capabilities simply by creating a movie controller, attaching it to our movie, and then giving it the first shot at handling any events we receive. And as if that weren't enough, the movie controller also provides an extremely easy way for us to perform basic editing operations on movies that support them. (Not all movies support cutting, copying, or pasting of movie segments; for instance, QuickTime VR movies do not.)

The Application Framework

Now it's time for a bit of a detour. As mentioned earlier, QuickTime provides an extensive set of services for handling digital media like sound, video, sprite animation, and the like. But of course we'll need to use other services to handle the basic graphical user interface for our QuickTime-savvy application (windows, menus, dialog boxes, and so forth). Since you're an experienced Macintosh programmer, you're already familiar with the ideas underlying event-driven programming on the Macintosh. Remember, though, that we want to support QuickTime programming on both Macintosh and Windows systems. So we'll need to address separately the issues specific to each operating system, while trying to factor out as much code as possible to share between the two systems.

Our general approach will go like this: we'll create two files, MacFramework.c and WinFramework.c, that handle the basic application services that are specific to the Macintosh and Windows operating systems, respectively. These services include starting up and shutting down the application, handling events and messages, creating windows, opening files dropped onto the application icon, and so forth. We won't delve very much into these framework files in this article, since there isn't very much in them of interest for QuickTime programmers. Suffice it to say that the Macintosh framework would look very familiar to anyone who cut their Mac programming eyeteeth on MacTech's "Getting Started" series (or on some similarly good source); it uses standard event-driven programming techniques to handle the user's actions. And the Windows framework is a very straightforward implementation of the multiple document interface (MDI) specification defined by Microsoft for creating and managing one or more document windows within a general frame window.

What's distinctive about MacFramework.c and WinFramework.c is that they have been carefully designed to call functions defined in a third file, ComFramework.c, for most QuickTime services or other services that are not system-specific. ComFramework.c also defines a number of functions that are substantially the same on both platforms but which may require several short platform-dependent blocks (introduced by the compiler flags TARGET_OS_MAC and TARGET_OS_WIN32).

Keep in mind that (in this article, at least) we want to support only the most basic playback and editing of QuickTime movies, which is exactly what is provided by the basic framework. In future articles, however, we'll want to add other capabilities to our applications. For instance, we'll want to handle some new menus, in addition to the standard File and Edit menus; and we'll want to perform some application-specific tasks at idle time (perhaps change the pan angle of a QuickTime VR movie). To make it easy to add such capabilities, we create yet another file, called ComApplication.c, which defines a number of functions that are called at particular times by the basic framework. For instance, after the framework does any necessary menu adjusting for the File and Edit menus (enabling certain menu items and disabling others), it calls the function QTApp_AdjustMenus, defined in ComApplication.c, to allow us to adjust any application-specific menus. Since we don't have any application-specific tasks to perform, for the moment at least, we can ignore ComApplication.c and instead turn our attention to the file ComFramework.c.

Handling Movie Windows

To get a taste for how our basic framework works, let's begin by considering how we want to manage our application's movie windows. On the Macintosh, a movie window is of type WindowPtr; on Windows, a movie window is of type HWND. To simplify the code that handles movie windows, we define a custom type that refers to either a Macintosh movie window or a Windows movie window, like this:

typedef WindowPtr				WindowReference;
typedef HWND						WindowReference;

We need to maintain some information for each movie window displayed by our application. We'll use the standard technique of defining a structure to hold this information and allocating an instance of that structure for each open movie window. Let's call this instance a "window object record".

typedef struct {
	WindowReference				fWindow;
	Movie								fMovie;
	MovieController 			fController;
	FSSpec								fFileFSSpec;
	short								fFileResID;
	short								fFileRefNum;
	Boolean							fCanResizeWindow;
	Boolean							fIsDirty;
	Boolean							fIsQTVRMovie;
	QTVRInstance					fInstance;
	OSType								fObjectType;
	Handle								fAppData;
} WindowObjectRecord,		*WindowObjectPtr, **WindowObject;

Notice that the first field of this structure, fWindow, is of type WindowReference, which (as you've just seen) is a WindowPtr on the Mac and an HWND on Windows. The fMovie and fController fields identify the movie and movie controller. The next three fields maintain information about the location of the movie file on disk and in memory. The three fields after that indicate whether the movie window can be resized (which is almost always true), whether the movie data has changed since it was opened or last saved, and whether the movie is a QuickTime VR movie. If the movie is a QuickTime VR movie, the fInstance field holds the QTVR instance associated with the movie. The fObjectType field holds an arbitrary identifier that is unique to our application; we use this field just to make sure that we've got a valid window object. Finally, the fAppData field holds a handle to any application-specific data. For now, we won't need to use this field.

When the user selects a movie file to open, we need to allocate a window object record and attach it to the window in which the movie is opened. The standard Macintosh way to do this is to use the SetWRefCon function to set the window's reference constant, an application-specific 32-bit value, to the handle to the window object record. Windows provides a similar capability to attach an application-specific 32-bit value to a window, with the SetWindowLong function. Listing 1 shows the code we use for creating a window object.

Listing 1: Creating a window object


void QTFrame_CreateWindowObject (WindowReference theWindow)
	WindowObject			myWindowObject = NULL;

	if (theWindow == NULL)
	// allocate space for a window object record and fill in some of its fields
	myWindowObject = (WindowObject)NewHandleClear(sizeof(WindowObjectRecord));
	if (myWindowObject != NULL) {
		(**myWindowObject).fWindow = theWindow;
		(**myWindowObject).fController = NULL;
		(**myWindowObject).fObjectType = kMovieControllerObject;
		(**myWindowObject).fInstance = NULL;
		(**myWindowObject).fCanResizeWindow = true;
		(**myWindowObject).fIsDirty = false;
		(**myWindowObject).fAppData = NULL;
	// associate myWindowObject (which may be NULL) with the window
	SetWRefCon(theWindow, (long)myWindowObject);
	SetWindowLong(theWindow, GWL_USERDATA, (LPARAM)myWindowObject);
	// associate a GrafPort with this window 
	CreatePortAssociation(theWindow, NULL, 0L);
	// set the current port to the new window

Internally, QuickTime does some of its drawing using QuickDraw, the collection of system software routines that perform graphic operations on the user's screen (and elsewhere). And, as you know, QuickDraw does all of its drawing within the current graphics port. On the Macintosh, there is a very close connection between a WindowPtr and a graphics port, but there is no such connection between Windows HWNDs and graphics ports. So, when our application is running on Windows, we need to call the CreatePortAssociation function to create a connection between the HWND and a graphics port (of type GrafPtr).

Once we've called CreatePortAssociation to associate a graphics port with an HWND, we can subsequently call the GetNativeWindowPort function to get a pointer to the graphics port that was associated with that window. Listing 2 defines a function that we can call from either Macintosh or Windows code to get a window's graphics port. (Now you can understand the last line in Listing 1, which sets the current graphics port to the port associated with the specified window.)

Listing 2: Getting the graphics port associated with a window


GrafPtr QTFrame_GetPortFromWindowReference (WindowReference theWindow)

Let's look briefly at a few other small utilities that we'll use extensively in our framework code. Keep in mind that our general goal here is to provide utilities that insulate us from the specific details of any particular operating system. One thing we'll need to do fairly often is retrieve the window-specific data that we've stored in the window object record associated with a given movie window. We can use the QTFrame_GetWindowObjectFromWindow function, defined in Listing 3 to do this. Aside from a few sanity checks (namely the calls to QTFrame_IsAppWindow and QTFrame_IsWindowObjectOurs), this function is essentially the reverse of attaching the window object record to a window.

Listing 3: Getting the window-specific data associated with a window


WindowObject QTFrame_GetWindowObjectFromWindow (WindowReference theWindow)
	WindowObject		myWindowObject = NULL;

	if (!QTFrame_IsAppWindow(theWindow))
	myWindowObject = (WindowObject)GetWRefCon(theWindow);
	myWindowObject = (WindowObject)GetWindowLong(theWindow, GWL_USERDATA);

	// make sure this is a window object
	if (!QTFrame_IsWindowObjectOurs(myWindowObject))

Finally, we'll often need to iterate through all open movie windows. On Windows, this is fairly simple, since the operating system provides an easy way for us to ask just for the first (or next) child of the MDI frame window, which we know to be a movie window. On the Macintosh, it's a bit harder, since we need to skip over any dialog windows or other types of windows that might be in our window list. We can use the functions QTFrame_GetFrontAppWindow and QTFrame_GetNextAppWindow, defined in Listings 4 and 5, to step through all open windows that belong to our application.

Listing 4: Getting the first application window


WindowReference QTFrame_GetFrontAppWindow (void)
	return(GetWindow(ghWnd, GW_HWNDFIRST));

One thing to notice in Listing 5 is that we did not find the next window by reading the nextWindow field of the window record, as used to be standard practice. Instead, we've used the accessor function GetNextWindow defined in the header file MacWindows.h. Here we're treating the window record as an opaque data structure and thereby facilitating our eventual move to Carbon-compatible APIs.

Listing 5: Getting the next application window


WindowReference QTFrame_GetNextAppWindow (WindowReference theWindow)
	return(theWindow == NULL ? NULL : GetNextWindow(theWindow));
	return(GetWindow(theWindow, GW_HWNDNEXT));

To find the front movie window, on the Macintosh, we'll just walk through the window list until we find the first window with a non-NULL window object attached to it, as shown in Listing 6.

Listing 6: Getting the first movie window


WindowReference QTFrame_GetFrontMovieWindow (void)
	WindowReference			myWindow;

	myWindow = QTFrame_GetFrontAppWindow();
	while ((myWindow != NULL) && (QTFrame_GetWindowObjectFromWindow(myWindow) == NULL))
		myWindow = QTFrame_GetNextAppWindow(myWindow);

	myWindow = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);


And to get the movie window that follows a specific movie window, we'll continue walking through the window list until we find the next window with a non-NULL window object, as shown in Listing 7.

Listing 7: Getting the next movie window


WindowReference QTFrame_GetNextMovieWindow (WindowReference theWindow)
	WindowReference			myWindow;

	myWindow = QTFrame_GetNextAppWindow(theWindow);
	while ((myWindow != NULL) && (QTFrame_GetWindowObjectFromWindow(myWindow) == NULL))
		myWindow = QTFrame_GetNextAppWindow(myWindow);

	myWindow = GetWindow(theWindow, GW_HWNDNEXT);


Handling Menus

Now we want to do the same thing for menus that we've done for windows, namely develop a unified way to refer to menus and menu items, so that we can (for instance) enable and disable menu items, or process the user's selection of menu items, in a platform-neutral manner. Happily, this is a simpler task than the one we just solved.

On the Macintosh, a particular menu item is specified using two pieces of information, the menu ID and the index of the item in the specified menu. On Windows, a menu item is specified by a single 16-bit "menu item identifier", which is an arbitrary value that we associate with the menu item. Because the value on Windows is arbitrary, we'll construct it by setting the high-order 8 bits to the Macintosh menu ID and the low-order 8-bits to the index of the menu item in the menu.

Suppose we use the following values for our resource and menu IDs in our Macintosh resource file:

#define kMenuBarResID					128
#define kAppleMenuResID				128
#define kFileMenuResID					129
#define kEditMenuResID					130

Then we can define our menu item identifiers like this:

#define IDS_FILEMENU					33024	// (kFileMenuResID<<8)+0
#define IDM_FILENEW						33025	// (kFileMenuResID<<8)+1
#define IDM_FILEOPEN					33026
#define IDM_FILECLOSE					33027
#define IDM_FILESAVE					33028
#define IDM_FILESAVEAS					33029
#define IDM_EXIT							33031

#define IDS_EDITMENU					33280	// (kEditMenuResID<<8)+0
#define IDM_EDITUNDO					33281	// (kEditMenuResID<<8)+1
#define IDM_EDITCUT						33283
#define IDM_EDITCOPY					33284
#define IDM_EDITPASTE					33285
#define IDM_EDITCLEAR					33286
#define IDM_EDITSELECTALL			33288

You might be wondering why we didn't just define, for instance, IDS_FILEMENU as (kFileMenuResID<<8)+0. In fact this works fine when developing either Mac or Windows applications using CodeWarrior, but it doesn't seem to work when using Microsoft Developer Studio on Windows machines. Go figure (literally!). Also, for those of you with calculators that don't have a "<<" key, bit-shifting left by 8 is the same as multiplying by 256.

In effect, we're simply adopting the Windows method of specifying menu items, but doing so in a manner that allows us to retrieve the Macintosh menu ID and menu item index from the arbitrary menu item identifier, using these macros:

#define MENU_IDENTIFIER(menuID,menuItem)	((menuID<<8)+(menuItem))
#define MENU_ID(menuIdentifier)				((menuIdentifier&0xff00)>>8)
#define MENU_ITEM(menuIdentifier)			((menuIdentifier&0x00ff))

Now we need to devise a way of referring to menus themselves in a cross-platform way. On the Macintosh, we access menus using variables and parameters of type MenuHandle, while on Windows, we use variables and parameters of type HMENU. Once again, we'll define a custom type that refers to either a Macintosh menu or a Windows menu, like this:

typedef MenuHandle				MenuReference;
typedef HMENU						MenuReference;

Let's see how this all fits together in practice. Suppose we want to enable or disable a particular menu item. For instance, the user may have edited a movie window, in which case we want to make sure that the Undo menu item in the Edit menu is enabled. We can use the function QTFrame_SetMenuItemState defined in Listing 8.

Listing 8: Enabling or disabling a menu item


void QTFrame_SetMenuItemState (MenuReference theMenu, UInt16 theMenuItem, short theState)
	if (theState == kEnableMenuItem)
		EnableMenuItem(theMenu, MENU_ITEM(theMenuItem));
		DisableMenuItem(theMenu, MENU_ITEM(theMenuItem));
	EnableMenuItem(theMenu, (UINT)theMenuItem, (UINT)theState);

On Windows, QTFrame_SetMenuItemState uses the Windows function EnableMenuItem to set the specified menu item to the desired state. On the Macintosh, it calls either of the two Macintosh functions EnableMenuItem or DisableMenuItem, depending on the value of theState.

QuickTime Support

Now let's get back to the task at hand, which is showing how to open and display QuickTime movies, and how to handle basic editing operations on those movies.

Opening a Movie File

Let's suppose that you've already got a file system specification record that indicates which movie file the user wants to open. You might have called the Standard File Package or (on Macintosh) the newer Navigation Services to elicit a file from the user, or you might have gotten the file specification from an Open Document Apple Event. At this point, you can call the function OpenMovieFile to open the movie file:

myErr = OpenMovieFile(&myFSSpec, &myRefNum, fsRdWrPerm);

Next you need to load the movie data from the file. You can do this by calling the NewMovieFromFile function, as follows:

myResID = 0;
myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);

Now you need to create a window in which to display the movie. This operation is platform-specific: on the Macintosh, you can call the NewCWindow function, or on Windows you can call the CreateWindowEx function. Once you've successfully created a window, you just need to pass that window to the QTFrame_CreateWindowObject function defined in Listing 1, which (as you saw) allocates some memory to hold information needed by our frameworks and attaches the window object record to the window.

Attaching a Movie Controller

So, at this point, we've opened the movie file and read the movie data from it. We've also created a window (which is not yet visible), created a window object, and attached the window object to the window. Before we can make the movie window visible, we need to create a movie controller and attach it to the window. We do this by calling the framework function QTFrame_SetupController:

myMC = QTFrame_SetupController(myMovie, myWindow, true);

The QTFrame_SetupController function is a tad lengthy, so we won't show it all here. But it does only four things of any real interest: it creates a new movie controller for the specified movie, it enables movie controller editing, it adds a grow box to the movie controller bar, and it installs a movie controller action filter function. We'll discuss movie editing a little later; for now, let's see how to do the other three tasks.

Before you can create a movie controller, you need to determine the rectangle within which the movie is going to be displayed. Our basic application draws the movie at its natural size, which we can obtain by calling the GetMovieBox function (making sure that the top-left corner of the movie is at 0,0):

GetMovieBox(myMovie, &myRect);
MacOffsetRect(&myRect, -myRect.left,;
SetMovieBox(myMovie, &myRect);

Then we can create a movie controller with this single line of code:

myMC = NewMovieController(myMovie, &myRect, mcTopLeftMovie);

Even though we've opened the move at its natural size, we'd like to allow the user to resize the movie window. By default, the movie controller does not provide this capability, so we need to do a little work to enable movie resizing. The first thing we need to do is find the upper bounds for the movie window size. In other words, we need to find the largest rectangle that can contain a movie window. We could set an arbitrary upper bounds for our movie window size, but instead we'll allow the user to resize a movie to fit as much of the available screen space as possible. On the Macintosh, we can get this area like this:

gMCResizeBounds = (**GetGrayRgn()).rgnBBox;

(This line of code isn't Carbon-compliant, of course. We still have a little bit of work to do before our Macintosh framework is fully Carbonized.) On Windows, we can call the GetDesktopWindow and GetWindowRect functions to get the size of the desktop. Note that GetWindowRect returns a structure of type RECT, which on Windows consists of four long integers. So we need to convert the RECT into a Rect, like this:

RECT				myRect;

GetWindowRect(GetDesktopWindow(), &myRect);
OffsetRect(&myRect, -myRect.left,; = (short);
gMCResizeBounds.left = (short)myRect.left;
gMCResizeBounds.right = (short)myRect.right;
gMCResizeBounds.bottom = (short)myRect.bottom;

Then, we can enable window resizing by calling the MCDoAction function with the mcActionSetGrowBoxBounds parameter:

MCDoAction(myMC, mcActionSetGrowBoxBounds, &gMCResizeBounds);

MCDoAction is a general-purpose tool for getting a movie controller to perform various actions. (If you take a look in the header file Movies.h, you'll see well over 60 defined movie controller actions.) We'll use MCDoAction extensively throughout this series of articles. For the moment, though, it's important to know that before the movie controller performs any action initiated by MCDoAction, it informs your application of the pending action and indeed allows your application to cancel that action. To get these notifications of pending actions, you need to install a movie controller action filter function, like this:

MCSetActionFilterWithRefCon(myMC, NewMCActionFilterWithRefConProc(QTApp_MCActionFilterProc), (long)myWindowObject);

The first parameter is the movie controller to which you want to attach a filter function. The second parameter is a universal procedure pointer for the filter function itself. The third parameter is an application-specific reference constant that is passed to the filter function whenever it is called. As you can see, we're passing the window object to the filter function so that we can gain access to the movie window's data inside that function.

Listing 9 shows a typical movie controller action filter function. This function handles only one action, mcActionControllerSizeChanged, which the movie controller sends to our filter function whenever the user has dragged the resize box in the controller bar. Our job is then to resize the associated movie window.

Listing 9: Intercepting movie controller actions


PASCAL_RTN Boolean QTApp_MCActionFilterProc (MovieController 		theMC, short theAction, void *theParams, long theRefCon)
#pragma unused(theMC, theParams)

	Boolean				isHandled = false;
	WindowObject		myWindowObject = NULL;
	myWindowObject = (WindowObject)theRefCon;
	if (myWindowObject == NULL)
	switch (theAction) {
		// handle window resizing
		case mcActionControllerSizeChanged:

	} // switch (theAction)

A movie controller action filter function should return false as its function result if it wants the movie controller to handle the action specified by the theAction parameter. Conversely, it should return true if it doesn't want the movie controller to handle the action. In the case of the mcActionControllerSizeChanged action, we return false to let the controller do any processing it needs to.

Handling Events

Once we've got a movie file opened in a window and have attached a movie controller to it, we need to let the movie controller handle any events that apply to it. (For instance, if the user hits the space bar, the movie controller should start or stop the movie, depending on its current playing state.) The main thing we need to do is pass the event to the MCIsPlayerEvent function, but how we do this differs between the Mac and Windows platforms.

On Macintosh, we get events in our main event loop by calling WaitNextEvent. When we retrieve an event in this way, we don't know which, if any, movie controller it might apply to. So, we'll just pass the event to all open movie controllers until we find one that accepts it. Listing 10 shows how we do this.

Listing 10: Handling events on the Macintosh


static Boolean QTFrame_CheckMovieControllers (EventRecord *theEvent)
	WindowPtr					myWindow;
	WindowObject				myWindowObject;
	MovieController			myMC;
	myWindow = QTFrame_GetFrontMovieWindow();
	while (myWindow != NULL) {
	 	myWindowObject = QTFrame_GetWindowObjectFromWindow(myWindow);
		if (myWindowObject != NULL) {
			myMC = (**myWindowObject).fController;
			if (myMC != NULL)
				if (MCIsPlayerEvent(myMC, theEvent))
		myWindow = QTFrame_GetNextMovieWindow(myWindow);


On Windows, however, system and user actions are handled somewhat differently. Windows sends messages describing those actions directly to the window procedure of the target window, so we know in advance which movie controller the action might apply to. The only "gotcha" is that MCIsPlayerEvent wants to get Macintosh-style events, not Windows-style messages. So, we need to call the function WinEventToMacEvent to translate the Windows message into a Macintosh event, as shown in Listing 11.

Listing 11: Handling events on Windows


WinEventToMacEvent(&myMsg, &myMacEvent);
// pass the Mac event to the movie controller if the movie window isn't minimized
if (!IsIconic(theWnd))
	MCIsPlayerEvent(myMC, (EventRecord *)&myMacEvent);

Editing a Movie

Some QuickTime movie controllers support the typical cut, copy, paste, and clear editing operations through a handful of high-level functions that are very easy to use. By default, a newly-created movie controller has editing turned off, so we need to explicitly turn it on, like this:

MCEnableEditing(myMC, true);

If you're interested in finding out whether a particular movie controller supports editing, you can inspect the value returned by MCEnableEditing, which is non-zero if the specified movie controller does not support editing. We'll ignore that return value here, since we'll dynamically determine whether a movie controller supports editing whenever we adjust our application's menus.

When the user selects an item in our Edit menu (or performs some equivalent keyboard operation), we simply need to call the corresponding movie controller function. For instance, if the user selects the Cut menu item, we'll call the MCCut function and also set a flag to indicate that the movie's data has changed:

myMovie = MCCut(myMC);
(**myWindowObject).fIsDirty = true;

MCCut removes the current movie selection from the movie associated with the specified movie controller. Moreover, MCCut returns the cut movie selection to us; this is useful if we want to allow the user to paste that segment back into the same movie (or indeed into some other movie). We need to call the PutMovieOnScrap function if we want to allow that segment to be pasted. Listing 12 shows our entire function for handling the Edit menu.

Listing 12: Handling items in the Edit menu


void QTFrame_HandleEditMenuItem (WindowReference theWindow, 		UInt16 theMenuItem)
	WindowObject			myWindowObject = NULL;
	MovieController		myMC = NULL;
	Movie						myMovie = NULL;
	myWindowObject = QTFrame_GetWindowObjectFromWindow(theWindow);
	myMC = QTFrame_GetMCFromWindow(theWindow);
	// make sure we have a valid movie controller and a valid window object
	if ((myMC == NULL) || (myWindowObject == NULL))

	switch (theMenuItem) {
			(**myWindowObject).fIsDirty = true;	break;
			myMovie = MCCut(myMC);
			(**myWindowObject).fIsDirty = true;	break;
			myMovie = MCCopy(myMC);				break;
			MCPaste(myMC, NULL);
			(**myWindowObject).fIsDirty = true;	break;
			(**myWindowObject).fIsDirty = true;	break;
			QTUtils_SelectAllMovie(myMC);		break;
		default:								break;
	} // switch (theMenuItem)
	// place any cut or copied movie segment onto the global scrap
	if (myMovie != NULL) {
		PutMovieOnScrap(myMovie, 0L);

The movie controller also provides an easy way for us to determine which Edit menu items need to be enabled or disabled at any time. The function MCGetControllerInfo returns a 32-bit set of flags that we can inspect to see the current status of the movie controller, such as whether the user has edited the movie. So, to enable or disable the Undo menu command, we can use code like this:

MCGetControllerInfo(myMC, &myFlags);
if (myFlags & mcInfoUndoAvailable)
	QTFrame_SetMenuItemState(myMenu, IDM_EDITUNDO,
	QTFrame_SetMenuItemState(myMenu, IDM_EDITUNDO, kDisableMenuItem);

See the function QTFrame_AdjustMenus in ComFramework.c for the complete story on adjusting all the Edit (and File) menu items.


Well, we've accomplished what we set out to do, namely show how to open QuickTime movie files in movie windows and handle user interactions with those movies. Along the way, we also took a fairly long look at some of the techniques we can use, here and in the future, to make sure that our code operates identically on both Macintosh and Windows operating systems. By spending the time now getting to understand how to use the platform-independent utilities defined in ComFramework.c, we have (I hope) made it easier for us to spend our time later focussing on the QuickTime-specific tasks we want to accomplish.

Before we close up shop, let's take a minute to discuss the source code that accompanies this month's article. I have included three project files created with Metrowerk's CodeWarrrior IDE version 4.0.2. These projects build PowerPC, 68K, and Windows versions of an application called QTShell, which is our bare-bones QuickTime viewing and editing application. I have also included the file QTShell.mak, which you can use with Microsoft Developer Studio to build a Windows application, if you prefer programming on a Windows machine. (The CodeWarrior project files should also work when using CodeWarrior on Windows, but I have not tested this.)

No matter which platform or development environment you develop on, you'll need to obtain the QuickTime-specific header files, libraries, and (on Windows) resource-building tools. These are available on the QuickTime Software Development Kit (SDK) CD, which I highly recommend if you really want to do some serious QuickTime programming. The same header files, libraries, and tools are found on the CD included in the excellent book Discovering QuickTime by George Towner (available through the DevDepot at Finally, you can download the necessary files from the QuickTime web site at


The basic Windows framework for the QTShell source code (as contained in the file WinFramework.c) is based on an earlier sample code package by Brian Friedkin, called MDIPlayer. The basic Macintosh framework (as contained in the file MacFramework.c) and the factoring of any application-specific code into the file ComAppliction.c is based on an earlier sample code package by Kent Sandvik, called MovieShell.

Tim Monroe ( is a software engineer on Apple's QuickTime team. He is currently developing sample code and utilities for the QuickTime software development kit.


Community Search:
MacTech Search:

Software Updates via MacUpdate

Posterino 3.3.6 - Create posters, collag...
Posterino offers enhanced customization and flexibility including a variety of new, stylish templates featuring grids of identical or odd-sized image boxes. You can customize the size and shape of... Read more
Together 3.8.3 - Store and organize all...
Together helps you organize your Mac, giving you the ability to store, edit and preview your files in a single clean, uncluttered interface. Features Smart storage. With simple drag-and-drop... Read more
iClock Pro 3.4.9 - Customize your menuba...
iClock Pro is a menu bar replacement clock for Apple's default clock. iClock Pro is an update, total rewrite and improvement to the popular iClock. Have the day, date and time in different fonts and... Read more
Things 2.8.12 - Elegant personal task ma...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more
Typinator 7.2 - Speedy and reliable text...
Typinator turbo-charges your typing productivity. Type a little. Typinator does the rest. We've all faced projects that require repetitive typing tasks. With Typinator, you can store commonly used... Read more
Spotify - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
beaTunes 4.6.14 - Organize your music co...
beaTunes is a full-featured music player and organizational tool for music collections. How well organized is your music library? Are your artists always spelled the same way? Any R.E.M. vs REM?... Read more
Vienna 3.1.10 :d05d7a5d: - RSS and Atom...
Vienna is a freeware and Open-Source RSS/Atom newsreader with article storage and management via a SQLite database, written in Objective-C and Cocoa, for the OS X operating system. It provides... Read more
Day One 2.1.8 - Maintain a daily journal...
Day One is the easiest and best-looking way to use a journal / diary / text-logging application for the Mac. Day One is well designed and extremely focused to encourage you to write more through... Read more
iDefrag 5.1.8 - Disk defragmentation and...
iDefrag helps defragment and optimize your disk for improved performance. Features include: Supports HFS and HFS+ (Mac OS Extended). Supports case sensitive and journaled filesystems. Supports... Read more

Latest Forum Discussions

See All

Fantasy MMORPG MU Origin adds new modes,...
MU Origin, Webzen’s highly popular fantasy MMORPG is getting ready to shake things up for the second time this year, as a new update makes its way to the Google Play and App Store from today. Introducing new systems, modes, and events, the land of... | Read more »
Blizzard is looking to hire a mobile dev...
A new thread on the popular video game rumor forum, NeoGAF, uncovered an interesting job listing over at Blizzard Entertainment. It appears the studio behindStarCraft, World of WarCraft, Hearthstone,andOverwatch is looking to bring on a new hire... | Read more »
Legend of Zelda meets Cooking Mama in ne...
Dungeon Chef is what happens when you mix the RPG elements (and style) of a Legend of Zelda game, with cooking elements. Although, now that The Legend of Zelda: Breath of the Wild also has cookingelements, so maybe the gameplay is not so novel.... | Read more »
ChordFlow (Music)
ChordFlow 1.0.0 Device: iOS Universal Category: Music Price: $6.99, Version: 1.0.0 (iTunes) Description: ChordFlow is a chord sequencer with a unique 4-track polyphonic arpeggiator, extensive chord library, MIDI out and Ableton Link... | Read more »
The Walking Dead: A New Frontier is out...
The newest season of Telltale Games'The Walking Dead is well underway. After the release of the third episode, "Above the Law" about a month ago, episode four, "Thicker Than Water" is hot and ready for more zombies and gut-wrenching emotional... | Read more »
Best games we played this week
Another week, another new wave of mobile games do dive into. We've dug through the list of apps that came out this week to tell you which apps are worth your sweet time. And while there weren't too many games this week, there were some big ones.... | Read more »
Vignettes (Games)
Vignettes 1.0.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.1 (iTunes) Description: Vignettes is a casual but unique exploration game without text or characters, where objects shapeshift as you spin them around... | Read more »
Get Me Outta Here is an 80s retro shoote...
Are you ready to fight some aliens? Because Crescent Moon Games has released the retro shooter Get Me Outta Here on iOS devices today. [Read more] | Read more »
Get a bunch of Apple productivity apps f...
If you're an Apple Mac owner, you're probably aware of the host of Apple productivity apps the company includes in all new Mac purchases. Apps like iMovie, Keynote, and of course, GarageBand. While you used to be able to also buy these apps... | Read more »
Terra Mystica (Games)
Terra Mystica 1.03 Device: iOS Universal Category: Games Price: $9.99, Version: 1.03 (iTunes) Description: Short Summary:≈≈≈≈≈≈≈≈≈≈≈≈≈ | Read more »

Price Scanner via

Use Apple’s Education discount to save up to...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free: -... Read more
Apple refurbished Apple Watches available sta...
Apple is now offering Certified Refurbished Series 1 and Series 2 Apple Watches for 14-16% off MSRP, starting at $229. An Apple one-year warranty is included with each watch. Shipping is free: Series... Read more
15-inch Touch Bar MacBook Pros, Apple refurbi...
Apple is offering Certified Refurbished 2016 15″ Touch Bar MacBook Pros for $360 to $420 off original MSRP. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2.6GHz... Read more
13-inch MacBook Airs on sale for up to $150 o... has 13″ MacBook Airs on sale for up to $150 off MSRP including free shipping: - 13″ 1.6GHz/128GB MacBook Air (sku MMGF2LL/A): $869.99 $130 off MSRP - 13″ 1.6GHz/256GB MacBook Air (sku... Read more
15-inch Touch Bar MacBook Pros on sale for $1...
B&H Photo has the new 2016 15″ Apple Touch Bar MacBook Pros in stock today and on sale for up to $200 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.7GHz Touch Bar... Read more
15-inch 2.7GHz Touch Bar MacBook Pros on sale...
Amazon has 2016 15″ 2.7GHz Apple Touch Bar MacBook Pros in stock today and on sale for $150-$200 off MSRP. Shipping is free: - 15″ 2.7GHz Touch Bar MacBook Pro Space Gray (sku MLH42LL/A): $2599 $200... Read more
Apple now offering Certified Refurbished 13-i...
Apple is now offering Certified Refurbished 2016 13″ Touch Bar MacBook Pros for $270-$300 off original MSRP. An Apple one-year warranty is included with each model, and shipping is free: - 13″ 2.9GHz... Read more
MyGiHealth Digestive Symptom Tracker Version...
My Total Health, Inc. has announced the release of MyGiHealth 2.1, an important update to their digestive symptom tracker developed exclusively for iPhone, iPad and iPod touch devices. MyGiHealth is... Read more
Galaxy S8 Materials Costs Highest by Far Comp...
The new Samsung Galaxy S8 equipped with 64 gigabytes (GB) of NAND flash memory carries a bill of materials (BOM) cost that comes out to US$301.60, much higher than for previous versions of the... Read more
iCarMode 4.0 Car Dashboard App For iOS Integr...
Indie developer Diego Resnik has announced the release of iCarMode 4.0, an update to his productivity app developed for iOS devices. iCarMode has positioned itself as a true car dashboard app,... Read more

Jobs Board

*Apple* Mac Computer Technician - GeekHampto...
…complex computer issues over the phone and in person? GeekHampton, Long Island's Apple Premium Service Provider, is looking for you! Come work with our crew Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Music Marketing Lead, iTunes & *Apple*...
# Music Marketing Lead, iTunes & Apple Music Job Number: 56868140 Culver City, California, United States Posted: Apr. 17, 2017 Weekly Hours: 40.00 **Job Summary** Read more
*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
*Apple* Mac Computer Technician - GeekHampto...
…complex computer issues over the phone and in person? GeekHampton, Long Island's Apple Premium Service Provider, is looking for you! Come work with our crew Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.