如何正确地将 AVAudioCompressedBuffer 转换为数据并返回
How to correctly convert AVAudioCompressedBuffer into Data and back
我有一个 AVAudioCompressedBuffer
实例被我的 AVAudioEngine
正确解码和播放。
问题是,在将其转换为 Data
然后再转换回 AVAudioCompressedBuffer
后,它不再可播放并抛出一个 kAudioCodecBadDataError
.
这就是我目前管理与 Data
之间的转换的方式:
// Convert AVAudioCompressedBuffer to Data
let capacity = Int(compressedBuffer.byteLength)
let compressedBufferPointer = compressedBuffer.data.bindMemory(to: UInt8.self, capacity: capacity)
var compressedBytes: [UInt8] = [UInt8].init(repeating: 0, count: capacity)
compressedBufferPointer.withMemoryRebound(to: UInt8.self, capacity: capacity) { sourceBytes in
compressedBytes.withUnsafeMutableBufferPointer {
[=10=].baseAddress!.initialize(from: sourceBytes, count: capacity)
}
}
let data = Data(compressedBytes)
// Convert Data to AVAudioCompressedBuffer
let compressedBuffer: AVAudioCompressedBuffer = AVAudioCompressedBuffer.init(format: format, packetCapacity: packetCapacity, maximumPacketSize: maximumPacketSize)
compressedBuffer.byteLength = byteLength
compressedBuffer.packetCount = packetCount
data.withUnsafeBytes {
compressedBuffer.data.copyMemory(from: [=11=].baseAddress!, byteCount: byteLength)
}
let buffer = compressedBuffer
所有缓冲区属性 (format, packetCapacity, maximumPacketSize, byteLength, packetCount, byteLength
) 的值在转换的两端都是相同的。
事实证明,出于某种原因,以这种方式转换 AVAudioCompressedBuffer
无法包含缓冲区的 packetDescriptions
。这些在缓冲区中存储为 AudioStreamPacketDescriptions
结构的 C-Style 数组。通过创建 Codable
结构 (PacketDescription
) 并分别映射描述对象,重新组装的缓冲区按预期工作。
var packetDescriptions = [PacketDescription]()
for index in 0..<compressedBuffer.packetCount {
if let packetDescription = compressedBuffer.packetDescriptions?[Int(index)] {
packetDescriptions.append(
.init(mStartOffset: packetDescription.mStartOffset,
mVariableFramesInPacket: packetDescription.mVariableFramesInPacket,
mDataByteSize: packetDescription.mDataByteSize))
}
}
packetDescriptions?.enumerated().forEach { index, element in
compressedBuffer.packetDescriptions?[index] = AudioStreamPacketDescription(mStartOffset: element.mStartOffset!,
mVariableFramesInPacket: element.mVariableFramesInPacket!,
mDataByteSize: element.mDataByteSize!)
}
我有一个 AVAudioCompressedBuffer
实例被我的 AVAudioEngine
正确解码和播放。
问题是,在将其转换为 Data
然后再转换回 AVAudioCompressedBuffer
后,它不再可播放并抛出一个 kAudioCodecBadDataError
.
这就是我目前管理与 Data
之间的转换的方式:
// Convert AVAudioCompressedBuffer to Data
let capacity = Int(compressedBuffer.byteLength)
let compressedBufferPointer = compressedBuffer.data.bindMemory(to: UInt8.self, capacity: capacity)
var compressedBytes: [UInt8] = [UInt8].init(repeating: 0, count: capacity)
compressedBufferPointer.withMemoryRebound(to: UInt8.self, capacity: capacity) { sourceBytes in
compressedBytes.withUnsafeMutableBufferPointer {
[=10=].baseAddress!.initialize(from: sourceBytes, count: capacity)
}
}
let data = Data(compressedBytes)
// Convert Data to AVAudioCompressedBuffer
let compressedBuffer: AVAudioCompressedBuffer = AVAudioCompressedBuffer.init(format: format, packetCapacity: packetCapacity, maximumPacketSize: maximumPacketSize)
compressedBuffer.byteLength = byteLength
compressedBuffer.packetCount = packetCount
data.withUnsafeBytes {
compressedBuffer.data.copyMemory(from: [=11=].baseAddress!, byteCount: byteLength)
}
let buffer = compressedBuffer
所有缓冲区属性 (format, packetCapacity, maximumPacketSize, byteLength, packetCount, byteLength
) 的值在转换的两端都是相同的。
事实证明,出于某种原因,以这种方式转换 AVAudioCompressedBuffer
无法包含缓冲区的 packetDescriptions
。这些在缓冲区中存储为 AudioStreamPacketDescriptions
结构的 C-Style 数组。通过创建 Codable
结构 (PacketDescription
) 并分别映射描述对象,重新组装的缓冲区按预期工作。
var packetDescriptions = [PacketDescription]()
for index in 0..<compressedBuffer.packetCount {
if let packetDescription = compressedBuffer.packetDescriptions?[Int(index)] {
packetDescriptions.append(
.init(mStartOffset: packetDescription.mStartOffset,
mVariableFramesInPacket: packetDescription.mVariableFramesInPacket,
mDataByteSize: packetDescription.mDataByteSize))
}
}
packetDescriptions?.enumerated().forEach { index, element in
compressedBuffer.packetDescriptions?[index] = AudioStreamPacketDescription(mStartOffset: element.mStartOffset!,
mVariableFramesInPacket: element.mVariableFramesInPacket!,
mDataByteSize: element.mDataByteSize!)
}