2015-06-10 45 views
0

我正在实现一个由AVCaptureVideoPreviewLayer组成的视图。除了顶部的导航栏(视图嵌入在导航控制器中)之外,该视图应占据整个屏幕。AVCaptureVideoPreviewLayer在iPhone6上正确显示

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

//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运行时,看到下面的截图,预览层不占用屏幕的整体(空白到相机视图的右边和导航栏下应该由预览层填满):

enter image description here

但是,它并适当地填充在屏幕上下面的iPhone 5截图(以及在iPhone 4,4S,5S和)。有没有人有任何洞察力为什么?

enter image description here

+0

第一件事,我会被记录,断点或“调试视图层次检查“是,如果在添加预览图层的时候'self.view'实际上有你期望它的边界。对我来说,它看起来很像UIView本身可以固定为320的宽度,例如,通过将其框架设置在代码或自动布局约束的某处。 – Gamma

回答

1

假设你在viewDidLoad创建这个视频预览层,视图控制器的看法尚未制定出来呢,正因为如此它framebounds不一定是他们会是怎样,一旦观点显示在屏幕上。你必须等待,直到视图布局,以设置预览层,你可以通过实现您的视图控制器的viewDidLayoutSubviews方法,像这样做的正确的帧:

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

这确保了任何当视图控制器视图的大小发生变化时,预览图层的大小也会发生变化。

+0

这很有道理。我在一个单独的'createAVSessionAndCameraOutput'方法中创建了视频预览,这是我从'viewDidLoad'调用的。我会尝试调用'viewDidLayoutSubviews'中的'createAVSessionAndCameraOutput来代替,然后看看结果如何。 – narner

+0

@narner好的!确保你最终不会创建多个'AVCaptureVideoPreviewLayer'并添加到你的视图层,因为'viewDidLayoutSubviews'可以被多次调用。 – TylerTheCompiler

+0

啊!我懂了。更好的策略是在'viewDidLoad'中创建'AVCaptureVideoPreviewLayer',然后在'viewDidLayoutSubviews'中设置位置? – narner

0

您可以使用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 

然后在某处你的视图控制器的实现:

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