iOS PCM轉(zhuǎn)WMV

1、最近在項目遇到上傳音頻到服務(wù)端處理錯誤問題;當(dāng)然一般情況下如果雙端商量好格式,通過iOS系統(tǒng)的錄音框架,上傳AVAudioRecorder錄取的音頻,沒什么問題。但是工作涉及的后端比較多,格式要求必須是WAV。這時候需要將原始錄制的PCM數(shù)據(jù),轉(zhuǎn)換為WAV格式。

2、首先來看看WAV和PCM分別是什么

WAV:wav是一種無損的音頻文件格式,WAV符合 PIFF(Resource Interchange File Format)規(guī)范。所有的WAV都有一個文件頭,這個文件頭音頻流的編碼參數(shù)。WAV對音頻流的編碼沒有硬性規(guī)定,除了PCM之外,還有幾乎所有支持ACM規(guī)范的編碼都可以為WAV的音頻流進(jìn)行編碼。

PCM:PCM(Pulse Code Modulation—-脈碼調(diào)制錄音)。所謂PCM錄音就是將聲音等模擬信號變成符號化的脈沖列,再予以記錄。PCM信號是由[1]、[0]等符號構(gòu)成的數(shù)字信號,而未經(jīng)過任何編碼和壓縮處理。與模擬信號比,它不易受傳送系統(tǒng)的雜波及失真的影響。動態(tài)范圍寬,可得到音質(zhì)相當(dāng)好的影響效果。

簡單來說:wav是一種無損的音頻文件格式,pcm是沒有壓縮的編碼方式。

3、WAV和PCM的關(guān)系

WAV可以使用多種音頻編碼來壓縮其音頻流,不過我們常見的都是音頻流被PCM編碼處理的WAV,但這不表示W(wǎng)AV只能使用PCM編碼,MP3編碼同樣也可以運(yùn)用在WAV中,和AVI一樣,只要安裝好了相應(yīng)的Decode,就可以欣賞這些WAV了。在Windows平臺下,基于PCM編碼的WAV是被支持得最好的音頻格式,所有音頻軟件都能完美支持,由于本身可以達(dá)到較高的音質(zhì)的要求,因此,WAV也是音樂編輯創(chuàng)作的首選格式,適合保存音樂素材。因此,基于PCM編碼的WAV被作為了一種中介的格式,常常使用在其他編碼的相互轉(zhuǎn)換之中,例如MP3轉(zhuǎn)換成WMA。

簡單來說:pcm是無損wav文件中音頻數(shù)據(jù)的一種編碼方式,但wav還可以用其它方式編碼。

4、既然知道WAV與PCM關(guān)系了,下一步就到了轉(zhuǎn)換成wav格式,這需要手動填充wav的文件頭信息。

簡單來講:從PCM轉(zhuǎn)成WAV格式,就是在錄音后得到的PCM數(shù)據(jù)加上文件頭信息

5、頭文件的格式,我們通過一張圖表來觀察

頭文件總共44個字節(jié),這里面的信息反映的也是錄制音頻的相關(guān)信息,參數(shù)是在初始化錄音時設(shè)置的。有幾個參數(shù)需要注意:

ChunkSize: SubChunk2Size + 36 (頭文件44個字節(jié),除去RIFF占4字節(jié)和當(dāng)前占的4字節(jié))

ByteRate = ?(Sample Rate * BitsPerSample * Channels) / 8.

BlckAlign = ?(BitsPerSample * Channels) / 8

SubChunk2Size = 音頻數(shù)據(jù)大小,也就是PCMData數(shù)據(jù)大小

我這里的設(shè)置,BitsPerSample = 16 , SampleRate = 16000, channels = 1

這些參數(shù)是錄音時設(shè)置的:

NSMutableDictionary*setting = [NSMutableDictionarydictionary];

//音頻格式

setting[AVFormatIDKey] =@(kAudioFormatLinearPCM);

//錄音采樣率(Hz)(影響音頻的質(zhì)量)

setting[AVSampleRateKey] =@(16000);

//音頻通道數(shù)1或2

setting[AVNumberOfChannelsKey] =@(1);

//線性音頻的位深度8、16、24、32,每次采樣16位,2個字節(jié) 既是BitsPerSample

setting[AVLinearPCMBitDepthKey] =@(16);?

//錄音的質(zhì)量

setting[AVEncoderAudioQualityKey] = [NSNumbernumberWithInt:AVAudioQualityHigh];

6、具體實現(xiàn):

```

NSData* WriteWavFileHeader(long totalAudioLen, long totalDataLen, long longSampleRate,int channels, long byteRate) {

Byte? header[44];

header[0] = 'R';? // RIFF/WAVE header

header[1] = 'I';

header[2] = 'F';

header[3] = 'F';

header[4] = (Byte) (totalDataLen & 0xff);? //file-size (equals file-size - 8)

header[5] = (Byte) ((totalDataLen >> 8) & 0xff);

header[6] = (Byte) ((totalDataLen >> 16) & 0xff);

header[7] = (Byte) ((totalDataLen >> 24) & 0xff);

header[8] = 'W';? // Mark it as type "WAVE"

header[9] = 'A';

header[10] = 'V';

header[11] = 'E';

header[12] = 'f';? // Mark the format section 'fmt ' chunk

header[13] = 'm';

header[14] = 't';

header[15] = ' ';

header[16] = 16;? // 4 bytes: size of 'fmt ' chunk, Length of format data.? Always 16

header[17] = 0;

header[18] = 0;

header[19] = 0;

header[20] = 1;? // format = 1 ,Wave type PCM

header[21] = 0;

header[22] = (Byte) channels;? // channels

header[23] = 0;

header[24] = (Byte) (longSampleRate & 0xff);

header[25] = (Byte) ((longSampleRate >> 8) & 0xff);

header[26] = (Byte) ((longSampleRate >> 16) & 0xff);

header[27] = (Byte) ((longSampleRate >> 24) & 0xff);

header[28] = (Byte) (byteRate & 0xff);

header[29] = (Byte) ((byteRate >> 8) & 0xff);

header[30] = (Byte) ((byteRate >> 16) & 0xff);

header[31] = (Byte) ((byteRate >> 24) & 0xff);

header[32] = (Byte) (channels * 16 / 8); // block align

header[33] = 0;

header[34] = 16; // bits per sample

header[35] = 0;

header[36] = 'd'; //"data" marker

header[37] = 'a';

header[38] = 't';

header[39] = 'a';

header[40] = (Byte) (totalAudioLen & 0xff);? //data-size (equals file-size - 44).

header[41] = (Byte) ((totalAudioLen >> 8) & 0xff);

header[42] = (Byte) ((totalAudioLen >> 16) & 0xff);

header[43] = (Byte) ((totalAudioLen >> 24) & 0xff);

return [[NSData alloc] initWithBytes:header length:44];;

}

```

頭文件詳細(xì)參考

C代碼參考

Java代碼參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容