首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Swift/Cocoa:如何将AVMutableComposition导出为wav或aiff音频文件

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

Stack Overflow用户
提问于 2021-10-11 19:40:40
回答 2查看 290关注 0票数 0

我有一个AVMutableComposition,它只包含要导出到.wav音频文件的音频。

我发现导出音频的最简单的解决方案是使用AVAssetExportSession,如下面这个简化的示例所示:

代码语言:javascript
运行
复制
let composition = AVMutableComposition()
// add tracks...

let exportSession = AVAssetExportSession(asset: composition,
                                         presetName: AVAssetExportPresetAppleM4A)!
exportSession.outputFileType = .m4a
exportSession.outputURL = someOutUrl
exportSession.exportAsynchronously {
    // done
}

但它只适用于.m4a

这个post提到,为了导出到其他格式,我们必须使用AVAssetReaderAVAssetWriter,但遗憾的是,它没有进一步详细介绍。

我试着去实现它,但却被困在了这个过程中。

这就是我到目前为止(再次简化)的内容:

代码语言:javascript
运行
复制
let composition = AVMutableComposition()
let outputSettings: [String : Any] = [
    AVFormatIDKey: kAudioFormatLinearPCM,
    AVLinearPCMIsBigEndianKey: false,
    AVLinearPCMIsFloatKey: false,
    AVLinearPCMBitDepthKey: 32,
    AVLinearPCMIsNonInterleaved: false,
    AVSampleRateKey: 44100.0,
    AVChannelLayoutKey: NSData(),
]

let assetWriter = try! AVAssetWriter(outputURL: someOutUrl, fileType: .wav)
let input = AVAssetWriterInput(mediaType: .audio, outputSettings: outputSettings)
assetWriter.add(input)
assetWriter.startWriting()
assetWriter.startSession(atSourceTime: CMTime.zero)
input.requestMediaDataWhenReady(on: .main) {

    // as I understand, I need to bring in data from my
    // AVMutableComposition here...

    let sampleBuffer: CMSampleBuffer = ???
    input.append(sampleBuffer)
}

assetWriter.finishWriting {
    // done
}

归根结底是我的问题:

您能提供一个将音频从AVMutableComposition导出到wav文件的工作示例吗?

EN

回答 2

Stack Overflow用户

发布于 2021-10-28 21:31:10

经过进一步的研究,我想出了以下的解决方案。

缺少的是AVAssetReader的用法。

(简化代码)

代码语言:javascript
运行
复制
// composition
let composition = AVMutableComposition()
// add stuff to composition

// reader
guard let assetReader = try? AVAssetReader(asset: composition) else { return }
assetReader.timeRange = CMTimeRange(start: .zero, duration: CMTime(value: composition.duration.value, timescale: composition.duration.timescale))
let assetReaderAudioMixOutput = AVAssetReaderAudioMixOutput(audioTracks: composition.tracks(withMediaType: .audio), audioSettings: nil)
assetReader.add(assetReaderAudioMixOutput)
guard assetReader.startReading() else { return }

// writer
let outputSettings: [String : Any] = [
    AVFormatIDKey: kAudioFormatLinearPCM,
    AVLinearPCMIsBigEndianKey: false,
    AVLinearPCMIsFloatKey: false,
    AVLinearPCMBitDepthKey: 32,
    AVLinearPCMIsNonInterleaved: false,
    AVSampleRateKey: 44100.0,
    AVChannelLayoutKey: NSData(),
]
guard let assetWriter = try? AVAssetWriter(outputURL: someOutUrl, fileType: .wav) else { return }
let writerInput = AVAssetWriterInput(mediaType: .audio, outputSettings: outputSettings)
assetWriter.add(writerInput)
guard assetWriter.startWriting() else { return }
assetWriter.startSession(atSourceTime: CMTime.zero)

let queue = DispatchQueue(label: "my.queue.id")
writerInput.requestMediaDataWhenReady(on: queue) {

    // capture assetReader in my block to prevent it being released
    let readerOutput = assetReader.outputs.first!

    while writerInput.isReadyForMoreMediaData {
        if let nextSampleBuffer = readerOutput.copyNextSampleBuffer() {
            writerInput.append(nextSampleBuffer)
        } else {
            writerInput.markAsFinished()
            assetWriter.endSession(atSourceTime: composition.duration)
            assetWriter.finishWriting() {
                DispatchQueue.main.async {

                    // done, call my completion
                }
            }
            break;
        }
    }
}
票数 0
EN

Stack Overflow用户

发布于 2021-10-11 23:18:26

正如您提到的,您正在成功地创建.m4a,为什么不将.m4a文件转换为.wav文件,只需在代码中添加一行代码

我只需将文件的扩展名更改为.wav,并删除.m4a文件,就可以工作了。

代码语言:javascript
运行
复制
func getDirectory() -> URL {
    let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentDirectory = path[0]
    return documentDirectory
}

let date = Date().timeIntervalSince1970

fileName = getDirectory().appendingPathComponent("\(date).m4a")
wavFileName = getDirectory().appendingPathComponent("\(date).wav")

try! FileManager.default.copyItem(at: fileName, to: wavFileName)
try! FileManager.default.removeItem(at: fileName)

我甚至播放了.wav文件,它运行得很好。

代码语言:javascript
运行
复制
audioPlayer = try! AVAudioPlayer(contentsOf: wavFileName)
audioPlayer.play()

请参阅上面的示例,此扩展替换是否会导致应用程序中的任何负载或时间?

票数 -4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69531635

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档