gpt4 book ai didi

ios - 使用 AVAudioConverter Swift 将 AAC 解码为 PCM 格式

转载 作者:技术小花猫 更新时间:2023-10-29 11:23:23 40 4
gpt4 key购买 nike

如何在 Swift 上使用 AVAudioConverter、AVAudioCompressedBuffer 和 AVAudioPCMBuffer 将 AAC 转换为 PCM?

在 WWDC 2015 上,507 Session 说 AVAudioConverter 可以编码和解码 PCM 缓冲区,显示了编码示例,但没有显示解码示例。我试过解码,但有些东西不起作用。我不知道:(

调用:

//buffer - it's AVAudioPCMBuffer from AVAudioInputNode(AVAudioEngine)
let aacBuffer = AudioBufferConverter.convertToAAC(from: buffer, error: nil) //has data
let data = Data(bytes: aacBuffer!.data, count: Int(aacBuffer!.byteLength)) //has data
let aacReverseBuffer = AudioBufferConverter.convertToAAC(from: data) //has data
let pcmReverseBuffer = AudioBufferConverter.convertToPCM(from: aacBuffer2!, error: nil) //zeros data. data object exist, but filled by zeros

转换代码:

class AudioBufferFormatHelper {

static func PCMFormat() -> AVAudioFormat? {

return AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)
}

static func AACFormat() -> AVAudioFormat? {

var outDesc = AudioStreamBasicDescription(
mSampleRate: 44100,
mFormatID: kAudioFormatMPEG4AAC,
mFormatFlags: 0,
mBytesPerPacket: 0,
mFramesPerPacket: 0,
mBytesPerFrame: 0,
mChannelsPerFrame: 1,
mBitsPerChannel: 0,
mReserved: 0)
let outFormat = AVAudioFormat(streamDescription: &outDesc)
return outFormat
}
}

class AudioBufferConverter {

static func convertToAAC(from buffer: AVAudioBuffer, error outError: NSErrorPointer) -> AVAudioCompressedBuffer? {

let outputFormat = AudioBufferFormatHelper.AACFormat()
let outBuffer = AVAudioCompressedBuffer(format: outputFormat!, packetCapacity: 8, maximumPacketSize: 768)

self.convert(from: buffer, to: outBuffer, error: outError)

return outBuffer
}

static func convertToPCM(from buffer: AVAudioBuffer, error outError: NSErrorPointer) -> AVAudioPCMBuffer? {

let outputFormat = AudioBufferFormatHelper.PCMFormat()
guard let outBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat!, frameCapacity: 4410) else {
return nil
}

outBuffer.frameLength = 4410
self.convert(from: buffer, to: outBuffer, error: outError)

return outBuffer
}

static func convertToAAC(from data: Data) -> AVAudioCompressedBuffer? {

let nsData = NSData(data: data)
let inputFormat = AudioBufferFormatHelper.AACFormat()
let buffer = AVAudioCompressedBuffer(format: inputFormat!, packetCapacity: 8, maximumPacketSize: 768)
buffer.byteLength = UInt32(data.count)
buffer.packetCount = 8

buffer.data.copyMemory(from: nsData.bytes, byteCount: nsData.length)
buffer.packetDescriptions!.pointee.mDataByteSize = 4

return buffer
}

private static func convert(from sourceBuffer: AVAudioBuffer, to destinationBuffer: AVAudioBuffer, error outError: NSErrorPointer) {

//init converter
let inputFormat = sourceBuffer.format
let outputFormat = destinationBuffer.format
let converter = AVAudioConverter(from: inputFormat, to: outputFormat)

converter!.bitRate = 32000

let inputBlock : AVAudioConverterInputBlock = { inNumPackets, outStatus in

outStatus.pointee = AVAudioConverterInputStatus.haveData
return sourceBuffer
}

_ = converter!.convert(to: destinationBuffer, error: outError, withInputFrom: inputBlock)
}
}

结果 AVAudioPCMBuffer 的数据为零。在消息中我看到错误:

AACDecoder.cpp:192:Deserialize:  Unmatched number of channel elements in payload
AACDecoder.cpp:220:DecodeFrame: Error deserializing packet
[ac] ACMP4AACBaseDecoder.cpp:1337:ProduceOutputBufferList: (0x14f81b840) Error decoding packet 1: err = -1, packet length: 0
AACDecoder.cpp:192:Deserialize: Unmatched number of channel elements in payload
AACDecoder.cpp:220:DecodeFrame: Error deserializing packet
[ac] ACMP4AACBaseDecoder.cpp:1337:ProduceOutputBufferList: (0x14f81b840) Error decoding packet 3: err = -1, packet length: 0
AACDecoder.cpp:192:Deserialize: Unmatched number of channel elements in payload
AACDecoder.cpp:220:DecodeFrame: Error deserializing packet
[ac] ACMP4AACBaseDecoder.cpp:1337:ProduceOutputBufferList: (0x14f81b840) Error decoding packet 5: err = -1, packet length: 0
AACDecoder.cpp:192:Deserialize: Unmatched number of channel elements in payload
AACDecoder.cpp:220:DecodeFrame: Error deserializing packet
[ac] ACMP4AACBaseDecoder.cpp:1337:ProduceOutputBufferList: (0x14f81b840) Error decoding packet 7: err = -1, packet length: 0

最佳答案

