0

Hi I am using PBJVision to do some video processing iOS. When setting to double default frame rate 24 fps -> 48 fps. I get the following error:

2015-10-16 15:02:48.929 RecordGram[2425:515618] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVCaptureVideoDevice setActiveVideoMinFrameDuration:] - the passed activeFrameDuration 1:48 is not supported by the device.  Use -activeFormat.videoSupportedFrameRateRanges to discover valid ranges.'

Here is the method from PBJVision where the error occurs. I highlighted the line where the error is. Note the method supportsVideoFrameRate: returns true.

// framerate

- (void)setVideoFrameRate:(NSInteger)videoFrameRate
{
if (![self supportsVideoFrameRate:videoFrameRate]) {
    DLog(@"frame rate range not supported for current device format");
    return;
}

BOOL isRecording = _flags.recording;
if (isRecording) {
    [self pauseVideoCapture];
}

CMTime fps = CMTimeMake(1, (int32_t)videoFrameRate);

if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {

    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    AVCaptureDeviceFormat *supportingFormat = nil;
    int32_t maxWidth = 0;

    NSArray *formats = [videoDevice formats];
    for (AVCaptureDeviceFormat *format in formats) {
        NSArray *videoSupportedFrameRateRanges = format.videoSupportedFrameRateRanges;
        for (AVFrameRateRange *range in videoSupportedFrameRateRanges) {

            CMFormatDescriptionRef desc = format.formatDescription;
            CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(desc);
            int32_t width = dimensions.width;
            if (range.minFrameRate <= videoFrameRate && videoFrameRate <= range.maxFrameRate && width >= maxWidth) {
                supportingFormat = format;
                maxWidth = width;
            }

        }
    }

    if (supportingFormat) {
        NSError *error = nil;
        if ([_currentDevice lockForConfiguration:&error]) {
            _currentDevice.activeVideoMinFrameDuration = fps; <<<<<<======ERROR IS HERE, THIS LINE IS WHERE THE ERROR OCCURS
            _currentDevice.activeVideoMaxFrameDuration = fps;
            _videoFrameRate = videoFrameRate;
            [_currentDevice unlockForConfiguration];
        } else if (error) {
            DLog(@"error locking device for frame rate change (%@)", error);
        }
    }

    [self _enqueueBlockOnMainQueue:^{
        if ([_delegate respondsToSelector:@selector(visionDidChangeVideoFormatAndFrameRate:)])
            [_delegate visionDidChangeVideoFormatAndFrameRate:self];
    }];

} else {

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    AVCaptureConnection *connection = [_currentOutput connectionWithMediaType:AVMediaTypeVideo];
    if (connection.isVideoMaxFrameDurationSupported) {
        connection.videoMaxFrameDuration = fps;
    } else {
        DLog(@"failed to set frame rate");
    }

    if (connection.isVideoMinFrameDurationSupported) {
        connection.videoMinFrameDuration = fps;
        _videoFrameRate = videoFrameRate;
    } else {
        DLog(@"failed to set frame rate");
    }

    [self _enqueueBlockOnMainQueue:^{
        if ([_delegate respondsToSelector:@selector(visionDidChangeVideoFormatAndFrameRate:)])
            [_delegate visionDidChangeVideoFormatAndFrameRate:self];
    }];
#pragma clang diagnostic pop

}

if (isRecording) {
    [self resumeVideoCapture];
}
}

Here is the supportsVideoFrameRate: method

- (BOOL)supportsVideoFrameRate:(NSInteger)videoFrameRate
{
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
    AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    NSArray *formats = [videoDevice formats];
    for (AVCaptureDeviceFormat *format in formats) {
        NSArray *videoSupportedFrameRateRanges = [format videoSupportedFrameRateRanges];
        for (AVFrameRateRange *frameRateRange in videoSupportedFrameRateRanges) {
            if ( (frameRateRange.minFrameRate <= videoFrameRate) && (videoFrameRate <= frameRateRange.maxFrameRate) ) {
                return YES;
            }
        }
    }

} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    AVCaptureConnection *connection = [_currentOutput connectionWithMediaType:AVMediaTypeVideo];
    return (connection.isVideoMaxFrameDurationSupported && connection.isVideoMinFrameDurationSupported);
#pragma clang diagnostic pop
}

return NO;
}

Anybody have any ideas?

izzy
  • 1,309
  • 1
  • 15
  • 25

1 Answers1

0

The problem here is that the "Active Device" or "activeFormat" is not what the code from PBJVision is checking. It is checking all formats and the default device...

So for the face camera 48 fps is not supported. simple check:

RGLog(@"default video frame rate = %ld", (long)[vision videoFrameRate]);
bool supportsDouble = [vision supportsVideoFrameRate:2*[vision videoFrameRate]];
bool supportsQuad = [vision supportsVideoFrameRate:4*[vision videoFrameRate]];
bool supportsHalf = [vision supportsVideoFrameRate:[vision videoFrameRate]/2];
bool supportsQuarter = [vision supportsVideoFrameRate:[vision videoFrameRate]/4];
RGLog(@"x2 = %d, x4 = %d, /2 = %d, /4 = %d", supportsDouble, supportsQuad, supportsHalf, supportsQuarter);

which logs

2015-10-16 15:32:24.279 RecordGram[2436:519667] default video frame rate = 24
2015-10-16 15:32:24.280 RecordGram[2436:519667] x2 = 0, x4 = 0, /2 = 1, /4 = 1

After changing the supportsVideoFrameRate: method to look at _currentDevice instead of [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]

- (BOOL)supportsVideoFrameRate:(NSInteger)videoFrameRate
{
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
    AVCaptureDevice *videoDevice = _currentDevice//[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    NSArray *formats = [videoDevice formats];
    for (AVCaptureDeviceFormat *format in formats) {
        NSArray *videoSupportedFrameRateRanges = [format videoSupportedFrameRateRanges];
        for (AVFrameRateRange *frameRateRange in videoSupportedFrameRateRanges) {
            if ( (frameRateRange.minFrameRate <= videoFrameRate) && (videoFrameRate <= frameRateRange.maxFrameRate) ) {
                return YES;
            }
        }
    }

} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    AVCaptureConnection *connection = [_currentOutput connectionWithMediaType:AVMediaTypeVideo];
    return (connection.isVideoMaxFrameDurationSupported && connection.isVideoMinFrameDurationSupported);
#pragma clang diagnostic pop
}

return NO;
}
izzy
  • 1,309
  • 1
  • 15
  • 25