3. 移动端采集架构

移动端音视频采集并不是“打开摄像头就能推流”这么简单。它是一条从硬件到应用层的完整链路:摄像头/麦克风传感器 → 系统采集框架 → 应用层 API → 编码器。理解这条链路,才能正确配置参数、处理权限和应对前后台切换。

一、采集链路与系统框架

在 Android 上,摄像头数据通过 Camera2(或 CameraX)API 获取,麦克风通过 AudioRecord 获取;在 iOS 上,摄像头和麦克风统一由 AVFoundation 框架管理,核心类是 AVCaptureSession。无论哪个平台,采集链路都可以抽象为四层:

  • 硬件层:CMOS 传感器、MEMS 麦克风,输出原始信号。
  • 系统框架层:Android 的 CameraService/AudioFlinger,iOS 的 AVFoundation,负责设备枚举、格式协商、缓冲区管理。
  • 应用 API 层:Camera2/CameraX、AudioRecord、AVCaptureDevice/AVCaptureSession,开发者直接调用的接口。
  • 数据处理层:将采集到的 YUV/RAW 帧和 PCM 音频送入编码器(如 MediaCodec、VideoToolbox)。

下图展示了移动端采集架构的核心数据流与关键控制点:

摄像头传感器 CMOS / 输出 YUV·RAW 麦克风传感器 MEMS / 输出 PCM 系统采集框架 Android: CameraService / AudioFlinger | iOS: AVFoundation Camera2 / CameraX AVCaptureDevice AudioRecord AVCaptureAudio 编码器 / 推流 MediaCodec · VideoToolbox · 音视频同步 关键控制点 📷 采集参数配置 分辨率 1280×720 | 帧率 30fps | 格式 NV21 🎤 音频参数配置 采样率 44100Hz | 单声道 | 16bit PCM 🔐 权限管理 CAMERA | RECORD_AUDIO | 运行时申请 🔄 前后台切换 onPause 释放 | onResume 重建 | 状态恢复 ⚠️ 异常处理 设备占用 | 权限拒绝 | 采集中断恢复

二、摄像头与麦克风 API 选型

Android 平台目前推荐使用 CameraX,它对 Camera2 做了封装,自动处理设备兼容性和生命周期,适合大多数直播、短视频场景。若需要精细控制曝光、对焦、多摄切换,则使用 Camera2。音频方面,AudioRecord 提供原始 PCM 数据,适合需要自定义前处理(如降噪、回声消除)的场景;若只需简单录音,MediaRecorder 更便捷但灵活性低。

iOS 平台统一使用 AVFoundation。核心流程是:创建 AVCaptureSession → 添加 AVCaptureDeviceInput(视频和音频各一个)→ 添加 AVCaptureVideoDataOutput / AVCaptureAudioDataOutput → 在代理回调中获取 CMSampleBuffer。AVCaptureSession 的 startRunning 和 stopRunning 是阻塞操作,必须放在串行队列中执行,否则会卡住主线程。

三、采集参数配置

视频采集参数主要包括分辨率、帧率、像素格式和方向。以 720p@30fps 为例,在 CameraX 中配置如下:

// CameraX 预览 + 采集配置示例
val preview = Preview.Builder()
    .setTargetResolution(Size(1280, 720))
    .setTargetRotation(Surface.ROTATION_0)
    .build()

val imageAnalysis = ImageAnalysis.Builder()
    .setTargetResolution(Size(1280, 720))
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
    .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888)
    .build()

// 帧率控制通过 Camera2Interop 扩展
val builder = Camera2Interop.Extender(imageAnalysis)
builder.setCaptureRequestOption(
    CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
    Range(30, 30)
)

音频参数方面,直播场景常用 44100Hz 采样率、单声道、16bit 量化。若对音质要求高(如音乐直播),可提升至 48000Hz 立体声。注意:采样率越高,单位时间数据量越大,44100Hz 单声道 16bit 每秒约 88.2KB,而 48000Hz 立体声 16bit 每秒约 192KB,带宽和编码压力相差一倍以上。

参数配置的核心原则是“匹配下游编码器能力”。如果编码器只支持 720p,采集 1080p 再缩放只会浪费 CPU 和内存。建议采集分辨率与编码分辨率保持一致,或采集略高于编码一档以便裁剪。

四、权限管理

移动端采集涉及两个危险权限:CAMERA 和 RECORD_AUDIO。两者都必须在运行时动态申请,且用户可能拒绝或只授予部分权限。正确的处理流程是:

  1. 在 AndroidManifest.xml / Info.plist 中声明权限。
  2. 启动采集前检查权限状态,未授权则发起请求。
  3. 用户拒绝后,展示解释性 UI,说明为什么需要该权限。
  4. 用户勾选“不再询问”后,引导跳转系统设置页手动开启。
  5. 权限被撤销时(如用户在设置中关闭),监听回调并停止采集、释放资源。

iOS 上还需注意:首次调用 AVCaptureDevice.requestAccess 时系统弹窗只出现一次,之后必须通过 AVAuthorizationStatus 判断并引导用户去“设置 → 隐私 → 相机/麦克风”中修改。

五、前后台切换处理

这是移动端采集最容易出问题的环节。当 App 退到后台,系统可能回收摄像头资源,或者直接终止采集会话。如果不做处理,回到前台后会出现黑屏、采集失败或崩溃。

Android 上的处理策略:在 onPause 中调用 cameraProvider.unbindAll() 释放摄像头,停止 AudioRecord;在 onResume 中重新绑定用例、重新启动采集。注意 CameraX 的 bindToLifecycle 会自动跟随 LifecycleOwner,但音频采集需要手动管理。

iOS 上的处理策略:监听 UIApplication.didEnterBackgroundNotification 和 willEnterForegroundNotification。进入后台时调用 captureSession.stopRunning(),回到前台时重新 startRunning()。如果 App 需要在后台继续采集音频(如录音场景),需在 Info.plist 中声明 UIBackgroundModes 为 audio,并配置 AVAudioSession 的 category 为 playAndRecord。

前后台切换时,采集参数可能发生变化。例如某些设备从后台恢复后,摄像头默认帧率或曝光会重置。建议在恢复采集后重新检查并应用参数配置,必要时重建整个采集管线。

六、采集状态检查清单

在实际工程中,可以用以下清单快速排查采集问题:

检查项正常表现异常处理
权限状态CAMERA 和 RECORD_AUDIO 均为已授权引导用户去设置页开启
设备可用性摄像头未被其他 App 占用提示“摄像头被占用”,延迟重试
采集帧率稳定在配置值 ±2fps降低分辨率或关闭美颜等前处理
音频数据PCM 缓冲区持续有数据写入检查 AudioRecord 状态和缓冲区大小
前后台恢复回到前台 1 秒内恢复预览重建采集会话,重新绑定用例