Преобразование буфера PCM в формат AA C ELD и наоборот - PullRequest
1 голос
/ 03 августа 2020

У меня проблемы с преобразованием линейного буфера 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

...