You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为AVAssetWriter同步AVCaptureVideoDataOutput与AVCaptureAudioDataOutput

相机应用音视频同步问题

我正在开发一款相机应用,采用两个AVCaptureSession分别处理视频和音频。通过AVCaptureVideoDataOutput和AVCaptureAudioDataOutput的代理接收CMSampleBuffer数据。

当启用视频防抖模式cinematicExtended时,AVCaptureVideoDataOutput会产生1-2秒的延迟,导致音频CMSampleBuffer比视频CMSampleBuffer提前1-2秒到达!

相关代码

func captureOutput(_ captureOutput: AVCaptureOutput,
                   didOutput sampleBuffer: CMSampleBuffer,
                   from _: AVCaptureConnection) {
  let type = captureOutput is AVCaptureVideoDataOutput ? "Video" : "Audio"
  let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
  print("Incoming \(type) buffer at \(timestamp.seconds) seconds...")
}

未启用防抖时的日志

Incoming Audio frame at 107862.52558333334 seconds...
Incoming Video frame at 107862.535921166 seconds...
Incoming Audio frame at 107862.54691666667 seconds...
Incoming Video frame at 107862.569257333 seconds...
Incoming Audio frame at 107862.56825 seconds...
Incoming Video frame at 107862.585925333 seconds...
Incoming Audio frame at 107862.58958333333 seconds...

启用防抖后的日志

Incoming Audio frame at 107862.52558333334 seconds...
Incoming Video frame at 107861.535921166 seconds...
Incoming Audio frame at 107862.54691666667 seconds...
Incoming Video frame at 107861.569257333 seconds...
Incoming Audio frame at 107862.56825 seconds...
Incoming Video frame at 107861.585925333 seconds...
Incoming Audio frame at 107862.58958333333 seconds...

从日志能明显看出,视频帧的到达时间比其预期展示时间晚近1秒!

现在的困境是:

  • 网上的AVAssetWriter使用指南都建议第一帧视频到达时启动会话,但我没法这么做——前1秒的视频帧来自用户开始录制之前,不能用。
  • 不能等1秒再启动,否则会丢失实时传输的1秒音频样本;
  • 也不能在第一帧音频到达时启动会话并丢弃此前的视频帧,因为视频帧时间戳和第一帧音频无法完全对齐,会导致视频开头出现空白帧。

请问有什么方法可以实现音视频同步?


解决方案思路

1. 时间戳偏移校准

收集初始的几帧音视频数据,计算两者的时间戳平均偏移值(比如音频时间戳均值减去视频时间戳均值),之后所有视频帧的时间戳都加上这个偏移量再写入AVAssetWriter,从根源对齐时间轴。

2. 预缓存视频帧

因为防抖模式会提前缓存1-2秒视频,所以在用户触发录制前就开始缓存带原始时间戳的视频帧。用户开始录制时,立刻启动AVAssetWriter处理音频,同时从缓存中找到时间戳与第一帧音频匹配的视频帧开始写入,后续实时处理新的音视频帧,既不丢音频也能避免开头空白。

3. 动态排序写入队列

启动AVAssetWriter时,以第一帧音频的时间戳作为会话起始时间。给音视频分别维护按时间戳排序的缓存队列,每次写入时取出队列中时间戳最早的帧,确保音视频按时序写入。如果起始时间前的视频帧未到达,先缓存音频帧,等对应视频帧到了再按顺序写入。

代码关键处理点

  • 用有序队列缓存音视频帧,保证时间戳顺序;
  • 用CMTime进行精确时间计算,避免浮点误差;
  • 写入时优先处理时间戳更早的帧,不管是音频还是视频。

内容的提问来源于stack exchange,提问作者mrousavy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 01:52:29