Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set a custom AVFrameRateRange for an AVCaptureSession

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.

like image 458
steve Avatar asked Feb 06 '14 19:02

steve


2 Answers

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];
}
like image 128
Praxiteles Avatar answered Oct 11 '22 16:10

Praxiteles


Code for choosing custom frame rate is as below - Added checks to Apple RosyWriter to verify if current format supports FPS chosen

- (void)configureCamera:(AVCaptureDevice *)videoDevice withFrameRate:(int)desiredFrameRate
{
    BOOL isFPSSupported = NO;
    AVCaptureDeviceFormat *currentFormat = [videoDevice activeFormat];
    for ( AVFrameRateRange *range in currentFormat.videoSupportedFrameRateRanges ) {
        if ( range.maxFrameRate >= desiredFrameRate && range.minFrameRate <= desiredFrameRate )        {
            isFPSSupported = YES;
            break;
        }
    }

    if( isFPSSupported ) {
        if ( [videoDevice lockForConfiguration:NULL] ) {
            videoDevice.activeVideoMaxFrameDuration = CMTimeMake( 1, desiredFrameRate );
            videoDevice.activeVideoMinFrameDuration = CMTimeMake( 1, desiredFrameRate );
            [videoDevice unlockForConfiguration];
        }
    }
}

In case current format (activeFormat) didn't support your chosen FPS, use below code to change activeFormat and then chose FPS. Will need to get format dimension to match your needs though.

- (void)configureCamera:(AVCaptureDevice *)device withFrameRate:(int)desiredFrameRate
{
    AVCaptureDeviceFormat *desiredFormat = nil;
    for ( AVCaptureDeviceFormat *format in [device formats] ) {
        for ( AVFrameRateRange *range in format.videoSupportedFrameRateRanges ) {
            if ( range.maxFrameRate >= desiredFrameRate && range.minFrameRate <= desiredFrameRate ) {
                desiredFormat = format;
                goto desiredFormatFound;
            }
        }
    }

    desiredFormatFound:
    if ( desiredFormat ) {
        if ( [device lockForConfiguration:NULL] == YES ) {
            device.activeFormat = desiredFormat ;
            device.activeVideoMinFrameDuration = CMTimeMake ( 1, desiredFrameRate );
            device.activeVideoMaxFrameDuration = CMTimeMake ( 1, desiredFrameRate );
            [device unlockForConfiguration];
        }
    }
}

Note: Usage of AVCaptureConnection videoMinFrameDuration to set FPS is deprecated.

like image 38
kiranpradeep Avatar answered Oct 11 '22 17:10

kiranpradeep