最近重新梳理AVFoundation框架,遂將之前的oc版本自定義相機(jī)重構(gòu)為swift版本
使用到的類主要有:
AVCaptureDevice 設(shè)備類,有許多設(shè)置,比如位置Position,聚焦模式FocusMode,曝光模式ExposureMode,閃光燈模式FlashMode。。。。。。
AVCaptureDeviceInput 輸入類,用于配置相機(jī),相對(duì)應(yīng)的有AVCaptureOutput輸出類
AVCaptureStillImageOutput 照片輸出類
AVCaptureSession 會(huì)話類,開啟和停止相機(jī)
AVCaptureVideoPreviewLayer 預(yù)覽層
文后有鏈接
使用:
1.相機(jī)搭建
1)懶加載各種相機(jī)配置
? ? 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)配置相機(jī)
? 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)添加手勢(shì)監(jiān)聽,閃光燈按鈕狀態(tài)
? ? 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)方法為設(shè)備加鎖,改變相機(jī)屬性必須,為自定義方法
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:)為自定義方法,為保存照片回調(diào)函數(shù),使用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)
? ? ? ? }
? ? }
注:需要先移除設(shè)備監(jiān)聽,再重新添加
4.閃光燈設(shè)置
? ? @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.點(diǎn)擊屏幕時(shí),對(duì)焦的動(dòng)畫
? ? @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)
? ? }