您的尝试存在一些问题:

  1. 您在转换数据时没有设置多个 数据包描述 -> AVAudioCompressedBuffer。您需要创建它们,因为 AAC 数据包的大小可变。您可以从原始 AAC 缓冲区复制它们,或者手动(哎哟)或使用 AudioFileStream api 从您的数据中解析它们。

  2. 您一遍又一遍地重新创建您的 AVAudioConverter - 每个缓冲区一次,丢弃它们的状态。例如AAC 编码器出于其自身原因需要添加 2112 帧静音才能重现您的音频,因此重新创建转换器会让您完全静音。

  3. 您一遍又一遍地向 AVAudioConverter 的输入 block 呈现相同的缓冲区。您应该只显示每个缓冲区一次。

  4. 32000 的比特率(对我来说)不起作用

目前能想到的就这些了。尝试对您的代码进行以下修改,而不是您现在这样调用:

(附注:我将一些单声道更改为立体声,这样我就可以在我的 Mac 上播放往返缓冲区,它的麦克风输入奇怪地是立体声 - 您可能需要将其改回)

(p.p.s 显然这里正在进行某种往返/序列化/反序列化尝试,但你到底想做什么?你想将 AAC 音频从一台设备流式传输到另一台设备吗?因为它可能更容易让另一个 API,如 AVPlayer 播放结果流,而不是自己处理数据包)

let aacBuffer = AudioBufferConverter.convertToAAC(from: buffer, error: nil)!
let data = Data(bytes: aacBuffer.data, count: Int(aacBuffer.byteLength))
let packetDescriptions = Array(UnsafeBufferPointer(start: aacBuffer.packetDescriptions, count: Int(aacBuffer.packetCount)))
let aacReverseBuffer = AudioBufferConverter.convertToAAC(from: data, packetDescriptions: packetDescriptions)!
// was aacBuffer2
let pcmReverseBuffer = AudioBufferConverter.convertToPCM(from: aacReverseBuffer, error: nil)

class AudioBufferFormatHelper {

static func PCMFormat() -> AVAudioFormat? {
return AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false)
}

static func AACFormat() -> AVAudioFormat? {

var outDesc = AudioStreamBasicDescription(
mSampleRate: 44100,
mFormatID: kAudioFormatMPEG4AAC,
mFormatFlags: 0,
mBytesPerPacket: 0,
mFramesPerPacket: 0,
mBytesPerFrame: 0,
mChannelsPerFrame: 1,
mBitsPerChannel: 0,
mReserved: 0)
let outFormat = AVAudioFormat(streamDescription: &outDesc)
return outFormat
}
}

class AudioBufferConverter {
static var lpcmToAACConverter: AVAudioConverter! = nil

static func convertToAAC(from buffer: AVAudioBuffer, error outError: NSErrorPointer) -> AVAudioCompressedBuffer? {

let outputFormat = AudioBufferFormatHelper.AACFormat()
let outBuffer = AVAudioCompressedBuffer(format: outputFormat!, packetCapacity: 8, maximumPacketSize: 768)

//init converter once
if lpcmToAACConverter == nil {
let inputFormat = buffer.format

lpcmToAACConverter = AVAudioConverter(from: inputFormat, to: outputFormat!)
// print("available rates \(lpcmToAACConverter.applicableEncodeBitRates)")
// lpcmToAACConverter!.bitRate = 96000
lpcmToAACConverter.bitRate = 32000 // have end of stream problems with this, not sure why
}

self.convert(withConverter:lpcmToAACConverter, from: buffer, to: outBuffer, error: outError)

return outBuffer
}

static var aacToLPCMConverter: AVAudioConverter! = nil

static func convertToPCM(from buffer: AVAudioBuffer, error outError: NSErrorPointer) -> AVAudioPCMBuffer? {

let outputFormat = AudioBufferFormatHelper.PCMFormat()
guard let outBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat!, frameCapacity: 4410) else {
return nil
}

//init converter once
if aacToLPCMConverter == nil {
let inputFormat = buffer.format

aacToLPCMConverter = AVAudioConverter(from: inputFormat, to: outputFormat!)
}

self.convert(withConverter: aacToLPCMConverter, from: buffer, to: outBuffer, error: outError)

return outBuffer
}

static func convertToAAC(from data: Data, packetDescriptions: [AudioStreamPacketDescription]) -> AVAudioCompressedBuffer? {

let nsData = NSData(data: data)
let inputFormat = AudioBufferFormatHelper.AACFormat()
let maximumPacketSize = packetDescriptions.map { $0.mDataByteSize }.max()!
let buffer = AVAudioCompressedBuffer(format: inputFormat!, packetCapacity: AVAudioPacketCount(packetDescriptions.count), maximumPacketSize: Int(maximumPacketSize))
buffer.byteLength = UInt32(data.count)
buffer.packetCount = AVAudioPacketCount(packetDescriptions.count)

buffer.data.copyMemory(from: nsData.bytes, byteCount: nsData.length)
buffer.packetDescriptions!.pointee.mDataByteSize = UInt32(data.count)
buffer.packetDescriptions!.initialize(from: packetDescriptions, count: packetDescriptions.count)

return buffer
}


private static func convert(withConverter: AVAudioConverter, from sourceBuffer: AVAudioBuffer, to destinationBuffer: AVAudioBuffer, error outError: NSErrorPointer) {
// input each buffer only once
var newBufferAvailable = true

let inputBlock : AVAudioConverterInputBlock = {
inNumPackets, outStatus in
if newBufferAvailable {
outStatus.pointee = .haveData
newBufferAvailable = false
return sourceBuffer
} else {
outStatus.pointee = .noDataNow
return nil
}
}

let status = withConverter.convert(to: destinationBuffer, error: outError, withInputFrom: inputBlock)
print("status: \(status.rawValue)")
}
}

关于ios - 使用 AVAudioConverter Swift 将 AAC 解码为 PCM 格式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51360127/

40 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com