4. 录制架构设计:音频源、视频源、编码器绑定、Muxer输出流程
4.1 边界与核心问题
录制架构是多媒体系统的“写端”——将音视频实时输入封装为持久化文件。核心边界是从 传感器驱动层到 文件抽象层,需解决以下矛盾:
- 实时性:编码与写入不能阻塞采集循环
- 同步性:音频/视频时间戳需保持统一时间基
- 容错性:源断开、编码器过载、磁盘满时须优雅降级
- 格式兼容:Muxer需支持 MP4、WebM、TS 等多容器
4.2 分层与组件职责
整个录制管道划分为 4 个边界清晰的层级:
| 层级 | 组件 | 职责 |
|---|---|---|
| 源层 | CameraSource / AudioSource | 驱动摄像头与麦克风,输出原始帧(NV12/YUV + PCM) |
| 编码层 | VideoEncoder / AudioEncoder | 接收原始帧,输出编码后 ES(H.264/H.265/AAC) |
| 绑定层 | TrackBinder / CodecProxy | 管理编码器生命周期,处理 MediaCodec 回调,输出复用时间戳 |
| 输出层 | MediaMuxer / FsWriter | 接收编码轨道数据,封装为容器文件 |
关键设计约束:编码层与源层之间不允许直接共享 Buffer 指针(跨进程边界),必须通过 Surface/ 共享内存传递,避免 ANR 与内存抖动。
4.3 数据流与控制流
主数据流(顺时针):
- CameraSource 通过
Surface投递 YUV 帧 → VideoEncoder - AudioSource 通过
ByteBuffer投递 PCM → AudioEncoder - 编码器输出
BufferInfo(含 PTS/标志)→ TrackBinder - TrackBinder 按 PTS 排序 → MediaMuxer 的
writeSampleData() - MediaMuxer 写入文件(MP4 moov box 需在 stop 时更新)
控制流(逆时针):
- App 层调用
startRecording()→ 启动所有源与编码器 - TrackBinder 监听编码器
onOutputBufferAvailable,背压控制:当 Muxer 写入慢时暂停给编码器注入帧 - 所有源完成 EOS 后 → 触发
stopRecording()→ 编码器 drain → Muxer stop → 文件 finalize
4.4 信任链路与同步策略
录制系统的正确性依赖跨组件的时间基对齐:
- 时钟源:统一使用
System.nanoTime()生成 PTS,避免各组件使用不同单调钟 - 音频驱动 PTS:AudioSource 以
AudioRecord.getTimestamp()为准,回传纳秒 - 视频驱动 PTS:CameraSource 以帧回调时间戳 + 帧间隔推算,输入 Surface 时由编码器自动分配
- Muxer 信任:MediaMuxer 要求所有轨道的 PTS 从 0 开始连续递增;TrackBinder 负责偏移校准
常见的信任断链:当使用第三方编码器(如 HW encoder 复用)时,编码器可能自行修改 PTS 或丢帧,导致 Muxer 输出的视频加速/慢放。必须在测试阶段记录编码器输出 PTS 序列,检查单调递增性。
4.5 选型权衡:软编码 vs 硬编码 vs 混合
| 维度 | 硬编码(MediaCodec) | 软编码(FFmpeg / x264) | 混合方案 |
|---|---|---|---|
| 功耗 | 低(专用 DSP) | 高(CPU 满载) | 中(视频硬编 + 音频软编) |
| 兼容性 | 不同厂商 bitstream 差异 | 完全可预测 | 需处理两者同步 |
| 编码质量 | 中(部分厂商弱) | 高(可调参数多) | 折中 |
| 延迟 | 低(管线优化) | 高(CPU 排队) | 可控 |
推荐策略:Android 10+ 优先使用
MediaCodec 硬编码 + MediaMuxer 原生 API;仅在需要定制编码参数(如 CBR vs VBR 精确码率)或 RTMP 直播场景时引入 FFmpeg 软编码。
4.6 风险点与缓解措施
- 编解码器重启延迟:横竖屏切换导致 Camera 重启,编码器需
stop()+release()后重建 → 预创建备用编码器池 - Muxer 写入瓶颈:SD 卡写入慢导致背压 → 使用双缓冲队列 + 超时降级(丢帧而不是丢文件)
- 时间戳溢出:长时间录制 PTS 超过
Long.MAX_VALUE→ 定期归一化 PTS 基线 - 跨进程 CameraSource 死锁:Camera HAL 报错导致回调不触发 → 设置 watchdog 超时自动 stop
4.7 落地步骤(架构实施路线)
- Step 1: 实现
AudioSource与CameraSource适配器,分别输出Frame对象(含 buf + pts + 标志位) - Step 2: 创建
EncoderManager,封装 MediaCodec 的 configure/start/stop/release,支持动态切换编码器类型 - Step 3: 实现
TrackBinder线程,维护音频/视频两条ConcurrentLinkedQueue,按 PTS 归并后喂给 Muxer - Step 4: 集成
MediaMuxer,添加文件命名策略与临时文件原子重命名 - Step 5: 添加背压监控指标(队列积压大小),在
onStateChanged回调中触发降级逻辑
4.8 验收标准
- 录制 60 秒 1080p30 + 立体声 AAC,输出 MP4 文件音画同步误差 < 40ms
- 连续录制 1 小时无崩溃、无漏帧(对比原始帧计数)
- 切换摄像头(前后)可连续录制,新片段 PTS 从 0 开始
- 磁盘满时回调
onError(ERROR_FILE_LIMIT),不生成损坏文件 - 横竖屏旋转 50 次后录制依然正常启动