从视频文件中提取音频数据并转换为AVAudioPCMBuffer的方法

ChatGPT4o 使用 ChatGPT 4o 回答

问题:

如何从视频文件中,读取所有轨道的音频数据,转换成AVAudioPCMBuffer, 获取 sampleRate

回答:

要从视频文件中读取所有轨道的音频数据并转换成 AVAudioPCMBuffer,同时获取采样率(sampleRate),你可以使用 AVFoundation 框架。以下是一个示例代码,展示了如何实现这一目标:

  1. 导入必要的框架。
  2. 使用 AVAsset 加载视频文件。
  3. 提取音频轨道并读取音频数据。
  4. 将音频数据转换为 AVAudioPCMBuffer
  5. 获取采样率。
import AVFoundation

func extractAudioBuffers(from videoURL: URL) {
    // 创建 AVAsset 实例
    let asset = AVAsset(url: videoURL)
    
    // 获取音频轨道
    let audioTracks = asset.tracks(withMediaType: .audio)
    
    for track in audioTracks {
        // 创建 AVAssetReader
        guard let assetReader = try? AVAssetReader(asset: asset) else {
            print("Failed to create AVAssetReader")
            continue
        }
        
        // 创建 AVAssetReaderTrackOutput
        let trackOutput = AVAssetReaderTrackOutput(track: track, outputSettings: [
            AVFormatIDKey: kAudioFormatLinearPCM
        ])
        
        assetReader.add(trackOutput)
        
        // 开始读取
        assetReader.startReading()
        
        // 获取音频格式描述
        let formatDescription = track.formatDescriptions.first as! CMAudioFormatDescription
        let audioStreamBasicDescription = CMAudioFormatDescriptionGetStreamBasicDescription(formatDescription)!.pointee
        
        // 获取���样率
        let sampleRate = audioStreamBasicDescription.mSampleRate
        print("Sample Rate: \(sampleRate)")
        
        // 创建 AVAudioFormat
        let audioFormat = AVAudioFormat(cmAudioFormatDescription: formatDescription)!
        
        // 读取音频数据并转换为 AVAudioPCMBuffer
        while let sampleBuffer = trackOutput.copyNextSampleBuffer() {
            guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else {
                continue
            }
            
            let length = CMBlockBufferGetDataLength(blockBuffer)
            var data = Data(count: length)
            data.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) in
                CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: length, destination: bytes.baseAddress!)
            }
            
            let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: AVAudioFrameCount(length) / audioFormat.streamDescription.pointee.mBytesPerFrame)!
            audioBuffer.frameLength = audioBuffer.frameCapacity
            
            data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
                let audioBufferPointer = audioBuffer.audioBufferList.pointee.mBuffers.mData!
                memcpy(audioBufferPointer, bytes.baseAddress!, length)
            }
            
            // 现在你可以使用 audioBuffer 了
            print("Extracted audio buffer with \(audioBuffer.frameLength) frames")
        }
    }
}

// 使用示例
let videoURL = URL(fileURLWithPath: "/path/to/your/video/file.mp4")
extractAudioBuffers(from: videoURL)

请注意:

  • 你需要替换 "/path/to/your/video/file.mp4" 为你的视频文件路径。
  • 这个示例代码假设视频文件中有音频轨道,并且音频格式是线性 PCM。如果音频格式不同,你可能需要调整 outputSettings
  • 这个示例代码没有处理所有可能的错误情况,实际应用中应添加更多的错误处理逻辑。

通过这个示例代码,你可以从视频文件中提取音频数据,转换为 AVAudioPCMBuffer,并获取采样率。