实验6_MPEG音频编码实验
MPEG音頻編碼實驗
- 一、MP2簡介
- 1、什么是MP2
- 2、MP2優缺點
- 1)優點
- 2)缺點
- 3、與MP3對比
- 二、MPEG簡介
- 1、什么是MPEG-1
- 2、音頻分層
- 三、音頻編碼——人類聽覺系統的感知特性
- 1、音頻壓縮——冗余信息
- 2、人類聽覺系統的感知特性
- 1)等響度曲線
- 2)頻域掩蔽效應
- 3、時域掩蔽效應
- 四、MPEG-1音頻壓縮編碼
- 1、MPEG-1 Audio LayerII編碼器原理圖
- 2、MPEG-I 心理聲學模型
- 3、多相濾波器
- 4、碼率分配
- 5、計算比例因子
- 五、MPEG-1 Audio Layer II編碼器代碼調試
- 1、編碼器main()函數中重要部分的注釋
- 2、基本功能
- 3、基本命令行參數——轉換格式為.mp2
- 4、輸出某一數據幀的信息——采樣率和目標碼率
- 5、輸出某一數據幀的信息——比例因子和比特分配表
- 六、結果展示——(噪聲、音樂、混合)
- 1、噪聲:
- 2、音樂:
- 3、混合:
一、MP2簡介
1、什么是MP2
MP2是MPEG-1 Layer II 的縮寫,它是一種有損壓縮的音頻格式,文件擴展名為.mp2。對于廣播電視制作行業的人來說,mp2是很常見的音頻文件格式。 MP2主要應用在標準化數字廣播和數字電視廣播(DAB,DMB,DVB)的數字音頻和視頻編碼。 標準MPEG II音頻格式支持32,44.1和48 kHz采樣率以及32至320 kbps /秒的比特率。
**注:**MP2音頻文件不是MPEG-2視頻文件。MPEG-2是視頻編碼的標準,其擴展名為.mpg。
2、MP2優缺點
1)優點
2)缺點
MP2文件格式通常用于廣播電視行業,所以在普通音頻播放器上的支持率不高。在一些播放器上播放MP2格式的音頻前,需轉換音頻格式。
3、與MP3對比
MP2與 MP3都是有損音頻格式,但兩者之間存在著一定的差異。 在音頻數據上,MP2相比MP3,數據壓縮較小,導致音頻文件較大。MP2文件以6:1和8:1的比例壓縮音頻信號,而MP3文件壓縮比為10:1到12:1。文件較小的MP3更易于在互聯網中傳播。 在應用范圍上,MP3的應用范圍更為廣泛。MP3可以在計算機、互聯網應用、各種音頻播放設備上都有很好的播放支持,而MP2主要是應用在數字廣播電視行業。
二、MPEG簡介
1、什么是MPEG-1
MPEG-1是MPEG組織制定的第一個視頻和音頻有損壓縮標準。視頻壓縮算法于1990年定義完成。1992年底,MPEG-1正式被批準成為國際標準。MPEG-1是為CD光碟介質定制的的視頻和音頻壓縮格式。一張70分鐘的CD光碟傳輸速率大約在1.4Mbps。而MPEG-1采用了塊方式的運動補償、離散余弦變換(DCT)、量化等技術,并為1.2Mbps傳輸速率進行了優化。MPEG-1隨后被Video CD采用作為核心技術。
2、音頻分層
MPEG-1音頻分三層,分別為MPEG-1 Layer1,MPEG-Layer2以及MPEG-Layer3,并且高層兼容低層。其中第三層協議被稱為MPEG-1 Layer 3,簡稱MP3。MP3已經成為廣泛流傳的的音頻壓縮技術。這次實驗中圍繞MP2(MPEG-Layer2)展開。
MPEG-1 Layer1采用每聲道192kbit/s,每幀384個樣本,32個等寬子帶,固定分割數據塊。子帶編碼用DCT(離散余弦變換)和(快速傅立葉變換)計算子帶信號量化bit數。采用基于頻域掩蔽效應的心理聲學模型,使量化噪聲低于掩蔽值。量化采用帶死區的線性量化器,主要用于數字盒式磁帶(DCC)。
MPEG-1 Layer2采用每聲道128kbit/s,每幀1152個樣本,32個子帶,屬不同分幀方式。采用共同頻域和時域掩蔽效應的心理聲學模型,并對高、中,低頻段的比特分配進行限制,并對比特分配、比例因子,取樣進行附加編碼。Layer2 廣泛用于數字電視,CD-ROM,CD-I和VCD等。
MPEG-1 Layer3采用每聲道64kbit/s,用混合濾波器組提高頻率分辨率,按信號分辨率分成6X32或18X32個子帶,克服平均32個子帶的Layer1,Layer2在中低頻段分辨率偏低的缺點。采用心理聲學模型2,增設不均勻量化器,量化值進行熵編碼。主要用于ISDN(綜合業務數字網)音頻編碼。
MPEG-1制定于1992年,為工業級標準而設計,它可針對SIF標準分辨率(對于NTSC制為352X240;對于PAL制為352X288)的圖像進行壓縮,傳輸速率為1.5Mbits/sec,每秒播放30幀,具有CD(指激光唱盤)音質,質量級別基本與VHS相當。MPEG的編碼速率最高可達4- 5Mbits/sec,但隨著速率的提高,其解碼后的圖象質量有所降低。
MPEG-1也被用于數字電話網絡上的視頻傳輸,如非對稱數字用戶線路(ADSL),視頻點播(VOD),以及教育網絡等。同時,MPEG-1也可被用做記錄媒體或是在INTERNET上傳輸音頻。
三、音頻編碼——人類聽覺系統的感知特性
1、音頻壓縮——冗余信息
無壓縮的數字音頻信號中主要存在兩方面的冗余信息:
一是聲音信號中本身存在的冗余:信號幅度分布是非均勻的(小幅度的樣值比大幅度樣值出現的概率高),且樣本之間存在相關性(時域冗余);
二是根據人耳的聽覺特性,可不對與聽覺無關的部分編碼。
2、人類聽覺系統的感知特性
1)等響度曲線
圖中每條曲線代表的人耳感受的響度相同,最下方一條曲線代表最小可聽閾,其下方區域的聲音人耳無法察覺,因此可以不編碼。
2)頻域掩蔽效應
上圖為 聲強為60 dB、頻率為1000 Hz純音的掩蔽效應
一個強純音會掩蔽在其附近同時發聲的弱純音,這種特性稱為頻域掩蔽,也稱同時掩蔽(simultaneous masking),如上圖所示。
從上圖中可以看到,聲音頻率在300 Hz附近、聲強約為60 dB的聲音掩蔽了聲音頻率在150 Hz附近、聲強約為40 db的聲音。又如,一個聲強為60 dB、頻率為1000 Hz的純音,另外還有一個1100 Hz的純音,前者比后者高18 dB,在這種情況下我們的耳朵就只能聽到那個1000 Hz的強音。如果有一個1000 Hz的純音和一個聲強比它低18 dB的2000 Hz的純音,那么我們的耳朵將會同時聽到這兩個聲音。要想讓2000 Hz的純音也聽不到,則需要把它降到比1000 Hz的純音低45 dB。一般來說,弱純音離強純音越近就越容易被掩蔽。
3、時域掩蔽效應
上圖為時域掩蔽圖
除了同時發出的聲音之間有掩蔽現象之外,在時間上相鄰的聲音之間也有掩蔽現象,并且稱為時域掩蔽。時域掩蔽又分為超前掩蔽(pre-masking)和滯后掩蔽(post-masking),如上圖所示。產生時域掩蔽的主要原因是人的大腦處理信息需要花費一定的時間。一般來說,超前掩蔽很短,只有大約5~20 ms,而滯后掩蔽可以持續50~200 ms。
同步掩蔽效應和不同頻率聲音的頻率和相對音量有關,而時間掩蔽則僅僅和時間有關。
如果兩個聲音在時間上特別接近,我們在分辨它們的時候就會有困難。例如,如果一個很響的聲音后面緊跟著一個很弱的聲音,后一個聲音就很難聽到。但是如果在第一個聲音停止后過一段時間再播放第二個聲音,后一個聲音就可以聽到。對純音一般來講,這個間隔時間是5毫秒。當然如果在時序上反過來,效果是一樣的。如果一個較低的聲音出現在一個較高的聲音之前,而且間隔很短,那個較低的聲音我們也聽不到。
四、MPEG-1音頻壓縮編碼
1、MPEG-1 Audio LayerII編碼器原理圖
MPEG-1中采用了感知音頻編碼,MPEG-1 Audio LayerII編碼器原理圖如下
可以看到,編碼器分為上下兩部分:上方部分為子帶編碼部分,這也是編碼的主線;下方的部分,是MPEG音頻編碼根據要求分配比特等內容的部分。
2、MPEG-I 心理聲學模型
心理聲學模型決定了各個子帶中允許的最大量化噪聲,小于它的量化噪聲都會被掩蔽。若子帶內的信號功率小于掩蔽閾值,則不進行編碼;否則,確定要編碼的系數所需的比特數,使量化引起的噪聲低于掩蔽效應;
? 通過子帶分析濾波器組使信號具有高的時間分辨率,確保在短暫沖擊信號情況下,編碼的聲音信號具有足夠高的質量
? 又可以使信號通過FFT運算具有高的頻率分辨率,這里Layer II采用1024點FFT(Layer I中采用512點),可以得到更準確的頻譜特性。
? 在低頻子帶中,為了保護音調和共振峰的結構,就要求用較小的量化階、較多的量化級數,即分配較多的位數來表示樣本值。而話音中的摩擦音和類似噪聲的聲音,通常出現在高頻子帶中,對它分配較少的位數
?將音頻信號分解成“樂音(tones)” 和“非樂音/噪聲”部分:因為兩種信號的掩蔽能力不同
?音調和非音調掩蔽成分的消除
利用標準中給出的絕對閾值消除被掩蔽成分;考慮在每個臨界頻帶內,小于0.5Bark的距離中只保留最高功率的成分
? 單個掩蔽閾值的計算
音調成分和非音調成分單個掩蔽閾值根據標準中給出的算法求得。
? 全局掩蔽閾值的計算
3、多相濾波器
數字音頻信號通過一個多相濾波器組,變換成32個等寬頻帶子帶,使得信號具有較高的時間分辨率,確保在短暫沖擊信號的情況下,編碼的聲音信號具有足夠高的質量。
但需要說明的是,高時域分辨率和高頻域分辨率是不可兼得的,我們需要做出權衡。
濾波器組的輸出是臨界頻帶經過量化的系數樣值。若一個子帶覆蓋多個臨界頻帶,則選擇具有最小NMR的臨界頻帶來計算分配給子帶的比特數。
4、碼率分配
噪聲-掩蔽比(noise-to-mask ratio, NMR):
NMR = SMR – SNR (dB)
其中SNR 由MPEG-I標準給定 (為量化水平的函數)
NMR:表示波形誤差與感知測量之間的誤差
算法:使整幀和每個子帶的總噪聲—掩蔽比最小
具體做法:
1、對每個子帶計算掩噪比MNR (dB)
2、找出其中具有最低MNR的子帶,并給該子帶多分配一些比特,
3、重新計算MNR,繼續分配,重復該步驟,直至沒有比特可以分配。
這樣可以使得在滿足比特率和掩蔽要求的前提下,使MNR最小
5、計算比例因子
?對各個子帶每36個樣點(Layer I為12個樣點)進行一次比例因子的計算,先確定12個連續樣值中的最大值,查Layer II、Layer I比例因子表中比這它大的最小值作為量化比例因子;
?每12個樣值計算出一個比例因子,Layer II中將每個子帶分為3組,每組各有12個取樣值,因此36個樣值具有3個比例因子;
?比例因子可以使得比較準確地計算出子帶的聲壓級;
?一般比例因子從低頻子帶到高頻子帶連續下降;
五、MPEG-1 Audio Layer II編碼器代碼調試
1、編碼器main()函數中重要部分的注釋
main()函數重要部分的代碼,根據上面的編碼步驟,對代碼進行注釋:
int main (int argc, char **argv) {typedef double SBS[2][3][SCALE_BLOCK][SBLIMIT];SBS *sb_sample;typedef double JSBS[3][SCALE_BLOCK][SBLIMIT];JSBS *j_sample;typedef double IN[2][HAN_SIZE];IN *win_que;typedef unsigned int SUB[2][3][SCALE_BLOCK][SBLIMIT];SUB *subband;frame_info frame;//這個結構體包含頭信息、比特分配表、子帶數等內容frame_header header;//這個結構體包含采樣頻率等信息char original_file_name[MAX_NAME_SIZE];//輸入的文件名char encoded_file_name[MAX_NAME_SIZE];//輸出的文件名short **win_buf;static short buffer[2][1152];static unsigned int bit_alloc[2][SBLIMIT], scfsi[2][SBLIMIT];//存放雙聲道各個子帶的比特分配表static unsigned int scalar[2][3][SBLIMIT], j_scale[3][SBLIMIT];// 存放雙聲道3組12個樣值的各個子帶的比例因子static double smr[2][SBLIMIT], lgmin[2][SBLIMIT], max_sc[2][SBLIMIT];// FLOAT snr32[32];short sam[2][1344]; /* was [1056]; */int model, nch, error_protection;//nch:聲道數,error_protection:錯誤保護措施static unsigned int crc;int sb, ch, adb;//abd:比特預算unsigned long frameBits, sentBits = 0;unsigned long num_samples;int lg_frame;int i;/* Used to keep the SNR values for the fast/quick psy models */static FLOAT smrdef[2][32];static int psycount = 0;extern int minimum;time_t start_time, end_time;int total_time;sb_sample = (SBS *) mem_alloc (sizeof (SBS), "sb_sample");j_sample = (JSBS *) mem_alloc (sizeof (JSBS), "j_sample");win_que = (IN *) mem_alloc (sizeof (IN), "Win_que");subband = (SUB *) mem_alloc (sizeof (SUB), "subband");win_buf = (short **) mem_alloc (sizeof (short *) * 2, "win_buf");/* clear buffers */memset ((char *) buffer, 0, sizeof (buffer));memset ((char *) bit_alloc, 0, sizeof (bit_alloc));memset ((char *) scalar, 0, sizeof (scalar));memset ((char *) j_scale, 0, sizeof (j_scale));memset ((char *) scfsi, 0, sizeof (scfsi));memset ((char *) smr, 0, sizeof (smr));memset ((char *) lgmin, 0, sizeof (lgmin));memset ((char *) max_sc, 0, sizeof (max_sc));//memset ((char *) snr32, 0, sizeof (snr32));memset ((char *) sam, 0, sizeof (sam));global_init ();header.extension = 0;frame.header = &header;frame.tab_num = -1; /* no table loaded */frame.alloc = NULL;header.version = MPEG_AUDIO_ID; /* Default: MPEG-1 */total_time = 0;time(&start_time); programName = argv[0];//exe文件名稱if (argc == 1) /* no command-line args */short_usage ();elseparse_args (argc, argv, &frame, &model, &num_samples, original_file_name,//命令行參數encoded_file_name);print_config (&frame, &model, original_file_name, encoded_file_name);//輸出文件參數/* this will load the alloc tables and do some other stuff */hdr_to_frps (&frame);nch = frame.nch;error_protection = header.error_protection;while (get_audio (musicin, buffer, num_samples, nch, &header) > 0) {//獲取音頻if (glopts.verbosity > 1)if (++frameNum % 10 == 0)fprintf (stderr, "[%4u]\r", frameNum);fflush (stderr);win_buf[0] = &buffer[0][0];win_buf[1] = &buffer[1][0];adb = available_bits (&header, &glopts);//計算比特預算lg_frame = adb / 8;if (header.dab_extension) {/* in 24 kHz we always have 4 bytes */if (header.sampling_frequency == 1)header.dab_extension = 4; /* You must have one frame in memory if you are in DAB mode */ /* in conformity of the norme ETS 300 401 http://www.etsi.org *//* see bitstream.c */if (frameNum == 1)minimum = lg_frame + MINIMUM;adb -= header.dab_extension * 8 + header.dab_length * 8 + 16;}{int gr, bl, ch;/* New polyphase filterCombines windowing and filtering. Ricardo Feb'03 */for( gr = 0; gr < 3; gr++ )//將36個值分成3組for ( bl = 0; bl < 12; bl++ )//每組做12此子代分解for ( ch = 0; ch < nch; ch++ )WindowFilterSubband( &buffer[ch][gr * 12 * 32 + 32 * bl], ch,&(*sb_sample)[ch][gr][bl][0] );//多相濾波器組}#ifdef REFERENCECODE{/* Old code. left here for reference */int gr, bl, ch;for (gr = 0; gr < 3; gr++)for (bl = 0; bl < SCALE_BLOCK; bl++)for (ch = 0; ch < nch; ch++) {window_subband (&win_buf[ch], &(*win_que)[ch][0], ch);filter_subband (&(*win_que)[ch][0], &(*sb_sample)[ch][gr][bl][0]);}} #endif#ifdef NEWENCODEscalefactor_calc_new(*sb_sample, scalar, nch, frame.sblimit);find_sf_max (scalar, &frame, max_sc);if (frame.actual_mode == MPG_MD_JOINT_STEREO) {/* this way we calculate more mono than we need *//* but it is cheap */combine_LR_new (*sb_sample, *j_sample, frame.sblimit);scalefactor_calc_new (j_sample, &j_scale, 1, frame.sblimit);} #elsescale_factor_calc (*sb_sample, scalar, nch, frame.sblimit);//計算比例因子pick_scale (scalar, &frame, max_sc);//選擇比例因子if (frame.actual_mode == MPG_MD_JOINT_STEREO) {/* this way we calculate more mono than we need *//* but it is cheap */combine_LR (*sb_sample, *j_sample, frame.sblimit);scale_factor_calc (j_sample, &j_scale, 1, frame.sblimit);} #endif//選擇心理聲學模型,計算SMRif ((glopts.quickmode == TRUE) && (++psycount % glopts.quickcount != 0)) {/* We're using quick mode, so we're only calculating the model every'quickcount' frames. Otherwise, just copy the old ones across */for (ch = 0; ch < nch; ch++) {for (sb = 0; sb < SBLIMIT; sb++)smr[ch][sb] = smrdef[ch][sb];}} else {/* calculate the psymodel */switch (model) {case -1:psycho_n1 (smr, nch);break;case 0: /* Psy Model A */psycho_0 (smr, nch, scalar, (FLOAT) s_freq[header.version][header.sampling_frequency] * 1000); break;case 1:psycho_1 (buffer, max_sc, smr, &frame);break;case 2:for (ch = 0; ch < nch; ch++) {psycho_2 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);}break;case 3:/* Modified psy model 1 */psycho_3 (buffer, max_sc, smr, &frame, &glopts);break;case 4:/* Modified Psycho Model 2 */for (ch = 0; ch < nch; ch++) {psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);}break; case 5:/* Model 5 comparse model 1 and 3 */psycho_1 (buffer, max_sc, smr, &frame);fprintf(stdout,"1 ");smr_dump(smr,nch);psycho_3 (buffer, max_sc, smr, &frame, &glopts);fprintf(stdout,"3 ");smr_dump(smr,nch);break;case 6:/* Model 6 compares model 2 and 4 */for (ch = 0; ch < nch; ch++) psycho_2 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);fprintf(stdout,"2 ");smr_dump(smr,nch);for (ch = 0; ch < nch; ch++) psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);fprintf(stdout,"4 ");smr_dump(smr,nch);break;case 7:fprintf(stdout,"Frame: %i\n",frameNum);/* Dump the SMRs for all models */ psycho_1 (buffer, max_sc, smr, &frame);fprintf(stdout,"1");smr_dump(smr, nch);psycho_3 (buffer, max_sc, smr, &frame, &glopts);fprintf(stdout,"3");smr_dump(smr,nch);for (ch = 0; ch < nch; ch++) psycho_2 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], //snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);fprintf(stdout,"2");smr_dump(smr,nch);for (ch = 0; ch < nch; ch++) psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);fprintf(stdout,"4");smr_dump(smr,nch);break;case 8:/* Compare 0 and 4 */ psycho_n1 (smr, nch);fprintf(stdout,"0");smr_dump(smr,nch);for (ch = 0; ch < nch; ch++) psycho_4 (&buffer[ch][0], &sam[ch][0], ch, &smr[ch][0], // snr32,(FLOAT) s_freq[header.version][header.sampling_frequency] *1000, &glopts);fprintf(stdout,"4");smr_dump(smr,nch);break;default:fprintf (stderr, "Invalid psy model specification: %i\n", model);exit (0);}if (glopts.quickmode == TRUE)/* copy the smr values and reuse them later */for (ch = 0; ch < nch; ch++) {for (sb = 0; sb < SBLIMIT; sb++)smrdef[ch][sb] = smr[ch][sb];}if (glopts.verbosity > 4) smr_dump(smr, nch);}#ifdef NEWENCODEsf_transmission_pattern (scalar, scfsi, &frame);main_bit_allocation_new (smr, scfsi, bit_alloc, &adb, &frame, &glopts);//main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);if (error_protection)CRC_calc (&frame, bit_alloc, scfsi, &crc);write_header (&frame, &bs);//encode_info (&frame, &bs);if (error_protection)putbits (&bs, crc, 16);write_bit_alloc (bit_alloc, &frame, &bs);//encode_bit_alloc (bit_alloc, &frame, &bs);write_scalefactors(bit_alloc, scfsi, scalar, &frame, &bs);//encode_scale (bit_alloc, scfsi, scalar, &frame, &bs);subband_quantization_new (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,*subband, &frame);//subband_quantization (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,// *subband, &frame);write_samples_new(*subband, bit_alloc, &frame, &bs);//sample_encoding (*subband, bit_alloc, &frame, &bs); #elsetransmission_pattern (scalar, scfsi, &frame);main_bit_allocation (smr, scfsi, bit_alloc, &adb, &frame, &glopts);//比特分配if (error_protection)CRC_calc (&frame, bit_alloc, scfsi, &crc);encode_info (&frame, &bs);//編碼if (error_protection)encode_CRC (crc, &bs);encode_bit_alloc (bit_alloc, &frame, &bs);encode_scale (bit_alloc, scfsi, scalar, &frame, &bs);subband_quantization (scalar, *sb_sample, j_scale, *j_sample, bit_alloc,//量化*subband, &frame);sample_encoding (*subband, bit_alloc, &frame, &bs); #endif/* If not all the bits were used, write out a stack of zeros */for (i = 0; i < adb; i++)put1bit (&bs, 0);if (header.dab_extension) {/* Reserve some bytes for X-PAD in DAB mode */putbits (&bs, 0, header.dab_length * 8);for (i = header.dab_extension - 1; i >= 0; i--) {CRC_calcDAB (&frame, bit_alloc, scfsi, scalar, &crc, i);/* this crc is for the previous frame in DAB mode */if (bs.buf_byte_idx + lg_frame < bs.buf_size)bs.buf[bs.buf_byte_idx + lg_frame] = crc;/* reserved 2 bytes for F-PAD in DAB mode */putbits (&bs, crc, 8);}putbits (&bs, 0, 16);}frameBits = sstell (&bs) - sentBits;if (frameBits % 8) { /* a program failure */fprintf (stderr, "Sent %ld bits = %ld slots plus %ld\n", frameBits,frameBits / 8, frameBits % 8);fprintf (stderr, "If you are reading this, the program is broken\n");fprintf (stderr, "email [mfc at NOTplanckenerg.com] without the NOT\n");fprintf (stderr, "with the command line arguments and other info\n");exit (0);}sentBits += frameBits;}close_bit_stream_w (&bs);if ((glopts.verbosity > 1) && (glopts.vbr == TRUE)) {int i; #ifdef NEWENCODEextern int vbrstats_new[15]; #elseextern int vbrstats[15]; #endiffprintf (stdout, "VBR stats:\n");for (i = 1; i < 15; i++)fprintf (stdout, "%4i ", bitrate[header.version][i]);fprintf (stdout, "\n");for (i = 1; i < 15; i++) #ifdef NEWENCODEfprintf (stdout,"%4i ",vbrstats_new[i]); #elsefprintf (stdout, "%4i ", vbrstats[i]); #endiffprintf (stdout, "\n");}fprintf (stderr,"Avg slots/frame = %.3f; b/smp = %.2f; bitrate = %.3f kbps\n",(FLOAT) sentBits / (frameNum * 8),(FLOAT) sentBits / (frameNum * 1152),(FLOAT) sentBits / (frameNum * 1152) *s_freq[header.version][header.sampling_frequency]);if (fclose (musicin) != 0) {fprintf (stderr, "Could not close \"%s\".\n", original_file_name);exit (2);}fprintf (stderr, "\nDone\n");time(&end_time);total_time = end_time - start_time;printf("total time is %d\n", total_time);exit (0); }2、基本功能
在命令行輸入-h便能輸出其基本功能
可得到如下圖結果
3、基本命令行參數——轉換格式為.mp2
最基本的命令行參數如下:
命令函參數 輸入文件名 輸出文件名輸入如下圖
此時使用默認的輸出比特率(192 kbps)。
運行程序便會得到下圖所示結果和一個為.mp2的文件
4、輸出某一數據幀的信息——采樣率和目標碼率
在print_config函數中我們可以看到已經輸出采樣頻率和文件碼率,如下面代碼中標注位置
void print_config (frame_info * frame, int *psy, char *inPath,char *outPath) {frame_header *header = frame->header;if (glopts.verbosity == 0)return;fprintf (stderr, "--------------------------------------------\n");fprintf (stderr, "Input File : '%s' %.1f kHz\n",(strcmp (inPath, "-") ? inPath : "stdin"),s_freq[header->version][header->sampling_frequency]);//采樣頻率fprintf (stderr, "Output File: '%s'\n",(strcmp (outPath, "-") ? outPath : "stdout"));fprintf (stderr, "%d kbps ", bitrate[header->version][header->bitrate_index]);//碼率fprintf (stderr, "%s ", version_names[header->version]);if (header->mode != MPG_MD_JOINT_STEREO)fprintf (stderr, "Layer II %s Psycho model=%d (Mode_Extension=%d)\n",mode_names[header->mode], *psy, header->mode_ext);elsefprintf (stderr, "Layer II %s Psy model %d \n", mode_names[header->mode],*psy);fprintf (stderr, "[De-emph:%s\tCopyright:%s\tOriginal:%s\tCRC:%s]\n",((header->emphasis) ? "On" : "Off"),((header->copyright) ? "Yes" : "No"),((header->original) ? "Yes" : "No"),((header->error_protection) ? "On" : "Off"));fprintf (stderr, "[Padding:%s\tByte-swap:%s\tChanswap:%s\tDAB:%s]\n",((glopts.usepadbit) ? "Normal" : "Off"),((glopts.byteswap) ? "On" : "Off"),((glopts.channelswap) ? "On" : "Off"),((glopts.dab) ? "On" : "Off"));if (glopts.vbr == TRUE)fprintf (stderr, "VBR Enabled. Using MNR boost of %f\n", glopts.vbrlevel);fprintf(stderr,"ATH adjustment %f\n",glopts.athlevel);fprintf (stderr, "--------------------------------------------\n");}因此我們只需將需要觀測的內容輸出到TRACE文件,因此在文件開頭位置定義宏:#define FRAME_TRACE 1,這樣設為1時就打開數據幀的TRACE文件;定義文件指針FILE *file;
并在main函數中打開文件
然后在print_config()函數中輸出采樣頻率和碼率,參考代碼如下:
#if FRAME_TRACEfprintf(outfile, "采樣頻率和碼率:\n");fprintf(outfile, "輸入文件:%s\n", inPath);fprintf(outfile, "輸出文件:%s\n", outPath);fprintf(outfile, "采樣頻率:%.1f kHz\n", s_freq[header->version][header->sampling_frequency]);fprintf(outfile, "輸出文件碼率:%d kbps\n", bitrate[header->version][header->bitrate_index]); #endif結果如下:
5、輸出某一數據幀的信息——比例因子和比特分配表
在主函數中可以看到在逐幀獲取音頻中有比特預算以及計算比例因子與選擇比例因子的函數的調用,如下(最后即為比例因子):
while (get_audio (musicin, buffer, num_samples, nch, &header) > 0) {//獲取音頻if (glopts.verbosity > 1)if (++frameNum % 10 == 0)fprintf (stderr, "[%4u]\r", frameNum);fflush (stderr);win_buf[0] = &buffer[0][0];win_buf[1] = &buffer[1][0];adb = available_bits (&header, &glopts);//計算比特預算lg_frame = adb / 8;if (header.dab_extension) {/* in 24 kHz we always have 4 bytes */if (header.sampling_frequency == 1)header.dab_extension = 4; /* You must have one frame in memory if you are in DAB mode */ /* in conformity of the norme ETS 300 401 http://www.etsi.org *//* see bitstream.c */if (frameNum == 1)minimum = lg_frame + MINIMUM;adb -= header.dab_extension * 8 + header.dab_length * 8 + 16;}{int gr, bl, ch;/* New polyphase filter//Combines windowing and filtering. Ricardo Feb'03 */for( gr = 0; gr < 3; gr++ )//將36個值分成3組for ( bl = 0; bl < 12; bl++ )//每組做12此子代分解for ( ch = 0; ch < nch; ch++ )WindowFilterSubband( &buffer[ch][gr * 12 * 32 + 32 * bl], ch,&(*sb_sample)[ch][gr][bl][0] );//多相濾波器組}#ifdef REFERENCECODE{/* Old code. left here for reference */int gr, bl, ch;for (gr = 0; gr < 3; gr++)for (bl = 0; bl < SCALE_BLOCK; bl++)for (ch = 0; ch < nch; ch++) {window_subband (&win_buf[ch], &(*win_que)[ch][0], ch);filter_subband (&(*win_que)[ch][0], &(*sb_sample)[ch][gr][bl][0]);}} #endif#ifdef NEWENCODEscalefactor_calc_new(*sb_sample, scalar, nch, frame.sblimit);find_sf_max (scalar, &frame, max_sc);if (frame.actual_mode == MPG_MD_JOINT_STEREO) {/* this way we calculate more mono than we need *//* but it is cheap */combine_LR_new (*sb_sample, *j_sample, frame.sblimit);scalefactor_calc_new (j_sample, &j_scale, 1, frame.sblimit);} #elsescale_factor_calc (*sb_sample, scalar, nch, frame.sblimit);//計算比例因子pick_scale (scalar, &frame, max_sc);//選擇比例因子因此只需將其中的比特預算、比例因子等輸出即可,須在后面添加代碼如下:
#if FRAME_TRACEif (frameNum == 2) {fprintf(outfile, "聲道數:%d\n", nch);fprintf(outfile, "目前觀測第 %d 幀\n", frameNum);fprintf(outfile, "\n");/* 比例因子 */fprintf(outfile, "比例因子:\n");for (ch = 0; ch < nch; ch++) // 每個聲道單獨輸出{fprintf(outfile, "聲道%2d\n", ch + 1);for (sb = 0; sb < frame.sblimit; sb++) // 每個子帶{fprintf(outfile, "子帶[%2d]:\t", sb + 1);for (int gr = 0; gr < 3; gr++) {fprintf(outfile, "%2d\t", scalar[ch][gr][sb]);}fprintf(outfile, "\n");}}fprintf(outfile, "\n");//比特分配表 fprintf(outfile, "比特分配表:\n"); //輸出比特分配結果for (ch = 0; ch < nch; ch++) {fprintf(outfile, "聲道%2d\n", ch + 1); //按聲道分配for (sb = 0; sb < frame.sblimit; sb++) {fprintf(outfile, "子帶[%2d]:\t%2d\n", sb + 1, bit_alloc[ch][sb]);}fprintf(outfile, "\n");}} #endif結果如下:
六、結果展示——(噪聲、音樂、混合)
1、噪聲:
2、音樂:
3、混合:
總結
以上是生活随笔為你收集整理的实验6_MPEG音频编码实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实验5_JPEG解码
- 下一篇: H.264实验