Technical Q&A QA1740

How to capture screen activity to a movie file using AV Foundation on OS X 10.7 Lion and later

Q:  How do I capture screen activity to a QuickTime movie on OS X 10.7 Lion and later?

A: On OS X 10.7 Lion and later, the way to make a movie of screen activity is to use AV Foundation.

// Create an image from the entire main display

CGImageRef image = CGDisplayCreateImage(kCGDirectMainDisplay);

See How to take an image snapshot of the screen on Mac OS X Lion for more information.

To perform a real-time screen capture and save it to a QuickTime movie file, you need minimally three AV objects:

In the following example, the code creates a capture session, adds a screen input to provide video frames, adds an output destination to save captured frames, starts the flow of data from the input to the output, and stops the flow in 5 seconds. By letting the class conform to the AVCaptureFileOutputRecordingDelegate protocol and setting the recording delegate properly, you can monitor when the recording is finished via the delegate method.

Listing 1  Conforming to the AVCaptureFileOutputRecordingDelegate protocol

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
 
@interface Recorder : NSObject <AVCaptureFileOutputRecordingDelegate> {
@private
    AVCaptureSession *mSession;
    AVCaptureMovieFileOutput *mMovieFileOutput;
    NSTimer *mTimer;
}
 
-(void)screenRecording:(NSURL *)destPath;
 
@end

Listing 2  Screen recording example

-(void)screenRecording:(NSURL *)destPath
{
    // Create a capture session
    mSession = [[AVCaptureSession alloc] init];
 
    // Set the session preset as you wish
    mSession.sessionPreset = AVCaptureSessionPresetMedium;
 
    // If you're on a multi-display system and you want to capture a secondary display,
    // you can call CGGetActiveDisplayList() to get the list of all active displays.
    // For this example, we just specify the main display.
    // To capture both a main and secondary display at the same time, use two active
    // capture sessions, one for each display. On Mac OS X, AVCaptureMovieFileOutput
    // only supports writing to a single video track.
    CGDirectDisplayID displayId = kCGDirectMainDisplay;
 
    // Create a ScreenInput with the display and add it to the session
    AVCaptureScreenInput *input = [[[AVCaptureScreenInput alloc] initWithDisplayID:displayId] autorelease];
    if (!input) {
        [mSession release];
        mSession = nil;
        return;
    }
    if ([mSession canAddInput:input])
        [mSession addInput:input];
 
    // Create a MovieFileOutput and add it to the session
    mMovieFileOutput = [[[AVCaptureMovieFileOutput alloc] init] autorelease];
    if ([mSession canAddOutput:mMovieFileOutput])
        [mSession addOutput:mMovieFileOutput];
 
    // Start running the session
    [mSession startRunning];
 
    // Delete any existing movie file first
    if ([[NSFileManager defaultManager] fileExistsAtPath:[destPath path]])
    {
        NSError *err;
        if (![[NSFileManager defaultManager] removeItemAtPath:[destPath path] error:&err])
        {
            NSLog(@"Error deleting existing movie %@",[err localizedDescription]);
        }
    }
 
    // Start recording to the destination movie file
    // The destination path is assumed to end with ".mov", for example, @"/users/master/desktop/capture.mov"
    // Set the recording delegate to self
    [mMovieFileOutput startRecordingToOutputFileURL:destPath recordingDelegate:self];
 
    // Fire a timer in 5 seconds
    mTimer = [[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(finishRecord:) userInfo:nil repeats:NO] retain];
}
 
-(void)finishRecord:(NSTimer *)timer
{
    // Stop recording to the destination movie file
    [mMovieFileOutput stopRecording];
 
    [mTimer release];
    mTimer = nil;
}
 
// AVCaptureFileOutputRecordingDelegate methods
 
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"Did finish recording to %@ due to error %@", [outputFileURL description], [error description]);
 
    // Stop running the session
    [mSession stopRunning];
 
    // Release the session
    [mSession release];
    mSession = nil;
}


Document Revision History


DateNotes
2015-05-20

Added additional notes about capturing the main and secondary displays at the same time. Other miscellaneous changes.

2011-08-10

Corrected a link.

2011-05-13

New document that shows how to capture screen activity to a movie file using AV Foundation on OS X 10.7 Lion and later.