斗龙战士2百诺被打屁股:MP3详解-程序中子函数代码详析(2)
来源:百度文库 编辑:中财网 时间:2024/05/04 08:52:44
3:函数read_decoder_table分析
int read_decoder_table(FILE *fi)
{
该函数的作用是将34个供解码的数值存入了变量ht[n].val中,以方便以后的解码调用
//HTN=34
int n,i,nn,t;
unsigned int v0,v1;
char command[100],line[100];
for (n=0;n
要进行34次循环因为有34个子表
/* .table number treelen xlen ylen linbits */
do {
fgets(line,99,fi);
从解码树表文件fi中读入98个字符然后在最后加“/0”组成字符窜存入树组line中,但是如果碰到回车则马上停止读入。
} while ((line[0] == '#') || (line[0] < ' '));
因为文件huffdec.txt中一行就有一个回车,所以往往取不到98个字符,就碰到了回车。
文件huffdec.txt中开始的部分是一些无用的说明部分是用#作为开头的,上面的这个循环就是为了去除无效行,直到取出一行有效行后进行下面的操作:
sscanf(line,"%s %s %u %u %u %u",command,ht[n].tablename,
&ht[n].treelen, &ht[n].xlen, &ht[n].ylen, &ht[n].linbits);
从一个字符串中读进与指定格式相符的数据存入相应的变量,即取出子表头信息,子表头信息包含表名,解码树长,x长,y长,和linbits这些参量。在这里的含义就是将.table 0 0 0 0 0中的.table存入command,0存入ht[n].tablename,...
if (strcmp(command,".end")==0)
判断两个字符串
return n;
如果command==.end说明已经循环完了34次,已经到了文件尾了,所以返回就可以了
else if (strcmp(command,".table")!=0) {
fprintf(stderr,"huffman table %u data corrupted\n",n);
return -1;
}
如果command!=.end&&!=.table报错
ht[n].linmax = (1<
计算出linmax参量(什么用处?)
do {
fgets(line,99,fi);
} while ((line[0] == '#') || (line[0] < ' '));
取出子表中第2行有效行
sscanf(line,"%s %u",command,&t);
取出该有效行中的有效参数
if (strcmp(command,".reference")==0) {
ht[n].ref = t;
ht[n].val = ht[t].val;
ht[n].treelen = ht[t].treelen;
if ( (ht[n].xlen != ht[t].xlen) ||
(ht[n].ylen != ht[t].ylen) ) {
fprintf(stderr,"wrong table %u reference\n",n);
return (-3);
};
while ((line[0] == '#') || (line[0] < ' ') ) {
fgets(line,99,fi);
}
}
文件中ht[n].ref的存在只是为了减小解码表的容量,但是增加了解码程序的代码长度
else if (strcmp(command,".treedata")==0) {
ht[n].ref = -1;
ht[n].val = (unsigned char (*)[2])
calloc(2*(ht[n].treelen),sizeof(unsigned char));
位变量val动态分配内存空间
if ((ht[n].val == NULL) && ( ht[n].treelen != 0 )){
fprintf(stderr, "heaperror at table %d\n",n);
exit (-10);
}
for (i=0;i
fscanf(fi,"%x %x",&v0, &v1);
ht[n].val[i][0]=(unsigned char)v0;
ht[n].val[i][1]=(unsigned char)v1;
}
将34个供解码的数值存入了变量ht[n].val中
fgets(line,99,fi); /* read the rest of the line */
}
else {
fprintf(stderr,"huffman decodertable error at table %d\n",n);
}
}
return n;
}
4:函数huffman_decoder分析
int huffman_decoder(struct huffcodetab *h, int *x, int *y, int *v, int *w)
{
参数说明这个函数需要一个指向相应霍夫曼表的结构体指针,根据霍夫曼解码表来查表解码,解码出来的数据先存到x,y,v,w上,然后在函数外,将值存入变量is中。本身这里的程序语句不难理解,前提是对霍夫曼查表法解码由足够的了解。往下的部分就不再作程序本身的介绍。只简单的了解数据的流程就可以了,这里数据是从全局buf中一个比特一个比特的取出,根据霍夫曼解码方法,通过对比表格,得到相应的解码后的数据。前面已经介绍了,为了方便霍夫曼解码,数据分了3个大区,其中大值区还分为3个小区。不同区里的比特选用的解码表不一样,解码出来的数据个数也是不一样的。具体实现方法还没有彻底弄通呢。
HUFFBITS level;
在前面的文件里面已经定义了#define HUFFBITS unsigned long int
还定义了HUFFBITS dmask = 1 << (sizeof(HUFFBITS)*8-1);
int point = 0;
int error = 1;
level = dmask;
if (h->val == NULL) return 2;
/* table 0 needs no bits */
if ( h->treelen == 0)
{ *x = *y = 0;
return 0;
}
/* Lookup in Huffman table. */
以下开始霍夫曼的查表法解码,即在解码表中查找对应的解码数据
do {
if (h->val[point][0]==0) { /*end of tree*/
*x = h->val[point][1] >> 4;
*y = h->val[point][1] & 0xf;
在数据组织形式上val是一对出现的val[point][0]表示val中第[point]对中的第一个数据
如果第point对val中的第一个数据是0的话,那么x,y根据上式确定
error = 0;
break;
}
if (hget1bit()) {
while (h->val[point][1] >= MXOFF) point += h->val[point][1];
point += h->val[point][1];
}
else {
while (h->val[point][0] >= MXOFF) point += h->val[point][0];
point += h->val[point][0];
}
level >>= 1;
} while (level || (point < ht->treelen) );
/* Check for error. */
if (error) { /* set x and y to a medium value as a simple concealment */
printf("Illegal Huffman code in data.\n");
*x = (h->xlen-1 << 1);
*y = (h->ylen-1 << 1);
}
/* Process sign encodings for quadruples tables. */
if (h->tablename[0] == '3'
&& (h->tablename[1] == '2' || h->tablename[1] == '3')) {
*v = (*y>>3) & 1;
*w = (*y>>2) & 1;
*x = (*y>>1) & 1;
*y = *y & 1;
/* v, w, x and y are reversed in the bitstream.
switch them around to make test bistream work. */
/* {int i=*v; *v=*y; *y=i; i=*w; *w=*x; *x=i;} MI */
if (*v)
if (hget1bit() == 1) *v = -*v;
if (*w)
if (hget1bit() == 1) *w = -*w;
if (*x)
if (hget1bit() == 1) *x = -*x;
if (*y)
if (hget1bit() == 1) *y = -*y;
}
/* Process sign and escape encodings for dual tables. */
else {
/* x and y are reversed in the test bitstream.
Reverse x and y here to make test bitstream work. */
/* removed 11/11/92 -ag
{int i=*x; *x=*y; *y=i;}
*/
if (h->linbits)
if ((h->xlen-1) == *x)
*x += hgetbits(h->linbits);
if (*x)
if (hget1bit() == 1) *x = -*x;
if (h->linbits)
if ((h->ylen-1) == *y)
*y += hgetbits(h->linbits);
if (*y)
if (hget1bit() == 1) *y = -*y;
}
return error;
}
三 反量化函数分析
void III_dequantize_sample(long int is[SBLIMIT][SSLIMIT], double xr[SBLIMIT][SSLIMIT], III_scalefac_t *scalefac, struct gr_info_s *gr_info, int ch, frame_params *fr_ps)
{
参数说明:is是该函数的解码对象,解码后存入xr,需要比例因子结构体,边信息结构体,以及帧信息
int ss,sb,cb=0,sfreq=fr_ps->header->sampling_frequency;
int stereo = fr_ps->stereo;
int next_cb_boundary, cb_begin, cb_width, sign;
/* choose correct scalefactor band per block type, initalize boundary */
反量化也是以颗粒为单位进行的,霍夫曼解码后的数据还是以颗粒为组织形式
if (gr_info->window_switching_flag && (gr_info->block_type == 2) )
if (gr_info->mixed_block_flag)
如果该颗粒是短块并且是混合型的短块则next_cb_boundary有下面的公式确定
next_cb_boundary=sfBandIndex[sfreq].l[1]; /* LONG blocks: 0,1,3 */
else {
如果是非混合型的短块那么需要的一些解码系数确定如下:
next_cb_boundary=sfBandIndex[sfreq].s[1]*3; /* pure SHORT block */
cb_width = sfBandIndex[sfreq].s[1];
cb_begin = 0;
}
else
如果是长块,那么系数确定如下
next_cb_boundary=sfBandIndex[sfreq].l[1]; /* LONG blocks: 0,1,3 */
系数确定后则可以进行解码操作:反量化操作就是一个公式计算过程:
以下便是对SBLIMIT*SSLIMIT即32*18=576个数据的依次反量化计算;
遵循的公式是xr[sb][ss] = pow( 2.0 , (0.25 * (gr_info->global_gain - 210.0)));
/* apply formula per block type */
for (sb=0 ; sb < SBLIMIT ; sb++) {
for (ss=0 ; ss < SSLIMIT ; ss++) {
if ( (sb*18)+ss == next_cb_boundary)
当要解码的数据位置正好落在边界的时候要作适当的调整
???这个所谓的边界是什么的边界???
{ /* Adjust critical band boundary */
if (gr_info->window_switching_flag && (gr_info->block_type == 2)) {
if (gr_info->mixed_block_flag) {
if (((sb*18)+ss) == sfBandIndex[sfreq].l[8]) {
如果这个颗粒是混合型的短块并且数据的位置还与sfBandIndex[sfreq].l[8])相同
那么要对next_cb_boundary等系数重新调整
next_cb_boundary=sfBandIndex[sfreq].s[4]*3;
cb = 3;
cb_width = sfBandIndex[sfreq].s[cb+1] -
sfBandIndex[sfreq].s[cb];
cb_begin = sfBandIndex[sfreq].s[cb]*3;
}
else if (((sb*18)+ss) < sfBandIndex[sfreq].l[8])
如果这个颗粒是混合型的短块并且数据的位置还小于sfBandIndex[sfreq].l[8])
那么要对next_cb_boundary等系数重新另一种调整如下
next_cb_boundary = sfBandIndex[sfreq].l[(++cb)+1];
else {
如果这个颗粒是混合型的短块并且数据的位置还大于sfBandIndex[sfreq].l[8])
那么要对next_cb_boundary等系数重新第三种调整如下
next_cb_boundary = sfBandIndex[sfreq].s[(++cb)+1]*3;
cb_width = sfBandIndex[sfreq].s[cb+1] -
sfBandIndex[sfreq].s[cb];
cb_begin = sfBandIndex[sfreq].s[cb]*3;
}
}
else {
如果是非混合型的短块,进行这样的调整:
next_cb_boundary = sfBandIndex[sfreq].s[(++cb)+1]*3;
cb_width = sfBandIndex[sfreq].s[cb+1] -
sfBandIndex[sfreq].s[cb];
cb_begin = sfBandIndex[sfreq].s[cb]*3;
}
}
else /* long blocks */
长块的话进行如下的调整:
??调整的意义是什么???
next_cb_boundary = sfBandIndex[sfreq].l[(++cb)+1];
}
/* Compute overall (global) scaling. */
xr[sb][ss] = pow( 2.0 , (0.25 * (gr_info->global_gain - 210.0)));
/* Do long/short dependent scaling operations. */
if (gr_info->window_switching_flag && (
((gr_info->block_type == 2) && (gr_info->mixed_block_flag == 0)) ||
((gr_info->block_type == 2) && gr_info->mixed_block_flag && (sb >= 2)) )) {
如果是一个非混合型的短块,或者是混合型的短块且(sb >= 2)
xr[sb][ss] *= pow(2.0, 0.25 * -8.0 *
gr_info->subblock_gain[(((sb*18)+ss) - cb_begin)/cb_width]);
xr[sb][ss] *= pow(2.0, 0.25 * -2.0 * (1.0+gr_info->scalefac_scale)
* (*scalefac)[ch].s[(((sb*18)+ss) - cb_begin)/cb_width][cb]);
}
else { /* LONG block types 0,1,3 & 1st 2 subbands of switched blocks */
xr[sb][ss] *= pow(2.0, -0.5 * (1.0+gr_info->scalefac_scale)
* ((*scalefac)[ch].l[cb]
+ gr_info->preflag * pretab[cb]));
}
/* Scale quantized value. */
sign = (is[sb][ss]<0) ? 1 : 0;
xr[sb][ss] *= pow( (double) abs(is[sb][ss]), ((double)4.0/3.0) );
if (sign) xr[sb][ss] = -xr[sb][ss];
}
}
}
四 立体声处理函数分析
void III_stereo(double xr[2][SBLIMIT][SSLIMIT], double lr[2][SBLIMIT][SSLIMIT], III_scalefac_t *scalefac, struct gr_info_s *gr_info, frame_params *fr_ps)
{ 参数说明:操作对象是反量化后的存在xr的数据,结果存放在lr,需要比例因子结构体,颗粒信息结构体,帧结构体
int sfreq = fr_ps->header->sampling_frequency;
int stereo = fr_ps->stereo;
int ms_stereo = (fr_ps->header->mode == MPG_MD_JOINT_STEREO) &&
(fr_ps->header->mode_ext & 0x2);
int i_stereo = (fr_ps->header->mode == MPG_MD_JOINT_STEREO) &&
(fr_ps->header->mode_ext & 0x1);
int sfb;
int i,j,sb,ss,ch,is_pos[576];
double is_ratio[576];
/* intialization */
立体声处理前的初始化工作:让is_pos[i]=0111B
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 交替使用的
is_pos[i] = 7;
if ((stereo == 2) && i_stereo )
这里主要要操作的是改变is_pos[i]如果is_pos[i]始终是初始化时的值7,那么立体声处理的时候
将没有办法进行模式i_stereo的解码。因为i_stereo的解码要将音讯资料中的低频分解出
来合成单声道资料,剩余的高频资料则合成另一个单声道资料,所以得弄清什么时候数据是
低频的,什么时候是高频的以下的代码完成的就是这一识别工作is_ratio[i]从而产生需要的系数
{ if (gr_info->window_switching_flag && (gr_info->block_type == 2))
{ if( gr_info->mixed_block_flag )
如果该帧是立体声的,并且是属于i_stereo模式的立体声并且该颗粒是混合型的短块
那么参数max_sfb先得到确定为0
{ int max_sfb = 0;
for ( j=0; j<3; j++ )
{ int sfbcnt;
sfbcnt = 2;
sfbcnt的作用是什么?
for( sfb=12; sfb >=3; sfb-- )
{下面的操作进行30次
int lines;
可能表征频带宽度
lines = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
注意:这样一减最小的结果也是4
i = 3*sfBandIndex[sfreq].s[sfb] + (j+1) * lines - 1;
这样计算i最小的结果也是3
while ( lines > 0 )
{ if ( xr[1][i/SSLIMIT][i%SSLIMIT] != 0.0 )
如果反量化的结果不是0,是0的话就不用进行立体声处理了
选择参数sfb=-10,lines=-10
{ sfbcnt = sfb;
sfb = -10;
lines = -10;
}
lines--;
i--;
}
}
sfb = sfbcnt + 1;
if ( sfb > max_sfb )
max_sfb = sfb;
while( sfb<12 )
{ sb = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
i = 3*sfBandIndex[sfreq].s[sfb] + j * sb;
for ( ; sb > 0; sb--)
{ is_pos[i] = (*scalefac)[1].s[j][sfb];
if ( is_pos[i] != 7 )
is_ratio[i] = tan( is_pos[i] * (PI / 12));
i++;
}
sfb++;
}
sb = sfBandIndex[sfreq].s[11]-sfBandIndex[sfreq].s[10];
sfb = 3*sfBandIndex[sfreq].s[10] + j * sb;
sb = sfBandIndex[sfreq].s[12]-sfBandIndex[sfreq].s[11];
i = 3*sfBandIndex[sfreq].s[11] + j * sb;
for ( ; sb > 0; sb-- )
{ is_pos[i] = is_pos[sfb];
is_ratio[i] = is_ratio[sfb];
i++;
}
}
if ( max_sfb <= 3 )
{ i = 2;
ss = 17;
sb = -1;
while ( i >= 0 )
{ if ( xr[1][i][ss] != 0.0 )
{ sb = i*18+ss;
i = -1;
} else
{ ss--;
if ( ss < 0 )
{ i--;
ss = 17;
}
}
}
i = 0;
while ( sfBandIndex[sfreq].l[i] <= sb )
i++;
sfb = i;
i = sfBandIndex[sfreq].l[i];
for ( ; sfb<8; sfb++ )
{ sb = sfBandIndex[sfreq].l[sfb+1]-sfBandIndex[sfreq].l[sfb];
for ( ; sb > 0; sb--)
{ is_pos[i] = (*scalefac)[1].l[sfb];
if ( is_pos[i] != 7 )
is_ratio[i] = tan( is_pos[i] * (PI / 12));
i++;
}
}
}
} else
如果该帧是立体声的,并且是属于i_stereo模式的立体声并且该颗粒是非混合型的短块
{ for ( j=0; j<3; j++ )
{ int sfbcnt;
sfbcnt = -1;
for( sfb=12; sfb >=0; sfb-- )
{ int lines;
lines = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
i = 3*sfBandIndex[sfreq].s[sfb] + (j+1) * lines - 1;
while ( lines > 0 )
{ if ( xr[1][i/SSLIMIT][i%SSLIMIT] != 0.0 )
{ sfbcnt = sfb;
sfb = -10;
lines = -10;
}
lines--;
i--;
}
}
sfb = sfbcnt + 1;
while( sfb<12 )
{ sb = sfBandIndex[sfreq].s[sfb+1]-sfBandIndex[sfreq].s[sfb];
i = 3*sfBandIndex[sfreq].s[sfb] + j * sb;
for ( ; sb > 0; sb--)
{ is_pos[i] = (*scalefac)[1].s[j][sfb];
if ( is_pos[i] != 7 )
is_ratio[i] = tan( is_pos[i] * (PI / 12));
i++;
}
sfb++;
}
sb = sfBandIndex[sfreq].s[11]-sfBandIndex[sfreq].s[10];
sfb = 3*sfBandIndex[sfreq].s[10] + j * sb;
sb = sfBandIndex[sfreq].s[12]-sfBandIndex[sfreq].s[11];
i = 3*sfBandIndex[sfreq].s[11] + j * sb;
for ( ; sb > 0; sb-- )
{ is_pos[i] = is_pos[sfb];
is_ratio[i] = is_ratio[sfb];
i++;
}
}
}
} else
{ i = 31;
ss = 17;
sb = 0;
while ( i >= 0 )
{ if ( xr[1][i][ss] != 0.0 )
{ sb = i*18+ss;
i = -1;
} else
{ ss--;
if ( ss < 0 )
{ i--;
ss = 17;
}
}
}
i = 0;
while ( sfBandIndex[sfreq].l[i] <= sb )
i++;
sfb = i;
i = sfBandIndex[sfreq].l[i];
for ( ; sfb<21; sfb++ )
{ sb = sfBandIndex[sfreq].l[sfb+1] - sfBandIndex[sfreq].l[sfb];
for ( ; sb > 0; sb--)
{ is_pos[i] = (*scalefac)[1].l[sfb];
if ( is_pos[i] != 7 )
is_ratio[i] = tan( is_pos[i] * (PI / 12));
i++;
}
}
sfb = sfBandIndex[sfreq].l[20];
for ( sb = 576 - sfBandIndex[sfreq].l[21]; sb > 0; sb-- )
{ is_pos[i] = is_pos[sfb];
is_ratio[i] = is_ratio[sfb];
i++;
}
}
}
for(ch=0;ch<2;ch++)
for(sb=0;sb
for(ss=0;ss
lr[ch][sb][ss] = 0;
if (stereo==2)
for(sb=0;sb
for(ss=0;ss
i = (sb*18)+ss;
if ( is_pos[i] == 7 ) {
if ( ms_stereo ) {
lr[0][sb][ss] = (xr[0][sb][ss]+xr[1][sb][ss])/1.41421356;
lr[1][sb][ss] = (xr[0][sb][ss]-xr[1][sb][ss])/1.41421356;
}
else {
lr[0][sb][ss] = xr[0][sb][ss];
lr[1][sb][ss] = xr[1][sb][ss];
}
}
else if (i_stereo ) {
lr[0][sb][ss] = xr[0][sb][ss] * (is_ratio[i]/(1+is_ratio[i]));
lr[1][sb][ss] = xr[0][sb][ss] * (1/(1+is_ratio[i]));
}
else {
printf("Error in streo processing\n");
}
}
else /* mono , bypass xr[0][][] to lr[0][][]*/
for(sb=0;sb
for(ss=0;ss
lr[0][sb][ss] = xr[0][sb][ss];
}
五 数据重排列函数分析
void III_reorder(double xr[SBLIMIT][SSLIMIT], double ro[SBLIMIT][SSLIMIT], struct gr_info_s *gr_info, frame_params *fr_ps)
{ 排列前的数据位置xr,排列后要存放的位置ro,需要颗粒结构体,和帧结构体
int sfreq=fr_ps->header->sampling_frequency;
int sfb, sfb_start, sfb_lines;
int sb, ss, window, freq, src_line, des_line;
for(sb=0;sb
for(ss=0;ss
ro[sb][ss] = 0;
if (gr_info->window_switching_flag && (gr_info->block_type == 2)) {
if (gr_info->mixed_block_flag) {
/* NO REORDER FOR LOW 2 SUBBANDS */
for (sb=0 ; sb < 2 ; sb++)
for (ss=0 ; ss < SSLIMIT ; ss++) {
ro[sb][ss] = xr[sb][ss];
}
在最下面的两个子带中数据的排列不需要变化
其它的子带要根据协议内容来变化
/* REORDERING FOR REST SWITCHED SHORT */
for(sfb=3,sfb_start=sfBandIndex[sfreq].s[3],
sfb_lines=sfBandIndex[sfreq].s[4] - sfb_start;
sfb < 13; sfb++,sfb_start=sfBandIndex[sfreq].s[sfb],
(sfb_lines=sfBandIndex[sfreq].s[sfb+1] - sfb_start))
for(window=0; window<3; window++)
for(freq=0;freq
src_line = sfb_start*3 + window*sfb_lines + freq;
des_line = (sfb_start*3) + window + (freq*3);
ro[des_line/SSLIMIT][des_line%SSLIMIT] =
xr[src_line/SSLIMIT][src_line%SSLIMIT];
}
}
else { /* pure short */
for(sfb=0,sfb_start=0,sfb_lines=sfBandIndex[sfreq].s[1];
sfb < 13; sfb++,sfb_start=sfBandIndex[sfreq].s[sfb],
(sfb_lines=sfBandIndex[sfreq].s[sfb+1] - sfb_start))
for(window=0; window<3; window++)
for(freq=0;freq
src_line = sfb_start*3 + window*sfb_lines + freq;
des_line = (sfb_start*3) + window + (freq*3);
ro[des_line/SSLIMIT][des_line%SSLIMIT] =
xr[src_line/SSLIMIT][src_line%SSLIMIT];
}
}
}
else { /*long blocks */
for (sb=0 ; sb < SBLIMIT ; sb++)
for (ss=0 ; ss < SSLIMIT ; ss++)
ro[sb][ss] = xr[sb][ss];
}}