采集视频
概述
音视频采集是直播架构的第一环,是视频的来源
其实视频的采集有多个应用场景:比如二维码开发
音视频采集包括两部分:
视频采集
音频采集
在iOS开发中,是可以同步采集视频&音频的,使用方式也非常简单
相关的采集API都封装在AVFoundation框架中,导入对应框架,实现功能即可
采集步骤
采集步骤文字描述
PS:如果做过二维码开发,应该对相关步骤非常熟悉(非常类似)
导入框架
相关API主要在AVFoundation框架中,因此需要先导入框架
创建捕捉会话(AVCaptureSession)
该会话用于连接之后的输入源&输出源
输入源:摄像头&话筒
输出源:拿到对应的音频&视频数据的出口
会话:用于将输入源&输出源连接起来
设置视频输入源&输出源
输入源(AVCaptureDeviceInput):从摄像头输入
输出源(AVCaptureVideoDataOutput):可以设置代理,在代理方法中拿到数据
将输入&输出添加到会话中
设置音频输入源&输出源
输入源(AVCaptureDeviceInput):从话筒输入
输出源(AVCaptureAudioDataOutput):可以设置代理,在代理方法中拿到数据
将输入&输出添加到会话中
添加预览图层(可选)
如果希望用户看到采集的画面,可以添加预览图层
该预览图层不是必须的,及时没有添加也可以正常采集数据
开始采集即可
调用会话(AVCaptureSession)的startRunning方法即可开始采集
代码解析
整体代码步骤
函数一(设置视频输入输出)
函数二(设置音频输入输出)
添加预览图层
遵守协议,实现代理方法
实现代码
整体步骤代码
// 1.创建捕捉会话 let session = AVCaptureSession() // 2.设置视频输入输出 setupVideoSource(session: session) // 3.设置音频输入输出 setupAudioSource(session: session) // 4.添加预览图层 setupPreviewLayer(session: session) // 5.开始扫描 session.startRunning()
函数一(设置视频输入输出)
// 给会话设置视频源(输入源&输出源) fileprivate func setupVideoSource(session : AVCaptureSession) { // 1.创建输入 // 1.1.获取所有的设备(包括前置&后置摄像头) guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else { return } // 1.2.取出获取前置摄像头 let d = devices.filter({ return $0.position == .front }).first // 1.3.通过前置摄像头创建输入设备 guard let videoInput = try? AVCaptureDeviceInput(device: d) else { return } // 2.创建输出源 // 2.1.创建视频输出源 let videoOutput = AVCaptureVideoDataOutput() // 2.2.设置代理,以及代理方法的执行队列(在代理方法中拿到采集到的数据) let queue = DispatchQueue.global() videoOutput.setSampleBufferDelegate(self, queue: queue) // 3.将输入&输出添加到会话中 // 3.1.添加输入源 if session.canAddInput(videoInput) { session.addInput(videoInput) } // 3.2.添加输出源 if session.canAddOutput(videoOutput) { session.addOutput(videoOutput) } // 4.给connect赋值 videoConnect = videoOutput.connection(withMediaType: AVMediaTypeVideo) }
函数二(设置音频输入输出)
// 给会话设置音频源(输入源&输出源) fileprivate func setupAudioSource(session : AVCaptureSession) { // 1.创建输入 guard let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) else { return } guard let audioInput = try? AVCaptureDeviceInput(device: device) else { return } // 2.创建输出源 let audioOutput = AVCaptureAudioDataOutput() let queue = DispatchQueue.global() audioOutput.setSampleBufferDelegate(self, queue: queue) // 3.将输入&输出添加到会话中 if session.canAddInput(audioInput) { session.addInput(audioInput) } if session.canAddOutput(audioOutput) { session.addOutput(audioOutput) } }
添加预览图
// 添加预览图层 fileprivate func setupPreviewLayer(session : AVCaptureSession) { // 1.创建预览图层 guard let previewLayer = AVCaptureVideoPreviewLayer(session: session) else { return } // 2.设置图层的属性 previewLayer.frame = view.bounds // 3.将图层添加到view中 view.layer.insertSublayer(previewLayer, at: 0) }
遵守协议,实现代理方法
extension ViewController : AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate { func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { if connection == videoConnect { print("视频数据") } else { print("音频数据") } }}
停止扫描
比如用户不再直接,我们需要停止扫描
移除预览图层(不再直播肯定不需要预览图层了)
停止扫描(调用session的stopRunning方法)
将session设置为nil(对象不再使用,指针置空)
@IBAction func stopScanning() { // 1.移除图层 previewLayer?.removeFromSuperlayer() // 2.停止扫描 session?.stopRunning() // 3.将对象重置为nil session = nil }
来源:小码哥