Reputation: 35
I've gone through the documentation and all the posts here, and I've gotten this far.
The function below should take an AVAsset and write out a .wav file. However, the file written out is of zero bytes. I'm not sure I can even inspect what the writer is writing at each step.
What am I missing?
static func writeAudioTrackToUrl(asset: AVAsset, _ url: URL) throws {
// initialize asset reader, writer
let assetReader = try AVAssetReader(asset: asset)
let assetWriter = try AVAssetWriter(outputURL: URL(fileURLWithPath: "/tmp/audiowav.wav"), fileType: .wav)
// get audio track
let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first!
// configure output audio settings
let audioSettings: [String : Any] = [
AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: 22050.0,
AVNumberOfChannelsKey: 1,
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false,
AVLinearPCMIsNonInterleaved: false
]
let assetReaderAudioOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: audioSettings)
if assetReader.canAdd(assetReaderAudioOutput) {
assetReader.add(assetReaderAudioOutput)
} else {
fatalError("could not add audio output reader")
}
let inputAudioSettings: [String:Any] = [AVFormatIDKey : kAudioFormatLinearPCM]
let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: inputAudioSettings, sourceFormatHint: (audioTrack.formatDescriptions[0] as! CMFormatDescription))
let audioInputQueue = DispatchQueue(label: "audioQueue")
assetWriter.add(audioInput)
assetWriter.startWriting()
assetReader.startReading()
assetWriter.startSession(atSourceTime: CMTime.zero)
audioInput.requestMediaDataWhenReady(on: audioInputQueue) {
while (audioInput.isReadyForMoreMediaData) {
let sample = assetReaderAudioOutput.copyNextSampleBuffer()
if (sample != nil) {
audioInput.append(sample!)
} else {
audioInput.markAsFinished()
DispatchQueue.main.async {
assetWriter.finishWriting {
assetReader.cancelReading()
}
}
break
}
}
}
}
Upvotes: 2
Views: 532
Reputation: 36074
The problem here is that you convert the input audio to the LPCM format described by audioSettings
, but then you give a sourceFormatHint
of audioTrack.formatDescriptions[0]
to the AVAssetWriterInput
.
This is a problem because the audio track format descriptions are not going to be LPCM but a compressed format, like kAudioFormatMPEG4AAC
.
Just drop the hint, I think it's for passing through compressed formats anyway.
Further, the LPCM in inputAudioSettings
is under specified - why not pass audioSettings
directly?
In summary, try this:
let audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: audioSettings)
p.s. don't forget to delete the output file before running, AVAssetWriter
doesn't seem to overwrite existing files
Upvotes: 2