Tutorial: Recording Media with QTKit for Mac OS X

Nov 16, 2011 | Apple, Mac OS X, Objective-C, Programming

Mac’s are very popular among creative professionals ranging from the user interface designer who designed your favorite iPhone app to the starving videographer who is just starting to break into the field via Youtube and Vimeo.

Recently, I have taken the plunge into Mac OS X application development and had a need to implement a number of multimedia functionality into the application: recording video via a built in or external camera and recording audio via the built in or external microphone and a number of other things. One way to this with a minimum level of effort is to use Apple’s QTKit; for those not familiar with Apple technologies QT stands for Quick Time which is Apple’s entrant into the multimedia player space.

There are number of things that you can do with QTKit but I am only going to focus on recording video and audio for this post. Additionally, I am making some assumptions about you, my reader: I assume that you know how to add a framework to an XCode project, I also assume that you know at least a introductory level of Objective-C and will not providing samples of what I consider boilerplate code.

Ok, so let’s get to it. Once you have imported QTKit, open the header file the class that you want to deal with the recording and declare some variables like so:

QTCaptureSession* session;
QTCaptureMovieFileOutput* fileOutput;
QTCaptureDeviceInput* videoInput;
QTCaptureDeviceInput* audioInput;

You are also going to want to create an NSButton to receive a click from the user. Jump into your implementation file and it’s time to start using those objects and making some more to actually determine how capable the system is of recording media. The following code is probably best put in an awakeFromNib or some similar function:

QTCaptureDevice* videoDevice = [QTCaptureDevice defaultInputDeviceWtihMediaType:QTMediaTypeVideo];
if (videoDevice) {
videoInput = [[QTCaptureDeviceInput alloc] initWithDevice:videoDevice];
...
}

Ok, so what we’ve done here is create videoDevice and set it to refer to whatever the default video recording device is for the user’s systems; I would be willing to gamble that you will be dealing with the built in camera pretty much all the time, but even if some silly user out there is doing something well… silly QTKit does a good job of abstracting specific hardware concerns away. I’ve omitted a good deal of code from my implementation above that basically does some safety checks and checks to see if the once device that you have found can also do audio recording and if it can assigns it that duty as well. These checks are mostly BOOL checks and simple checks from the hasMediaType method.

Once you have your input device / devices configured it is time to actual configure how the media will be recorded:

QTCaptureConnection* connection;
NSEnumerator* enumerator = [[fileOutput connections] objectEnumerator];
while ((connection = [enumerator nextObject])) {
QTCompressionOptions* options = nil;
if (mediaType isEqualToString:QTMediaTypeVideo]) {
options = [QTCompressionOptions compressionOptionsWithIdentifier:@”QTCompressionOptions240SizeH264”];
} else If ...
}

Basically, all this code does is create a few objects and loop over some data (I know that’s a pretty hardcore oversimplification but from an implementation standpoint, that is all you really need to know) and then determine how to encode the data to be output. Again, I have shown the code for the video, but the code to encode the audio is very similar.

In the last code chunk I neglected to explain what fileOutput was. Simply put it is an object that, as its name suggests, represents the resulting data after it has been properly encoded. So using that object we can do:

[fileOutput setCompressionOptions:options forConnection:connection];
[session startRunning];

And there you go. Your output will know be encoded to whatever you set in the above loop, so if you kept my code, your video would be in H264. The last line of code should be self explanatory, so I am just going to move on.

Your fileOutput object has one more important job to do: determine where to write the resulting file or if to write it at all. Remember when I recommended that you create a button and an IBAction? Well, you are going to use it now. Put the following code in your IBAction:

[fileOutput recordToOutputFileURL:[NSURL fileURLWithPath:@”/Users/share/movie.mov”]];

Basically, all this does is tell you fileOutput object where to write its data. Fair warning, that last code sample breaks Apple’s new sandboxing rules for the Mac AppStore, so if you want to be in the Mac AppStore, you are going to have to write the data within your application’s own sandbox; see Apple’s developer docs for more details on the new sandboxing rules. Also, the keen eyed coder will notice that my samples require manual memory management, but I did not include and release statements. Be sure to manage your memory properly.

If you have any questions or comments, sound off in the comments. Additionally, I can be reached on Twitter @dominucco.

More from Mike:

About Me

Hi! I’m Mike! I’m a software engineer who codes at The Mad Botter INC. You might know me from Coder Radio or The Mike Dominick Show.  Drop me a line if you’re interested in having some custom mobile or web development done.

Follow Me

© 2024 Copyright Michael Dominick | All rights reserved