最近重新梳理AVFoundation框架,遂将之前的oc版本自定义相机重构为swift版本
使用到的类主要有:
AVCaptureDevice 设备类,有许多设置,比如位置Position,聚焦模式FocusMode,曝光模式ExposureMode,闪光灯模式FlashMode。。。。。。
AVCaptureDeviceInput 输入类,用于配置相机,相对应的有AVCaptureOutput输出类
AVCaptureStillImageOutput 照片输出类
AVCaptureSession 会话类,开启和停止相机
AVCaptureVideoPreviewLayer 预览层
文后有链接
使用:
1.相机搭建
1)懒加载各种相机配置
lazy var captureSession :AVCaptureSession= {
let captureSessionTmp =AVCaptureSession()
if captureSessionTmp.canSetSessionPreset(AVCaptureSession.Preset.photo) {
captureSessionTmp.sessionPreset = AVCaptureSession.Preset.photo
}
return captureSessionTmp
}()
lazy var captureDeviceInput :AVCaptureDeviceInput? = {
let captureDevice =getCameraDeviceWithPosition(position:AVCaptureDevice.Position.back)
do{
let captureDeviceInputTmp =try AVCaptureDeviceInput.init(device: captureDevice!)
return captureDeviceInputTmp
}catch{
print(error)
}
return nil
}()
lazy var captureStillImageOutput :AVCaptureStillImageOutput= {
let captureStillImageOutputTmp =AVCaptureStillImageOutput()
captureStillImageOutputTmp.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]
return captureStillImageOutputTmp
}()
lazy var captureVideoPreviewLayer :AVCaptureVideoPreviewLayer= {
let captureVideoPreviewLayerTmp =AVCaptureVideoPreviewLayer.init(session:captureSession)
return captureVideoPreviewLayerTmp
}()
2)配置相机
if captureSession.canAddInput(captureDeviceInput!) {
captureSession.addInput(captureDeviceInput!)
}
if captureSession.canAddOutput(captureStillImageOutput) {
captureSession.addOutput(captureStillImageOutput)
}
let layer =ViewContainer.layer
layer.masksToBounds=true
captureVideoPreviewLayer.frame = layer.bounds
captureVideoPreviewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
layer.insertSublayer(captureVideoPreviewLayer, below: focusCursor.layer)
3)添加手势监听,闪光灯按钮状态
private func addNotificationToCaptureDevice(captureDevice :AVCaptureDevice) {
changeDeviceProperty{ (captureDevice)in
captureDevice.isSubjectAreaChangeMonitoringEnabled = true
}
NotificationCenter.default.addObserver(self, selector: #selector(areaChange(noti:)), name: Notification.Name.AVCaptureDeviceSubjectAreaDidChange, object: captureDevice)
}
注:func changeDeviceProperty(propertyChange :PropertyChangeBlock)方法为设备加锁,改变相机属性必须,为自定义方法
private func addGenstureRecognizer() {
let tap =UITapGestureRecognizer.init(target:self, action:#selector(tapScreen(tapGesture:)))
ViewContainer.addGestureRecognizer(tap)
}
2.拍照
let captureConnection =captureStillImageOutput.connection(with:AVMediaType.video)
captureStillImageOutput.captureStillImageAsynchronously(from: captureConnection!) { (imageDataSampleBuffer, error)in
if imageDataSampleBuffer !=nil{
let imageData =AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)
let image =UIImage.init(data: imageData!)
UIImageWriteToSavedPhotosAlbum(image!,self,#selector(self.imageDidFinishSavingWithError(image:error:contextInfo:)),nil)
}
}
注:imageDidFinishSavingWithError(image:error:contextInfo:)为自定义方法,为保存照片回调函数,使用toast提示用户是否成功
3.前置/后置摄像头切换
@IBAction func toggleButtonClick(_sender:UIButton) {
let currentDevice =captureDeviceInput?.device
let currentPosition = currentDevice?.position
removeNotificationFromCaptureDevice(captureDevice: currentDevice!)
var toChangeDevice :AVCaptureDevice?
var toChangePosition =AVCaptureDevice.Position.front
if currentPosition ==AVCaptureDevice.Position.unspecified|| currentPosition ==AVCaptureDevice.Position.front{
toChangePosition =AVCaptureDevice.Position.back
}
toChangeDevice =getCameraDeviceWithPosition(position: toChangePosition)
addNotificationToCaptureDevice(captureDevice: toChangeDevice!)
do{
let toChangeDeviceInput =tryAVCaptureDeviceInput.init(device: toChangeDevice!)
captureSession.beginConfiguration()
captureSession.removeInput(captureDeviceInput!)
if captureSession.canAddInput(toChangeDeviceInput) {
captureSession.addInput(toChangeDeviceInput)
captureDeviceInput= toChangeDeviceInput
}
captureSession.commitConfiguration()
setFlashModeButtonStatus()
}catch{
print(error)
}
}
注:需要先移除设备监听,再重新添加
4.闪光灯设置
@IBAction func flashOffClick(_sender:UIButton) {
setFlashMode(flashMode: AVCaptureDevice.FlashMode.off)
setFlashModeButtonStatus()
}
@IBAction func flashOnClick(_sender:UIButton) {
setFlashMode(flashMode: AVCaptureDevice.FlashMode.on)
setFlashModeButtonStatus()
}
@IBAction func flashAutoClick(_sender:UIButton) {
setFlashMode(flashMode: AVCaptureDevice.FlashMode.auto)
setFlashModeButtonStatus()
}
private func setFlashMode(flashMode :AVCaptureDevice.FlashMode) {
changeDeviceProperty{ (captureDevice)in
if captureDevice.isFlashModeSupported(flashMode) {
captureDevice.flashMode= flashMode
}
}
}
5.聚焦模式,曝光模式
private func setFocusMode(focusMode :AVCaptureDevice.FocusMode) {
changeDeviceProperty{ (captureDevice)in
if captureDevice.isFocusModeSupported(focusMode) {
captureDevice.focusMode= focusMode
}
}
}
private func setExposureMode(exposureMode :AVCaptureDevice.ExposureMode) {
changeDeviceProperty{ (captureDevice)in
if captureDevice.isExposureModeSupported(exposureMode) {
captureDevice.exposureMode= exposureMode
}
}
}
6.点击屏幕时,对焦的动画
@objc private func tapScreen(tapGesture :UITapGestureRecognizer) {
let pointTap = tapGesture.location(in:ViewContainer)
let pointCamera =captureVideoPreviewLayer.captureDevicePointConverted(fromLayerPoint: pointTap)
setFocusCursorWithPoint(point: pointTap)
focusWithMode(focusMode:AVCaptureDevice.FocusMode.autoFocus, exposureMode:AVCaptureDevice.ExposureMode.autoExpose, point: pointCamera)
}
demo 链接:https://github.com/licl19/CustomCameraDemo.git