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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 05:15:37