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

使用AVAudioFile读取时AVAudioPCMBuffer与文件长度不一致的原因

音频读取中字节数与帧数差异的原因解析

首先明确两个核心概念的本质区别:

  • AVAudioFile.length 返回的是音频文件的总字节数,不是音频帧数。
  • AVAudioPCMBuffer.frameLength 返回的是缓冲区中的音频帧数,每一帧的字节数由你指定的PCM格式决定。

为什么用Int16格式时数值不同?

你的原音频是16位(2字节)单声道,意味着每个音频采样点(单声道下就是一帧)占用2字节:

  • 文件总字节数是90881,可读取的完整帧数为 90881 ÷ 2 = 45440(因为90881是奇数,最后1字节无法组成完整的16位采样,会被自动忽略)。
  • 所以读取后buffer.frameLength为45440(帧数),而file.length是原始字节数90881,两者单位不同,数值自然存在差异。

为什么用Int32格式时你观察到数值一致?

这里存在一个误解:当用.pcmFormatInt32读取原16位音频时,AVAudioFile会自动将每个16位采样扩展为32位(高位补0),转换后的帧数和原文件一致,仍然是45440,而非90881。

你看到buffer.frameLength等于file.length,大概率是因为代码中创建buffer时错误地用file.length(字节数)作为frameCapacity的参数,实际读取后buffer.frameLength应该保持原文件的帧数45440。你可以自行验证:对于Int32单声道格式,每帧占用4字节,缓冲区的总字节数应为 45440 × 4 = 181760,远大于90881。


正确的缓冲区创建方式

创建AVAudioPCMBuffer时,应该用原文件的帧数作为frameCapacity,而非字节数,避免单位混淆:

let audio = Bundle.main.url(forResource: "00001", withExtension: "wav")
let file = try! AVAudioFile(forReading: audio!)
// 计算原文件的总帧数:总字节数 ÷ 每帧字节数
let bytesPerFrame = UInt32(file.fileFormat.streamDescription.pointee.mBytesPerFrame)
let totalFrames = file.length / bytesPerFrame

let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: file.fileFormat.sampleRate, channels: 1, interleaved: false)
let buffer = AVAudioPCMBuffer(pcmFormat: format!, frameCapacity: AVAudioFrameCount(totalFrames))
try! file.read(into: buffer!)

var array = Array(UnsafeBufferPointer(start: buffer?.int16ChannelData![0], count:Int(buffer!.frameLength)))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 21:32:28