5

I'm doing some screen recording on the OSX 10.8 with AVFoundation. I'm using the sessionPreset "AVCaptureSessionPresetPhoto" to record the entire screen. One thing I'd like to change is the quality of the movie file that is created.

AVCaptureSessionPresetPhoto seems to be required to actually capture the full screen without clipping.

According to the documentation here: http://developer.apple.com/library/mac/#documentation/AVFoundation/Reference/AVCaptureSession_Class/Reference/Reference.html

"You use this property to customize the quality level or bitrate of the output. For possible values of sessionPreset, see “Video Input Presets.” The default value is AVCaptureSessionPresetHigh."

However, for Video Input Presets, the only options are these constants: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVCaptureSession_Class/Reference/Reference.html#//apple_ref/occ/cl/AVCaptureSession

NSString *const AVCaptureSessionPresetPhoto;

NSString *const AVCaptureSessionPresetHigh;

NSString *const AVCaptureSessionPresetMedium;

NSString *const AVCaptureSessionPresetLow;

NSString *const AVCaptureSessionPreset320x240;

NSString *const AVCaptureSessionPreset352x288;

NSString *const AVCaptureSessionPreset640x480;

NSString *const AVCaptureSessionPreset960x540;

NSString *const AVCaptureSessionPreset1280x720;

AVCaptureSessionPresetPhoto does the work of capturing the full screen without clipping, but the final quality is somewhat underwhelming. There are visible artifacts due to the lower bitrate that is used by default.

How can I go about increasing the bitrate of the final recording?

Below is a sample of my current code.

    mSession = [[AVCaptureSession alloc] init];

    mSession.sessionPreset = AVCaptureSessionPresetPhoto;

    CGDirectDisplayID displayId = kCGDirectMainDisplay;

    AVCaptureScreenInput *input = [[AVCaptureScreenInput alloc] initWithDisplayID:displayId];
    if (!input) {
        mSession = nil;
        return;
    }        

    if ([mSession canAddInput:input]){
        [mSession addInput:input];
    }

    mMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
    if ([mSession canAddOutput:mMovieFileOutput])
        [mSession addOutput:mMovieFileOutput];

    [mSession startRunning];

    if ([[NSFileManager defaultManager] fileExistsAtPath:[destPath path]])
    {
        NSError *err;
        if (![[NSFileManager defaultManager] removeItemAtPath:[destPath path] error:&err])
        {
            NSLog(@"Error deleting existing movie %@",[err localizedDescription]);
        }
    }

    [mMovieFileOutput startRecordingToOutputFileURL:destPath recordingDelegate:self];

    mTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(finishRecord:) userInfo:nil repeats:NO];
Lebyrt
  • 1,376
  • 1
  • 9
  • 18
Geuis
  • 41,122
  • 56
  • 157
  • 219

2 Answers2

6

If you need fine control over the bitrate of the MP4/MOV H.264 bit stream then you will need to use AVFoundation's AVAssetWriter. For the video input you would setup the properties like in this post. Take a look at the AVVideoAverageBitRateKey. Also note the AVVideoMaxKeyFrameIntervalKey key. If you plan on doing post production on the video then I recommend using 1 for the key frame interval. For an example of using AVAssetWriter check out the RosyWriter or AVCamDemo sample applications from Apple. Let me know if you would like more explanation.

Community
  • 1
  • 1
Steve McFarlin
  • 3,576
  • 1
  • 25
  • 24
  • Thanks a lot for the info Steve. Definitely is going to help. The bit I'm having a hard time figuring out, based on the various code samples I've seen, is how to go about using the AVCaptureScreenInput as the input source. Most of what I've seen involves capturing video from a camera source, or converting NSArray of images into movies. – Geuis Aug 26 '12 at 08:00
  • I am not sure about capturing from the screen. The docs seem to indicate you can just use it as a capture input in place of a video input. – Steve McFarlin Aug 30 '12 at 00:22
2

This can actually be done without using an AVAssetWriter. Here is some sample code.

for connection in movieFileOutput.connections {
     let settings = movieFileOutput.outputSettings(for: connection)
     var newSettings = settings
     var sub = newSettings[AVVideoCompressionPropertiesKey] as? [String: Any]
     sub![AVVideoAverageBitRateKey] = NSNumber(integerLiteral: 4000000)
     newSettings[AVVideoCompressionPropertiesKey] = sub!
     movieFileOutput.setOutputSettings(newSettings, for: connection)
  }

Of course you still need to determine that your AVCaptureConnection is your video connection. (You should also safely unwrap the optionals unlike my sample code)

Dharman
  • 30,962
  • 25
  • 85
  • 135
nitro805
  • 33
  • 5