piemonte / PBJVision

📸 iOS Media Capture – features touch-to-record video, slow motion, and photography
MIT License
1.94k stars 324 forks source link

AVCaptureDeviceFormats are not used unless setVideoFrameRate happens after setCurrentDevice #302

Closed tettoffensive closed 3 years ago

tettoffensive commented 8 years ago

For the longest time I couldn't figure out why PBJVision was recording 640x480 even though my device (iPhone 5s) supports much higher quality. I was hoping to get 1920x1080. But the issue is that the formats loop below was never executed because videoDevice is nil. I solved this by recalling [self setVideoFrameRate:_videoFrameRate] in _setCurrentDevice:

- (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);

    AVCaptureDevice *videoDevice = _currentDevice;
    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;
        [_captureSession beginConfiguration];  // the session to which the receiver's AVCaptureDeviceInput is added.
        if ([_currentDevice lockForConfiguration:&error]) {
            [_currentDevice setActiveFormat:supportingFormat];
            _currentDevice.activeVideoMinFrameDuration = fps;
            _currentDevice.activeVideoMaxFrameDuration = fps;
            _videoFrameRate = videoFrameRate;
            [_currentDevice unlockForConfiguration];
        } else if (error) {
            DLog(@"error locking device for frame rate change (%@)", error);
        }
    }
    [_captureSession commitConfiguration];
    [self _enqueueBlockOnMainQueue:^{
        if ([_delegate respondsToSelector:@selector(visionDidChangeVideoFormatAndFrameRate:)])
            [_delegate visionDidChangeVideoFormatAndFrameRate:self];
    }];

    if (isRecording) {
        [self resumeVideoCapture];
    }
}
piemonte commented 8 years ago

thanks @tettoffensive appreciate the help :v: