如何在 swift 中将 .caf 音频文件转换为 .mp4 文件

问题描述 投票:0回答:3

我正在使用带有

AVAudioRecorder
的设备麦克风录制音频,它返回 .caf 格式的文件,该文件只能在 Apple 设备上播放,但不能在 Android 设备上播放。由于Apple不支持.mp3文件,所以我想在上传到服务器之前将其转换为.mp4格式。 .mp4 仅适用于音频吗?我可以用
AVAssetExportSession
转换它吗?

以下是录音机代码:

func setupAudioRecorder ()
    {

    let fileMgr = FileManager.default
    let dirPaths = fileMgr.urls(for:.documentDirectory,
                                in:.userDomainMask)

    let soundFileURL = dirPaths[0].appendingPathComponent("myaudio.caf")

    let recordSettings =
        [AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue,
         AVEncoderBitRateKey: 16,
         AVNumberOfChannelsKey: 2,
         AVSampleRateKey: 44100.0] as [String : Any]

    do {
        try audioSession.setCategory(
            AVAudioSessionCategoryPlayAndRecord)
    } catch let error as NSError {
        print("audioSession error: \(error.localizedDescription)")
    }

    do {
        try audioRecorder = AVAudioRecorder(url: soundFileURL,
                                            settings: recordSettings as [String : AnyObject])
        audioRecorder?.prepareToRecord()
    } catch let error as NSError {
        print("audioSession error: \(error.localizedDescription)")
    }
}
ios swift xcode avaudiorecorder avassetexportsession
3个回答
14
投票

经过大量搜索,我可以使用这段代码将.caf转换为.mp4

    let audioURL = ".caf audio file url"

    let fileMgr = FileManager.default

    let dirPaths = fileMgr.urls(for: .documentDirectory,
                                in: .userDomainMask)

    let outputUrl = dirPaths[0].appendingPathComponent("audiosound.mp4")

    let asset = AVAsset.init(url: audioURL)

    let exportSession = AVAssetExportSession.init(asset: asset, presetName: AVAssetExportPresetHighestQuality)

    // remove file if already exits
    let fileManager = FileManager.default
    do{
        try? fileManager.removeItem(at: outputUrl)

    }catch{
        print("can't")
    }


    exportSession?.outputFileType = AVFileTypeMPEG4

    exportSession?.outputURL = outputUrl

    exportSession?.metadata = asset.metadata

    exportSession?.exportAsynchronously(completionHandler: {
        if (exportSession?.status == .completed)
        {
            print("AV export succeeded.")

           // outputUrl to post Audio on server

        }
        else if (exportSession?.status == .cancelled)
        {
            print("AV export cancelled.")
        }
        else
        {
            print ("Error is \(String(describing: exportSession?.error))")

        }
    })

0
投票

您可以直接以 MPEG4 AAC 格式录制,无需额外的转换步骤。将

AVFormatIDKey
kAudioFormatMPEG4AAC
值结合使用,并将采样率降低至 8000 或 16000。


0
投票

async
mp4导出方法

这是基于已接受答案的稍微修改、格式化和缩短的变体。

它使用

async
方法,您只需传递
.caf
文件的
URL
即可将
URL
返回到导出的
.mp4
文件:

/// Exports a `.caf` audio file located at `inputAudioURL` to returned `URL` (in temporary directory).
/// - Parameter inputAudioURL: The `.caf` file's `URL`.
/// - Returns: The output `URL` of the exported `.mp4` file or `nil` if export failed.
func exportToMP4(inputAudioURL: URL) async -> URL? {

    // Extracts file name from input URL and appends `.mp4`
    let fileName = inputAudioURL.deletingPathExtension().lastPathComponent.appending(".mp4")

    // Creates output URL for temporary directory.
    guard let outputURL = NSURL.fileURL(withPathComponents: [NSTemporaryDirectory(), fileName]),
          let exportSession = AVAssetExportSession(
            asset: AVAsset(url: inputAudioURL),
            presetName: AVAssetExportPresetHighestQuality
          ) else { return nil }

    // Removes file if it already exists.
    try? FileManager.default.removeItem(at: outputURL)

    exportSession.outputFileType = AVFileType.mp4
    exportSession.outputURL = outputURL

    await exportSession.export()
    if exportSession.status == .completed {
        return outputURL
    } else {
        print("mp4 export did not complete")
        return nil
    }
}

async
变体

如果您的代码库不支持

async
方法(或者您只是由于某种原因不喜欢它们),那么使用完成处理程序也是如此:

/// Exports a `.caf` audio file located at `inputAudioURL` to returned `URL` (in temporary directory).
/// - Parameter inputAudioURL: The `.caf` file's `URL`.
/// - Returns: The output `URL` of the exported `.mp4` file or `nil` if export failed.
func exportToMP4(inputAudioURL: URL, didFinish: ((URL?) -> Void)?) {

    // Extracts file name from input URL and appends `.mp4`
    let fileName = inputAudioURL.deletingPathExtension().lastPathComponent.appending(".mp4")

    // Creates output URL for temporary directory.
    guard let outputURL = NSURL.fileURL(withPathComponents: [NSTemporaryDirectory(), fileName]),
          let exportSession = AVAssetExportSession(
            asset: AVAsset(url: inputAudioURL),
            presetName: AVAssetExportPresetHighestQuality
          ) else { didFinish?(nil); return }

    // Removes file if it already exists.
    try? FileManager.default.removeItem(at: outputURL)

    exportSession.outputFileType = AVFileType.mp4
    exportSession.outputURL = outputURL

    exportSession.exportAsynchronously {
        if exportSession.status == .completed {
            didFinish?(outputURL)
        } else {
            print("mp4 export did not complete")
            didFinish?(nil)
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.