我正在使用带有
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)")
}
}
经过大量搜索,我可以使用这段代码将.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))")
}
})
您可以直接以 MPEG4 AAC 格式录制,无需额外的转换步骤。将
AVFormatIDKey
与 kAudioFormatMPEG4AAC
值结合使用,并将采样率降低至 8000 或 16000。
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)
}
}
}