MacDevCenter    
 Published on MacDevCenter (http://www.macdevcenter.com/)
 http://www.macdevcenter.com/pub/a/mac/2003/08/15/quicktime_cocoa.html
 See this if you're having trouble printing code examples


Integrating QuickTime with Cocoa

by Douglas Welton
08/15/2003

This is the first in a series of articles about integrating QuickTime technology into your Cocoa applications. My intent with this series is to provide the introductory steps for those of you who are new to QuickTime, to cover many of the common tasks and issues that may crop up during your development cycle, and to share my experience so that, hopefully, you can avoid some of the mistakes I've made along the way.

I'll start out by providing an overview of QuickTime, then some insight into the interfaces between Cocoa and QuickTime, and finish up with an example of a "simple" QuickTime Movie Player that you can include in your own applications.

What is QuickTime?

In the early 1990s, Apple introduced QuickTime, a collection of application programmer interfaces (APIs) and components that support the creation, manipulation, and playback of multimedia and interactive content. Using the QuickTime API, programmers can work with media types such as video, images, and audio, as well as vector-based graphics and animation, 3D modeling data, panoramic objects, MIDI-formatted music, and user-defined media types. QuickTime components provide access to variety of services, such as image compression/decompression, video digitizing, and pre-defined effects that can be performed on one or more media types.

Related Reading

Objective-C Pocket Reference

Objective-C Pocket Reference
By Andrew M. Duncan

Table of Contents
Index

Read Online--Safari Search this book on Safari:
 

Code Fragments only

The movie is used as a metaphor to describe any time-based sequence of data that can be manipulated by QuickTime. The data can be a sequence of images (like a cinematic movie), or audio samples, or stock quotes, or any type of data that varies over time. A typical movie might contain several streams of data, called tracks. For example, a .mov file might contain a movie with two streams, a video track and a sound track.

The QuickTime API is quite extensive and beyond the scope of this article. So I would suggest that before you begin a project of your own that you spend some time with the QuickTime documentation available at the Apple developer web site.

QuickTime Comes to Cocoa

During the 1990s, QuickTime had helped Apple become successfully positioned as a leader in multimedia and interactive technology. So, when Apple bought NeXT in the late 1990s, the challenge facing Apple was how to integrate one of its homegrown key technologies with Cocoa, the new development environment acquired from NeXT. QuickTime did not have an object-oriented interface and was based on QuickDraw, Apple's pre-Mac-OS-X imaging architecture. Cocoa, on the other hand, was defined by the objects in Foundation and AppKit. Cocoa's image architecture was also based on Quartz, the PDF-based graphical system that Apple had chosen as its go-forward technology.

The solution was to introduce two new objects into Cocoa's AppKit. The NSMovie object was provided to encapsulate the QuickTime movie metaphor, and NSMovieView provided insulation from the differences in the underlying image architectures.

All of QuickTime in One Object?

Let's take a look at the NSMovie object. This object fits my notion of a shallow encapsulation. The NSMovie class contains only a few methods, which provide you with access to the QuickTime Movie data type, but does not allow you to directly modify the movie's data. In other words, using NSMovie, you can get a pointer to the movie for display purposes, but you can't use NSMovie itself to change a movie's playback attributes or contents.

The NSMovie class contains methods that allow you to do three basic things:

  1. Initialize a new NSMovie object.
  2. Filter the file types used for initialization.
  3. Return basic info about the QuickTime Movie pointer being encapsulated.

First, NSMovie objects can be initialized from a URL, a pasteboard, or an existing QuickTime Movie pointer. NSMovie can be initialized with any type of data that QuickTime will accept using the methods -initWithURL:byReference, -initWithPasteboard, or -initWithMovie. This includes video, audio, and still images. Also, you may need to use a URL for initialization from HTTP and RSTP resources.

The following example shows how to initialize an instance of NSMovie using a sample movie contained in an application's bundle:

NSString *Example_Path;
NSURL *Example_URL;
NSMovie *Example_Movie;

//+
// Load the movie from within the current Bundle
//-

Example_Path = [[NSBundle mainBundle] pathForResource: @"Sample_Movie" 
ofType: @"mov"];
Example_URL = [NSURL fileURLWithPath: Example_Path];
Example_Movie = [[NSMovie alloc] initWithURL: Example_URL byReference: YES];

Second, NSMovie provides methods to help you filter file types and pasteboards that can be used to initialize an object instance. Using -canInitWithPasteboard and -movieUnfilteredPasteboardTypes, you can test the suitability for initialization using a particular pasteboard or retrieve a list of pasteboard types that will be accepted. Additionally, you may also find it useful to use -movieUnfilteredFileTypes to restrict the choices a user has when selecting files.

The following is an example of how you might use NSMovie to filter the file types that will be selectable from an NSOpenPanel.

//+
// Create and display an open panel with only movie types selectable
//-

Add_Video_Panel = [NSOpenPanel openPanel];
Button_Clicked = [Add_Video_Panel runModalForDirectory: NSHomeDirectory() 
file: nil types: [NSMovie movieUnfilteredFileTypes]];

Finally, NSMovie can be used to return information about the QuickTime movie that it has encapsulated. The method -QTMovie returns the QuickTime Movie pointer that is the source for the NSMovie object. This is the key ingredient for extending the value of NSMovie when working with QuickTime. With a Movie pointer in hand, you can use functions from the QuickTime API to access, manipulate, and change any QuickTime attributes that are unavailable from NSMovie.

The following example illustrates how to access several QuickTime movie attributes that are not available from NSMovie:

- (void) Get_QuickTime_Attributtes: (NSMovie *)Example_Movie
{
Movie QuickTime_Movie;
TimeScale Time_Scale;
TimeValue Current_Time, Movie_Length;

QuickTime_Movie = [Example_Movie QTMovie];
Current_Time = GetMovieTime( QuickTime_Movie, nil );
Time_Scale = GetMovieTimeScale( QuickTime_Movie );
Movie_Length = GetMovieDuration( QuickTime_Movie );
}

On the Screen, Please!

Okay, so you have an NSMovie object ... now what? Most of the time, the answer to that question will be that you need to play it. That's where NSMovieView comes in.

Figure 1. An NSMovieView
Figure 1. An NSMovieView

Figure 1 illustrates a typical use of NSMovieView. In this case, the view is displayed with a movie controller, which allows the user to play the movie, set the volume, reposition the play head, and make selections.

Before you get started working with NSMovieView, I recommend that you get thoroughly familiar with the features and behavior of Apple's QuickTime Player. Much of the functionality of NSMovieView is demonstrated directly in the features of the QuickTime Player.

In most cases, you will use the Interface Builder to create and set up your NSMovieView. The Cocoa Graphic Views palette contains an NSMovieView that you can drag onto the windows of your application.

Figure 2. Cocoa Graphic Views
Figure 2. Cocoa Graphic Views

To create the window in Figure 1, I dragged the NSMovieView from the palette onto my application's window.

Figure 3. Sample Application Window and Inspector
Figure 3. Sample Application Window and Inspector

The Interface Builder Inspector (the right-hand window in Figure 3) is used to set the attributes for your NSMovieView. I wired the necessary outlets and actions and added a small piece of code to initialize the movie, and voila!

Surely There Is More To It Than That!

Instead of going through the various methods for NSMovieView one at a time, I have put together a small example that illustrates a wide variety of NSMovieView's functionality.

Figure 4 illustrates what the final version of the example application will look like.

Figure 4. NSMovie_Example Application
Figure 4. NSMovie_Example Application

So, how do we get there?

I'll assume that you have done some (even a small amount) Cocoa programming and that you are familiar with Apple's Developer Tools — Project Builder (PB) and Interface Builder (IB).

Let's Build Our Own QuickTime Movie Player!

The design of our example will be simple and have the following attributes:

Here's the step-by-step recipe that I used to make this example. You may wish to download the source code and follow along as we go through the process.

Step One: Create a New Project

Start up Project Builder and select New Project from the File menu. When the Project Builder Assistance displays a list of project types, select "Cocoa Application," then enter the name "NSMovie_Example."

Step Two: Build the User Interface

Double-click the MainMenu.nib file in the Project Builder "Groups & Files" tab and Interface Builder will be started for you. To build my user interface, I have dragged five elements from the IB palette onto my application window: an NSMovieView, an NSSlider (horizontal with tick marks), an NSTextField, an NSButton (borderless), and another NSSlider (horizontal without tick marks).

Next, I used the IB inspector to set the attributes for each element:

The result can be seen in Figure 5.

Figure 5. Building the NSMovie_Example user interface
Figure 5. Building the NSMovie_Example user interface
click for larger view

Step Three: Outlets, Actions, and Controllers

The NSMovie_Example application will need a controller to handle the actions initiate by the user interface. From the Interface Builder Classes menu, I created and instantiated an NSObject subclass named NSMovie_Example_Controller.

Figure 6. NSMovie_Example_Controller
Figure 6. NSMovie_Example_Controller

Figure 6 shows the IB inspector after I have created outlets for each of the interface elements. Additionally, I have created four Actions (-Scrub_Movie, -Set_Volume, -Start_Movie, and -Stop_Movie) that will respond to users' actions.

To complete the process, I used the "Create Files..." item on the IB Classes menu to create Objective C source files for my controller and add them to my project.

Step Four: Completing the Project Setup

Returning to Project Builder, the project setup is completed by organizing the source code and resource files.

In addition to the template files that are provided when NSMovie_Example was created, I have already added files for the button images (Play.tiff and Pause.tiff) and the controller object (NSMovie_Example_Controller.m and NSMovie_Example_controller.h). To complete the project, I added three more files:

Once these were added, I created a couple of new groups within the project, and the result is a "Groups & Files" tab that looks like the following:

Figure 7. NSMovie_Example Project Builder Groups & Files
Figure 7. NSMovie_Example Project Builder Groups & Files

Step Five: Completing the Source Code for NSMovie_Example_Controllers

To finish the coding, I needed to add the logic for the Action methods in the NSMovie_Example_Controller. In addition to the four Action methods I had specified in the Interface Builder, I needed to add two more methods to the controller: -awakeFromNib and -Update_Player_Feedback.

Here's the pseudo-code description for each method:

This method completes the initialization of the controller object. The main tasks are to load the movie einsteins_legacy.mov from the application bundle, make the resulting NSMovie object the current movie in Movie_View, initialize Time_Display, and set the parameters of Scrub_Slider to match the duration of the newly loaded movie.

This method is invoked when someone moves the scrub slider. The main task is to adjust the movie's current time (using SetMovieTimeValue()) to mirror the value represented by the slider's current position. Additionally, Time_Display must be updated to reflect the current movie time.

This method is invoked when the user moves the volume slider. The main task is to adjust the Movie_View's volume to reflect the current position of Volume_Slider.

This method is invoked after a user clicks the Control_Button (in its normal state). The main tasks are to start playback in the Movie_View and adjust the action of the Control_Button so that the next click will stop the movie. This method also creates a repeating NSTimer (Scrub_Timer) that fires every tenth of a second, sending a message to -Update_Player_Feedback, which in turn animates Scrub_Slider and Time_Display.

This method is invoked after a user clicks the Control_Button (in its alternate state). The main tasks are to stop playback in the Movie_View and adjust the action of the Control_Button so that the next click will start the movie. This method also stops the repeating time (Scrub_Timer) and resets Scrub_Slider to its initial position.

This method is invoked every tenth of second by Scrub_Timer. The main task is to animate Scrub_Slider and Time_Display to reflect the current playback time of Movie_View. If Movie_View is done playing, then movie playback is stopped and Scrub_Slider and Time_Display are reset to their initial values.

Step Six: Compile It and Watch My Movie

Special thanks to my friend Wes Vasher. He's responsible for whipping up a short movie for this project.

We've Only Just Begun ...

Hopefully, I've given you enough to get you going on integrating QuickTime into your next Cocoa project.

This QuickTime overview is just the tip of the iceberg. Before you take on your own project, I suggest that you dig deeply into the QuickTime reference materials available at Apple's Developer site. Most notably, check out the QuickTime sample code that uses Cocoa.

The NSMovie_Example project is a place to start, but by no means does it encompass all the functionality that QuickTime makes available to you. I would suggest that you take the source code, play with it and modify it to your own purposes (try adding a movie to your About Box).

That's all for now!

Douglas Welton is the president of Einstein's Legacy that created Cinematics, an innovative new media player that helps you to build and manage playlists of digital movies on your Macintosh.


Return to MacDevCenter.com

Copyright © 2007 O'Reilly Media, Inc.