音视频的采集

概述

  • 音视频采集是直播架构的第一环,是视频的来源
    其实视频的采集有多个应用场景:比如二维码开发

  • 音视频采集包括两部分
    视频采集
    音频采集

  • 在iOS开发中,是可以同步采集视频&音频的,使用方式也非常简单

  • 相关的采集API都封装在AVFoundation框架中,导入对应框架,实现功能即可

采集步骤

相关API主要在AVFoundation框架中,因此需要先导入框架

创建捕捉会话(AVCaptureSession)

  • 该会话用于连接之后的输入源&输出源
    
  • 输入源:摄像头&话筒
    
  • 输出源:拿到对应的音频&视频数据的出口
    
  • 会话:用于将输入源&输出源连接起来
    
fileprivate lazy var session = AVCaptureSession()

设置视频输入源&输出源

  • 输入源(AVCaptureDeviceInput):从摄像头输入
    
  • 输出源(AVCaptureVideoDataOutput):可以设置代理,在代理方法中拿到数据
    
  • 将输入&输出添加到会话中
    
 // 给会话设置视频源(输入源&输出源)
fileprivate func setupVideoSource() {
        // 1.创建输入
        // 1.1.获取所有的设备(包括前置&后置摄像头)builtInTelephotoCamera,builtInDualCamera,builtInTrueDepthCamera
        guard let device = AVCaptureDevice.DiscoverySession.init(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .front).devices.first else { return }
        
        // 1.3.通过前置摄像头创建输入设备
        guard let videoInput = try? AVCaptureDeviceInput(device: device) else { return }
        self.vedioInput = videoInput
        // 2.创建输出源
        // 2.1.创建视频输出源
        let videoOutput = AVCaptureVideoDataOutput()
        
        // 2.2.设置代理,以及代理方法的执行队列(在代理方法中拿到采集到的数据)
        let queue = DispatchQueue.global()
        videoOutput.setSampleBufferDelegate(self, queue: queue)
        
        self.videoOutPut = videoOutput
        
        // 3.将输入&输出添加到会话中
        addToSession(videoInput, videoOutput)
    }
    
     // 添加到session
    fileprivate func addToSession(_ input: AVCaptureInput,_ output: AVCaptureOutput) {
        // 3.将输入&输出添加到会话中
        session.beginConfiguration()
        if session.canAddInput(input) {
            session.addInput(input)
        }
        if session.canAddOutput(output) {
            session.addOutput(output)
        }
        session.commitConfiguration()
    }

设置音频输入源&输出源

  • 输入源(AVCaptureDeviceInput):从话筒输入
    
  • 输出源(AVCaptureAudioDataOutput):可以设置代理,在代理方法中拿到数据
    
  • 将输入&输出添加到会话中
    
// 给会话设置音频源(输入源&输出源)
    fileprivate func setupAudioSource() {
        // 1.创建输入
        guard let device = AVCaptureDevice.DiscoverySession.init(deviceTypes: [.builtInMicrophone], mediaType: .audio, position: .unspecified).devices.first else { return }
        guard let audioInput = try? AVCaptureDeviceInput(device: device) else { return }
        
        // 2.创建输出源
        let audioOutput = AVCaptureAudioDataOutput()
        let queue = DispatchQueue.global()
        audioOutput.setSampleBufferDelegate(self, queue: queue)
        
        addToSession(audioInput, audioOutput)
    }

添加预览图层(可选)

  • 如果希望用户看到采集的画面,可以添加预览图层
    
  • 该预览图层不是必须的,及时没有添加也可以正常采集数据
    
// 添加预览图层
    fileprivate func setupPreviewLayer() {
        // 1.创建预览图层
        let previewLayer = AVCaptureVideoPreviewLayer(session: session)
        
        // 2.设置图层的属性
        previewLayer.frame = view.bounds
        
        // 3.将图层添加到view中
        view.layer.insertSublayer(previewLayer, at: 0)
        self.previewLayer = previewLayer
    }

