Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios AVCaptureVideoPreviewLayer可正确显示,iPhone 6除外_Ios_Objective C_Iphone_Uiview_Avcapturesession - Fatal编程技术网

Ios AVCaptureVideoPreviewLayer可正确显示,iPhone 6除外

Ios AVCaptureVideoPreviewLayer可正确显示,iPhone 6除外,ios,objective-c,iphone,uiview,avcapturesession,Ios,Objective C,Iphone,Uiview,Avcapturesession,我正在努力实现一个由AVCaptureVideoPreviewLayer组成的视图。该视图应该占据整个屏幕,但顶部的导航栏除外(该视图嵌入在导航控制器中) 下面的代码显示了我如何设置捕获会话,并将前置摄像头添加为输入(如果可用) //Set up capture Session session = [[AVCaptureSession alloc]init]; session.sessionPreset = AVCaptureSessionPresetPhoto; //Add a camera

我正在努力实现一个由AVCaptureVideoPreviewLayer组成的视图。该视图应该占据整个屏幕,但顶部的导航栏除外(该视图嵌入在导航控制器中)

下面的代码显示了我如何设置捕获会话,并将前置摄像头添加为输入(如果可用)

//Set up capture Session
session = [[AVCaptureSession alloc]init];
session.sessionPreset = AVCaptureSessionPresetPhoto;

//Add a camera as input if we have a front-facing camera available
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
NSError *error;

for (AVCaptureDevice *device in devices) {
    if ([device position] == AVCaptureDevicePositionBack) {
        //Set our input
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
        [session addInput:input];
        if (!input) {
            NSLog(@"No Input");
        }
    }
}
下面是配置输出的位置,相机输出视图作为子视图添加,帧由视图的边界确定

//Output
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
[session addOutput:output];
output.videoSettings = @{ (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA) };

//Preview Layer
AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
previewLayer.frame = self.view.bounds;
self.view.translatesAutoresizingMaskIntoConstraints = NO;

previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:previewLayer];
正如您在iPhone 6上运行时在下面的屏幕截图中所看到的,预览层不会占据整个屏幕(相机视图右侧和导航栏下方的空白应由预览层填充):

然而,它确实在下面的iPhone5屏幕截图(以及iPhone4、4S和5S)上适当地填满了屏幕。有人知道为什么吗


假设您在
viewdiload
中创建此视频预览层,视图控制器的视图尚未布局,因此其
帧和
边界在视图显示在屏幕上后不一定是这样。您必须等待视图布局完成,以设置预览层的正确帧,这可以通过实现视图控制器的
viewdilayoutsubviews
方法来实现,如下所示:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    self.previewLayer.frame = self.view.bounds;
}

这可以确保视图控制器的视图在任何时候改变大小,预览层也会改变大小。

您可以使用
AVCaptureVideoPreviewLayer
作为
UIView
子类的背景层,然后将此视图的实例作为子视图添加到视图控制器的视图中。通过这种方式,您可以使用约束以任意方式定位视频捕获预览,就像对任何其他视图一样

下面是一个如何做到这一点的示例:

// MyCaptureVideoPreviewView.h

#import <AVFoundation/AVFoundation.h>

@interface MyCaptureVideoPreviewView : UIView

@property (nonatomic, readonly) AVCaptureVideoPreviewLayer *layer;
@property (nonatomic) AVCaptureSession *session;

- (instancetype)initWithFrame:(CGRect)frame session:(AVCaptureSession *)session;

@end


// MyCaptureVideoPreviewView.m

@implementation MyCaptureVideoPreviewView

@dynamic layer;

+ (Class)layerClass {
    return [AVCaptureVideoPreviewLayer class];
}

- (AVCaptureSession *)session {
    return self.layer.session;
}

- (void)setSession:(AVCaptureSession *)session {
    self.layer.session = session;
}

- (instancetype)initWithFrame:(CGRect)frame session:(AVCaptureSession *)session {
    self = [super initWithFrame:frame];
    if (self) {
        self.session = session;
    }
    return self;
}

@end

我要通过日志、断点或“调试视图层次结构”检查的第一件事是,在添加预览层
self.View
时,它是否具有您期望的边界。对我来说,它看起来很像UIView本身可以被固定为320的宽度,例如,通过在代码中的某个地方设置框架或通过自动布局约束。这很有意义。我是在一个单独的
createavsessionandcameraaoutput
方法中创建视频预览的,我是从
viewDidLoad
调用这个方法的。我将尝试从
viewDidLayoutSubviews`调用
createAVSessionAndCameraOutput`并查看结果。@narner好的!但是,请确保您不会创建多个
AVCaptureVideoPreviewLayer
s并将其添加到视图的层中,因为
viewdilayoutsubviews
可能会被多次调用。啊!我懂了。更好的策略是在
viewDidLoad
中创建
AVCaptureVideoPreviewLayer
,然后在
viewDidLayoutSubviews
中设置位置吗?@narner Yep!至少我会这么建议。只创建一次,然后在
viewdilayoutsubviews
中更新框架。
MyCaptureVideoPreviewView *previewView = [[MyCaptureVideoPreviewView alloc] initWithFrame:self.view.bounds
                                                                                  session:session];
previewView.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
previewView.translatesAutoresizingMaskIntoConstraints = NO;

[self.view addSubview:previewView];

// Add whatever constraints you want. Here we just match the superview's bounds:
NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[previewView]|" options:kNilOptions
                                                                metrics:nil views:NSDictionaryOfVariableBindings(previewView)];
NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[previewView]|" options:kNilOptions
                                                                metrics:nil views:NSDictionaryOfVariableBindings(previewView)];

[self.view addConstraints:vConstraints];
[self.view addConstraints:hConstraints];