TweetFollow Us on Twitter

Developing Applications With The QuickTime For Cocoa Kit

Volume Number: 21 (2005)
Issue Number: 6
Column Tag: Programming

QuickTime Toolkit

Back To The Future, Part II

by Tim Monroe

Developing Applications With The QuickTime For Cocoa Kit

In the previous QuickTime Toolkit article ("Back to the Future" in MacTech, May 2005), we began looking at Apple's new Cocoa framework for displaying and modifying QuickTime movies, called the QuickTime For Cocoa Kit or the QTKit. We saw how to open and display a movie in a window of a Cocoa document-based application; we also saw how to manipulate movies using command-line tools, which would be quite useful for batch processing via shell scripts or other scripting mechanisms.

Introduction

In this article, we'll continue our investigation of the QTKit framework, which is available in QuickTime 7 on both Panther and Tiger. We'll see how to extend the sample application KitEez that we began developing in the previous article to support the complete set of standard document behaviors (Save, Save As, Revert, and so forth). Toward the end of this article, we'll see how to restrict the file types displayed in the file-opening dialog box. Then in the next article, we'll wrap up our tour of the QTKit by looking at some advanced uses of its classes and methods.

Document Behaviors

So far, our sample application KitEez is able to open any kind of file that QuickTime can handle -- standard movies files, Flash files, MP3 files, MPEG-4 files, AIFF files, text files, and so forth -- and display the movie data in a Cocoa document window. Figure 1 shows a typical KitEez document window. As you can see, the movie and the movie controller bar completely fill the content region of the window. As you can also see from the hourglass shape of the thumb in the movie controller bar, the movie is editable using the items in the Edit menu or their standard keyboard shortcuts.


Figure 1. A window that contains a QTMovieView

Because movies opened using KitEez are editable, we'll want to support all the standard document behaviors: Undo/Redo, Save, Save As, Revert to the last saved version, and so forth. If you have developed Cocoa document-based applications before, then you'll know that Cocoa provides a sophisticated document architecture that tracks changes to a document and responds appropriately to user actions. For instance, if the user tries to close an edited but unsaved document window, Cocoa will display a sheet that prompts the user to save or discard those changes. The Cocoa document architecture, however, has no knowledge of what it means to save a QuickTime movie, so we'll need to override a few NSDocument methods to add that and other standard document behaviors to our sample application.

Supporting Editing Operations

It's actually trivially easy to support the standard undo and redo mechanism for edits made to a QuickTime movie that is displayed in a QTMovieView in a Cocoa document window. All we need to do is make the associated QTMovie object editable, and we saw how to do this in the previous article with this single line of code:

[movie setAttribute:[NSNumber numberWithBool:YES] 
                  forKey:QTMovieEditableAttribute];

Once we've executed this line of code, the movie can be edited using QTMovieView methods like cut:, copy:, paste:, trim:, and the like. Indeed, the default behavior of the Edit menu items is to issue these IB actions, so we need to write exactly 1 line of code (shown above) to have a full-fledged movie editing application.

QTKit provides the standard multiple-level undo and redo processing. A user can cut, copy, and paste to his or her heart's content and then undo all those editing operations. Also, QTKit automatically provides the standard drag-and-drop editing operations. A user can drag a movie segment out of a movie window and into any other object that can accept dragged movie data. Figure 2 shows the drag image being dragged out of a movie window.


Figure 2. A dragged movie segment

The performance of the dragging in QTKit-based applications is vastly improved over that provided by the standard movie controller. In some benchmarks, the creation of the drag image alone was over 3000 times faster in QTKit applications than in applications using the movie controller's drag-and-drop capability.

Saving an Edited Movie

