使用 AudioConverter Swift 将 .m4a 文件转换为 .aiff
Posted
技术标签:
【中文标题】使用 AudioConverter Swift 将 .m4a 文件转换为 .aiff【英文标题】:Converting .m4a file to .aiff using AudioConverter Swift 【发布时间】:2017-01-03 04:01:05 【问题描述】:我正在尝试使用来自this post 的答案将 .m4a 格式的给定音频文件转换为 .aiff 格式。我已将代码转换为 Swift 3.0。
func convertAudio(_ url: URL, outputURL: URL)
var error : OSStatus = noErr
var destinationFile : ExtAudioFileRef? = nil
var sourceFile : ExtAudioFileRef? = nil
var srcFormat : AudiostreamBasicDescription = AudioStreamBasicDescription()
var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
var audioConverter : AudioConverterRef? = nil
ExtAudioFileOpenURL(url as CFURL, &sourceFile)
var thePropertySize: UInt32 = UInt32(MemoryLayout.stride(ofValue: srcFormat))
ExtAudioFileGetProperty(sourceFile!, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat)
dstFormat.mSampleRate = 44100 //Set sample rate
dstFormat.mFormatID = kAudioFormatLinearPCM
dstFormat.mChannelsPerFrame = 1
dstFormat.mBitsPerChannel = 16
dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame
dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame
dstFormat.mFramesPerPacket = 1
dstFormat.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger
//Create destination file
ExtAudioFileCreateWithURL(outputURL as CFURL, kAudioFileAIFFType, &dstFormat, nil,
AudioFileFlags.eraseFile.rawValue, &destinationFile)
ExtAudioFileSetProperty(sourceFile!, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
ExtAudioFileSetProperty(destinationFile!, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
var size : UInt32 = UInt32(MemoryLayout.stride(ofValue: audioConverter))
ExtAudioFileGetProperty(destinationFile!, kExtAudioFileProperty_AudioConverter, &size, &audioConverter)
var canResume : UInt32 = 0
size = UInt32(MemoryLayout.stride(ofValue: canResume))
error = AudioConverterGetProperty(audioConverter!, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume)
let bufferByteSize : UInt32 = 32768
var srcBuffer = [UInt8](repeating: 0, count: 32768)
var sourceFrameOffset : ULONG = 0
print("Converting audio file")
while(true)
var fillBufList = AudioBufferList(
mNumberBuffers: 1,
mBuffers: AudioBuffer(
mNumberChannels: 2,
mDataByteSize: UInt32(srcBuffer.count),
mData: &srcBuffer
)
)
var numFrames : UInt32 = 0
if(dstFormat.mBytesPerFrame > 0)
numFrames = bufferByteSize / dstFormat.mBytesPerFrame
ExtAudioFileRead(sourceFile!, &numFrames, &fillBufList)
if(numFrames == 0)
error = noErr;
break;
sourceFrameOffset += numFrames
error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList)
ExtAudioFileDispose(destinationFile!)
ExtAudioFileDispose(sourceFile!)
问题是audioConverter
在这一行似乎为零
error = AudioConverterGetProperty(audioConverter!, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume)
而且我似乎无法弄清楚为什么。我错过了什么?
【问题讨论】:
你似乎没有初始化audioConverter
,因此它有它的默认值 - nil
@Cristik 不会设置在ExtAudioFileGetProperty(destinationFile!, kExtAudioFileProperty_AudioConverter, &size, &audioConverter)
中吗?如果不是,那么初始化它的正确方法是什么?
【参考方案1】:
跳过 AudioConverterGetProperty
您实际上并没有使用它。
以下 sn-p 将音频文件转换为 AIFF:它以一种受支持的格式读取 sourceFile
,创建一个 AIFF
编码器,并使用 bufferByteSize
缓冲区循环遍历它。错误会得到温和处理。
完整代码,swift 3:
func convertAudio(_ url: URL, outputURL: URL)
var error : OSStatus = noErr
var destinationFile : ExtAudioFileRef? = nil
var sourceFile : ExtAudioFileRef? = nil
var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
ExtAudioFileOpenURL(url as CFURL, &sourceFile)
var thePropertySize: UInt32 = UInt32(MemoryLayout.stride(ofValue: srcFormat))
ExtAudioFileGetProperty(sourceFile!,
kExtAudioFileProperty_FileDataFormat,
&thePropertySize, &srcFormat)
dstFormat.mSampleRate = 44100 //Set sample rate
dstFormat.mFormatID = kAudioFormatLinearPCM
dstFormat.mChannelsPerFrame = 1
dstFormat.mBitsPerChannel = 16
dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame
dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame
dstFormat.mFramesPerPacket = 1
dstFormat.mFormatFlags = kAudioFormatFlagIsBigEndian |
kAudioFormatFlagIsSignedInteger
// Create destination file
error = ExtAudioFileCreateWithURL(
outputURL as CFURL,
kAudioFileAIFFType,
&dstFormat,
nil,
AudioFileFlags.eraseFile.rawValue,
&destinationFile)
reportError(error: error)
error = ExtAudioFileSetProperty(sourceFile!,
kExtAudioFileProperty_ClientDataFormat,
thePropertySize,
&dstFormat)
reportError(error: error)
error = ExtAudioFileSetProperty(destinationFile!,
kExtAudioFileProperty_ClientDataFormat,
thePropertySize,
&dstFormat)
reportError(error: error)
let bufferByteSize : UInt32 = 32768
var srcBuffer = [UInt8](repeating: 0, count: 32768)
var sourceFrameOffset : ULONG = 0
while(true)
var fillBufList = AudioBufferList(
mNumberBuffers: 1,
mBuffers: AudioBuffer(
mNumberChannels: 2,
mDataByteSize: UInt32(srcBuffer.count),
mData: &srcBuffer
)
)
var numFrames : UInt32 = 0
if(dstFormat.mBytesPerFrame > 0)
numFrames = bufferByteSize / dstFormat.mBytesPerFrame
error = ExtAudioFileRead(sourceFile!, &numFrames, &fillBufList)
reportError(error: error)
if(numFrames == 0)
error = noErr;
break;
sourceFrameOffset += numFrames
error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList)
reportError(error: error)
error = ExtAudioFileDispose(destinationFile!)
reportError(error: error)
error = ExtAudioFileDispose(sourceFile!)
reportError(error: error)
支持方式:
func reportError(error: OSStatus)
// Handle error
调用:
let sourceUrl = URL(string: Bundle.main.path(forResource: "sample", ofType: "mp3")!)
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask,
true)
let documentsDirectory = URL(string: paths.first!)
let destUrl = documentsDirectory?.appendingPathComponent("converted.aiff")
if let sourceUrl = sourceUrl, let destUrl = destUrl
print("from \(sourceUrl.absoluteString) to \(destUrl.absoluteString)")
convertAudio(sourceUrl, outputURL: destUrl)
【讨论】:
除了使用kAudioFileWAVEType
之外,还有什么其他改变可以导出到wav吗?使用 WAVE 类型时,error = ExtAudioFileSetProperty(destinationFile!,
出现零崩溃。我需要将 m4a 导出为 wav 或 flac。
@MarcosGriselli 在 MP3 转换中遇到相同类型的错误。你找到解决办法了吗?
@MarcosGriselli 我被 CAF 格式的类似问题困扰。到目前为止有什么解决方案吗?以上是关于使用 AudioConverter Swift 将 .m4a 文件转换为 .aiff的主要内容,如果未能解决你的问题,请参考以下文章
使用 AudioConverter 将 PCM 转换为 AAC 并使用 AVAssetWriter 写入 .mp4 文件时音频失真