Set a custom AVFrameRateRange for an AVCaptureSession

steve picture steve · Feb 6, 2014 · Viewed 7.2k times · Source

I'm trying to take 5 pictures every second with AVCaptureSession and I'm not sure I understand what AVFrameRange means. Currently I have some code that sets up the device:

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

and tries to set the activeVideoMinFrameDuration and activeVideoMaxFrameDuration to a custom value of CMTimeMake(1, 5). Apple tells me I can only use one of the AVFrameRanges that they've provided.

When I NSLogged them, I get (2, 30), (2,60), and (2,24). I first want to know what this means? Is this the frame rate at which the camera will run or an interval for capturing frames (i.e. what I'm trying to do)?

If it isn't, what can I do to save 5 frames every second on my sampleBufferDelegate method? Currently it gives me every single frame because the method is called every single time there is a frame, so I just need some pointer on how I can grab just 5 at each second.

Answer

Praxiteles picture Praxiteles · May 25, 2014

Here is working code we have used that sets the frame rate at 5 per second.

If you measure calls to CaptureOutput while using this code, you can see that the camera frames are called every 200 msecs (i.e. which is 5 frames per second.) (We just tested this to confirm.)

Change desiredFrameRate to get other camera frame rates.

- (void)attemptToConfigure5FPS
{
    NSError *error;
    if (![self lockForConfiguration:&error]) {
        NSLog(@"Could not lock device %@ for configuration: %@", self, error);
        return;
    }

    AVCaptureDeviceFormat *format = self.activeFormat;
    double epsilon = 0.00000001;

    int desiredFrameRate = 5;

    for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) {

            if (range.minFrameRate <= (desiredFrameRate + epsilon) &&
            range.maxFrameRate >= (desiredFrameRate - epsilon)) {

            self.activeVideoMaxFrameDuration = (CMTime){
                .value = 1,
                .timescale = desiredFrameRate,
                .flags = kCMTimeFlags_Valid,
                .epoch = 0,
            };
            self.activeVideoMinFrameDuration = (CMTime){
                .value = 1,
                .timescale = desiredFrameRate,
                .flags = kCMTimeFlags_Valid,
                .epoch = 0,
            };           
            break;
        }
    }

    [self unlockForConfiguration];
}