When the user selects the Save item in the File menu, the first responder's saveDocument: method is executed. The NSDocument implementation of this method checks to see whether a file is already associated with the document; if not, it displays the file-saving sheet to elicit a filename and location from the user. This will never actually happen in KitEez, since we only ever open movies from existing files. But it might happen that an edited movie cannot be saved into the file it was opened from. For instance, KitEez is able to open MP3 files as QuickTime movies (transparently invoking its MP3 import component), which are then fully editable. But QuickTime does not provide an MP3 export component, so KitEez is unable to save the edited data back into the original MP3 file. In that case, we'd want to display the file-saving sheet so that the user can save the data as a QuickTime movie file (.mov).

The QTMovie class provides a method that we can use to determine whether a movie object can be saved into its associated file, canUpdateMovieFile. Listing 1 shows our override of the saveDocument: method.

Listing 1: Saving a document

- (IBAction)saveDocument:(id)sender
{
   if ([[movieView movie] canUpdateMovieFile])
      [super saveDocument:sender];
   else
      [super saveDocumentAs:sender];
}

This is simple enough: if the movie can be saved into the file it was opened from, then we just call NSDocument's saveDocument: method; otherwise we call its saveDocumentAs: method.

NSDocument's saveDocument: and saveDocumentAs: methods internally call writeWithBackupToFile:ofType:saveOperation: to actually write the document data into the associated file. We can override that method to save the edited movie data into the original movie file or into the newly-selected destination file. Listing 2 shows our override method.

Listing 2: Writing out the movie data

- (BOOL)writeWithBackupToFile:(NSString *)fileName 
      ofType:(NSString *)documentTypeName 
      saveOperation:(NSSaveOperationType)saveOperationType
{
   BOOL success = NO;

   if (saveOperationType == NSSaveOperation)
      success = [[movieView movie] updateMovieFile];
   else if (saveOperationType == NSSaveAsOperation) {
      success = [[movieView movie]writeToFile:fileName 
                                                withAttributes:nil];
      if (success) {
         QTMovie *newMovie = [QTMovie movieWithFile:fileName error:nil];

         [movieView setMovie:newMovie];
         [self initializeMovieWindow];
      }
   }
	
   return success;
}

When the requested operation is NSSaveOperation, we simply call the updateMovieFile method to update the movie atom in the movie file. When the requested operation is NSSaveAsOperation, we need to do a little more work. As you can see, we first call the QTMovie method writeToFile:withAttributes: with a nil dictionary of attributes. This has the effect of writing only the movie atom into the destination file. What we end up with in this case is a reference movie, that is, a movie whose media data is located in some other file. If instead we wanted a self-contained movie file, we could call writeToFile:withAttributes: with a dictionary that indicates that we want the movie to be flattened into the destination file, like this:

success = [[movieView movie] writeToFile:fileName
                                          withAttributes:[NSDictionary 
            dictionaryWithObject:[NSNumber numberWithBool:YES] 
            forKey:QTMovieFlatten]];

I'll leave it as an easy exercise for the reader to add an accessory view to the save panel that allows the user to determine whether a movie is saved as a reference movie or as a self-contained movie, like the one displayed by the QuickTime Player application (Figure 3).


Figure 3. An accessory view in a save panel

As you know, the standard behavior when performing a Save As operation is to replace the movie in the movie view with the movie in the new destination file. So, once we've called writeToFile:withAttributes:, we then need to open the movie in the new file and set it as the movie displayed in the movie view. Then we need to perform any movie configuration that must happen when a movie is opened. As you can see, we call the method initializeMovieWindow, defined in Listing 3. This code is lifted wholesale from the windowControllerDidLoadNib: method we considered in the previous article on QTKit.

Listing 3: Initializing a movie and its window

- (void)initializeMovieWindow
{
   QTMovie *movie = [movieView movie];

   // make the movie editable
	
[movie setAttribute:[NSNumber numberWithBool:YES] 
                forKey:QTMovieEditableAttribute];

   // use the QTKit's resize indicator, not NSWindow's

[[movieView window] setShowsResizeIndicator:NO];
   [movieView setShowsResizeIndicator:YES];

   // add a listener for size-changed notifications

   [[NSNotificationCenter defaultCenter] addObserver:self 
         selector:@selector(boundsDidChange:) 
         name:QTMovieSizeDidChangeNotification object:movie];
}

