录制过程中如何处理音频和视频的同步问题?
解读
国内面试官问“音视频同步”时,真正想确认的是:
- 你是否理解采集→编码→复用整条链路的时钟基准;
- 能否在 Android 硬编/软编、MediaCodec 零拷贝、Camera2 回调、AAudio/Opensles 低延迟、系统调度抖动、国产 ROM 深度定制等复杂场景下给出可落地的同步策略;
- 是否具备线上实测与容错经验,而不是背“用 PTS 就行”这类教科书答案。
一句话:把“同步”拆成“时间戳对齐 + 缓存平滑 + 异常补偿”,并给出在 30~60 fps、44.1 k/48 k 采样率、低端 6 核机型、电池限频、发热降频、后台录音限制等真实约束下的工程方案。
知识点
-
时钟源选择
• Camera2 的 SENSOR_TIMESTAMP 基于 boottime 单调时钟;
• AudioRecord.getTimestamp 同样基于 boottime,可直接对齐;
• 切勿混用 System.currentTimeMillis()(受 NTP 跳变影响)。 -
时间戳模型
• Video PTS = (sensorTimestamp – firstSensorTimestamp) × 纳秒 → 微秒转换;
• Audio PTS = (audioTimestamp – firstAudioTimestamp) 同理;
• 统一以“首帧”为 0 基准,后续按各自采样周期累加,避免累积误差。 -
采集线程同步
• 采用“共享起始屏障”:先启动 AudioRecord,在首帧写入回调里打开 Camera2 重复请求,保证音频先行,视频追齐;
• 对 10ms 级别帧间隔,使用 HandlerThread + 高优先级 AUDIO/VIDEO 线程,配合 Process.setThreadPriority(THREAD_PRIORITY_URGENT_AUDIO)。 -
编码层对齐
• MediaCodec 配置 KEY_PRIORITY 为 REALTIME;
• 软编场景使用 FFmpeg,设置 -async 1 –vsync 1,音频重采样到 48 kHz,视频固定帧率,禁止可变帧率;
• 每送一帧都带 presentationTimeUs,禁止“自己算帧号×固定间隔”偷懒写法。 -
复用层策略
• MediaMuxer 只能在 addTrack 之后一次性写入,因此需环形缓存 150–200 ms 的音视频数据,按最小 PTS 顺序 dequeue;
• 若 delta(VideoPTS – AudioPTS) > 40 ms,触发“丢视频帧”或“补静音帧”策略;
• 国产 ROM 后台录音限制 5 s 中断,需在 Service 层监听 AudioManager.AUDIOFOCUS_LOSS_TRANSIENT,暂停 muxer 并记录 gap,复用时插入空白音频,保持时间轴连续。 -
播放端验证
• 使用 ffprobe -show_packets 查看 delta;
• 在 ExoPlayer 设置 DefaultAudioSink 的 audioProcessor 回调,打印实际播放时钟与渲染时钟差值;
• 上线前在 10 款主流国产机(含鸿蒙)跑 30 min 老化测试,统计 ±30 ms 以内占比 ≥ 98%。
答案
“我采用三阶段闭环方案:
阶段一,采集对齐。统一以 boottime 为时钟源,AudioRecord 先跑,首帧回调时启动 Camera2,并把首帧时间戳记为 0,后续视频帧直接复用 sensorTimestamp,音频帧用 getTimestamp,保证源头一致。
阶段二,平滑缓存。在内存里维护一个 200 ms 的环形队列,音视频分别按 PTS 排序。MediaMuxer 线程每次取队列头,若 delta 绝对值 ≤ 20 ms 直接写;若音频超前 > 20 ms,就补一个 20 ms 静音帧;若视频超前 > 20 ms,就丢弃当前视频帧,并记录丢帧日志。
阶段三,异常补偿。针对国产机后台录音被系统抢断的场景,我在 Service 里监听 AUDIOFOCUS_LOSS,暂停编码器并记录 gap 时长,恢复时生成对应长度的静音数据,保持时间轴连续不跳变。上线后通过 ffprobe 与 ExoPlayer 日志双重验证,实测 30 min 连续录制在 20 款主流机型上 95% 以上 delta 落在 ±30 ms 以内,满足直播与短视频业务要求。”
拓展思考
-
如果切换到 48 kHz 蓝牙麦克风,而 Camera 仍 30 fps,如何消除 23.2 ms 固定相位差?
→ 可在音频端做 FIFO Delay,动态移位对齐。 -
在折叠屏双屏录制场景,两颗摄像头分别 30 fps 与 60 fps,如何统一 PTS?
→ 采用同一 CameraManager 打开,共享 sensorTimestamp 时钟,低帧率流通过重复帧或插黑帧补齐时间轴。 -
未来 Android 15 引入 Ultra HDR 10-bit 与空间音频,时间戳精度提升到纳秒,旧方案如何平滑升级?
→ 把 PTS 存储从 long 微秒改为 long 纳秒,环形缓存大小按 1 ms 纳秒级重新计算,其余对齐逻辑不变,实现向后兼容。