因此,我正在尝试学习Core Media的基础知识,因为我需要在应用程序中处理真实的音频样本。现在我知道我需要配置AVCaptureSession
设置、用于采集样本的AVCaptureDevice
和处理设备输入并通过captureOutput(...)
方法“通知”AVCaptureAudioDataSampleBufferDelegate
的AVCaptureDataOutput
。
现在,这个方法将样本作为CMSampleBuffer
对象传递,根据Apple的CM文档,它将包含零个或多个媒体(在我的例子中是音频)样本和一个CMBlockBuffer
,即
[...]一个CFType对象,表示可能不连续的内存区域中连续的数据偏移量[...]范围。
好吧,这有点让人困惑。我不是一个母语为英语的人,我很难理解这是什么意思。为什么我需要这个来访问我的样本?它们不是存储为原始二进制数据的数组吗(因此同质和连续)?我猜这与Core Media管理底层内存的方式有关,但我不明白。
最后一批样本也是通过CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer
方法访问的,该方法需要一个指向AudioBufferList
的不安全可变指针和一个指向可选CMBlockBuffer
的指针,第一个将填充指向可选CMBlockBuffer
的指针,然后我可能(也可能不)能够通过myAudioBufferList.mBuffers.mData
访问样本,可能是nil
。
来自Apple开发人员代码片段的示例代码:
public func captureOutput(_ output: AVCaptureOutput,
didOutput sampleBuffer: CMSampleBuffer,
from connection: AVCaptureConnection) {
var audioBufferList = AudioBufferList()
var blockBuffer: CMBlockBuffer?
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(
sampleBuffer,
bufferListSizeNeededOut: nil,
bufferListOut: &audioBufferList,
bufferListSize: MemoryLayout.stride(ofValue: audioBufferList),
blockBufferAllocator: nil,
blockBufferMemoryAllocator: nil,
flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
blockBufferOut: &blockBuffer)
guard let data = audioBufferList.mBuffers.mData else {
return
}
}
这背后的内存模型(或管道)是什么?我真诚地感谢任何帮助。
1条答案
按热度按时间vuktfyat1#
它们不是存储为原始二进制数据的数组吗(因此是同质的和连续的)?
不可以。它们不是这样存储的,这就是为什么你必须使用CMBlockBuffer来处理它们。如果需要,你可以使用
withUnsafeMutableBytes
将它们强制放到一个连续的块中,但是这可能会强制进行复制,并且不能保证闭包接收到的指针在闭包之外有效。分配和复制内存都是代价高昂的操作。在实时音频中,最好尽可能避免这些操作。CMBlockBuffer可以将现有的内存块缝合在一起,而无需分配单个大块,然后进行复制。它可以只使用指向所有现有块的指针。
保留意味着增加缓冲区上的引用计数。多个对象可以引用相同的块而不需要复制。这是一个引用计数系统。保留增加计数,释放减少计数。当它达到零时,内存块可供重用或被释放。
大多数时候Swift程序员并不需要真正与这个保留/释放系统交互,只是为了避免保留周期。细节通常由ARC自动处理。但是在性能关键的上下文中理解它可能是有用的。请参见Core Foundation的内存管理编程指南。(核心媒体类型通常是核心基础类型,并遵循与可可/ObjC规则略有不同的核心基础规则。)
请参见CMMemoryPool,以了解如何使用此函数。