AVCaptureSession 获得与 iPhone 内置摄像头相同的设置

Posted

技术标签:

【中文标题】AVCaptureSession 获得与 iPhone 内置摄像头相同的设置【英文标题】:AVCaptureSession get same settings as built in iPhone camera 【发布时间】:2018-07-25 00:23:06 【问题描述】:

我已经坚持了很长一段时间了。当我使用 iPhone 上的内置相机应用程序录制时,似乎有一个缩放因子。但是,当我在我的应用程序中使用 AVCaptureSession 时,我似乎无法获得相同的结果。这是我正在谈论的一个例子。顶部是从 iPhone 相机应用程序录制的,底部是使用 AVCaptureSession 在我的应用程序内录制的。这就像发生了鱼眼效应。我的相机设置代码如下。

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

【问题讨论】:

【参考方案1】:

好吧,我终于想通了。问题是在某些格式上支持视频稳定,所以如果可以的话,Apple 会使用它。问题是我没有在可以的时候打开它。基本上检查该选项是否可用于设备的活动格式并将其打开自动。

 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;

【讨论】:

以上是关于AVCaptureSession 获得与 iPhone 内置摄像头相同的设置的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 iOS 中的 AVCaptureSession v AVAudioSession 冲突?

如何记录使用 AVCaptureSession 捕获的第一个和最后一个电影帧的确切时间?

iOS 相机 AVCaptureSession 在纵向与横向大小或分辨率

离开 ViewController 时停止 AVCaptureSession

从后台返回后的 AVCapturesession 处理

使用 AVCaptureSession 录制视频