分解 Uint32 的数据字节缓冲区

Posted

技术标签:

【中文标题】分解 Uint32 的数据字节缓冲区【英文标题】:Decomposing Data byte buffer for Uint32 【发布时间】:2018-10-18 13:14:40 【问题描述】:

我正在使用 AVCaptureSession 捕获音频。在用于处理捕获的数据的回调函数中,我将流放入数据结构(字节缓冲区)中。看起来 Data 是 UInt8(对于字节缓冲区有意义),但我相信流数据是 UInt32。

我不确定我应该执行以下哪一项,但我无法让其中任何一项发挥作用。我:

    将 Data 转换为 UInt32 而不是 UInt8? 从数据中读取时,需要 4 个字节来制作 UInt32? 将我的捕获会话更改为 UInt8? 放弃数据结构,自己做?

我的回调函数是:

    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) 

    var audioBufferList = AudioBufferList()
    var data = Data()
    var blockBuffer: CMBlockBuffer?

    // Put the sample buffer in to a list of audio buffers (audioBufferList)
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, bufferListSizeNeededOut: nil, bufferListOut: &audioBufferList, bufferListSize: MemoryLayout<AudioBufferList>.size, blockBufferAllocator: nil, blockBufferMemoryAllocator: nil, flags: 0, blockBufferOut: &blockBuffer)
    // Extract the BufferList in to an array of buffers
    let buffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, count: Int(audioBufferList.mNumberBuffers))
    // for each buffer, extract the frame.  There should only be one buffer as we are recording in mono!
    for audioBuffer in buffers 
        assert(audioBuffer.mNumberChannels == 1)        // it should always be 1 for mono channel
        let frame = audioBuffer.mData?.assumingMemoryBound(to: UInt8.self)
        data.append(frame!, count: Int(audioBuffer.mDataByteSize) / 8)
    

    // limit how much of the sample we pass through.
    viewDelegate?.gotSoundData(data.prefix(MAX_POINTS))

所有的gotSoundData都从视图到多个子视图进行处理

func addSamples(samples: Data) 
    //if (isHidden)  return 

    samples.forEach  sample in
        [...process each byte...]
    

我可以看到 Data.append 有定义:

mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int)

【问题讨论】:

你确定是 8bit 而不是 16bit? 我在描述中添加了数据是 Uint8。我不确定流在什么位置。现在找不到。想知道我是否对 CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer 上的 UInt32 标志感到困惑。我移植的旧 AudioUnit 代码是 SInt16。 好的 - 我会说你是对的,它是 16 位的。我还没有发现任何要说的东西,但是帧是 1024 个样本,它的大小是 2048 字节......每个样本 16 位。问题仍然存在……我如何一次读取 2 个字节的数据。 所以可能是let pData = UnsafeMutablePointer&lt;Int16&gt;(yourBuffer.data),然后是let sampleArray = UnsafeMutableBufferPointer&lt;Int16&gt;( start: pData, count: Int(yourBuffer.mDataByteSize)/sizeof(Int16))。然后sampleArray 是您的 16 位值数组。 第一行失败,因为 yourBuffer 是 UnsafeMutableRawPointer(从 UnsafeBufferPointer 返回)不能成为 UnsafeMutablePointer。 【参考方案1】:

Meggar 帮助我专注于选项 4 - 使用我自己的结构 [Int16]。如果有人对选项 1 感兴趣,请查看我稍后发现的此链接,该链接扩展了 Data 以获取更多数据类型: round trip Swift number type to/from Data

回调函数:

    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) 
    var audioBufferList = AudioBufferList()
    var blockBuffer: CMBlockBuffer?

    // Put the sample buffer in to a list of audio buffers (audioBufferList)
    CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, bufferListSizeNeededOut: nil, bufferListOut: &audioBufferList, bufferListSize: MemoryLayout<AudioBufferList>.size, blockBufferAllocator: nil, blockBufferMemoryAllocator: nil, flags: 0, blockBufferOut: &blockBuffer)
    // Extract the BufferList in to an array of buffers
    let audioBuffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, count: Int(audioBufferList.mNumberBuffers))
    // For each buffer, extract the samples
    for audioBuffer in audioBuffers 
        let samplesCount = Int(audioBuffer.mDataByteSize) / MemoryLayout<Int16>.size
        let samplesPointer = audioBufferList.mBuffers.mData!.bindMemory(to: Int16.self, capacity: samplesCount)
        let samples = UnsafeMutableBufferPointer<Int16>(start: samplesPointer, count: samplesCount)
        //convert to a "safe" array for ease of use in delegate.
        var samplesArray:[Int16] = []
        for sample in samples 
            samplesArray.append(sample)
        
        viewDelegate?.gotSample(samplesArray)
            

消费功能几乎保持不变:

func addSamples(samples: [Int16]) 
    samples.forEach  sample in
        [...process each Int16...]
    

【讨论】:

以上是关于分解 Uint32 的数据字节缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

试图理解这个#define

切片时返回错误索引值的数据类型

在字节缓冲区中复制结构

OFDArrayBuffer 和 Uint8Array

OFDArrayBuffer 和 Uint8Array

如何将 uint32_t 数字移动到 char[]?