It's perhaps worth mentioning that the writeWithBackupToFile:ofType:saveOperation: method is deprecated in Mac OS X version 10.4 and later. Since however we want our application to run under all environments supporting QTKit, including Mac OS X version 10.3.9, we'll stick with this method.

Reverting to the Last Saved Version of a Movie

There remains just one document behavior for us to implement, namely reverting to the last saved version of a movie file. When the user selects the Revert item in the File menu, the Cocoa document handling code displays the sheet shown in Figure 4.


Figure 4. The Revert sheet

If the user presses the Revert button, the revertDocumentToSaved: method in the first responder is invoked. We won't override that method, so that method in the NSDocument class will be called. Rather, we'll override the revertToSavedFromFile:ofType: method, as shown in Listing 4.

Listing 4: Reverting to a saved movie file

- (BOOL)revertToSavedFromFile:(NSString *)fileName 
            ofType:(NSString *)type
{
   QTMovie *newMovie = [QTMovie movieWithFile:fileName error:nil];

   [movieView setMovie:newMovie];
   [self initializeMovieWindow];

   return YES;
}

As in the Save As case shown in Listing 3, we open the specified file and assign it to the movie view; then we perform the required initialization of the movie and movie window. Also, we return the value YES to make sure that the change count of the document is cleared.

So, we have successfully implemented a reasonably complete set of document-related behaviors in our sample application KitEez, using just a very few QTMovie methods: canUpdateMovieFile, updateMovieFile, and writeToFile:withAttributes:. At no point did we need to step outside the methods provided by QTKit into the underlying Carbon APIs. This stands in stark contrast to the work we needed to do in our earlier Cocoa movie-playing application MooVeez, which relied on the now-deprecated Cocoa classes NSMovie and NSMovieView for its QuickTime support. I invite you to take a second look at the article describing those classes ("The Cocoanuts" in MacTech, December 2002); by comparing the Carbon-laced methods we had to write there with the purely Cocoa-based methods we've seen here, you will get a very good appreciation of how big an advancement the QTKit is over those earlier classes.

Openable File Types

