Swift5中基于AVAssetWriter实现CMSampleBuffer静音功能的技术问询
iOS AVAssetWriter 静音功能实现方案
你的思路是正确的:当isMuted为true时,需要向assetWriterAudioInput写入与原音频格式、时长、时间戳完全一致的静音CMSampleBuffer,这样才能保证音视频流的同步性,避免AVAssetWriter因音频流中断、格式不匹配而报错。
先修正原代码的笔误
你代码里的issued应该是isMuted的拼写错误,修正后捕获输出的逻辑才会正确:
else if output == audioOutput { if isMuted { // 修正为isMuted let silenceBuffer = createSilenceBuffer(from: sampleBuffer) assetWriterAudioInput?.append(silenceBuffer) } else { assetWriterAudioInput?.append(sampleBuffer) } }
实现createSilenceBuffer函数
要创建静音样本,核心是复用原音频的格式描述、时长、时间戳,仅将音频数据替换为全0的静音数据。以下是完整实现:
func createSilenceBuffer(from sampleBuffer: CMSampleBuffer) -> CMSampleBuffer? { // 1. 获取原样本的关键信息 guard let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer), let timingInfo = CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: 1, arrayToFill: nil), let sampleSize = CMSampleBufferGetSampleSizeArray(sampleBuffer, entryCount: 1, arrayToFill: nil) else { return nil } var timingInfoArray = timingInfo var sampleSizeArray = sampleSize // 2. 创建静音的音频数据缓冲区 let channelCount = AudioFormatGetChannelCount(formatDescription) let sampleCount = CMSampleBufferGetNumSamples(sampleBuffer) let bytesPerSample = AudioFormatGetBytesPerSample(formatDescription) let totalBytes = Int(channelCount) * Int(sampleCount) * Int(bytesPerSample) // 分配全0的音频数据 let silenceData = Data(repeating: 0, count: totalBytes) var audioBufferList = AudioBufferList() audioBufferList.mNumberBuffers = 1 audioBufferList.mBuffers.mNumberChannels = channelCount audioBufferList.mBuffers.mDataByteSize = UInt32(totalBytes) silenceData.withUnsafeBytes { buffer in audioBufferList.mBuffers.mData = UnsafeMutableRawPointer(mutating: buffer.baseAddress) } // 3. 创建新的CMSampleBuffer var silenceBuffer: CMSampleBuffer? let status = CMSampleBufferCreateReady( allocator: kCFAllocatorDefault, dataBuffer: nil, formatDescription: formatDescription, sampleCount: sampleCount, sampleTimingEntryCount: 1, sampleTimingArray: &timingInfoArray, sampleSizeEntryCount: 1, sampleSizeArray: &sampleSizeArray, sampleBufferOut: &silenceBuffer ) // 将静音数据写入样本缓冲区 if status == noErr, let buffer = silenceBuffer { CMSampleBufferSetDataBufferFromAudioBufferList( buffer, blockBufferAllocator: kCFAllocatorDefault, blockBufferMemoryAllocator: kCFAllocatorDefault, flags: 0, audioBufferList: &audioBufferList ) } return silenceBuffer }
关键注意事项
- 格式一致性:必须保证静音样本的格式(采样率、位深、声道数)、时长、时间戳与原音频完全匹配,否则会导致音视频不同步或AVAssetWriter写入失败。
- 性能优化:如果录制时长较长,可以提前预计算静音数据的模板,避免每次都重新分配内存,提升运行效率。
- 错误处理:实现中加入了必要的可选值判断和状态检查,避免因原样本信息缺失导致崩溃。
内容的提问来源于stack exchange,提问作者Yuuu
相关产品推荐
相关产品推荐

