本文将前文的继续Kcamera项目,并使用AVCaptureSession获取摄像头采集到的视频.但是实际的视频录制和照片拍摄将在后面的文章中才会实现.
实现步骤
创建预览视图类
新建PreView类继承自UIView,PreView用来展示一个摄像头当前拍摄内容的实时预览视图.更具体的说,我们将使用AVCaptureVedioPreviewLayer方法实现这一预览.
打开Main.storyboard,修改根view的层次结构如下:
其中preView和controlView与父视图上下左右约束都为0,CameraModeView的约束与之前相同,但其父视图修改为controlView.
并在preView的identity inspector面板中将Custom Class修改为我们创建的PreView类.
打开PreView.swift,添加如下代码修改Preview的图层类型:
override class func layerClass()->AnyClass
{
return AVCaptureVideoPreviewLayer.self
}
重写session属性的访问方法,保证采集到的数据直接输出到图层中:
var session:AVCaptureSession!{
get{
return (self.layer as! AVCaptureVideoPreviewLayer).session
}set(newValue){
(self.layer as! AVCaptureVideoPreviewLayer).session = newValue
}
}
设置音频会话类型
在AppDelegate的application(application:didFinishLaunchingWithOptions:)方法返回前加入如下代码:
let session = AVAudioSession.sharedInstance()
try! session.setCategory(AVAudioSessionCategoryPlayAndRecord)
try! session.setActive(true)
创建捕捉模型
新建CaptureModel类继承自NSObject,用来处理视频采集的具体行为.
初始化捕捉会话
在CaptureModel类中添加一个捕捉会话:
//捕捉会话
var captureSession:AVCaptureSession!
设置捕捉对话的代码如下:
//捕捉会话
func setupSession() -> Bool {
//1. 创建捕捉会话
self.captureSession = AVCaptureSession()
//2. 设置视频采集质量
self.captureSession.sessionPreset = AVCaptureSessionPresetHigh
//3. 设置视频采集设备(默认返回后置摄像头)
let videoDevice = AVCaptureDevice .defaultDeviceWithMediaType(AVMediaTypeVideo)
//4. 把采集设备封装为一个AVCaptureDeviceInput对象(这里忽略了错误处理)
let videoInput = try? AVCaptureDeviceInput(device: videoDevice)
//4. 在捕捉会话中添加AVCaptureDeviceInput对象
if videoInput != nil {
if self.captureSession.canAddInput(videoInput) {
self.captureSession.addInput(videoInput)
}
}else{
return false
}
//5. 参照设置视频采集输入的步骤,将音频采集输入添加到捕捉会话中
let audioDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeAudio)
let audioInput = try? AVCaptureDeviceInput(device: audioDevice)
if audioInput != nil {
if self.captureSession .canAddInput(audioInput) {
self.captureSession.addInput(audioInput)
}
}else{
return false
}
return true
}
启动捕捉会话
在设置捕捉会话之后,如果需要进行实际的视频采集,还需要启动会话,用来启动数据流并使其处于准备捕捉图片或视频的状态.
在CaptureModel类中增加一个属性:
//由于捕捉会话的启动是一个同步调用,所以需要异步调用
let globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
启动捕捉会话的方法如下:
//启动捕捉会话
func startSession() -> Void {
if !self.captureSession.running{
dispatch_sync(self.globalQueue, {
self.captureSession.startRunning()
})
}
}
停止捕捉会话
//停止捕捉会话
func stopSession() -> Void {
if self.captureSession.running {
dispatch_sync(self.globalQueue, {
self.captureSession.stopRunning()
})
}
}
处理隐私需求
当应用程序试图访问麦克风或相机时,系统会弹出一个对话框询问用户是否同意授权.但当对话框出现时,系统并没有中断来等待用户响应,而是立即返回一个设备,比如调用音频设备则返回静音的设备,如果是相机则返回黑白帧.直到用户同意了授权,才会实际开始捕捉视频或音频.如果用户不允许授权,则这个会话期间不会记录任何内容.
所以我们需要在初始化捕捉会话时,判断当前程序对相机和麦克风的访问状态,在初始化捕捉会话的setupSession()方法最前面加入如下代码:
//0. 判断权限
let videoAuthStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
if videoAuthStatus == .Denied || videoAuthStatus == .Restricted {
UIAlertView(title: "提示", message: "请在iPhone的“设置-隐私-相机”选项中,允许访问相机 ", delegate: nil, cancelButtonTitle: "确定").show()
return false
}
let audioAuthStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo)
if audioAuthStatus == .Denied || audioAuthStatus == .Restricted {
UIAlertView(title: "提示", message: "请在iPhone的“设置-隐私-相机”选项中,允许访问麦克风 ", delegate: nil, cancelButtonTitle: "确定").show()
return false
}
测试
打开Main.storyboard,将preView连接为ViewController的@IBOutlet属性:
@IBOutlet weak var preView: PreView!
接着在viewDidLoad()方法中添加如下代码:
self.captureModel = CaptureModel()
if self.captureModel.setupSession() {
self.preView.session = self.captureModel.captureSession
self.captureModel.startSession()
}
}
运行程序,就可以看到后置摄像头采集到的视频内容了.