OPhone应用开发_MP3帧结构

介于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

3121

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

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

B

2

2019

MPEG音频版本号,其中MPEG 2.5

为非官方版本

00  MPEG 2.5

01  保留版本

10  MPEG 2

11  MPEG 1

C

2

1817

层(Layer)版本号

00  保留版本号

01  Layer 3

10  Layer 2

11  Layer 1

D

1

16

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

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

E

4

1512

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

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

F

2

1110

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

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

G

1

9

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

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

Layer 2Layer 3的填充位

长度为1个字节

H

1

8

私有标识位

I

2

76

声道模式

00  立体声

01  联合立体声

10  双声道

11  单声道

J

2

54

模式的扩展,只有声道模

式为01时才有意义

K

1

3

版权标识

L

1

2

原版标识

M

2

10

目前此标志位很少使用

表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 = file;  
  20.         try {  
  21.             FileInputStream fis = new FileInputStream(file.getPath());  
  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.         long offset = -1;  
  35.         long index = time / 260;  
  36.         offset = ((F) v.get((int) index)).offset;  
  37.         return offset;  
  38.     }  
  39.  
  40.     private void parse(InputStream is) throws MP3Exception {  
  41.         try {  
  42.             int position = file.getFrameOffset();  
  43.             //帧的结束位置,也就是ID3V1的起始位置  
  44.             long count = file.getLength() - 128;  
  45.             //计算帧的个数,每10个帧放入到Vector中  
  46.             int fc = 0;  
  47.             //存储10个帧的大小  
  48.             int fs = 0;  
  49.             while (is.available() > 0 && position < count) {  
  50.                 //同步帧头位置  
  51.                 int first = is.read();  
  52.                 while (first != 255 && first != -1) {  
  53.                     first = is.read();  
  54.                 }  
  55.                 int second = is.read();  
  56.                 if (second > 224) {  
  57.                     int third = is.read();  
  58.                     int forth = is.read();  
  59.  
  60.                     int i20 = getBit(second, 4);  
  61.                     int i19 = getBit(second, 3);  
  62.                     if (i20 == 0 & i19 == 0)  
  63.                         throw new MP3Exception
    ("MPEG 2.5 is not supported");  
  64.                     //获得MPEG版本号  
  65.                     version = i19 == 0 ? 2 : 1;  
  66.  
  67.                     int i18 = getBit(second, 2);  
  68.                     int i17 = getBit(second, 1);  
  69.                     layer = (4 - ((i18 << 1) + i17));  
  70.  
  71.                     int i16 = getBit(second, 0);  
  72.  
  73.                     int i15 = getBit(third, 7);  
  74.                     int i14 = getBit(third, 6);  
  75.                     int i13 = getBit(third, 5);  
  76.                     int i12 = getBit(third, 4);  
  77.                     //查表获得比特率  
  78.                     int bitRate = convertBitrate(i15, 
    i14, i13, i12) * 1000;  
  79.  
  80.                     int i11 = getBit(third, 3);  
  81.                     int i10 = getBit(third, 2);  
  82.                     //查表获得抽样率  
  83.                     int sampleRate = convertSamplerate(i11, i10);  
  84.  
  85.                     int padding = getBit(third, 1);  
  86.                     //计算帧的大小  
  87.                     int size = ((version == 1 ? 144 : 72) * bitRate)  
  88.                             / sampleRate + padding;  
  89.                     is.skip(size - 4);  
  90.                     fs += size;  
  91.                     fc++;  
  92.                     if (fc == 10) {  
  93.                         //每10帧存储一次  
  94.                         F f = new F(position, fs);  
  95.                         v.add(f);  
  96.                         fc = 0;  
  97.                         fs = 0;  
  98.                     }  
  99.                     positionposition = position + size;  
  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.         int 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.         if (version == 1) {  
  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.         int[][] convert = { { 0, 0, 0, 0, 0, 0 }, { 32, 32, 32, 32, 32, 8 },  
  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.         int index1 = (in1 << 3) | (in2 << 2) | (in3 << 1) | in4;  
  147.         int index2 = (version - 1) * 3 + layer - 1;  
  148.         return convert[index1][index2];  
  149.     }  
  150.  
  151.     private int getBit(int input, int bit) {  
  152.         return (input & (1 << bit)) > 0 ? 1 : 0;  
  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.     }  

 

posted on 2010-04-06 14:44  香格里拉\(^o^)/  阅读(679)  评论(0编辑  收藏  举报