基礎(chǔ)篇_7.音頻編碼WAV

學(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ù)塊),它的格式如下圖所示

WAV_file_format.png
WAV中的常見編碼格式.png

該格式的實(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 

字段解析:

image

代碼實(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;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容