开始采集即可
调用会话(AVCaptureSession)的startRunning方法即可开始采集

 // 开始采集
 session.startRunning()

停止扫描

  • 比如用户不再直接,我们需要停止扫描
    
  • 移除预览图层(不再直播肯定不需要预览图层了)
    
  • 停止扫描(调用session的stopRunning方法)
    
  • 将session设置为nil(对象不再使用,指针置空)
    
// 停止采集
session.stopRunning()

切换镜头(前置&后置摄像头)

切换步骤

  •     给切换过程添加动画
    
  •     获取当前摄像头是前置还是后置
    
  •     取出相反的摄像头(之前是前置,这次取出后置)
    
  •     通过新摄像头重新获取设备(AVCaptureDevice)
    
  •     通过设备(AVCaptureDevice)创建新的输入(AVCaptureDeviceInput)
    
  •     移除旧input&添加新的input
    
  •     注意:修改session配置之前先调用开启修改配置选项,配置完成后,调用提交修改配置选项
    
  •     session?.beginConfiguration()
    
  •     session?.commitConfiguration()
    
  •     保存新的input
    
/// 切换摄像头
    @IBAction func rotateCamera(_ sender: UIButton) {
        
        // 0.执行动画
        let rotaionAnim = CATransition()
        rotaionAnim.type =  .fade
        rotaionAnim.subtype = .fromLeft
        rotaionAnim.duration = 0.5
        view.layer.add(rotaionAnim, forKey: nil)
        
        
        // 拿到之前的设备
        guard let vedioInput = vedioInput else {
            return
        }
        // 计算现在要切换的设备(如果之前是前置现在就是后置)
        let position: AVCaptureDevice.Position = vedioInput.device.position == .front ? .back : .front
        // 获取对象的输入对象
        guard let device = AVCaptureDevice.DiscoverySession.init(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: position).devices.first else { return }
        
        // 通过设备创建输入设备
        guard let newVideoInput = try? AVCaptureDeviceInput(device: device) else { return }
        // 记录当前的设备
        self.vedioInput = newVideoInput
        // 移除之前的  添加新的
        session.beginConfiguration()
        session.removeInput(vedioInput )
        if session.canAddInput(newVideoInput) {
            session.addInput(newVideoInput)
        }
        session.commitConfiguration()
    }

写入文件

**写入文件步骤**
  •     创建AVCaptureMovieFileOutput对象
    
  •     用于将音频视频写入文件
    
  •     将movieFileOutput对象,添加到session的输出中
    
  •     写入文件也是一种输出
    
  •     设置视频的稳定模式
    
  •     不设置可能会出现视频跳帧等问题
    
  •     通常设置为自动即可
    
  •     开始写入
    
  •     录制完成,停止写入即可
    
/// 存储音视频到文件
    fileprivate func setupMovieOutputFile() {
        // 获取文件的输出对象
        let fileOutput = AVCaptureMovieFileOutput()
        self.movieFileOutput = fileOutput
        // 创建文件路径
        let filePath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/app.mp4"
        
        let fileUrl = URL(fileURLWithPath: filePath)
        // 获取视频的连接
        let connection = fileOutput.connection(with: .video)
        // 设置视频的稳定模式
        connection?.automaticallyAdjustsVideoMirroring = true
        
        session.beginConfiguration()
        if session.canAddOutput(fileOutput) {
            session.addOutput(fileOutput)
        }
        session.commitConfiguration()
        
        fileOutput.startRecording(to: fileUrl, recordingDelegate: self)
    }

停止写入代码

// 0.停止写入
        self.movieFileOutput?.stopRecording()

在代理方法中监听开始、结束事件

extension ViewController : AVCaptureFileOutputRecordingDelegate {
    func capture(_ captureOutput: AVCaptureFileOutput!, didStartRecordingToOutputFileAt fileURL: URL!, fromConnections connections: [Any]!) {
        print("开始录制")
    }

    func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
        print("停止录制")
    }
}

Demo地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值