使用AVFileType.wav导出音频报错"Invalid output filetype"求助
解决AVFoundation导出WAV时"Invalid output filetype"错误的问题
我之前也踩过这个坑!你遇到的问题核心原因是:AVAssetExportSession并不支持直接将AVComposition导出为WAV格式,而AVFileType.m4a属于MP4封装格式,是AVAssetExportSession原生支持的输出类型,所以能正常工作。
WAV是基于无压缩PCM的音频容器,AVAssetExportSession的设计主要针对压缩的媒体容器(比如MP4、MOV),所以直接指定AVFileType.wav会触发"Invalid output filetype"错误。
正确的WAV导出方案
要导出WAV格式,我们可以换用AVAudioEngine来渲染你的合成音频,再用AVAudioFile写入WAV文件,下面是适配你需求的代码示例:
import AVFoundation func createSound(soundFiles: [String], outputFile: String) throws { // 1. 复用你原有的合成逻辑创建音频组合 let composition = AVMutableComposition() var startTime = kCMTimeZero for soundFile in soundFiles { guard let url = URL(fileURLWithPath: soundFile) else { throw NSError(domain: "SoundError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的音频文件路径"]) } let asset = AVAsset(url: url) guard let audioTrack = asset.tracks(withMediaType: .audio).first else { continue } let timeRange = CMTimeRange(start: .zero, duration: asset.duration) guard let compositionTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) else { throw NSError(domain: "CompositionError", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法添加合成轨道"]) } try compositionTrack.insertTimeRange(timeRange, of: audioTrack, at: startTime) startTime = CMTimeAdd(startTime, asset.duration) } // 2. 使用AVAudioEngine渲染并导出为WAV let engine = AVAudioEngine() let playerNode = AVAudioPlayerNode() engine.attach(playerNode) // 获取合成音频的格式信息 guard let audioFormatDesc = composition.tracks(withMediaType: .audio).first?.formatDescriptions.first as? CMAudioFormatDescription, let avAudioFormat = AVAudioFormat(cmAudioFormatDescription: audioFormatDesc) else { throw NSError(domain: "FormatError", code: -3, userInfo: [NSLocalizedDescriptionKey: "无法获取音频格式"]) } engine.connect(playerNode, to: engine.mainMixerNode, format: avAudioFormat) // 创建用于写入WAV的文件对象 let outputURL = URL(fileURLWithPath: outputFile) guard let outputAudioFile = try? AVAudioFile(forWriting: outputURL, settings: [ AVFormatIDKey: kAudioFormatLinearPCM, AVSampleRateKey: avAudioFormat.sampleRate, AVNumberOfChannelsKey: avAudioFormat.channelCount, AVLinearPCMBitDepthKey: 16, AVLinearPCMIsBigEndianKey: false, AVLinearPCMIsFloatKey: false ], commonFormat: .pcmFormatInt16, interleaved: true) else { throw NSError(domain: "FileError", code: -4, userInfo: [NSLocalizedDescriptionKey: "无法创建WAV输出文件"]) } // 准备音频读取与播放录制 let assetReader = try AVAssetReader(asset: composition) guard let readerOutput = AVAssetReaderTrackOutput(track: composition.tracks(withMediaType: .audio).first!, outputSettings: [ AVFormatIDKey: kAudioFormatLinearPCM ]) else { throw NSError(domain: "ReaderError", code: -5, userInfo: [NSLocalizedDescriptionKey: "无法创建音频读取器"]) } assetReader.add(readerOutput) engine.prepare() try engine.start() playerNode.play() assetReader.startReading() // 读取合成音频数据并写入WAV文件 while assetReader.status == .reading { if let sampleBuffer = readerOutput.copyNextSampleBuffer() { let audioBuffer = try AVAudioPCMBuffer(cmSampleBuffer: sampleBuffer) try outputAudioFile.write(from: audioBuffer) CMSampleBufferInvalidate(sampleBuffer) } } // 收尾操作 playerNode.stop() engine.stop() if assetReader.status == .failed { throw assetReader.error! } }
关键说明
- 我们保留了你原有的
AVMutableComposition合成逻辑,通过AVAssetReader读取合成后的音频数据,再用AVAudioFile写入符合WAV标准的线性PCM数据。 - WAV的核心是线性PCM编码,所以写入时必须指定
AVFormatIDKey: kAudioFormatLinearPCM,同时配置匹配的采样率、通道数、位深等参数。 - 建议将导出逻辑放在后台队列执行,避免长时间阻塞主线程影响UI响应。
内容的提问来源于stack exchange,提问作者Harry Stuart
相关产品推荐
相关产品推荐

