我有两种方法(一种用于音频,一种用于视频),它们通过各自的 AVAssetWriterInput 将它们各自的样本附加到 AVAssetWriter。一切都适用于简单的启动和停止情况。这里的一些背景是音频流来自 coreAudio,我在其中应用了回声抑制,而视频馈送来自通过 setSampleBufferDelegate 从 AVCaptureVideoDataOutput 馈送的 AVCaptureVideoDataOutputSampleBufferDelegate。
问题是当我想暂停录制并稍后恢复录制时,提要的音频和视频部分会发生不同的事情。到目前为止,我一直无法在暂停恢复后保持音频和视频同步。
似乎在通过 appendSampleBuffera 附加音频样本数据时,即使 CMSampleBufferRef 具有准确的时间戳,它似乎也不会“跳过”没有样本的时间段。我的意思是,当附加音频样本时,它并不真正关心 CMSampleBuffer 上的时间戳是什么......它只是不断堆积样本,即使有(例如)120 秒音频数据中的间隙,它不会为它创造一个“空白空间”。
坦率地说,我不在乎,只要视频样本的行为相同(但事实并非如此)。对于视频样本,生成的视频编码确实会跳过样本,尽管它会在没有数据的时间段内产生一个延长的空视频帧。
因此,从一个简单的实现来看,在暂停期间,您会在暂停期间获得一个空白视频部分,但对于音频部分,您会连续获得下一个未暂停部分的样本。这意味着暂停和取消暂停(通过禁止向 avasset writer 添加缓冲区数据)会导致音频和视频之间完全不同步。
我尝试过的补救措施:
使用 CMSetAttachment() 设置 kCMSampleBufferAttachmentKey_FillDiscontinuitiesWithSilence - 对于音频通道,希望它会像视频流一样做。这根本没有效果。我可能做错了,但没有关于这方面的真正文档,所以在这个黑暗中拍摄。
为受影响的“暂停”持续时间添加我自己的空样本(通过 appendLapsedAudiotime)。问题是我认为我的缓冲区不正确,我不清楚是否可以添加一个只有 0 或 1 个样本的音频缓冲区,并将其延长很长一段时间。如果我还将音频缓冲区格式更改为在整个暂停期间执行 1 个样本,这可能是可能的,但下游低级 API 不太可能会喜欢不稳定的采样率设置)。
使用 CMSampleBufferCreateCopyWithNewTiming() 更改视频的呈现时间,以与音频的行为一致。事实证明,这既不稳定又不起作用。我对此进行了多次迭代,包括调整音频和视频的时间戳。可能我在那里犯了错误,但考虑到几乎没有文档,我也对这种方法视而不见。
使用多个 startSessionAtSourceTime / endSessionAtSourceTime 以及在暂停状态期间抑制写入戳记,但这不起作用,实际上 Apples 头文件中的一个注释提醒您这不受支持(与他们的在线文档相反):注意:目前不支持多个样本编写会话。在调用 endSessionAtSourceTime 后第二次调用 startSessionAtSourceTime: 时出错:
所以我的下一个方法是创建多个 AVAsset。当有“暂停开始”时,我将完成录制,当有“暂停停止”时,我将开始一个全新的录制,当一切都说完后,我将使用 AVAssetComposition 来再次将它们串在一起。我对这种方法有点紧张,因为我发现在设置新的 av 捕获时,快速 av 捕获会停止并开始在各个地方出现莫名其妙的失败。我可能不得不强制“取消暂停”等待一段时间,然后才能尝试开始新的 av 捕获。
所以问题是......有更好的方法吗?