使用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
相关产品推荐
相关产品推荐

