介于ID3V2和ID3V1之间的部分称作MP3帧,这些帧构成了MP3的音频部分。每个MP3帧由帧头和数据块组成,之间还可能包含2个字节的CRC校验位,校验位是否存在依赖于帧头的第16比特位的值。以比特率为区分标准,MP3可以分为可变比特率和不变比特率两种格式。比特率代表每秒钟的数据量,一般单位是kbps。比特率越高,MP3的音质越好,但是文件也越大。每个MP3帧固定时长为26ms,因此可变比特率的帧大小可能是不同的,而不变比特率的帧大小是固定的,只要分析了第1个帧的大小就可以知道后面帧的大小。

帧头长度是4个字节,也就是32比特,其布局如下所示。每个比特的意义在表7-3中做了详细的介绍。




  1. AAAAAAAA  AAABBCCD  EEEEFFGH  IIJJKLMM 

表7-3  帧头的比特描述



标识


长度


位置


描述


A


11


31~21


11位的帧同步数据,可以通过查找


同步位来确定帧的起始位置


B


2


20~19


MPEG音频版本号,其中MPEG 2.5


为非官方版本


00  MPEG 2.5


01  保留版本


10  MPEG 2


11  MPEG 1


C


2


18~17


层(Layer)版本号


00  保留版本号


01  Layer 3


10  Layer 2


11  Layer 1


D


1


16


保护位,0代表帧头后紧跟2个字


节的CRC校验位;1代表无保护


E


4


15~12


比特率索引值,根据表7-4中的内容


可以查询比特率的值,单位是kbps


F


2


11~10


抽样率索引值,根据表7-5中的内容


可以查询抽样率的值,单位是Hz


G


1


9


填充位,0代表无填充,1代表有填充。


对于Layer 1,填充位长度为4个字节;


Layer 2和Layer 3的填充位


长度为1个字节


H


1


8


私有标识位


I


2


7~6


声道模式


00  立体声


01  联合立体声


10  双声道


11  单声道


J


2


5~4


模式的扩展,只有声道模


式为01时才有意义


K


1


3


版权标识


L


1


2


原版标识


M


2


1~0


目前此标志位很少使用




表7-4  比特率索引表(单位:kbps)



比特位


V1 L1


V1 L2


V1 L3


V2 L1


V2 L2


V2 L3


0000


0


0


0


0


0


0


0001


32


32


32


32


32


8


0010


64


48


40


64


48


16


0011


96


56


48


96


56


24


0100


128


64


56


128


64


32


0101


160


80


64


160


80


64


0110


192


96


80


192


96


80


0111


224


112


96


224


112


56


1000


256


128


112


256


128


64




续表



比特位


V1 L1


V1 L2


V1 L3


V2 L1


V2 L2


V2 L3


1001


288


160


128


288


160


128


1010


320


192


160


320


192


160


1011


352


224


192


352


224


112


1100


384


256


224


384


256


128


1101


416


320


256


416


320


256


1110


448


384


320


448


384


320


1111


0


0


0


0


0


0




表7-5  抽样率索引(单位:Hz)



比特位


MPEG 1


MPEG 2


MPEG 2.5


00


44100


22050


11205


01


48000


24000


12000


10


32000


16000


8000


11


0


0


0




MP3帧体的大小由MPEG版本号、比特率、抽样率和填充位4个因素确定。计算公式为:

帧大小= ((MPEG版本号== 1?144:72) * 比特率)/抽样率 + 填充位

解析MP3帧是较复杂的,且直接关系到后面分割MP3文件的工作。对于不变比特率的情况比较简单,不需要完全解析整个MP3文件就可以知道帧数、帧的大小等信息。但是,对于可变比特率的情况就显得比较复杂了,必须逐个分析MP3帧才能确定帧的大小,也只有分析了整个MP3文件才能确定帧的数量。为了能兼顾可变和不变比特率两种情况,我们考虑解析整个MP3文件,然后把每个帧的大小和在文件中的位移存储在一个Vector中,这样就可以通过时间来定位到帧的位置,便于切割MP3文件。通常一个MP3文件可能包含10000多个帧,如果所有帧都存储在Vector中,将消耗很大的内存空间,且Vector中的元素越多,查询的速度也就越慢。为了优化程序,把10个帧作为一个大帧存储在Vector中,这样在切割时依然可以精确到260ms,甚至还可以把20个帧作为一个整体,这样的效率会更高一些,内存使用更少一些,只是会丧失一些切割的精度。

 

 

Frames类的构造器中包含了MP3File类型的参数,这样可以方便获得MP3帧的起始位置。Frames类的源码如下所示:



1. package com.ophone.chapter7_5;  
2.  
3. import java.io.FileInputStream;  
4. import java.io.FileNotFoundException;  
5. import java.io.IOException;  
6. import java.io.InputStream;  
7. import java.util.Vector;  
8.  
9. public class Frames {  
10.  
11.     private static int version;  
12.     private static int layer;  
13.     private MP3File file;  
14.     //存储帧在文件中的位移和大小  
15.     private Vector<F> v = new Vector<F>();  
16.  
17.     public Frames(MP3File file) throws MP3Exception {  
18.         //引用MP3File,方便获得MP3帧开始的位置  
19. this.file
20.         try {  
21. fis = new
22.             //定位到帧起始位置,开始解析  
23.             fis.skip(file.getFrameOffset());  
24.             parse(fis);  
25.         } catch (FileNotFoundException e) {  
26.             e.printStackTrace();  
27.         } catch (IOException ex) {  
28.             ex.printStackTrace();  
29.         }  
30.     }  
31.  
32.     //将传入的媒体时间转换为在文件中的位置  
33.     public long time2offset(long time) {  
34. offset
35. index = time
36. offset
37.         return offset;  
38.     }  
39.  
40.     private void parse(InputStream is) throws MP3Exception {  
41.         try {  
42. position = file.getFrameOffset();  
43.             //帧的结束位置,也就是ID3V1的起始位置  
44. count = file.getLength() - 128;  
45.             //计算帧的个数,每10个帧放入到Vector中  
46. fc = 0;  
47.             //存储10个帧的大小  
48. fs = 0;  
49. > 0 && position < count) {  
50.                 //同步帧头位置  
51. first = is.read();  
52.                 while (first != 255 && first != -1) {  
53. first = is.read();  
54.                 }  
55. second = is.read();  
56. >
57. third = is.read();  
58. forth = is.read();  
59.  
60. i20 = getBit(second, 4);  
61. i19 = getBit(second, 3);  
62. i20 == 0 & i19
63.                         throw new MP3Exception
("MPEG 2.5 is not supported");  64.                     //获得MPEG版本号  
65. version = i19
66.  
67. i18 = getBit(second, 2);  
68. i17 = getBit(second, 1);  
69. layer = (4 - ((i18 << 1) + i17));  
70.  
71. i16 = getBit(second, 0);  
72.  
73. i15 = getBit(third, 7);  
74. i14 = getBit(third, 6);  
75. i13 = getBit(third, 5);  
76. i12 = getBit(third, 4);  
77.                     //查表获得比特率  
78. bitRate = convertBitrate(i15, 
i14, i13, i12) * 1000;  79.  
80. i11 = getBit(third, 3);  
81. i10 = getBit(third, 2);  
82.                     //查表获得抽样率  
83. sampleRate = convertSamplerate(i11, i10);  
84.  
85. padding = getBit(third, 1);  
86.                     //计算帧的大小  
87. size = ((version
88.                             / sampleRate + padding;  
89.                     is.skip(size - 4);  
90.                     fs += size;  
91.                     fc++;  
92. fc
93.                         //每10帧存储一次  
94. f = new
95.                         v.add(f);  
96. fc = 0;  
97. fs = 0;  
98.                     }  
99. positionposition
100.                 }  
101.             }  
102.             //将剩余的帧放入Vector中  
103.             if (fs != 0) {  
104.                 v.add(new F(position, fs));  
105.             }  
106.         } catch (IOException e) {  
107.             e.printStackTrace();  
108.         }  
109.     }  
110.     //根据表7-5计算抽样率  
111.     protected int convertSamplerate(int in1, int in2) {  
112. sample = 0;  
113.         switch ((in1 << 1) | in2) {  
114.         case 0:  
115. sample = 44100;  
116.             break;  
117.         case 1:  
118. sample = 48000;  
119.             break;  
120.         case 2:  
121. sample = 32000;  
122.             break;  
123.         case 3:  
124. sample = 0;  
125.             break;  
126.         }  
127. version
128.             return sample;  
129.         } else {  
130.             return sample / 2;  
131.         }  
132.     }  
133.     //根据表7-4计算比特率  
134.     protected int convertBitrate(int in1, int in2, int in3, int in4) {  
135. convert
136.                 { 64, 48, 40, 64, 48, 16 }, { 96, 56, 48, 96, 56, 24 },  
137.                 { 128, 64, 56, 128, 64, 32 }, { 160, 80, 64, 160, 80, 64 },  
138.                 { 192, 96, 80, 192, 96, 80 }, { 224, 112, 96, 224, 112, 56 },  
139.                 { 256, 128, 112, 256, 128, 64 },  
140.                 { 288, 160, 128, 288, 160, 128 },  
141.                 { 320, 192, 160, 320, 192, 160 },  
142.                 { 352, 224, 192, 352, 224, 112 },  
143.                 { 384, 256, 224, 384, 256, 128 },  
144.                 { 416, 320, 256, 416, 320, 256 },  
145.                 { 448, 384, 320, 448, 384, 320 }, { 0, 0, 0, 0, 0, 0 } };  
146. index1 = (in1 << 3) | (in2 << 2) | (in3 << 1) | in4;  
147. index2
148.         return convert[index1][index2];  
149.     }  
150.  
151.     private int getBit(int input, int bit) {  
152.         return (input & (1 << bit)) >
153.     }  
154.  
155.     class F {  
156.         int offset;  
157.         int size;  
158.         public F(int _offset, int _size) {  
159. offset = _offset;  
160. size = _size;  
161.         }  
162.     }  
163. }