You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift/Cocoa开发:如何将AVMutableComposition导出为wav或aiff音频文件

完整可运行实现代码

import AVFoundation

func exportAudioToWav(composition: AVMutableComposition, outputURL: URL, completion: @escaping (Bool, Error?) -> Void) {
    // 提前删除同路径已存在的文件,避免写入失败
    try? FileManager.default.removeItem(at: outputURL)
    
    // 初始化资源读取器
    guard let assetReader = try? AVAssetReader(asset: composition) else {
        completion(false, NSError(domain: "AudioExport", code: -1, userInfo: [NSLocalizedDescriptionKey: "资源读取器初始化失败"]))
        return
    }
    
    // 读取合成对象中的音频轨道
    guard let audioTrack = composition.tracks(withMediaType: .audio).first else {
        completion(false, NSError(domain: "AudioExport", code: -2, userInfo: [NSLocalizedDescriptionKey: "未找到音频轨道"]))
        return
    }
    
    // 配置读取器输出参数:直接输出WAV要求的LinearPCM格式
    let readerOutputSettings: [String: Any] = [
        AVFormatIDKey: kAudioFormatLinearPCM,
        AVLinearPCMIsBigEndianKey: false,
        AVLinearPCMIsFloatKey: false,
        AVLinearPCMBitDepthKey: 16,
        AVLinearPCMIsNonInterleaved: false,
        AVSampleRateKey: 44100.0,
        AVNumberOfChannelsKey: 2
    ]
    let readerOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: readerOutputSettings)
    readerOutput.alwaysCopiesSampleData = false
    if assetReader.canAdd(readerOutput) {
        assetReader.add(readerOutput)
    }
    
    // 初始化资源写入器,指定输出格式为wav
    guard let assetWriter = try? AVAssetWriter(outputURL: outputURL, fileType: .wav) else {
        completion(false, NSError(domain: "AudioExport", code: -3, userInfo: [NSLocalizedDescriptionKey: "资源写入器初始化失败"]))
        return
    }
    
    // 写入器输入参数和读取器输出参数保持一致
    let writerInputSettings: [String: Any] = readerOutputSettings
    let writerInput = AVAssetWriterInput(mediaType: .audio, outputSettings: writerInputSettings)
    writerInput.expectsMediaDataInRealTime = false
    if assetWriter.canAdd(writerInput) {
        assetWriter.add(writerInput)
    }
    
    // 启动读写流程
    assetWriter.startWriting()
    assetWriter.startSession(atSourceTime: .zero)
    guard assetReader.startReading() else {
        completion(false, assetReader.error)
        return
    }
    
    // 用自定义串行队列处理数据读写,避免阻塞主线程
    let processQueue = DispatchQueue(label: "com.audio.export.queue")
    writerInput.requestMediaDataWhenReady(on: processQueue) {
        while writerInput.isReadyForMoreMediaData {
            // 从读取器拉取音频样本
            guard let sampleBuffer = readerOutput.copyNextSampleBuffer() else {
                // 读取完成或出现错误
                if assetReader.status == .completed {
                    writerInput.markAsFinished()
                    assetWriter.finishWriting {
                        DispatchQueue.main.async {
                            completion(assetWriter.status == .completed, assetWriter.error)
                        }
                    }
                } else {
                    DispatchQueue.main.async {
                        completion(false, assetReader.error)
                    }
                }
                return
            }
            // 将样本写入输出文件
            if !writerInput.append(sampleBuffer) {
                DispatchQueue.main.async {
                    completion(false, assetWriter.error)
                }
                return
            }
            CMSampleBufferInvalidate(sampleBuffer)
        }
    }
}

使用示例

// 你的音频合成对象,已完成轨道添加逻辑
let composition = AVMutableComposition()
// 此处省略你添加音频轨道、编辑时间线的代码...

// 生成输出文件路径,示例为存到沙盒Documents目录
let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let outputURL = documentsDir.appendingPathComponent("exported_audio.wav")

// 调用导出方法
exportAudioToWav(composition: composition, outputURL: outputURL) { success, error in
    if success {
        print("导出成功,文件路径:\(outputURL.path)")
    } else {
        print("导出失败:\(error?.localizedDescription ?? "未知错误")")
    }
}

注意事项

  • 如果需要调整音频参数(比如单声道、48k采样率、32位深度),直接修改readerOutputSettings里的对应字段即可,只要符合LinearPCM格式规范都可以正常生成WAV文件
  • 如果你的AVMutableComposition包含多条音频轨道,给AVAssetReader添加对应数量的AVAssetReaderTrackOutput分别读取写入即可
  • 导出前请确保合成对象的音频轨道、时间范围配置完整正确

内容的提问来源于stack exchange,提问作者de.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 22:06:03