当前位置: 首页 > news >正文

(七)深入了解AVFoundation-采集:采集系统架构与 AVCaptureSession 全面梳理

引言

在 iOS 开发中,AVFoundation 是构建音视频功能的强大底层框架。而在音视频功能中,“采集”往往是最基础也是最关键的一环。从摄像头捕捉图形、到麦克风获取声音,构建一条高效且稳定的采集链是开发高质量音视频应用的前提。

本系列将逐步深入 AVFoundation的采集机制,了解它的地方设计与实际使用。在本篇中,我们会聚集在采集系统的核心管理单元——AVCaptureSession,从整体架构出发,梳理采集链路的组成方式与搭建流程。

AVCaptureSession 的职责与系统架构

在 AVFoundation 中,AVCaptureSession 是整个采集系统的中心协调者。它的主要职责包括:

  1. 管理输入(Input)与输出(Output)设备:例如摄像头、麦克风作为输入,图像帧输出、音频数据输出作为输出。
  2. 协调数据流的流动:确保从设备捕获到的数据正确地传递到输出模块。
  3. 统一管理采集回话的生命周期:如开始采集startRunning()、停止采集stopRunning()、中断与恢复。
  4. 维护链接配置:控制比如视频方向、镜像、视频稳定等细节。

简而言之,AVCaptureSession 就像是一个数据总管,它把输入设备(比如摄像头、麦克风)和输出目标(比如屏幕预览、数据编码器)连接在一起,并统一管理整个采集链条的工作状态。

采集系统的基本架构可以理解成这样一个数据流动图。

简化来说就是:设备->输入->Session->输出->处理展示。

  • 一个 AVCaptureSession 可以同时管理多个输入输出(比如前后摄像头切换,或者同时采集视频与音频)。
  • 输入与输出设备必须通过 session.addInput() / session.addOutput() 正式添加到会话中,才会参与采集。
  • 建议在 专用串行 DispatchQueue 中配置 Session,避免 UI 卡顿。

输入 + 输出:构建采集模型的两大核心

在 AVFoundation 采集系统中,采集链条的两大基本构成单元就是:

  1. 输入(Input)
  2. 输出(Output)

理解输入输出的工作原理和使用方式,是搭建稳定采集系统的基础。

输入(Input):采集数据的源头

输入负责吧硬件设备(如摄像头、麦克风)链接到AVCaptureSession中。

在实际开发中,我们通常就是使用AVCaptureDeviceInput 来包装摄像头和麦克风。

以摄像头为例:

// 1. 获取摄像头设备
guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {fatalError("未找到后置摄像头")
}// 2. 将设备包装成输入
let cameraInput = try AVCaptureDeviceInput(device: camera)// 3. 添加到 Session
if session.canAddInput(cameraInput) {session.addInput(cameraInput)
}

注意事项:

  1. 添加输入前要用 canAddInput(_:) 检查是否可以添加。
  2. 注意捕获设备可能没有权限,需要提前请求授权。
  3. 创建 AVCaptureDeviceInput 可能抛异常,使用 try。

输出(Output):采集数据的去向

输出负责接收采集到的数据,并将其交给需要的地方处理,比如:

  • 显示预览画面
  • 实时处理图像
  • 保存到文件
  • 推流到服务器

输出的类型有很多种:

输出类别

相关类名

描述

图像数据输出

AVCaptureVideoDataOutput

原始视频帧数据回调

音频数据输出

AVCaptureAudioDataOutput

原始音频数据回调

拍照输出

AVCapturePhotoOutput

拍摄静态照片

录制文件输出

AVCaptureMovieFileOutput

录制成视频文件

元数据输出(如二维码)

AVCaptureMetadataOutput

检测并返回元数据(条形码、二维码)

输出基本使用流程(以视频数据输出为例)

// 1. 创建输出
let videoOutput = AVCaptureVideoDataOutput()// 2. 配置输出参数(如像素格式)
videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
]// 3. 设置代理回调队列
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "VideoOutputQueue"))// 4. 添加到 Session
if session.canAddOutput(videoOutput) {session.addOutput(videoOutput)
}

代理方法示例(捕获到每一帧数据):

extension YourClass: AVCaptureVideoDataOutputSampleBufferDelegate {func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {// 处理每一帧图像}
}

注意事项:

  • 回调通常发生在自定义的串行队列上,避免占用主线程。
  • 输出设备也需要使用 canAddOutput(_:) 检查后再添加。

输入(Input) 负责采集硬件数据,输出(Output)负责把采集到的数据交给你处理或者保存。

输入输出就像水管的两端,中间由 AVCaptureSession 统一协调和流转。

搭建完整采集链条

在前面了解了 AVCaptureSession 的基本架构,以及输入(Input)和输出(Output)之后,这一部分,我们直接从实际角度出发,梳理一次完整搭建采集链条的流程。

完整流程

搭建完整采集链条,核心步骤可以总结为:

