【问题标题】:iOS Code to Convert m4a to WAV将 m4a 转换为 WAV 的 iOS 代码
【发布时间】:2023-04-01 22:57:01
【问题描述】:

是否有任何代码 sn-ps 显示如何将 M4a 文件转换为 WAV?我知道有些库可以反过来转换。

谢谢。

【问题讨论】:

标签: ios audio core-audio file-conversion


【解决方案1】:

AVFoundation 框架中的 AVAssetReader 和 AVAssetWriter 可用于读取 AAC 文件并将该数据写入 iOS 设备上的 WAV/RIFF 文件。 Apple 开发者网站上有示例代码。这不仅仅是一个简短的 sn-p。

【讨论】:

  • 感谢使用,这就是我现在正在处理的问题。我正在将代码转换为 Swift,因为该示例代码使用的是 C++。
【解决方案2】:

如果其他人需要一些代码来执行此操作,它是在 Swift 中

func convertAudioFile(sourceURL: CFURLRef, destinationURL: 
CFURLRef, outputFormat: OSType , 
outputSampleRate: Float64) ->  OSStatus
{
var error : OSStatus = noErr
var destinationFile : ExtAudioFileRef = nil
var sourceFile : ExtAudioFileRef = nil

var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()

var audioConverter : AudioConverterRef = nil

audioConverter = AudioConverterRef.init()

ExtAudioFileOpenURL(sourceURL, &sourceFile)

var thePropertySize: UInt32 = UInt32(strideofValue(srcFormat))

ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat)

dstFormat.mSampleRate = (outputSampleRate == 0 ? srcFormat.mSampleRate : outputSampleRate)  //Set sample rate

dstFormat.mFormatID = outputFormat
dstFormat.mChannelsPerFrame = 1
dstFormat.mBitsPerChannel = 16
dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame
dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame
dstFormat.mFramesPerPacket = 1
dstFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger // little-endian

//Create destination file
ExtAudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &dstFormat, nil,
    AudioFileFlags.EraseFile.rawValue, &destinationFile)

ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
ExtAudioFileSetProperty(destinationFile, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)

var size : UInt32 = UInt32(strideofValue(audioConverter))

ExtAudioFileGetProperty(destinationFile, kExtAudioFileProperty_AudioConverter, &size, &audioConverter)

var canResume : UInt32 = 0

size = UInt32(strideofValue(canResume))

error = AudioConverterGetProperty(audioConverter, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume)

let bufferByteSize : UInt32 = 32768
var srcBuffer = [UInt8](count: 32768, repeatedValue: 0)

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)

let audioAsset = AVURLAsset.init(URL: destinationURL, options: nil)
if(audioAsset.duration.seconds < 5.0){
    error = -2500
}

return error;

【讨论】:

  • 如果我想将 m4a 文件转换为 wav 文件,我应该通过哪个 OSTypeoutputSampleRate
  • 是的。你想使用 kAudioFormatLinearPCM 的 OSType 和 16000 的 outputSampleRate
  • 很老的代码,Swift 3 有很多变化。
  • 我会把它留给其他人来更新到 Swift 3
  • Swift 3 用于AIFF 格式stackoverflow.com/a/41437453/218152
【解决方案3】:

这是对@O2U answere 的编辑。如上代码实际上并没有将其转换为波形文件。请在//Create destination file ExtAudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &dstFormat, nil, AudioFileFlags.EraseFile.rawValue, &destinationFile)行以上代码中使用“kAudioFileWAVEType”而不是“kAudioFileCAFType”

【讨论】:

  • 您是否更改了其他内容?当我使用kAudioFileWAVEType 时没有设置destinationFile
  • 不,除此之外没有任何改变。请检查您的目标网址是否正确,这可能是未设置目标文件的问题。
  • @MarcosGriselli 搞定了。在更改为 kAudioFileWAVEType 时,您还必须添加相应的标志 kLinearPCMFormatFlagIsPacked。检查这个stackoverflow.com/a/65522764/4524195
【解决方案4】:

只是为了更新 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 = kLinearPCMFormatFlagIsPacked |
    kAudioFormatFlagIsSignedInteger

    // Create destination file
    error = ExtAudioFileCreateWithURL(
        outputURL as CFURL,
        kAudioFileWAVEType,
        &dstFormat,
        nil,
        AudioFileFlags.eraseFile.rawValue,
        &destinationFile)
    print("Error 1 in convertAudio: \(error.description)")

    error = ExtAudioFileSetProperty(sourceFile!,
                                    kExtAudioFileProperty_ClientDataFormat,
                                    thePropertySize,
                                    &dstFormat)
    print("Error 2 in convertAudio: \(error.description)")

    error = ExtAudioFileSetProperty(destinationFile!,
                                    kExtAudioFileProperty_ClientDataFormat,
                                    thePropertySize,
                                    &dstFormat)
    print("Error 3 in convertAudio: \(error.description)")

    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)
        print("Error 4 in convertAudio: \(error.description)")

        if(numFrames == 0){
            error = noErr;
            break;
        }

        sourceFrameOffset += numFrames
        error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList)
        print("Error 5 in convertAudio: \(error.description)")
    }

    error = ExtAudioFileDispose(destinationFile!)
    print("Error 6 in convertAudio: \(error.description)")
    error = ExtAudioFileDispose(sourceFile!)
    print("Error 7 in convertAudio: \(error.description)")
}

【讨论】:

  • 除了使用 kAudioFileMP3Type 导出到 MP3 是否有任何其他更改?我在错误 = ExtAudioFileSetProperty(destinationFile!, when using MP3 type 时遇到零崩溃
  • 您可能需要尝试不同的 mFormatFlags。您会注意到,这与 kAudioFileMP3Type 以外的公认答案之间存在差异。
【解决方案5】:

这是 MScottWaller 的 Swift 3 答案的 Objective-C 版本。你需要@import AudioToolbox。

-(void) convertAudio:(NSURL*)url outputURL:(NSURL*)outputURL
{
    OSStatus error = noErr;
    ExtAudioFileRef destinationFile = nil;
    ExtAudioFileRef sourceFile = nil;

    AudioStreamBasicDescription srcFormat;
    AudioStreamBasicDescription dstFormat;

    ExtAudioFileOpenURL((__bridge CFURLRef)url, &sourceFile);


    UInt32 thePropertySize = sizeof(srcFormat); //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 = kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger;

    // Create destination file
    error = ExtAudioFileCreateWithURL(
                                      (__bridge CFURLRef)outputURL,
                                      kAudioFileWAVEType,
                                      &dstFormat,
                                      nil,
                                      kAudioFileFlags_EraseFile,
                                      &destinationFile);
    NSLog(@"Error 1 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);

    error = ExtAudioFileSetProperty(sourceFile,
                                    kExtAudioFileProperty_ClientDataFormat,
                                    thePropertySize,
                                    &dstFormat);
    NSLog(@"Error 2 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);

    error = ExtAudioFileSetProperty(destinationFile,
                                    kExtAudioFileProperty_ClientDataFormat,
                                    thePropertySize,
                                    &dstFormat);
    NSLog(@"Error 3 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);

    const UInt32 bufferByteSize = 32768;
    UInt8 srcBuffer[bufferByteSize];// = [UInt8](repeating: 0, count: 32768)
    memset(srcBuffer, 0, bufferByteSize);
    unsigned long sourceFrameOffset = 0;

    while(true)
    {
        AudioBufferList fillBufList;
        fillBufList.mNumberBuffers = 1;
        fillBufList.mBuffers[0].mNumberChannels = 2;
        fillBufList.mBuffers[0].mDataByteSize = bufferByteSize;
        fillBufList.mBuffers[0].mData = &srcBuffer;

        UInt32 numFrames = 0;

        if(dstFormat.mBytesPerFrame > 0){
            numFrames = bufferByteSize / dstFormat.mBytesPerFrame;
        }

        error = ExtAudioFileRead(sourceFile, &numFrames, &fillBufList);
        NSLog(@"Error 4 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);

        if(numFrames == 0)
        {
            error = noErr;
            break;
        }

        sourceFrameOffset += numFrames;
        error = ExtAudioFileWrite(destinationFile, numFrames, &fillBufList);
        NSLog(@"Error 5 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    }

    error = ExtAudioFileDispose(destinationFile);
    NSLog(@"Error 6 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
    error = ExtAudioFileDispose(sourceFile);
    NSLog(@"Error 7 in convertAudio: %d - %@", error, [NSError errorWithDomain:NSOSStatusErrorDomain code:error userInfo:nil].description);
}

【讨论】:

    【解决方案6】:

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

    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 文件,它运行良好。

    audioPlayer = try! AVAudioPlayer(contentsOf: wavFileName)
    audioPlayer.play()
    

    像这样将文件扩展名从 .m4a 转换为 .wav 有什么缺点吗?

    【讨论】:

    • 我其实也有兴趣了解这些缺点。我总是更改文件扩展名并且看不到任何后果。也许对您的答案投反对票的人会愿意解释一下?
    • 是的,我也没有看到任何缺点,你可以投票吗?
    【解决方案7】:

    我试图在 Swift 5 中将 m4a 转换为 Wav 格式。

    以上所有代码都已过时且无法正常工作。 经过一些调整后,这里是工作示例

    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 = kLinearPCMFormatFlagIsPacked |
        kAudioFormatFlagIsSignedInteger
    
    
        // Create destination file
        error = ExtAudioFileCreateWithURL(
            outputURL as CFURL,
            kAudioFileWAVEType,
            &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
        print(error)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-17
      • 2011-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多