Per your other comment/question
,如果您可以得到解码的PCM样本,您可以添加一个RIFF/WAV,使用的字节类似于下面的C常量(取自
WAV_HEADER_TEMPLATE
)
static const unsigned char WAV_HEADER_TEMPLATE[44]={
'R','I','F','F',
0xFF,0xFF,0xFF,0x7F,
'W','A','V','E',
'f','m','t',' ',
0x10,0x00,0x00,0x00,
0x03,0x00,
0x02,0x00,
0x80,0xBB,0x00,0x00,
0x00,0xDC,0x05,0x00,
0x08,0x00,
0x20,0x00,
'd','a','t','a',
0xFF,0xFF,0xFF,0x7F
};
this C function
也建议阅读。
-
0x01
应用于指定格式代码的PCM
-
“数据大小”是解码音频的总字节大小
-
(完整解决方案:
Libopus Kit
)
iOS的Swift代码
(
)
guard let url = Bundle.main.url(forResource: "foo", withExtension: "opus") else { return }
print("url: \(url)")
do {
let fileData = try Data(contentsOf: url)
let extractedPCM = AudioUtil.extractPCM(from: fileData, for: OpusAudioSetting())
let wavHeader = AudioUtil.createWavHeader(pcmInfo: PCMInfo(), pcmDataSizeInBytes: Int32(extractedPCM.count))
let wavAudioData = AudioUtil.generateWav(header: wavHeader, pcmData: extractedPCM)
playData(audioData: wavAudioData)
} catch let error {
print(error)
}
音频工具
import Foundation
import OpusKit
public class AudioUtil {
private init(){}
public static func createWavHeader(pcmInfo: PCMInfo, pcmDataSizeInBytes dataSize: Int32) -> Data {
let WAV_HEADER_SIZE:Int32 = 44
let fileSize:Int32 = dataSize + WAV_HEADER_SIZE
let sampleRate:Int32 = 16000
let subChunkSize:Int32 = 16
let format:Int16 = 1
let channels:Int16 = 1
let bitsPerSample:Int16 = 16
let byteRate:Int32 = sampleRate * Int32(channels * bitsPerSample / 8)
let blockAlign: Int16 = (bitsPerSample * channels) / 8
let header = NSMutableData()
header.append([UInt8]("RIFF".utf8), length: 4)
header.append(byteArray(from: fileSize), length: 4)
header.append([UInt8]("WAVE".utf8), length: 4)
header.append([UInt8]("fmt ".utf8), length: 4)
header.append(byteArray(from: subChunkSize), length: 4)
header.append(byteArray(from: format), length: 2)
header.append(byteArray(from: channels), length: 2)
header.append(byteArray(from: sampleRate), length: 4)
header.append(byteArray(from: byteRate), length: 4)
header.append(byteArray(from: blockAlign), length: 2)
header.append(byteArray(from: bitsPerSample), length: 2)
header.append([UInt8]("data".utf8), length: 4)
header.append(byteArray(from: dataSize), length: 4)
return header as Data
}
public static func extractPCM(from audioData: Data, for setting: OpusAudioSetting) -> Data {
OpusKit.shared.initialize(
sampleRate: setting.sampleRate,
numberOfChannels: setting.channels,
packetSize: setting.packetSize,
encodeBlockSize: setting.encodeBlockSize)
let decodedPCMData = extractAndDecodeAudioData(from: audioData)
return decodedPCMData
}
public static func extractAndDecodeAudioData(from fileData: Data, headerSize: Int = 1) -> Data {
}
private static func byteArray<T>(from value: T) -> [UInt8] where T: FixedWidthInteger {
return withUnsafeBytes(of: value.littleEndian) { Array($0) }
}
public static func generateWav(header wavHeader: Data, pcmData: Data) -> Data {
var wavData = Data()
wavData.append(wavHeader)
wavData.append(pcmData)
return wavData
}
}
public struct OpusAudioSetting {
var sampleRate: opus_int32 = 16000
var channels: opus_int32 = 1
var packetSize: opus_int32 = 320
var encodeBlockSize: opus_int32 = 320
}
public struct PCMInfo {
var sampleRate:Int32 = 16000
var channels:Int16 = 1
var bitsPerSample:Int16 = 16
}