工作图片大全卡通图片:MP3详解-MP3代码的总体框架
来源:百度文库 编辑:偶看新闻 时间:2024/05/05 15:32:08
偶看新闻是一部内容开放、自由的互动网络百科全书
客观、专业、权威的知识性百科全书
来源:百度文库 编辑:偶看新闻 时间:2024/05/05 15:32:08
Mp3的解码总体上可分为9个过程:比特流分解,霍夫曼解码,逆量化处理,立体声处理,频谱重排列,抗锯齿处理,IMDCT变换,子带合成,pcm输出。
为了解上述9个过程的由来,简要描述mp3的压缩流程。声音是一个模拟信号,对声音进行采样,量化,编码将得到PCM数据。PCM又称为脉冲编码调制数据,是电脑可以播放的最原始的数据,也是MP3压缩的源。为了达到更大的数据压缩率,MPEG标准采用子带编码技术将PCM数据分成32个子带,每个子带都是独立编码的(参考《数字音频原理与应用》221页)。然后将数据变换到频域下分析,MPEG采用的是改进的离散余弦变换,也可以使用傅利叶变换(参考《数字音频原理与应用》225)。再下来为了重建立体声进行了频谱按特定规则的排列,随后立体声处理,处理后的数据按照协议定义进行量化。为了达到更大的压缩,再进行霍夫曼编码。最后将一些系数与主信息融合形成mp3文件。
解码是编码的反过程大概如下:
l 所谓比特流分解是指将mp3文件以二进制方式打开,然后根据其压缩格式的定义,依次从这个mp3文件中取出头信息,边信息,比例因子信息等。这些信息都是后面的解码过程中需要的。(这部分是代码理解中的难点)。
l 霍夫曼编码是一种无损压缩编码,属于熵编码。Mp3的解码可以通过公式实时进行数据的解码,但往往采用的是通过查表法实现解码(节省了CPU时间资源)。(这部分是mp3解码工作量中最大的一部分,也是代码理解中的难点)。
l 逆量化处理只是几个公式的操作,代码理解中不难
l 立体声处理:这部分的处理也只是对几个公式的操作,代码理解不难,但原理上理解有些难度(**参考:了解下面的部分可以较好地理解代码中的立体声处理函数Joint Stereo 是一种立体声编码技巧,主要分为 Intensity Stereo(IS)和 Mid/Side (M/S) stereo 两种。 IS 的是在比较低流量时使用,利用了人耳对于低频讯号指向性分辨能力的不足,将音讯资料中的低频分解出来合成单声道资料,剩余的高频资料则合成另一个单声道资料,并另外纪录高频资料的位置资讯,来重建立体声的效果。例如钢琴独奏的录音就可以利用这种方法在有限的资料流量中减少音场资讯却大幅增加音色资讯。Mid/Side (M/S) stereo 在左右声道资料相似度大时常被用到,纪录方式是将左右声道音讯合并 (L+R) 得到新的一轨,再将左右声道音讯相减 (L-R) 得到 另外一轨,然后再将这两轨资料用上面提到听觉心理学模型与滤波器处理。Mid/Side (M/S) stereo 与 IS 一样的是利用部分相位 (phase) 资讯的损失来换得较高的音色纪录资讯。一般的 MP3 是 Mid/Side stereo 和 Intensity Stereo 交替使用的)
l 频谱重排列,抗锯齿处理,IMDCT变换,子带合成:这4个过程都是对若干公式的操作代码易懂,至于为什么要用这些公式,估计需要对MPEG编码有个了解才行。
l PCM的输出是与c语言对文件的处理相关的。对文件的处理在比特流分解和霍夫曼解码中最先接触到。看到了上述的两个环节,这一部分难度为0。
综上,对代码的理解难点集中在前两个环节,一是比特流分解,二是霍夫曼解码。比特流的分解难点在于c语言编程知识的应用。通过这部分的学习可以进一步熟悉c语言的应用,和一些算法的精短描述(很简约但是有些不好懂)。霍夫曼解码部分的学习可以掌握霍夫曼的查表解码方法,很有学习价值的…… -_-
以下罗列一份最简单的MP3解码的主程序段代码,目的是对MP3解码主程序极其大致的结构有个直观的认识。
#include
#include
#include "common.h"
#include "decode.h"
void main(int argc, char**argv)
{
FILE *musicout;
Bit_stream_struc bs;
frame_params fr_ps;
III_side_info_t III_side_info;
III_scalefac_t III_scalefac;
unsigned int old_crc;
layer info;
int sync, clip;
int done = FALSE;
unsigned long frameNum=0;
unsigned long bitsPerSlot;
unsigned long sample_frames;
typedef short PCM[2][SSLIMIT][SBLIMIT];
PCM *pcm_sample;
pcm_sample = (PCM *) mem_alloc((long) sizeof(PCM), "PCM Samp");
if (argc==1) {
printf("Useage:decode file.mp3 output.pcm\n");
return;
}
fr_ps.header = &info;
if ((musicout = fopen(argv[2], "w+b")) == NULL) {
printf ("Could not create \"%s\".\n", argv[2]);
exit(1);
}
open_bit_stream_r(&bs, argv[1], BUFFER_SIZE);
sample_frames = 0;
while(!end_bs(&bs)) {
//尝试帧同步
sync = seek_sync(&bs, SYNC_WORD, SYNC_WORD_LENGTH);
if (!sync) {
done = TRUE;
printf("\nFrame cannot be located\n");
out_fifo(*pcm_sample, 3, &fr_ps, done, musicout, &sample_frames);
break;
}
//解码帧头
decode_info(&bs, &fr_ps);
//将fr_ps.header中的信息解读到fr_ps的相关域中
hdr_to_frps(&fr_ps);
//输出相关信息
if(frameNum == 0)
WriteHdr(&fr_ps);
printf("\r%05lu", frameNum++);
if (info.error_protection)
buffer_CRC(&bs, &old_crc);
switch (info.lay) {
case 3:
{
int nSlots, main_data_end, flush_main;
int bytes_to_discard, gr, ch, ss, sb;
static int frame_start = 0;
bitsPerSlot = 8;
//取Side信息
III_get_side_info(&bs, &III_side_info, &fr_ps);
nSlots = main_data_slots(fr_ps);
//读主数据(Audio Data)
for (; nSlots > 0; nSlots--) /* read main data. */
hputbuf((unsigned int) getbits(&bs,8), 8);
main_data_end = hsstell() / 8; /*of privious frame*/
if ( flush_main=(hsstell() % bitsPerSlot) ) {
hgetbits((int)(bitsPerSlot - flush_main));
main_data_end ++;
}
bytes_to_discard = frame_start - main_data_end - III_side_info.main_data_begin ;
if( main_data_end > 4096 ) { frame_start -= 4096;
rewindNbytes( 4096 );
}
frame_start += main_data_slots(fr_ps);
if (bytes_to_discard < 0) {
printf("Not enough main data to decode frame %d. Frame discarded.\n",
frameNum - 1); break;
}
for (; bytes_to_discard > 0; bytes_to_discard--) hgetbits(8);
clip = 0;
for (gr=0;gr<2;gr++) {
double lr[2][SBLIMIT][SSLIMIT],ro[2][SBLIMIT][SSLIMIT];
//主解码
for (ch=0; ch
long int is[SBLIMIT][SSLIMIT]; /*保存量化数据*/
int part2_start;
part2_start = hsstell();
//获取比例因子
III_get_scale_factors(&III_scalefac,&III_side_info, gr, ch, &fr_ps);
//Huffman解码
III_hufman_decode(is, &III_side_info, ch, gr, part2_start, &fr_ps);
//反量化采样
III_dequantize_sample(is, ro[ch], &III_scalefac, &(III_side_info.ch[ch].gr[gr]), ch, &fr_ps);
}
//立体声处理
III_stereo(ro, lr, &III_scalefac, &(III_side_info.ch[0].gr[gr]), &fr_ps);
for (ch=0; ch
double re[SBLIMIT][SSLIMIT];
double hybridIn[SBLIMIT][SSLIMIT];/* Hybrid filter input */
double hybridOut[SBLIMIT][SSLIMIT];/* Hybrid filter out */
double polyPhaseIn[SBLIMIT]; /* PolyPhase Input. */
III_reorder(lr[ch], re, &(III_side_info.ch[ch].gr[gr]), &fr_ps);
//抗锯齿处理
III_antialias(re, hybridIn, /* Antialias butterflies. */
&(III_side_info.ch[ch].gr[gr]), &fr_ps);
//IMDCT
for (sb=0; sb
III_hybrid(hybridIn[sb], hybridOut[sb], sb, ch, &(III_side_info.ch[ch].gr[gr]), &fr_ps);
}
for (ss=0;ss<18;ss++) //多相频率倒置
for (sb=0; sb
if ((ss%2) && (sb%2))
hybridOut[sb][ss] = -hybridOut[sb][ss];
for (ss=0;ss<18;ss++) { //多相合成
for (sb=0; sb
polyPhaseIn[sb] = hybridOut[sb][ss];
//子带合成
clip += SubBandSynthesis(polyPhaseIn, ch, &((*pcm_sample)[ch][ss][0]));
}
}
//PCM输出
/* Output PCM sample points for one granule(颗粒). */
out_fifo(*pcm_sample, 18, &fr_ps, done, musicout, &sample_frames);
}
if(clip > 0)
printf("\n%d samples clipped.\n", clip);
}
break;
default:
printf("\nOnly layer III supported!\n");
exit(1);
break;
}
}
close_bit_stream_r(&bs);
fclose(musicout);
printf("\nDecoding done.\n");
return;
}