AVCaptureSession resolution doesn't change with AVCaptureSessionPreset

1.8k Views Asked by At

I want to change the resolution of pictures I take with the camera on OS X with AV Foundation.

But even if I change the resolution of my AVCaptureSession, the output picture size doesn't change. I always have a 1280x720 picture.

I want a lower resolution because I use these pictures in a real time process and I want the program to be faster.

This is a sample of my code:

 session = [[AVCaptureSession alloc] init];

if([session canSetSessionPreset:AVCaptureSessionPreset640x360]) {
    [session setSessionPreset:AVCaptureSessionPreset640x360];
}

AVCaptureDeviceInput *device_input = [[AVCaptureDeviceInput alloc] initWithDevice:
                                       [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][0] error:nil];

if([session canAddInput:device_input])
    [session addInput:device_input];

still_image = [[AVCaptureStillImageOutput alloc] init];

NSDictionary *output_settings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
[still_image setOutputSettings : output_settings];

[session addOutput:still_image];

What should I change in my code?

2

There are 2 best solutions below

1
On BEST ANSWER

I have also run into this issue and found a solution that seems to work. For some reason on OS X, StillImageOutput breaks the capture session presets.

What I did was change the AVCaptureDevice's active format directly. Try this code right after you add your StillImageOutput to your Capture Session.

//Get a list of supported formats for the device
NSArray *supportedFormats = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][0] formats];

//Find the format closest to what you are looking for
//  this is just one way of finding it
NSInteger desiredWidth = 640;
AVCaptureDeviceFormat *bestFormat;
for (AVCaptureDeviceFormat *format in supportedFormats) {
    CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions((CMVideoFormatDescriptionRef)[format formatDescription]);
    if (dimensions.width <= desiredWidth) {
        bestFormat = format;
    }
}

[[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][0] lockForConfiguration:nil];
[[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][0] setActiveFormat:bestFormat]; 
[[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][0] unlockForConfiguration];

It is possible that there are other ways of fixing this issue but this is fixed it for me.

0
On

So I had this problem also, but using the raw AVCaptureVideoDataOutput instead of JPG.

The issue is that the session presets Low/Medium/High actually affects the capture device in some ways, for example framerate, but it won't change the hardware capture resolution - it will always capture at 1280x720. The idea, I think, is that a normal Quicktime output device will figure this out and add a scaling step to 640x480 (for example) if the session preset is to Medium.

But when using the raw outputs, they won't care about the preset desired dimensions.

The solution, contrary to Apples documentation on videoSettings, is to add the requested dimensions to the videoSettings:

        NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                    [NSNumber numberWithDouble:640], (id)kCVPixelBufferWidthKey,
                    [NSNumber numberWithDouble:480], (id)kCVPixelBufferHeightKey,
                    [NSNumber numberWithInt:kCMPixelFormat_422YpCbCr8_yuvs], (id)kCVPixelBufferPixelFormatTypeKey,
                    nil];
    [captureoutput setVideoSettings:outputSettings];

I say contrary to Apples docs, because the docs say that the FormatTypeKey is the only key allowed here. But the bufferheight/width keys actually do work and are needed.