01 前言
本文是 iOS/Android 音视频开发专题 第十篇,该专题中项目代码将在 Github 进行托管,你可在微信公众号( GeekDev )后台回复 资料 获取项目地址。
在上篇文章 AVFoundation 框架介绍 一文中,我们简单介绍了 AVFoundation 的整体架构。在本篇文章中,我们将从一个简单的相机实例入手,从零开发一个 AVCam 相机App。
该相机应用支持捕获照片和录制一段视频。根据设备情况还支持深度数据,哑光人像(Portrait effects matte) 和实时照片捕获(Live Photos)。
运行 AVCam, 需要在 iOS13 或 更高版本的 iOS 设备,由于 XCode 无法访问设备的摄像头,因此该示例无法在 Simulator 中使用。
本期内容:
AVCaptureSession 创建与配置
拍摄一张 Photo
拍摄一张 Live Photos
捕获图像深度及肖像数据
录制视频文件
结束语
初始化 AVCaptureSession
配置 AVCamPreviewView 及 AVCaptureVideoPreviewLayer
配置 AVCatpureDevice, AVCatpureDeviceInput 及 AVCatpureDevice Input
配置相机相关权限
AVCaptureSession 是负责协调沟通 AVCatpureDevice 及 AVCatpueOutput 的中间对象。 AVCaptureSession 从摄像头和麦克风 AVCatpureDevice 设备中接收采集到的输入数据,并将数据发送至 AVCatpueOutput ,最终生成一张照片或者视频文件。
在 AVCam 示例 AVCamCameraViewController 中 viewDidLoad 方法中,我们首先创建了一个 AVCaptureSession 。
如果将采集到的画面显示屏幕上,我们需要可以通过两种方式。
一种为 AVCaptureVideoPreviewLayer 设置一个 AVCaptureSession ,iOS 系统自动会将采集到的画面输出到 View 中。
另外一种方式是通过为 AVCaptureSession 添加 AVCaptureVideoDataOutput , AVCaptureVideoDataOutput 可以将采集到数据 CMSampleBufferRef 输出给客户端,我们可以通过 OpenGL ES 将画面渲染到视图上。
AVCaptureVideoDataOutput 的控制粒度更精细,我们可以在渲染到屏幕之前,对 CMSampleBufferRef 进行处理。后边我们介绍 GPUImage 时会介绍该部分内容。
AVCaptureVideoPreviewLayer 是 CALayer 的子类,可用于显示 AVCaptureSession 采集到的视频画面。
为 AVCaptureVideoPreviewLayer 的 session 属性设置 AVCaptureSession 实例,就建立了两者的关系。
在 AVCam 项目中我们使用了另外一种创建 AVCaptureVideoPreviewLayer 的方式 ,就是为我们自定义的 AVCamPreviewView 视图指定 layerClass 。这种方式方便我们进行页面布局。
为 configureSession 方法中, [self.session begconfiguration] 用于将多个配置转为原子更新,当你为 AVCaptureSession 添加或删除 input , output 或配置其他参数时,并不会立即生效,直到客户端调用 [session commitConfiguration] 时才会提交到 AVCaptureSession 中。 如果 begconfiguration 和 commitConfiguration 存在嵌套,仅当最外层调用时才会被应用。 begconfiguration , commitConfiguration 必须成对出现。
通过 sessionPresent 可以设置相机采集分辨率,该配置可以在相机运行时动态设置。在 AVCam 实例中我们取值为 AVCapturePresetPhoto ,系统会分配一个最佳的分辨率。
sessionPresent 是一个枚举值,除了 AVCapturePresetPhoto 外,我们还可以指定以下选项:
AVCaptureSessionPresetLow 低质量.
AVCaptureSessionPresetMedium 中等 质量.
AVCaptureSessionPresetHigh 高质量
AVCaptureSessionPresetPhoto
AVCaptureSessionPresetInputPriority
AVCaptureSessionPreset960x540
AVCaptureSessionPreset1280x720
AVCaptureSessionPreset1920x1080
AVCaptureSessionPreset3840x2160
AVCaptureSessionPreset320*480
AVCaptureSessionPreset640x480
AVCaptureSessionPreset652x288
AVCaptureSessionPresetInputPriority 是不是一脸懵逼? 从 iOS 7 开始,在特定的设备硬件中,iOS 支持高帧率视频采集(被称为 Slomo 视频)。
在之前采集的视频帧率一般最高在 30fps, 高帧率视频采集支持 50fps 60fps 120fps... 。在低帧率采集模式下, 通过 session . sessionPresent 和 AVCaptureDevice 的 setActiveVideoMinFrameDuration: / setActivityVideoMaxFrameDuration: 可以别设置采集分辨率及帧率。高帧率下 Apple 弃用了这种方式,要求我们为 AVCaptureDevice 指定合适的 activeFormat 格式。如果你通过 activeFormat 的方式设置采集配置,之前的 sessionPresent 将会被重置为 AVCaptureSessionPresetInputPriority。
高帧率视频的具体用法 ,在 AVCam 项目中我们会涉及到。目前 AVCam 中 sessionPresent 被设置为 AVCaptureSessionPresetHigh 。
现在 AVCaptureSession 已经被创建完成,紧接着我们的任务是为它添加具体的采集输入设备 ( AVCaptureDevice )。
在之前的文章中我们已经知道, AVCaptureDevice 是一个抽象类,每个具体的示例都会对应一个设备,例如摄像机或麦克风。
AVCaptureDevice 的创建有两种方式,第一种是通过 AVCaptureDevice 提供的类方法,另外一种是 通过 AVCaptureDeviceDiscoverySession 提供的类方法。
在这里我们暂且使用 AVCaptureDevice 创建,完整的函数签名如下:
[ AVCaptureDevic deviceWithDeviceType:AVCaptureDeviceType mediaType:AVMediaType position:AVCaptureDevicePosition];
AVCaptureDeviceTypeBuiltInMichrophone 麦克风设备
AVCaptureDeviceTypeBuiltInWideAngleCamera 内置广角相机设备
AVCaptureDeviceTypeBuiltInTelephotoCamera 内置的相机设备 焦距比广角相机长。 注意: 此类设备只能使用 AVCaptureDeviceDiscoverySession 发现
AVCaptureDeviceTypeBuiltInUltraWideCamera 比广角相机焦距短的内置相机设备。 注意: 此类设备只能使用 AVCaptureDeviceDiscoverySession 发现
AVCaptureDeviceTypeBuiltInDualCamera 一种由两个固定的焦距照相机组成的 设备 。一个是广角镜头(Wide),一个是远摄镜头 (Telephoto)。
AVCaptureDeviceTypeBuiltInDualWideCamera 一种由两个固定焦距照相机组成的 设备 。一个是超宽镜头(Ultra Wide),一个是广角镜头(Wide Angle)。
AVCaptureDeviceTypeBuiltInTripleCamera 一种有三个固定焦距照相机组成的 设备 。一个超宽镜头( Ultra Wide ),一个广角镜头( Wide Angle )和一个远摄镜头( Telephoto )组成。
AVCaptureDeviceTypeBuiltInTrueDepthCamera 一种由两台摄像机组成的设备。一台 YUV 和一台红外线。红外线摄像头可提供高质的深度信息,该信息可与 YUV 摄像头产生的帧同步并进行透视纠正。两台摄像头的分辨率可能不通透,但他们的相同的纵横比。
AVMediaTypeVideo 视频
AVMediaTypeAudio 音频
AVMediaTypeText 文本
AVMediaTypeSubtitle 字幕
AVMediaTypeMetadata 元数据
AVCaptureDevicePositionUnspecified 未指定
AVCaptureDevicePositionBack 后置
AVCaptureDevicePositionFront 前置
AVCaptureDevice 创建完成后,根据图示我们还缺一个 AVCatpureDeviceInput。
AVCatpureDeviceInput 同样为我们提供提供了类方法。
[ AVCatpureDeviceInput deviceInputWithDevice:AVCaptureDevice error:NSError];
接下来就是将 AVCaptureDeviceInput 添加到 AVCaptureSession 中, AVCaptureDeviceInput 可以从指定的 AVCatpureDevice 采集媒体数据并交由 AVCaptureSession 。
在添加设备之前,我们有必要看看 AVCatpureSession 的详细接口。
canSetSessionPreset:(AVCaptureSessionPreset)preset 是否支持该 preset
canAddInput:(AVCaptureInput *)input 是否可以添加指定的采集输入设备
addInput:(AVCaptureInput *)input 添加采集输入设备
removeIn p ut :(AVCaptureInput * ) input 移除指定的采集输入设备
canAddOutput:(AVCaptureOutput *)output 是 否可以添加指 定的输出接口
addOutput:( AVCa ptureOutput *)output 添加采集输出接口
removeOutput :(AVCaptureOutput * ) outp ut 移除 指定的 输出接口
startRuning 启动采集会话,开始采集并输出
stopRuning 停止采集会话
为 AVCatpureSession 添加采集设备,需使用 addInput :(AVCaptureInput *)input 函数。
添加完成后, 使用 startRuning 启动采集会话 ,就可以看到相机捕获的画面。
可是这里我们没有指定 output 啊?? 不知道你记得 AVCaptureVideoPreviewLayer , previewLayer 内部维护的就是一个 Ouput,获取到相机数据后,渲染到视图上。后边我们录制视频时,会涉及到 Ou p ut 。
配置权限千万不要忘记,需要我们在 plist 中配置相关说明。
还需要在启动相机之前,让用户授权。
当用户授权完成后,使用 [session startRuning] 启动相机采集。
完整代码可以参考 AVCam 项目。
关注 GeekDev 公众号你将在第一时间获取最新内容。
如果你想了解更多信息回复 资料 获取。
往期内容:
下期预告:
使用 AVFoundation 开发一款相机 APP
◆ ◆ ◆
我来评几句
登录后评论已发表评论数()