I'm trying to take a local m4a file and compress/down-sample this file (For the purposes of making a smaller file).
Now I stuck with error when I try to append sample buffer.
Error description:
*** 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'
Code where I try compress original audio file into same file format but with lower bitrate:
@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
}
}
}
}
The original audio have settings:
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
]
Code for URL to original file:
class func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
Edited:
here is full description of Error:
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'
The errors says that asset writer wants uncompressed sample buffers, but the
AVAssetReaderTrackOutput
header file says:Your file is an
.m4a
file so the samples are likely going to be compressed as AAC.To get uncompressed linear PCM, pass
kAudioFormatLinearPCM
as theAVFormatIDKey
inoutputSettings
:Note that you are decoding and re-encoding or transcoding your file.