(十)深入了解AVFoundation-采集:录制视频功能的实现

(一)深入了解AVFoundation:框架概述与核心模块解析-CSDN博客

(二) 深入了解AVFoundation - 播放:AVFoundation 播放基础入门-CSDN博客

(三)深入了解AVFoundation-播放:AVPlayer 进阶 播放状态 & 进度监听全解析_avplayer 播放状态-CSDN博客

(四)深入理解AVFoundation-播放:高度自定义视频播放器 UI-CSDN博客

(五)深入了解AVFoundation-播放:多音轨、字幕、倍速播放与横竖屏切换-CSDN博客

(六)深入了解AVFoundation-播放:AirPlay、画中画后台播放_air.av-CSDN博客

(七)深入了解AVFoundation-采集:采集系统架构与 AVCaptureSession 全面梳理_avcapturesession startrunning子线程调用-CSDN博客

(八)深入了解AVFoundation-采集:拍照功能的实现_ios avcapturephotooutput-CSDN博客

(九)深入了解AVFoundation-采集:拍照 摄像头切换、拍照参数和照片数据EXIF 信息-CSDN博客

(十)深入了解AVFoundation-采集:录制视频功能的实现-CSDN博客

(十一)深入了解AVFoundation-采集:二维码识别-CSDN博客

(十二)深入了解AVFoundation-采集:人脸识别与元数据处理-CSDN博客

引言

在前文章中,我们深入探讨了如何通过 AVCaptureSession 配置 iOS 中的捕捉输入及输出。并通过使用 AVCaptureDeviceInput 和 AVCapturePhotoOutput,我们实现了基础的照片捕获功能,并配置了 PHPreviewView 来显示实时预览。

在本篇中,我们将继续沿用前两篇的基本配置思路,但重点转向如何实现 高清视频和音频的录制。尽管大部分配置流程和前面的内容相似,主要区别在于,我们需要使用 AVCaptureMovieFileOutput 来处理视频录制,并结合音频输入和输出进行同步。通过这种方式,我们可以实现一个完整的多媒体录制系统,同时捕获视频和音频流。

搭建视频录制功能

为了更好的理解视频录制整体搭建流程,我们将其功能封装到一个 PHCaptureRecordController 类中,它将会负责视频录制的全部操作流程:

  1. 配置 AVCaptureSession。
  2. 添加摄像头输入。
  3. 添加视频录制输出。
  4. 启动与停止会话。
  5. 处理视频录制完成数据。

1. 类的基本结构

我们先来创建一个PHCaptureRecordController类,大致结构如下:

import UIKit
import AVFoundation

class PHCaptureRecordController: NSObject {
    
    /// 会话
     let session = AVCaptureSession()
    /// 输出
    private let moviceFileOutput = AVCaptureMovieFileOutput()
    /// 输入
    private var captureDeviceInput: AVCaptureDeviceInput?
    /// 队列
    private let sessionQueue = DispatchQueue(label: "com.example.captureSession")
    /// 代理
    weak var delegate: PHCaptureProtocol?
    
    /// 配置会话
    func setupConfigureSession() {
       
    }
    
    /// 启动会话
    func startSession() {
       
    }
    
    /// 停止会话
    func stopSession() {
       
    }
    
    /// 开始录制
    func startRecording() {
       
    }
    
    /// 停止录制
    func stopRecording() {
       
    }
    
   
}

可以看到我们在类的内部维护了:

  1. session:采集会话。
  2. moviceFileOutput:用于视频录制的会话输出。
  3. captureDeviceInput:当前使用的会话输入。
  4. sessionQueue:串行队列,保证采集相关操作的线程安全。
  5. delegate:代理,负责错误和结果的回调。

2. 配置采集会话

我们在 setupConfigureSession 方法中需要完成三个操作:

  1. 设置会话预设。
  2. 添加摄像头输入。
  3. 添加照片输出。