  1. 创建 AVCaptureSession
  2. 选择并创建输入设备(Input)
  3. 选择并创建输出设备(Output)
  4. 添加输入与输出到 Session
  5. 配置连接参数(如摄像头方向、镜像等)
  6. 创建预览层(可选)
  7. 启动 Session

整体的伪代码流程如下:

// 1. 创建 Session
let session = AVCaptureSession()// 2. 配置 preset
session.sessionPreset = .high// 3. 创建输入(摄像头)
guard let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),let cameraInput = try? AVCaptureDeviceInput(device: camera),session.canAddInput(cameraInput) else {return
}
session.addInput(cameraInput)// 4. 创建输出(视频数据输出)
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "VideoOutputQueue"))
if session.canAddOutput(videoOutput) {session.addOutput(videoOutput)
}// 5. 配置连接(方向、镜像)
if let connection = videoOutput.connection(with: .video) {connection.videoOrientation = .portraitconnection.isVideoMirrored = false
}// 6. 创建预览层(可选)
let previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = .resizeAspectFill
previewLayer.frame = view.bounds
view.layer.addSublayer(previewLayer)// 7. 启动 Session
session.startRunning()

采集分辨率的控制开关

sessionPreset 负责定义采集的数据质量,比如分辨率、码率、帧率等。

常见的 preset 有:

Preset

说明

.high

高质量(设备自动适配)

.medium

中等质量,适配中速网络上传场景

.low

低质量,适合弱网传输

.hd1280x720

720p 高清

.hd1920x1080

1080p 高清

.photo

照片质量(高分辨率)

注意:

  • preset 需要在 startRunning() 之前设置。
  • preset 要与输入设备能力匹配,否则设置无效,比如某些前置摄像头不支持 4K 采集。
  • 可以使用 session.canSetSessionPreset(_:) 检查兼容性。

连接(AVCaptureConnection)管理

在 Session 里,输入与输出之间的通道,叫做 AVCaptureConnection。

连接对象允许我们进一步微调采集流的细节,比如:

  • 方向(Orientation)
  • 镜像(Mirrored)
  • 视频防抖(Video Stabilization)
  • 自动对焦/曝光/白平衡(某些连接可以关联控制)

一般情况下,我们需要手动设置采集方向为竖屏:

if let connection = videoOutput.connection(with: .video),connection.isVideoOrientationSupported {connection.videoOrientation = .portrait
}

很多 app 前置摄像头拍照是镜像模式,也可以通过 Connection 设置:

if camera.position == .front,let connection = videoOutput.connection(with: .video),connection.isVideoMirrored {connection.isVideoMirrored = true
}

线程注意点:采集是高度异步的

Session 的 startRunning 和 stopRunning 是同步调用,但异步完成,因此推荐在后台线程调用。

输出的数据回调 (captureOutput(_:didOutput:from:)) 是在你指定的 DispatchQueue里触发的,不是主线程。如果在回调里要更新 UI,需要回到主线程。

DispatchQueue.global().async {session.startRunning()
}// 回调中处理 UI
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {DispatchQueue.main.async {// 更新 UI,比如显示帧率}
}

结语

在本篇内容中,我们从整体视角出发,完整梳理了 AVCaptureSession 为核心的采集系统,包括它的职责、输入输出模型,以及如何搭建一条基本的采集链条。

同时也深入探讨了 preset 设置、连接管理 和 线程注意事项 等关键细节,帮助你在实际项目中少踩坑。

可以看到,AVFoundation 的采集体系虽然灵活强大,但也有一定的复杂度。理解 Session 是怎么组织 Input 和 Output 的,掌握 Connection 上的各种参数调优,才能真正驾驭底层采集系统。

接下来的博客我们将继续AVFoudation的采集篇章,我们将在这个基础上,进一步探索更多实战话题。

相关文章:

  • 【解决方法】关于解决QGC地面站4.4.3中文BUG,无法标注航点的问题
  • 【大语言模型DeepSeek+ChatGPT+python】最新AI-Python机器学习与深度学习技术在植被参数反演中的核心技术应用
  • 效率就是竞争力
  • 算法题(130):激光炸弹
  • 每日一题(小白)回溯篇7
  • Vue中如何优雅地阻止特定标签的移除并恢复其原始位置
  • 剑指Offer(数据结构与算法面试题精讲)C++版——day17
  • [c语言日寄]免费文档生成器——Doxygen在c语言程序中的使用
  • 特伦斯便携钢琴V20有哪些优势
  • [预备知识]1. 线性代数基础
  • 4月21日星期一今日早报简报微语报早读
  • 颠覆传统!毫秒级响应的跨平台文件同步革命,远程访问如本地操作般丝滑
  • FTTR 全屋光纤架构分享
  • 【原创】Ubuntu20.04 安装 Isaac Gym 仿真器
  • 视频分析设备平台EasyCVR安防视频小知识:安防监控常见故障精准排查方法
  • init_tcicb函数有调用,但snapshot函数没调用
  • Spring AOP优化in查询,性能提升巨大
  • Unreal如何使用后处理材质实现一个黑屏渐变效果
  • Linux常见指令介绍中(入门级)
  • VSCode远程图形化GDB
  • 62岁中国国际商会副会长、康力电梯创始人王友林逝世
  • “中国共产党的故事——习近平新时代中国特色社会主义思想在重庆的实践”重庆经贸推介会成功举办
  • 北京理工大学解除宫某聘用关系,该教师被指涉嫌骚扰猥亵学生
  • 女子伸腿阻止列车关门等待同行人员,被深圳铁路警方行政拘留
  • 由“环滁皆山”到“环滁皆景”,滁州如何勾勒“文旅复兴”
  • 医院招聘误发内部信息反获好评,求职者就需要这样的“敞亮”