In the previous article introducing QTKit, we saw that we can very easily configure the file-opening dialog box to list all files openable by QuickTime by overriding the panel:shouldShowFilename: method and calling the canInitWithFile: class method. That method returns YES just in case a specified file can be used to initialize a QTMovie object. For certain purposes, however, we might want to restrict the types of files that the user can open to some more limited set. For instance, as you probably know, QuickTime can open text files with its text movie importer -- which converts the text into a series of frames in a text track. (See "Word is Out" in MacTech, November 2000 for more information on QuickTime's text-handling capabilities.) But it's doubtful that most applications that can open and display QuickTime movies would want to allow text files to be opened by the user. Ditto for HTML files. Ditto for PDF files.

QTKit provides an easy way to allow the user to open only the kinds of files that would normally be considered as media files and hence openable by a QuickTime application. Instead of using the canInitWithFile: method, we can use the movieFileTypes: method. This too is a class method, so you don't need to have an existing QTMovie object in order to call it.

The movieFileTypes: method returns an NSArray of file types and file extensions that can be opened by QuickTime. This method takes one parameter, which indicates the kinds of file types that you want to be included in the array. Currently these flags are defined for specifying file types:

typedef enum {
   QTIncludeStillImageTypes         = 1 << 0,
   QTIncludeTranslatableTypes       = 1 << 1,
   QTIncludeAggressiveTypes         = 1 << 2,
   QTIncludeCommonTypes             = 0,
   QTIncludeAllTypes                = 0xffff
} QTMovieFileTypeOptions;

Passing the value QTIncludeCommonTypes indicates that you want the array to contain only those file types and extensions that are commonly thought of as openable by QuickTime; this includes the extensions .mov and .mqv, as well as any file types that can be imported in place by QuickTime. (Recall that to be able to import a file in place is to be able to import the file without having to create a new file to hold the imported data.)

The QTIncludeStillImageTypes flag indicates that you want the array to include, in addition to the common file types, all types of files that can be opened by QuickTime using one of its available graphics importers. The QTIncludeTranslatableTypes flag indicates that you want the array to include also those file types that can be opened by QuickTime using one of its available movie importers, whether or not the file data can be imported in place; this array excludes however any file types that would require an aggressive importer. (An aggressive importer is one that can handle file types like text or HTML that would not normally be considered openable by QuickTime.) Finally, the QTIncludeAggressiveTypes flag indicates that you want the array to include file types that require an aggressive importer.

Obviously, the QTIncludeAllTypes flag sets all the bits in the options parameter and requests that the returned array include file types and file extensions for all files that QuickTime can open, using any available graphics or movie importer. Passing the array associated with the QTIncludeAllTypes flag to NSOpenPanel's runModalForTypes: method is essentially identical to using the canInitWithFile: method inside our panel:shouldShowFilename: override method.

It's important to realize that, for instance, the array returned when specifying the QTIncludeStillImageTypes flag will include all file types and extensions for still image files as well as all file types and extensions for the common movie types. That is to say, that array does not contain only the file types and extensions for still image types. If you wanted an array like that, you would need to use Component Manager functions to iterate through all installed components and select only those of type GraphicsImporterComponentType. Listing 5 shows how you might do that.

Listing 5: Finding still image types

0
fileTypes = [NSMutableArray array];
ComponentDescription findCD = {0, 0, 0, 0, 0};
ComponentDescription infoCD = {0, 0, 0, 0, 0};
Component comp = NULL;
OSErr err = noErr;

findCD.componentType = GraphicsImporterComponentType;
findCD.componentSubType = 0;
findCD.componentManufacturer = 0;
findCD.componentFlags = 0;
findCD.componentFlagsMask = cmpIsMissing | 
                                       graphicsExporterIsBaseExporter;

while (comp = FindNextComponent(comp, &findCD)) {
   err = GetComponentInfo(comp, &infoCD, nil, nil, nil);
   if (err == noErr) {
      if (infoCD.componentFlags & 
                        movieImportSubTypeIsFileExtension)
         [fileTypes addObject:[[[NSString 
            stringWithCString:(char *)&infoCD.componentSubType 
            length:sizeof(OSType)] 
            stringByTrimmingCharactersInSet:[NSCharacterSet 
               whitespaceCharacterSet]] lowercaseString]];
      else 
         [fileTypes addObject:[NSString 
            stringWithFormat:@"\'%@\'", [NSString 
            stringWithCString:(char *)&infoCD.componentSubType 
            length:sizeof(OSType)]]];
   }
}

Conclusion

In this article, we've added the standard document-handling behaviors to our KitEez sample application. We've seen how to use QTKit methods to support saving an edited movie into its original file or into a new file, and we've seen how to revert to the last saved version of a movie file. KitEez is now a reasonably complete multi-document movie opening and editing application.

In the next article, we'll take a look at some of the more advanced operations we can use the QTKit framework to perform. We'll see how to add images to an existing QuickTime movie, work with notifications and delegates, and execute QTKit methods on a secondary thread.


Tim Monroe is a member of the QuickTime engineering team at Apple. You can contact him at monroe@mactech.com. The views expressed here are not necessarily shared by his employer.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

BusyContacts 1.6.4 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
Steam 4.0 - Multiplayer and communicatio...
Steam is a digital distribution, digital rights management, multiplayer and communications platform developed by Valve Corporation. It is used to distribute a large number of games and related media... Read more
OmniGraffle Pro 7.19.3 - Create diagrams...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more
OmniGraffle 7.19.3 - Create diagrams, fl...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
Hopper Disassembler 5.3.3- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
calibre 5.35.0 - Complete e-book library...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Sound Studio 4.10.0 - Robust audio recor...
Sound Studio lets you easily record and professionally edit audio on your Mac. Easily rip vinyls and digitize cassette tapes, or record lectures and voice memos. Prepare for live shows with live... Read more
Sparkle Pro 4.0 - Visual website creator...
Sparkle Pro will change your mind if you thought building websites wasn't for you. Sparkle is the intuitive site builder that lets you create sites for your online portfolio, team or band pages, or... Read more
Dropbox 140.4.1951 - Cloud backup and sy...
Dropbox for Mac is a file hosting service that provides cloud storage, file synchronization, personal cloud, and client software. It is a modern workspace that allows you to get to all of your files... Read more
FotoMagico 6.0.5 - Powerful slideshow cr...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more

Latest Forum Discussions

See All

Best iPhone Game Updates: ‘Garena Free F...
Hello everyone, and welcome to the week! It’s time once again for our look back at the noteworthy updates of the last seven days. I got busted last week for not including the obligatory free-to-play matching puzzle game update of the week, and my... | Read more »
‘Horizon Chase’ China Spirit DLC Release...
Following the release of the excellent reveal of the Horizon Chase Senna Forever expansion, the game will be getting a new DLC on mobile platforms today. Today, the Horizon Chase China Spirit DLC pack will release on iOS and Android bringing in 9... | Read more »
‘PUZZLED’ from SNK and Hamster Is Out No...
Following ZED BLADE ACA NeoGeo earlier this month, SNK has brought over another game in the ACA NeoGeo series to both iOS and Android in the form of PUZZLED. SNK and Hamster originally brought the series to mobile with Samurai Shodown IV, Alpha... | Read more »
A House Full of Covid – The TouchArcade...
It’s been a rough week as both of our young children tested positive for Covid, and since recording this early on Friday my wife has tested positive now too. Thankfully the kids seemed to recover fairly quickly and are mostly back to normal, and I... | Read more »
TouchArcade Game of the Week: ‘Krispee S...
Krispee Street is a new hidden object game from Frosty Pop that is based on their popular and almost painfully sweet webcomic Krispee. This is one of the latest titles to be added to the Netflix Games catalog, which means you’ll need to log into... | Read more »
SwitchArcade Round-Up: ‘Escape Lala’, ‘B...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 21st, 2022. In today’s article, we’ve got a lot of new releases. A lot. There were eight on the schedule when I went to bed last night. There were twenty-four when I woke up... | Read more »
Beta Testers Needed for Huge Version 2.0...
Ya’ll remember Dungeon Raid, right? The phenomenal matching RPG hybrid that launched on mobile more than a decade ago, but was more or less abandoned by its developer only to die a slow death on the App Store before the 32-bit Appocalypse finally... | Read more »
‘Ark Legends’ Gives Players a Chance to...
It’s Airpods and Amazon gift cards galore as Melting Games opens pre-registration for Ark Legends. The upcoming mobile RPG is giving away tons of in-game goodies such as gold, energy, iron core, hero summon chest and rare iron core to players who... | Read more »
‘Nickelodeon Extreme Tennis’ Out Now on...
Nickelodeon Extreme Tennis () from Old Skull Games and Nickelodeon is this week’s new Apple Arcade release. Nickelodeon Extreme Tennis features characters from old and new Nickelodeon shows including SpongeBob, TMNT, and many more. The tennis game... | Read more »
SwitchArcade Round-Up: ‘RPGolf Legends’,...
Hello gentle readers, and welcome to the SwitchArcade Round-Up for January 20th, 2022. In today’s article, we’ve got a massive amount of new releases to check out. We’ve got summaries of all of them, from heaven to hell. We also have the lists of... | Read more »

Price Scanner via MacPrices.net

Verizon’s 2022 iPad promo: $100-$310 off any...
Verizon has cellular-capable iPads on sale for $100-$310 off MSRP when purchased with an Unlimited service plan. Sale price is applied to your account monthly over a 24 or 30 month period, depending... Read more
Sunday Sale: Apple AirPods are on sale for up...
Amazon has Apple AirPods on sale for $10-$100 off MSRP today, depending on the model. All are in stock today with free delivery: – AirPods Max headphones (Blue): $449 $100 off MSRP – AirPods Max... Read more
These Apple resellers are offering 13″ M1 Mac...
Apple resellers are offering discounts on 13″ MacBook Pros with M1 Apple Silicon processors ranging up to $150 off MSRP. Here’s where to get one today: (1): Apple’s 13″ MacBook Pros with M1 Apple... Read more
Amazon lowers prices on select 13″ M1 MacBook...
Amazon has select Apple 13″ M1 MacBook Airs on sale for $150 off MSRP this weekend, starting at only $849. Their prices are the lowest available for new MacBook Airs today. Stock may come and go, so... Read more
Apple has 13″ M1 MacBook Airs back in stock s...
Apple has restocked a full line of 13″ M1 MacBook Airs, Certified Refurbished, starting at only $849 and up to $190 off original MSRP. These are the cheapest M1-powered MacBooks for sale today at... Read more
In stock and on sale! 16″ 10-Core M1 Pro MacB...
Amazon has new 16″ 10-Core/512GB M1 Pro MacBook Pros in stock today and on sale for $50 off MSRP including free shipping. Their prices are the lowest available for new M1 Pro 16″ MacBook Pro from any... Read more
Deal Alert!: 14″ M1 Pro with 10-Core CPU in s...
Amazon has the new 14″ M1 Pro MacBook Pro with a 10-Core CPU and 16-Core GPU in stock today and on sale for $2299.99 including free shipping. Their price is $200 off Apple’s standard MSRP, and it’s... Read more
Apple has 24-inch M1 iMacs (8-Core CPU/8-Core...
Apple has restocked a wide array of 24-inch M1 iMacs with 8-Core CPUs and 8-Core GPUs in their Certified Refurbished store. Models are available starting at only $1269 and range up to $260 off... Read more
Select 24″ M1 iMacs are on sale for $100 off...
Sales of Apple’s new 24″ M1 iMacs have been rare since its introduction, perhaps due to global supply issues. However, B&H is offering a $100 discount on select 24″ iMacs, and they’re in stock... Read more
M1 Mac minis are back in stock today at Apple...
Apple has M1-powered Mac minis available in their Certified Refurbished section starting at only $589 and up to $140 off MSRP. Each mini comes with Apple’s one-year warranty, and shipping is free: –... Read more

Jobs Board

Registered Nurse (RN) Employee Health PSJH -...
…is calling for a Registered Nurse (RN) Employee Health PSJH to our location in Apple Valley, CA.** We are seeking a Registered Nurse (RN) Employee Health PSJH to be Read more
Systems Administrator - Pearson (United State...
…and troubleshoot Windows operating systems (workstation and server), laptop computers, Apple iPads, Chromebooks and printers** + **Administer and troubleshoot all Read more
IT Assistant Level 1- IT Desktop Support Anal...
…providing tier-1 or better IT help desk support in a large Windows and Apple environment * Experience using IT Service Desk Management Software * Knowledge of IT Read more
Human Resources Business Partner PSJH - Provi...
…**is calling a** **Human Resources Business Partner, PSJH** **to our location in Apple Valley, CA.** **Applicants that meet qualifications will receive a text with Read more
Manager Community Health Investment Programs...
…is calling a Manager Community Health Investment Programs PSJH to our location in Apple Valley, CA.** **Qualified candidates will be invited to do a self-paced video Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.