
iOS摄像头与媒体捕捉
本文记录的是苹果官方文档Cameras and Media Capture的阅读中文笔记, 以及相关自己的理解。
本框架用于实现调用iOS设备的音频以及视频输入输出设备, 在屏幕上显示相机的实时预览, 以及拍照等功能.
请求媒体捕捉访问权限
如果你的App要使用摄像头,需要在Info.plist文件的NSCameraUsageDescription指定使用摄像头的原因。
如果你的App要使用麦克风,需要在Info.plist文件的NSMicrophoneUsageDescription指定使用麦克风的原因。
请注意,如果没有指定对应API的使用原因,那么你在调用相关API时,系统会将你的App终结。
检查授权情况
苹果官方文档建议我们在使用以上这些API之前首先使用 AVCaptureDevice.authorizationStatus(for:) 检查应用权限的授予情况,如果没有被授予使用权限,需要使用AVCaptureDevice.requestAccess(for:completionHandler:)来显示弹框,请求权限。
1 | switch AVCaptureDevice.authorizationStatus(for: .video) { |
请注意,如果摄像或者拍照不是你的App的主要功能,那么你只能在会使用到相关功能的时候才可以请求权限。
请求保存媒体权限
如果是使用上述API拍摄的视频或者照片,请使用PHPhotoLibrary以及PHAssetCreationRequest类。这些类会使用到相册的读写权限,所以需要指定NSPhotoLibraryUsageDescription字段。
如果只是想保存UIImage对象,请使用 UIImageWriteToSavedPhotosAlbum(::::) 方法,此方法会使用到相册的写入权限。请注意,如果图片对象来自AVFoundation( AVCapturePhotoOutput),不推荐使用此方法写入,因为UIImage中不会包含图片中的全部信息。
如果想保存一段视频,请使用 UISaveVideoAtPathToSavedPhotosAlbum(::::) 方法,此方法同样会使用到相册的写入权限。
以上两个方法都需要指定NSPhotoLibraryAddUsageDescription字段。
配置媒体捕获与输出设备
AVCaptureSession类用于整合输入流(媒体输入设备,比如摄像头,麦克风)和输出流(媒体输出设备,比如相机预览,扬声器等),是输入流与输出流交互的管道。开发者通过AVCaptureConnection类将输入流额输出流绑定。
AVCaptureDevice类代表了物理媒体捕获设备,比如相机以及麦克风。
AVCaptureDeviceInput类代表一个输入流,它基于一个captureDevice,比如前置相机,话筒等。负责与captureSession交互。
AVCaptureDeviceOutput类代表了一个输出流,这是一个抽象类,它描述的是媒体输出的方式,比如图片输出:AVCapturePhotoOutput,用于描述的是静态图像,Live Photo等媒体输出方式。
所以初始化session之后,就是开始配置:
1 | // 固定语法,开始AVCaptureSession类的配置 |
AVCaptureDevice的可选值有这些:
1 | // 内置麦克风 |
一个captureSession可以配置多个输入以及输出流,比如需求是需要同时调用后置摄像头以及麦克风,你可以这样写:
1 | captureSession.beginConfiguration() |
下一步,添加输出流:
1 | let photoOutput = AVCapturePhotoOutput() |
输出并不依赖于硬件,所以只需要添加一个输出流,配置完成之后调用commitConfiguration。这里只是进行了一个最基础的captureSession的配置,一般来说,只需要一个输入以及输出流,一个流程就算是走通了。
视频格式的媒体捕获,对应的输出类型是AVCaptureMovieFileOutput。
####显示相机预览
实时预览到相机捕获到的画面,是基于AVCaptureVideoPreviewLayer类,它是CALayer的子类。它通过session属性与captureSession交互。
你可以以直接操作CALayer的方式,初始化previewLayer,设置session属性,然后self.view.layer.addSubLayer(previewLayer)的方式使用,也可以:
1 | // 苹果官方Demo给出的方案 |
然后是设置session:
1 | self.videoPreviewView.videoPreviewLayer.session = self.captureSession |
请注意,如果你的拍照页面支持横向拍摄的话,请使用
AVCaptureVideoPreviewLayer的connection属性来获得当前设备拍摄朝向。
1
2
3
4
5
6
7 // 在进入sessionQueue之前取得这个属性,是为了确保UI级别的操作都在主线程进行,session的操作都在sessionQueue进行。
let videoPreviewLayerOrientation = videoPreviewView.videoPreviewLayer.connection?.videoOrientation
sessionQueue.async {
if let photoOutputConnection = self.photoOutput.connection(with: .video) {
photoOutputConnection.videoOrientation = videoPreviewLayerOrientation!
}
}
跑起来吧
至此,基本的配置工作已经完成了,接下来就是让数据流在输入以及输出流中跑起来。
1 | self.captureSession.startRunning() |
处理错误
退出页面时,请记得调用captureSession的stopRunning()方法,因为应用在后台时调用相机,是被苹果禁止的,这也是未越狱的苹果设备上,没有“偷拍应用”的原因。
另外需要注意的是,硬件的调用有可能被其他系统行为打断(比如有电话进来)。
AVCaptureSession类提供了一系列的NotificationName,其中包括session开始运行,结束运行,或者session被打断:
1 | // startRunning()调用完成之后发送此通知 |
拍摄
准备工作
创建一个AVCapturePhotoSettings类,并配置相关设置。这些设置将在拍照时使用,比如拍照时是否打开闪光灯等属性;
1 | let capturePhotoSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg]) |
Next Step,使用NSData或者将照片保存到相册
遵循AVCapturePhotoCaptureDelegate并实现相关代理方法。一般来说我们只需要关心拍照结果:
1 | func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { |
AVCapturePhotoCaptureDelegate的其他代理方法是用来追踪拍照进度的,分别代表 开始曝光,结束曝光,开始处理,结束处理等时间点。
若要拍摄Live Photo,请查看:官方文档。
- 标题: iOS摄像头与媒体捕捉
- 作者: Aron
- 创建于 : 2019-05-19 20:30:00
- 更新于 : 2025-10-14 09:29:25
- 链接: https://likeso.github.io/2019/05/19/cameras-and-media-capture/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。