Генерация видео или аудио с использованием необработанного PCM - PullRequest
0 голосов
/ 16 мая 2018

Как происходит генерация файла .mov или .m4a с использованием массивов Int16 в качестве стереоканала для звука?

Я могу легко сгенерировать необработанные данные PCM как [Int16] из файла .mov, сохранить их в двух файлах leftChannel.pcm и rightChannel.pcm и выполнить некоторые операции для последующего использования. Но я не могу восстановить видео из этих файлов.

Будет работать любой процесс, то есть прямая генерация видео с использованием необработанного PCM или промежуточного этапа генерации m4a из PCM.

Обновление:

Я выяснил, как преобразовать массив PCM в аудиофайл. Но он не будет играть.

private func convertToM4a(leftChannel leftPath : URL, rightChannel rigthPath : URL, converterCallback : ConverterCallback){

    let m4aUrl = FileManagerUtil.getTempFileName(parentFolder: FrameExtractor.PCM_ENCODE_FOLDER, fileNameWithExtension: "encodedAudio.m4a")
    if FileManager.default.fileExists(atPath: m4aUrl.path) {
        try! FileManager.default.removeItem(atPath: m4aUrl.path)
    }
    do{
        let leftBuffer = try NSArray(contentsOf: leftPath, error: ()) as! [Int16]
        let rightBuffer = try NSArray(contentsOf: rigthPath, error: ()) as! [Int16]

        let sampleRate = 44100
        let channels = 2
        let frameCapacity = (leftBuffer.count + rightBuffer.count)/2

        let outputSettings = [
            AVFormatIDKey : NSInteger(kAudioFormatMPEG4AAC),
            AVSampleRateKey : NSInteger(sampleRate),
            AVNumberOfChannelsKey : NSInteger(channels),
            AVAudioFileTypeKey : NSInteger(kAudioFileAAC_ADTSType),
            AVLinearPCMIsBigEndianKey : true,
            ] as [String : Any]

        let audioFile = try AVAudioFile(forWriting: m4aUrl, settings: outputSettings, commonFormat: .pcmFormatInt16, interleaved: false)

        let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: Double(sampleRate), channels: AVAudioChannelCount(channels), interleaved: false)!

        let pcmBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(frameCapacity))!
        pcmBuffer.frameLength = pcmBuffer.frameCapacity

        for i in 0..<leftBuffer.count {
            pcmBuffer.int16ChannelData![0][i] = leftBuffer[i]
        }

        for i in 0..<rightBuffer.count {
            pcmBuffer.int16ChannelData![1][i] = rightBuffer[i]
        }

        try! audioFile.write(from: pcmBuffer)

        converterCallback.m4aEncoded(to: m4aUrl)

    } catch {
        print(error.localizedDescription)
    }
}

Сохранение файла в формате .m4a с AVAudioFileTypeKey в качестве m4a type приводило к ошибке неверного файла.

Сохранение файла в формате .aac с указанными выше настройками воспроизводит файл, но с нарушенным звуком. Просто гудящий звук с некоторым эффектом замедления оригинального звука, сначала я думал, что это как-то связано с входом и выходом частоты дискретизации, но это не так.

Я предполагаю, что что-то не так в словаре вывода. Любая помощь будет оценена.

1 Ответ

0 голосов
/ 30 мая 2018

По крайней мере создание файла AAC с кодом, который вы показываете, работает.

Я записал два NSArrays с действительными аудиоданными Int16 и с вашим кодом получил действительный результат, который, например, при воспроизведении (используясуффикс .aac) в QuickTime Player звучит так же, как и ввод.

encoded audio

Как вы создаете вход?

Например, гудение звука (с большим количеством шума) происходит, если вы читаете в аудиоданные, использующие AVAudioFormat с форматом, например, .pcmFormatInt16 , но фактически считываемые данные имеют формат .pcmFormatFloat32 (чаще всего формат по умолчанию).К сожалению, если вы попытаетесь это сделать, предупреждения времени выполнения не будет.

В этом случае попробуйте использовать .pcmFormatFloat32 .Если вам это нужно в Int16 , вы можете преобразовать его самостоятельно, в основном отобразив [-1,1] в [-32768,32767] для обоих каналов.

let fac = Float(1 << 15)
for i in 0..<count {
    let val = min(max(inBuffer!.floatChannelData![ch][i] * fac, -fac), fac - 1)
    xxx[I] = Int16(val)
}
...
...