iOS双AVCaptureSession录制音视频不同步问题求助
双AVCaptureSession音视频录制同步问题求助
背景说明
我采用两个独立的AVCaptureSession分别处理视频和音频录制,目标是实现动态启停音频会话而不中断视频会话——复刻Snapchat、Instagram的逻辑:打开相机时后台音乐可持续播放,仅在开始录制时因AVAudioSession.setCategory(..)调用出现轻微卡顿。但目前无法同步两个会话,将CMSampleBuffer写入AVAssetWriter时,音视频始终存在明显不同步问题。
问题表现
- 音视频时序偏差:视频帧比第一个音频样本早近1秒开始播放,后期视频停止/冻结时音频仍在播放,延迟显著;
- 视频包含无效帧:录制内容中混入了
startRecording()调用前的视频帧。
核心代码示例
let videoCaptureSession = AVCaptureSession() let audioCaptureSession = AVCaptureSession() func setup() { // ...添加videoCaptureSession输出(AVCaptureVideoDataOutput) // ...添加audioCaptureSession输出(AVCaptureAudioDataOutput) videoCaptureSession.startRunning() } func startRecording() { self.assetWriter = AVAssetWriter(outputURL: tempURL, fileType: .mov) self.videoWriter = AVAssetWriterInput(...) assetWriter.add(videoWriter) self.audioWriter = AVAssetWriterInput(...) assetWriter.add(audioWriter) AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: [.mixWithOthers, .defaultToSpeaker]) audioCaptureSession.startRunning() // <-- 延迟启动 } func captureOutput(_ captureOutput: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from _: AVCaptureConnection) { // 在自定义RecordingSession(AVAssetWriter)中录制视频帧/音频样本到文件 if isRecording { switch captureOutput { case is AVCaptureVideoDataOutput: self.videoWriter.append(sampleBuffer) case is AVCaptureAudioDataOutput: // TODO: 是否需要更新PresentationTimestamp来同步另一个捕获会话? self.audioWriter.append(sampleBuffer) default: break } } }
解决方案建议
1. 统一时间基准,修正帧时间戳
两个AVCaptureSession的时钟基准独立,需手动对齐时间戳:
- 在
startRecording()启动音频会话后,捕获第一个音频样本的presentationTimestamp作为同步基准audioStartTime; - 对后续视频帧,计算其原时间戳与
startRecording()触发时刻的视频时间差,将该差值叠加到audioStartTime上,得到修正后的视频时间戳,再写入videoWriter。
2. 过滤录制前的无效视频帧
视频会话提前启动会缓存大量历史帧,需设置时间阈值过滤:
- 在
startRecording()中,记录当前最新视频帧的presentationTimestamp作为videoStartThreshold; - 在
captureOutput的视频分支中,先判断当前帧的presentationTimestamp是否大于等于videoStartThreshold,仅符合条件的帧才执行append操作。
3. 优化音频会话启动逻辑
AVAudioSession配置和音频会话启动存在延迟,可调整时机减少偏差:
- 提前在
setup()阶段配置音频会话的category,但保持非激活状态; - 在
startRecording()时仅激活音频会话,确保audioCaptureSession.startRunning()完成后再接收音频帧,避免丢失初始音频样本导致同步错位。
4. 用像素缓冲区适配器精准控制视频写入
直接写入CMSampleBuffer难以精准控制时间戳时,可改用AVAssetWriterInputPixelBufferAdaptor:
- 将视频帧转换为
CVPixelBuffer,手动设置修正后的时间戳; - 通过适配器将处理后的像素缓冲区写入
AVAssetWriter,实现更精准的时序控制。
内容的提问来源于stack exchange,提问作者mrousavy
相关产品推荐
相关产品推荐

