使用 CMSampleBuffer 生成 Float32 数组(Float32 PCM 数据)

Posted

技术标签:

【中文标题】使用 CMSampleBuffer 生成 Float32 数组(Float32 PCM 数据)【英文标题】:Generating Float32 Array (Float32 PCM data) using CMSampleBuffer 【发布时间】:2018-06-05 07:34:48 【问题描述】:

我从摄像头收到带有CMSampleBuffer 格式数据的音频的回调,但我无法将此数据转换为 PCM 数据。

我遵循了 Apple copyPCMData、UnsafeMutablePointer、AudioBufferList 提供的文档,但最后我得到的只是 0.0

这是我的代码:

private let pcmBufferPointer = UnsafeMutablePointer<AudioBufferList>.allocate(capacity: 1024)

init(....)
    //...
    let unsafeRawPointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 0)
    let audioBuffer = AudioBuffer(mNumberChannels: 1, mDataByteSize: 4, mData: unsafeRawPointer)
    let audioBufferList = AudioBufferList(mNumberBuffers: 0, mBuffers: audioBuffer)
    self.pcmBufferPointer.initialize(repeating: audioBufferList, count: 1024)



//CMSampleBuffer obtained from AVCaptureAudioDataOutputSampleBufferDelegate
private func audioFrom(sampleBuffer: CMSampleBuffer) -> Void 
    let status = CMSampleBufferCopyPCMDataIntoAudioBufferList(sampleBuffer, 0, 1024, pcmBufferPointer)
    if status == 0 
        Logger.log(key: "Audio Sample Buffer Status", message: "Buffer copied to pointer")
        let dataValue = pcmBufferPointer[0].mBuffers.mData!.load(as: Float32.self) //Tried with Int, Int16, Int32, Int64 and Float too
        Logger.log(key: "PCM Data Value", message: "Data value : \(dataValue)") //prints 0.0
    else
        Logger.log(key: "Audio Sample", message: "Buffer allocation failed with status \(status)")
    

【问题讨论】:

【参考方案1】:

终于搞定了。

必须添加额外的步骤将AudioBufferList 指针转换为AudioList 指针

if status == 0 
    let inputDataPtr = UnsafeMutableAudioBufferListPointer(pcmBufferPointer)
    let mBuffers : AudioBuffer = inputDataPtr[0]
    if let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData)
        let dataPointer = bufferPointer.assumingMemoryBound(to: Int16.self)
        let dataArray = Array(UnsafeBufferPointer.init(start: dataPointer, count: 1024))
        pcmArray.append(contentsOf: dataArray)
    else
        Logger.log(key: "Audio Sample", message: "Failed to generate audio sample")
    
else
    Logger.log(key: "Audio Sample", message: "Buffer allocation failed with status \(status)")

以上代码仅适用于单通道 PCM 数据。对于 2 通道数据,请参阅以下 GIST - https://gist.github.com/hotpaw2/ba815fc23b5d642705f2b1dedfaf0107

【讨论】:

以上是关于使用 CMSampleBuffer 生成 Float32 数组(Float32 PCM 数据)的主要内容,如果未能解决你的问题,请参考以下文章

CMSampleBuffer 的样本呈现时间代表啥?

如何在 Swift 中将 CMSampleBuffer 转换为数据?

将 CMSampleBuffer 转换为 UIImage

使用 AVAssetReader 读取 mp4 文件时第一个音频 CMSampleBuffer 丢失

使用准确的 CMTime 将 AudioBuffer 转换为 CMSampleBuffer

从CMSampleBuffer获取曝光时间(EXIF)