对技术执着
分类:
2015-03-14 17:08:27
原文地址:MP3解码算法分析(5)——MP3帧头处理 作者:gliethttp
:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://kware.blogbus.com/logs/30741724.html
1. 读 32bit 的帧头,头处理的主处理流程
Header.read_header(Bitstream, Crc16[] crcp) [javazoom.jl.decoder]
int headerstring; // 帧头的32位对应的32位整数
int channel_bitrate; // 比特率
boolean sync = false; // 同步判断
do {
headerstring = stream.syncHeader(syncmode);// 同步并获取帧头的32位整数
_headerstring = headerstring;
if (syncmode==Bitstream.INITIAL_SYNC) { // 如果是初始化同步
h_version = ((headerstring >>> 19) & 1); // 求取第 19 位的版本号
if (((headerstring >>> 20) & 1) == 0) // 第 20 位为: MPEG2.5 detection
if (h_version == MPEG2_LSF)
h_version = MPEG25_LSF;
else
throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
// 第 10-11 位为采样率
if ((h_sample_frequency = ((headerstring >>> 10) & 3)) == 3)
throw stream.newBitstreamException(Bitstream.UNKNOWN_ERROR);
}
h_layer = 4 - (headerstring >>> 17) & 3; // 第 17-18 位为层号 Layer I/II/III
h_protection_bit = (headerstring >>> 16) & 1; // 第 16 位为保护位 Protect
h_bitrate_index = (headerstring >>> 12) & 0xF; // 第 12-15 位为比特率
h_padding_bit = (headerstring >>> 9) & 1; // 第 9 位为补齐位
h_mode = ((headerstring >>> 6) & 3); // 第 6-7 位为模式位
h_mode_extension = (headerstring >>> 4) & 3; // 第 4-5 位为模式扩展位
if (h_mode==JOINT_STEREO) h_intensity_stereo_bound = (h_mode_extension << 2) + 4;
else h_intensity_stereo_bound = 0; // 用不到
if (((headerstring >>> 3) & 1)==1) h_copyright = true; // 第 3 位版权等信息
if (((headerstring >>> 2) & 1)==1) h_original = true; // 第 2 位为 Home 信息
if (h_layer==1) h_number_of_subbands = 32; // 计算子带数(subbands),Layer I 有 32 个子带
else {
channel_bitrate = h_bitrate_index; // 计算每个信道的比特率
if (h_mode != SINGLE_CHANNEL)
if (channel_bitrate == 4) channel_bitrate = 1;
else channel_bitrate -= 4;
if ((channel_bitrate == 1) || (channel_bitrate == 2))
if (h_sample_frequency == THIRTYTWO) h_number_of_subbands = 12;
else h_number_of_subbands = 8;
else
if ((h_sample_frequency == FOURTYEIGHT) || ((channel_bitrate >= 3)
&& (channel_bitrate <= 5)))
h_number_of_subbands = 27;
else
h_number_of_subbands = 30;
}
if (h_intensity_stereo_bound > h_number_of_subbands)
h_intensity_stereo_bound = h_number_of_subbands;
calculate_framesize(); // 计算帧尺寸和槽数(framesize/nSlots)
stream.read_frame_data(framesize); // 读取帧数据(framedata):
if(stream.isSyncCurrentPosition(syncmode)){// 当前位置同步
if (syncmode==Bitstream.INITIAL_SYNC) { // 如果是初始化同步
syncmode = Bitstream.STRICT_SYNC; // 设定为严格同步
stream.set_syncword(headerstring & 0xFFF80CC0); // 设定同步字,0xFFF80CC0 为同步字掩码
}
sync = true; // 目前同步
} else {
stream.unreadFrame(); // 当前不同步,把帧数据退回去缓冲区中
}
} while (!sync); // 如果未同步重读
stream.parse_frame(); // 分析帧
if (h_protection_bit == 0) { // 帧中包含 16 位的 crc 校验和
checksum = (short)stream.get_bits(16); // 取出 16 位的 crc 校验和到 checksum
if (crc == null)
crc = new Crc16();
crc.add_bits(headerstring, 16); // ?把头 16 位加入校验
crcp[0] = crc; // 把校验器返回 crcp[]
} else
crcp[0] = null; // 无校验
}
2. 帧尺寸计算,计算帧尺寸(单位为字节),抛掉头尺寸。
public int calculate_framesize() {
if (h_layer == 1) { // 层 Layer I,公式:fs = 12 * br / sf
framesize = (12 * bitrates[h_version][0][h_bitrate_index])
/ frequencies[h_version][h_sample_frequency];
if (h_padding_bit != 0 ) framesize++;
framesize <<= 2; // 每槽 4bytes
nSlots = 0;
} else { // 层 Layer II/III,公式:fs = 144 * br / sf
framesize = (144 * bitrates[h_version][h_layer - 1][h_bitrate_index])
/ frequencies[h_version][h_sample_frequency];
if (h_version == MPEG2_LSF || h_version == MPEG25_LSF)
framesize >>= 1; // 每槽 4bits
if (h_padding_bit != 0) // 对齐位
framesize++;
if (h_layer == 3) { // 层 Layer III 槽调整
if (h_version == MPEG1) { // MPEG1
nSlots = framesize
- ((h_mode==SINGLE_CHANNEL) ? 17:32) // 减去 边(side)信息尺寸
- ((h_protection_bit!=0) ? 0 : 2) // 减去 CRC 尺寸
- 4; // 减去 头尺寸
} else { // MPEG-2 LSF, MPEG-2.5 LSF
nSlots = framesize
- ((h_mode==SINGLE_CHANNEL) ? 9:17) // 减去 边(side)信息尺寸
- ((h_protection_bit!=0) ? 0 : 2) // 减去 CRC 尺寸
- 4; // 减去 头尺寸
}
} else { // 层 Layer II 槽为 0
nSlots = 0;
}
}
framesize -= 4; // 再扣去一遍头尺寸?
return framesize; // 返回
}
3. 帧头是否同步,即检查头32位整数的合法性
public boolean isSyncMark(int headerstring, int syncmode, int syncword) {
boolean sync = false; // 同步变量
if (syncmode==INITIAL_SYNC) { // 初始化同步
sync=((headerstring&0xFFE00000)==0xFFE00000); // MPEG 2.5
} else { // 否则要检查内部合法性
sync=((headerstring&0xFFF80C00)==syncword) // 同步字相同,且:
&&(((headerstring&0x000000C0)==0x000000C0)==single_ch_mode);
}
if (sync) // 过滤掉非法采样率
sync = (((headerstring >>> 10) & 3)!=3);
if (sync) // 过滤掉非法层
sync = (((headerstring >>> 17) & 3)!=0);
if (sync) // 过滤掉非法版本
sync = (((headerstring >>> 19) & 3)!=1);
return sync; // 返回是否同步
}
4. 帧数据分析,转化读入的字节为每4个转化为一个32位整数。问题:为什么要这样做?
void parse_frame() throws BitstreamException {
int b=0;
byte[] byteread = frame_bytes; // 予处理:帧字节缓冲
int bytesize = framesize; // 帧尺寸(单位字节)
for (int k=0; k
b0 = byteread[k];
if (k+1
| (b2 << 8) | b3; // 后读的 b2, b3 在低位
}
wordpointer = 0; // 后处理:字指针复位 0,范围:0 ~ 整数字个数-1
bitindex = 0; // 位指针复位 0,范围:0 ~ 31
}
5. 从缓冲区读入指定位数到一个无符号整数的低位部分 LSB(1~16)
public int get_bits(int number_of_bits) {
int returnvalue = 0;
int sum = bitindex + number_of_bits; // bitindex为当前字wordpointer下的当前位数指针
if (wordpointer < 0) wordpointer = 0; // 这儿有个问题,wordpointer 能是-1吗?!
if (sum <= 32) { // 所有位包含在当前字中*wordpointer,没跨32位字
returnvalue = (framebuffer[wordpointer] >>> (32 - sum))
& bitmask[number_of_bits]; // bitmask[] = {0,1,3,7,15,31,63,127,...}
if ((bitindex+=number_of_bits)==32) { // 位指针前移 number_of_bits 位
bitindex = 0; // bitindex==32, 即 bitindex = 0
wordpointer++; // 字指针前移一个字
}
} else { // 跨字处理
int Right = (framebuffer[wordpointer] & 0x0000FFFF); // 上字后半部分
wordpointer++; // 字指针前移一个字
int Left = (framebuffer[wordpointer] & 0xFFFF0000); // 下子前半部分
returnvalue = ((Right << 16) & 0xFFFF0000)
| ((Left >>> 16)& 0x0000FFFF); // 整字合并
returnvalue >>>= 48 - sum; // 截尾便于掩码操作
returnvalue &= bitmask[number_of_bits]; // 掩码出想读的位数字
bitindex = sum - 32; // 位指针前移到位结束处
}
return returnvalue; // 返回想读的位数字
}
6. 首个帧头处理初始化——Decoder.initialize(header)
private void initialize(Header header) throws DecoderException {
float scalefactor = 32700.0f; // 评论:允许客户化缩放系数(Scale Factor)
int mode = header.mode();
int layer = header.layer();
int channels = (mode==Header.SINGLE_CHANNEL ? 1 : 2);
if (output==null) // 设置创建输出缓冲区,如果客户端未设置
output = new SampleBuffer(header.frequency(), channels);
float[] factors = equalizer.getBandFactors();// 均衡器在解码器创建时已创建,获取其各波段系数
filter1 = new SynthesisFilter(0, scalefactor, factors); // 创建合成过滤器 1
if (channels==2) // 评论:允许为立体声输出单声道
filter2 = new SynthesisFilter(1, scalefactor, factors); // 创建合成过滤器 2
outputChannels = channels;
outputFrequency = header.frequency();
initialized = true; // 初始化完成标志,以后不必再初始化。405
}