Search code examples
iosobjective-cavcapturesessionavcapturedeviceios-camera

AVCaptureSession get same settings as built in iPhone camera


I've been stuck on this for quite some time. There appears to be a zoom factor when I am recording with the built in camera app on my iPhone. However, I cannot seem to get the same result when I use an AVCaptureSession inside of my app. Here is an example of what I'm talking about. The top was recorded from the iPhone camera app, and the bottom was recorded inside of my app using AVCaptureSession. It's like there is a fish eye effect occurring. My code for setting up my camera is below.

Default iPhone camera recording

AVCaptureSession recording

- (void)configureCameraSession{
_captureSession = [AVCaptureSession new];

[_captureSession beginConfiguration];

_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

if(!_device){
    [self noValidCamera];
    return;
}

AVCaptureDeviceFormat *currentFormat;
int frameRate = 60;
for (AVCaptureDeviceFormat *format in _device.formats)
{
    NSArray *ranges = format.videoSupportedFrameRateRanges;
    AVFrameRateRange *frameRates = ranges[0];

    //CMVideoFormatDescriptionGet
    int resolutionWidth = CMVideoFormatDescriptionGetDimensions(format.formatDescription).width;
    if(frameRates.maxFrameRate > 59 && resolutionWidth >= 1920){
        CameraFormat *cformat = [[CameraFormat alloc] init];
        cformat.format = format;
        cformat.fps = 60;
        if(frameRates.maxFrameRate > 119){
            cformat.fps = 120;
        }
        if(frameRates.maxFrameRate > 239){
            cformat.fps = 240;
        }

        NSString *resolution;

        if(resolutionWidth > 1920){
            resolution = @"4K ";
        }
        else{
            resolution = [[NSNumber numberWithInt:CMVideoFormatDescriptionGetDimensions(format.formatDescription).height] stringValue];
            resolution = [resolution stringByAppendingString:@"p "];
        }

        //stringValue];
        NSString *fps = [[NSNumber numberWithInt:cformat.fps] stringValue];
        fps = [fps stringByAppendingString:@" FPS"];
        cformat.label = [resolution stringByAppendingString:fps];

        BOOL isUniqueFormat = YES;
        for(int i = 0; i < [_formatList count]; i++){
            if([_formatList[i].label isEqualToString:cformat.label]){
                isUniqueFormat = NO;
                break;
            }
        }
        if(isUniqueFormat){
            [_formatList addObject:cformat];
            frameRate = cformat.fps;
            currentFormat = cformat.format;
        }
    }
}

if(!currentFormat){
    [self noValidCamera];
    return;
}

_currentCameraFormat = _analysisViewController.currentCameraFormat;
if(_currentCameraFormat.fps == 0){
    _currentCameraFormatIndex = 0;
    _currentCameraFormat = _formatList[_currentCameraFormatIndex];
    _analysisViewController.currentCameraFormat = _currentCameraFormat;
    currentFormat = _currentCameraFormat.format;
    frameRate = _currentCameraFormat.fps;
}
else{
    currentFormat = _currentCameraFormat.format;
    frameRate = _currentCameraFormat.fps;
}

NSString *resolution;
if(CMVideoFormatDescriptionGetDimensions(currentFormat.formatDescription).width > 1920){
    resolution = @"4K ";
}
else{
    resolution = [[NSNumber numberWithInt:CMVideoFormatDescriptionGetDimensions(currentFormat.formatDescription).height] stringValue];
    resolution = [resolution stringByAppendingString:@"p "];
}
NSString *fps = [[NSNumber numberWithInt:frameRate] stringValue];
fps = [fps stringByAppendingString:@" FPS  ▼"];

[self.videoLabelButton setTitle:[resolution stringByAppendingString:fps] forState:UIControlStateNormal];

[_device lockForConfiguration:nil];
_device.activeFormat = currentFormat;
_device.activeVideoMinFrameDuration = CMTimeMake(1, frameRate);
_device.activeVideoMaxFrameDuration = CMTimeMake(1, frameRate);
[_device unlockForConfiguration];

//Input
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:nil];
[_captureSession addInput:input];

//Output
_movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];

if([_captureSession canAddOutput:_movieFileOutput]){
    [_captureSession addOutput:_movieFileOutput];
}

[self setMovieOutputOrientation];

//Preview Layer
_previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
_previewView = [[UIView alloc] initWithFrame:self.imageView.bounds];
[self addFocusToView:_previewView];
[_previewView addSubview:self.imageView];

_previewLayer.frame = _previewView.bounds;
_previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[_previewView.layer addSublayer:_previewLayer];

_previewLayer.connection.videoOrientation = [self videoOrientationFromCurrentDeviceOrientation];

AVCaptureVideoStabilizationMode stabilizationMode = AVCaptureVideoStabilizationModeCinematic;
if ([_device.activeFormat isVideoStabilizationModeSupported:stabilizationMode]) {
    [_previewLayer.connection setPreferredVideoStabilizationMode:stabilizationMode];
}

[self.view addSubview:_previewView];
[self.view addSubview:self.topInfoBar];
[self.view addSubview:self.recordButton];
[self.view addSubview:self.doneButton];

[_captureSession commitConfiguration];
[_captureSession startRunning];

}


Solution

  • Okay so I finally figured it out. The issue was that on some formats video stabilization is supported so Apple will use it if it can. The problem is that I was not turning this on when I could. Basically check to see if that option is available for the device's active format and turn it on Auto.

     AVCaptureConnection *videoConnection = nil;
    for (AVCaptureConnection *connection in [_movieFileOutput connections]){
        for ( AVCaptureInputPort *port in [connection inputPorts]){
            if ([[port mediaType] isEqual:AVMediaTypeVideo]){
                videoConnection = connection;
            }
        }
    }
    
    if([videoConnection isVideoOrientationSupported]){
        [videoConnection setVideoOrientation:[self videoOrientationFromCurrentDeviceOrientation]];
    }
    
    
    //Check if we can use video stabilization and if so then set it to auto
    if (videoConnection.supportsVideoStabilization) {
        videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
    }