当我尝试使用 AVAssetWriterInput swift compress/down-sample 音频文件时出现错误

Getting an error when I try to compress/down-sample the audio file using AVAssetWriterInput swift

我正在尝试获取一个本地 m4a 文件和 compress/down-sample 这个文件(为了制作一个更小的文件)。

现在,当我尝试附加示例缓冲区时遇到错误。

错误描述:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVAssetWriterInput appendSampleBuffer:] Cannot append sample buffer: Input buffer must be in an uncompressed format when outputSettings is not nil'

我尝试将原始音频文件压缩成相同文件格式但比特率较低的代码:

@objc func nextTapped() {
        let audioURL = RecordWhistleViewController.getWhistleURL()
        
        var asset = AVAsset.init(url: audioURL)
        let exportPath = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("out.m4a").path
        print("export PATH IS \(exportPath)")
        
        let exportURL = URL(fileURLWithPath: exportPath)
        
        var readerError: Error? = nil
        var reader: AVAssetReader? = nil
        do {
            reader = try AVAssetReader(asset: asset)
        } catch {
            print("error in reader \(error)")
        }
        
        let track = asset.tracks(withMediaType: .audio)[0]
        let readerOutput = AVAssetReaderTrackOutput(track: track, outputSettings: nil)
        reader?.add(readerOutput)
        
        var writerError: Error? = nil
        var writer: AVAssetWriter? = nil
        do {
            writer = try AVAssetWriter(outputURL: exportURL, fileType: .m4a)
        } catch {
            print("ERROR IN writer \(error)")
        }
        
        var channelLayout = AudioChannelLayout()
        memset(&channelLayout, 0, MemoryLayout<AudioChannelLayout>.size)
        channelLayout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo
        
        let outputSettings = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 12000,
            AVNumberOfChannelsKey: 2,
            AVEncoderBitRateKey: 128000,
            AVChannelLayoutKey: Data(bytes: &channelLayout, count: MemoryLayout<AudioChannelLayout>.size)
            
        ] as [String : Any]
        
        let writerInput = AVAssetWriterInput(mediaType: .audio, outputSettings: outputSettings as? [String: Any])
        writerInput.expectsMediaDataInRealTime = false
        writer?.add(writerInput)
        
        writer?.startWriting()
        writer?.startSession(atSourceTime: .zero)
        
        reader?.startReading()
        let mediaInputQueue = DispatchQueue(label: "mediaInputQueue")
        writerInput.requestMediaDataWhenReady(on: mediaInputQueue) {
            print("Asset writer ready: \(writerInput.isReadyForMoreMediaData)")
            while writerInput.isReadyForMoreMediaData {
                var nextBuffer: CMSampleBuffer?
                nextBuffer = readerOutput.copyNextSampleBuffer()
                if nextBuffer != nil {
                    if let nextBuffer = nextBuffer {
                        print("adding buffer")
                        writerInput.append(nextBuffer)
                    }
                } else {
                    writerInput.markAsFinished()
                    reader?.cancelReading()
                    writer?.finishWriting {
                        print("Asset writer finished writing")
                    }
                    break
                }
            }
        }
        
    }

原音频有设置:

let settings = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 12000,
            AVNumberOfChannelsKey: 1,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
        ]

原文件URL的代码:

class func getDocumentsDirectory() -> URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        let documentsDirectory = paths[0]
        return documentsDirectory
    }

已编辑:

这里是错误的完整描述:

assetWriter_finishBuildingAudioTrackWithSourceFormatDescription signalled err=-12413 (kFigAssetWriterError_InappropriateSourceFormat) (AssetWriter can only compress LPCM audio) at /Library/Caches/com.apple.xbs/Sources/EmbeddedCoreMedia_Sim/EmbeddedCoreMedia-2765.6/Prototypes/Export/FigAssetWriter.c:636

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[AVAssetWriterInput appendSampleBuffer:] Cannot append sample buffer: Input buffer must be in an uncompressed format when outputSettings is not nil'

错误表明资产作者需要未压缩的样本缓冲区,但 AVAssetReaderTrackOutput 头文件显示:

A value of nil for outputSettings configures the output to vend samples in their original format as stored by the specified track.

您的文件是 .m4a 文件,因此样本可能会被压缩为 AAC。

要获得未压缩的线性 PCM,请将 kAudioFormatLinearPCM 作为 outputSettings 中的 AVFormatIDKey 传递:

let readerOutputSettings = [
    AVFormatIDKey: kAudioFormatLinearPCM
]

let readerOutput = AVAssetReaderTrackOutput(track: track, outputSettings: readerOutputSettings)

请注意,您正在对文件进行解码和重新编码或转码。