У меня проблемы с преобразованием линейного буфера PCM в сжатый буфер AA C ELD (Enhanced Low Delay).
Я получил рабочий код для преобразования в формат ilb c из этого вопрос: AVAudioCompressedBuffer в массив UInt8 и наоборот
Этот подход работал нормально.
Я изменил входные данные для формата на это:
let packetCapacity = 8
let maximumPacketSize = 96
lazy var capacity = packetCapacity * maximumPacketSize // 768
let convertedSampleRate: Double = 16000
lazy var aaceldFormat: AVAudioFormat = {
var descriptor = AudioStreamBasicDescription(mSampleRate: convertedSampleRate, mFormatID: kAudioFormatMPEG4AAC_ELD, mFormatFlags: 0, mBytesPerPacket: 0, mFramesPerPacket: 0, mBytesPerFrame: 0, mChannelsPerFrame: 1, mBitsPerChannel: 0, mReserved: 0)
return AVAudioFormat(streamDescription: &descriptor)!
}()
Преобразование в сжатый буфер работало нормально, и я смог преобразовать буфер в массив UInt8.
Однако преобразование обратно в буфер PCM не сработало. Входной блок для преобразования обратно в буфер выглядит следующим образом:
func convertToBuffer(uints: [UInt8], outcomeSampleRate: Double) -> AVAudioPCMBuffer? {
// Convert to buffer
let compressedBuffer: AVAudioCompressedBuffer = AVAudioCompressedBuffer(format: aaceldFormat, packetCapacity: AVAudioPacketCount(packetCapacity), maximumPacketSize: maximumPacketSize)
compressedBuffer.byteLength = UInt32(capacity)
compressedBuffer.packetCount = AVAudioPacketCount(packetCapacity)
var compressedBytes = uints
compressedBytes.withUnsafeMutableBufferPointer {
compressedBuffer.data.copyMemory(from: $0.baseAddress!, byteCount: capacity)
}
guard let audioFormat = AVAudioFormat(
commonFormat: AVAudioCommonFormat.pcmFormatFloat32,
sampleRate: outcomeSampleRate,
channels: 1,
interleaved: false
) else { return nil }
guard let uncompressor = getUncompressingConverter(outputFormat: audioFormat) else { return nil }
var newBufferAvailable = true
let inputBlock : AVAudioConverterInputBlock = {
inNumPackets, outStatus in
if newBufferAvailable {
outStatus.pointee = .haveData
newBufferAvailable = false
return compressedBuffer
} else {
outStatus.pointee = .noDataNow
return nil
}
}
guard let uncompressedBuffer: AVAudioPCMBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: AVAudioFrameCount((audioFormat.sampleRate / 10))) else { return nil }
var conversionError: NSError?
uncompressor.convert(to: uncompressedBuffer, error: &conversionError, withInputFrom: inputBlock)
if let err = conversionError {
print("couldnt decompress compressed buffer", err)
}
return uncompressedBuffer
}
Блок ошибки после срабатывания метода преобразования и вывода «слишком мало битов осталось во входном буфере». Кроме того, похоже, что входной блок вызывается только один раз.
Я пробовал разные коды, и это один из наиболее распространенных результатов. Я также не уверен, что проблема заключается в начальном преобразовании из буфера pcm в массив uint8, хотя я получаю массив UInt8, заполненный 768 значениями каждые 0,1 секунды (иногда массив содержит несколько нулей в конце, что не происходит в формате ilb c.
Вопросы:
1. Выполняется ли начальное преобразование из буфера pcm в массив uint8 с правильным подход? Действительны ли параметры packetCapacity, capacity и maximumPacketSize? -> Опять же, похоже, работает
2. Не хватает ли мне чего-то при преобразовании обратно в буфер pcm? Кроме того, я использую переменные правильно?
3. Кто-нибудь достиг этого преобразования без использования C в проекте?
** EDIT: ** Я также работал с подход из этого сообщения: Декодировать AA C в формат PCM с использованием AVAudioConverter Swift
Он отлично работает с форматом AA C, но не с AAC_LD или AAC_ELD