學(xué)習(xí)整理的相關(guān)章節(jié)鏈接:
基礎(chǔ)篇_1.音視頻學(xué)習(xí)框架
基礎(chǔ)篇_2. 顏色空間模型 RBG、YUV、HSV
基礎(chǔ)篇_3.圖像編碼之Bmp
基礎(chǔ)篇_4.音頻基礎(chǔ)概念
基礎(chǔ)篇_5.音頻數(shù)據(jù)采集
基礎(chǔ)篇_6.音頻編碼PCM
基礎(chǔ)篇_7.音頻編碼WAV
基礎(chǔ)篇_8.音頻編碼MP3\AAC
1.WAV編碼
編碼包括了兩方面內(nèi)容,一是按一定格式存儲(chǔ)數(shù)據(jù),二是采用一定的算法壓縮數(shù)據(jù)。
WAV格式對(duì)音頻流的編碼沒有硬性規(guī)定,支持非壓縮的PCM(Puls Code Modulation)脈沖編碼調(diào)制格式,還支持壓縮型的微軟自適應(yīng)分脈沖編碼調(diào)制Microsoft ADPCM(Adaptive Differential Puls Code Modulation)、國(guó)際電報(bào)聯(lián)盟(International Telegraph Union)制定的語(yǔ)音壓縮標(biāo)準(zhǔn)ITUG.711 a-law、ITU G.711-law、IMA ADPCM、ITU G.723 ADPCM (Yamaha)、GSM 6.10、ITU G.721 ADPCM編碼和其它壓縮算法。MP3編碼同樣也可以運(yùn)用在WAV中,只要安裝相應(yīng)的Decode,就可以播放WAV中的MP3音樂
特點(diǎn):音質(zhì)非常好(因?yàn)橥ǔS玫木幋a都是非壓縮的PCM),大量軟件都支持
適用場(chǎng)景:多媒體開發(fā)的中間文件、保存音樂和音效素材
2.將PCM音頻數(shù)據(jù)轉(zhuǎn)換成WAV格式
WAV為微軟公司(Microsoft)開發(fā)的一種聲音文件格式,它符合RIFF(Resource Interchange File Format)文件規(guī)范,用于保存Windows平臺(tái)的音頻信息資源,被Windows平臺(tái)及其應(yīng)用程序所廣泛支持。WAVE文件通常只是一個(gè)具有單個(gè)“WAVE”塊的RIFF文件,該塊由兩個(gè)子塊(”fmt”子數(shù)據(jù)塊和”data”子數(shù)據(jù)塊),它的格式如下圖所示


該格式的實(shí)質(zhì)就是在PCM文件的前面加了一個(gè)文件頭,每個(gè)字段的的含義為
typedef struct{
char ChunkID[4];//內(nèi)容為"RIFF"
unsigned long ChunkSize;//存儲(chǔ)文件的字節(jié)數(shù)(不包含ChunkID和ChunkSize這8個(gè)字節(jié))
char Format[4];//內(nèi)容為"WAVE"
}WAVE_HEADER;
typedef struct{
char Subchunk1ID[4];//內(nèi)容為"fmt"
unsigned long Subchunk1Size;//存儲(chǔ)該子塊的字節(jié)數(shù)(不含前面的Subchunk1ID和Subchunk1Size這8個(gè)字節(jié))
unsigned short AudioFormat;//存儲(chǔ)音頻文件的編碼格式,例如若為PCM則其存儲(chǔ)值為1,若為其他非PCM格式的則有一定的壓縮。
unsigned short NumChannels;//通道數(shù),單通道(Mono)值為1,雙通道(Stereo)值為2,等等
unsigned long SampleRate;//采樣率,如8k,44.1k等
unsigned long ByteRate;//每秒存儲(chǔ)的bit數(shù),其值=SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign;//塊對(duì)齊大小,其值=NumChannels * BitsPerSample/8
unsigned short BitsPerSample;//每個(gè)采樣點(diǎn)的bit數(shù),一般為8,16,32等。
}WAVE_FMT;
typedef struct{
char Subchunk2ID[4];//內(nèi)容為“data”
unsigned long Subchunk2Size;//內(nèi)容為接下來(lái)的正式的數(shù)據(jù)部分的字節(jié)數(shù),其值=NumSamples * NumChannels * BitsPerSample/8
}WAVE_DATA;
比如下面的例子
這里是一個(gè)WAVE文件的開頭72字節(jié),字節(jié)顯示為十六進(jìn)制數(shù)字:
52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00
22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00
24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d
字段解析:

代碼實(shí)現(xiàn)為
int simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,const char *wavepath)
{
typedef struct WAVE_HEADER{
char fccID[4];
unsigned long dwSize;
char fccType[4];
}WAVE_HEADER;
typedef struct WAVE_FMT{
char fccID[4];
unsigned long dwSize;
unsigned short wFormatTag;
unsigned short wChannels;
unsigned long dwSamplesPerSec;
unsigned long dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short uiBitsPerSample;
}WAVE_FMT;
typedef struct WAVE_DATA{
char fccID[4];
unsigned long dwSize;
}WAVE_DATA;
if(channels==0||sample_rate==0){
channels = 2;
sample_rate = 44100;
}
int bits = 16;
WAVE_HEADER pcmHEADER;
WAVE_FMT pcmFMT;
WAVE_DATA pcmDATA;
unsigned short m_pcmData;
FILE *fp,*fpout;
fp=fopen(pcmpath, "rb");
if(fp == NULL) {
printf("open pcm file error\n");
return -1;
}
fpout=fopen(wavepath, "wb+");
if(fpout == NULL) {
printf("create wav file error\n");
return -1;
}
//WAVE_HEADER
memcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));
memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));
fseek(fpout,sizeof(WAVE_HEADER),1);
//WAVE_FMT
pcmFMT.dwSamplesPerSec=sample_rate;
pcmFMT.dwAvgBytesPerSec=pcmFMT.dwSamplesPerSec*sizeof(m_pcmData);
pcmFMT.uiBitsPerSample=bits;
memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));
pcmFMT.dwSize=16;
pcmFMT.wBlockAlign=2;
pcmFMT.wChannels=channels;
pcmFMT.wFormatTag=1; //1就是pcm
fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout);
//WAVE_DATA;
memcpy(pcmDATA.fccID,"data",strlen("data"));
pcmDATA.dwSize=0;
fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);
fread(&m_pcmData,sizeof(unsigned short),1,fp);
while(!feof(fp)){
pcmDATA.dwSize+=2;
fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
fread(&m_pcmData,sizeof(unsigned short),1,fp);
}
pcmHEADER.dwSize=44+pcmDATA.dwSize;
rewind(fpout);
fwrite(&pcmHEADER,sizeof(WAVE_HEADER),1,fpout);
fseek(fpout,sizeof(WAVE_FMT),SEEK_CUR);
fwrite(&pcmDATA,sizeof(WAVE_DATA),1,fpout);
fclose(fp);
fclose(fpout);
return 0;
}