并且保证这些操作需要在会话 beginConfiguration 与 commitConfiguration 方法之间执行。

    /// 配置会话
    func setupConfigureSession() {
        session.beginConfiguration()
        // 1.设置会话预设
        setupSessionPreset()
        // 2.设置会话输入
        if !setupSessionInput() {
            delegate?.captureError(NSError(domain: "PHCaptureController", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Failed to add input"]))
            return
        }
        // 3.设置会话输出
        if !setupSessionOutput() {
            delegate?.captureError(NSError(domain: "PHCaptureController", code: 1002, userInfo: [NSLocalizedDescriptionKey: "Failed to add output"]))
            return
        }
        session.commitConfiguration()
    }

2.1 设置会话预设

在配置 AVCaptureSession 时,我们需要选择适当的预设(preset)来确定录制视频的质量。AVCaptureSession 提供了多种预设选项,每个选项对应不同的视频分辨率和帧率。

例如,以下代码设置会话的预设为 .high,这意味着录制的视频将以较高的质量进行处理,适用于需要高清视频的场景:

    /// 设置会话话预设
    private func setupSessionPreset() {
        session.sessionPreset = .high
    }

2.2 设置会话输入

在视频录制中我们要同时设置摄像头及麦克风的输入,并确保这两个输入都成功被添加到会话,有一个失败则认为是设置失败。

    /// 设置会话输入
    private func setupSessionInput(device: AVCaptureDevice? = nil) -> Bool {
        // 1.获取摄像头
        guard let device = device else { return false }
        do {
            captureDeviceInput = try AVCaptureDeviceInput(device: device)
            if session.canAddInput(captureDeviceInput!) {
                session.addInput(captureDeviceInput!)
            } else {
                return false
            }
        } catch {
            delegate?.captureError(error)
            return false
        }
        //2.获取麦克风
        guard let audioDevice = AVCaptureDevice.default(for: .audio) else { return false }
        do {
            let audioInput = try AVCaptureDeviceInput(device: audioDevice)
            if session.canAddInput(audioInput) {
                session.addInput(audioInput)
                return true
            } else {
                return false
            }
        } catch {
            delegate?.captureError(error)
            return false
        }
    }
    

2.3 设置回话输出

在完成输入设备的配置之后,我们需要设置输出设备,以便从会话中捕获视频、音频数据。

/// 设置会话输出
    private func setupSessionOutput() -> Bool {
        if session.canAddOutput(moviceFileOutput) {
            session.addOutput(moviceFileOutput)
            return true
        } else {
            return false
        }
        
    }

3. 会话的启动与停止

我们同样使用单独的串行队列来管理会话的启动与停止,避免出现线程问题。

    /// 启动会话
    func startSession() {
        sessionQueue.async {
            if !self.session.isRunning {
                self.session.startRunning()
            }
        }
    }
    
    /// 停止会话
    func stopSession() {
        sessionQueue.async {
            if self.session.isRunning {
                self.session.stopRunning()
            }
        }
    }

4. 开始与停止录制

在配置好输入设备和输出设备后,我们可以通过 AVCaptureMovieFileOutput 来控制视频的录制。AVCaptureMovieFileOutput 提供了两个主要方法:startRecording 和 stopRecording,用于开始和停止视频录制。

开始录制

开始录制时,我们需要指定一个文件保存路径,并调用 startRecording 方法开始录制。以下是实现代码:

/// 开始录制
func startRecording() {
    // 设置输出文件路径
    let outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("output.mov")
    
    // 启动录制
    moviceFileOutput.startRecording(to: outputURL, recordingDelegate: self)
}
  1. 输出路径:我们使用 FileManager.default.temporaryDirectory 来创建一个临时文件夹,并为录制的视频指定一个保存路径。这里保存的是 .mov 格式的视频文件。
  2. 启动录制:调用 startRecording(to: recordingDelegate:) 方法,传入输出文件路径和录制的代理对象。代理对象负责处理录制过程中产生的各种事件,例如录制的开始、停止、失败等。
停止录制

录制完成后,我们需要调用 stopRecording 方法来结束录制,并将录制的视频保存到指定的文件路径中。以下是停止录制的代码实现:

/// 停止录制
func stopRecording() {
    // 停止录制
    moviceFileOutput.stopRecording()
}

调用 stopRecording() 后,AVCaptureMovieFileOutput 会停止录制视频,并将录制的视频保存到先前指定的输出路径。此时,代理方法会被触发,我们可以在代理方法中处理保存的文件或进行其他后续操作。

5. 录制完成的代理方法

当视频录制完成时,AVCaptureMovieFileOutput 会调用 AVCaptureFileOutputRecordingDelegate 的 fileOutput(_:didFinishRecordingTo:from:connections:error:) 方法。我们可以通过这个方法获取录制的文件路径,并处理录制结果。

以下是代理方法的代码实现:

// MARK: AVCaptureFileOutputRecordingDelegate
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: (any Error)?) {
    if let error = error {
        // 录制过程中发生错误,调用错误回调
        delegate?.captureError(error)
    } else {
        // 录制完成,处理视频文件
        // 可以将 outputFileURL 移动到你想要保存的位置
        delegate?.captureVideo(outputFileURL)
    }
}
  1. outputFileURL:这是录制视频的输出文件 URL,包含了录制完成的视频文件路径。你可以根据需要将其移动或拷贝到其他位置进行后续处理。
  2. connections:表示输出连接的数组,通常情况下,我们只关心视频录制的连接。
  3. error:如果录制过程中出现错误,该参数会包含错误信息。我们可以检查并处理错误。

结语

在本篇中,我们详细介绍了如何在 iOS 中实现高清视频与音频的录制。从配置 AVCaptureSession 和添加输入输出设备,到设置视频和音频的录制输出,我们逐步完成了录制会话的初始化和控制。特别是在开始与停止录制部分,我们展示了如何通过 AVCaptureMovieFileOutput 控制录制的启动与停止,并通过代理方法处理录制完成后的文件。

接下来,你可以根据项目需求进一步优化视频录制体验,例如添加实时预览、录制过程中动态调整质量,或者对录制的文件进行后期处理(如视频编辑、转码等)。

感谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值