博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MP3文件结构及解码概述
阅读量:5129 次
发布时间:2019-06-13

本文共 6488 字,大约阅读时间需要 21 分钟。

MP3文件结构概述

Layer-3音频文件。MPEG(MovingPicture Experts Group)在汉语中译为活动图像专家组,特指活动影音压缩标准,MPEG音频文件是MPEG1标准中的声音部分。也叫MPEG音频层,它依据压缩质量和编码复杂程度划分为三层,即Layer-1Layer2Layer3。且分别相应MP1MP2MP3这三种声音文件,并依据不同的用途,使用不同层次的编码。MPEG音频编码的层次越高,编码器越复杂,压缩率也越高。MP1MP2的压缩率分别为4161-81,而MP3的压缩率则高达101-121

MP3文件大体分为三部分:TAG_V2(ID3V2),音频数据。TAG_V1(ID3V1),当中ID3V2ID3V1的补充,并非全部的MP3都有ID3V2补充。即是不是全部的MP3文件都有ID3V2

ID3V2

        假设MP3文件存在ID3V2。则一定在文件的头部,ID3V2结构分为头部(header)和若干标签帧。当中头部长度为10字节。10个字节的结构如表1

0

1

2

3

4

5

6

7

8

9

内容为”ID3”

版本

副版本

存放标志的字节

ID3V2总大小(帧头和之后的若干标签帧总和)

1

由于345字节所代表的意义并非MP3解码的重点,故此仅仅讲解前三字节和后四字节:

  1.  从表1可看出推断MP3文件是否存在ID3V2。仅仅须要推断文件前三个字节是否是”ID3”

  2. ID3V2数据大小计算公司:

total_size = (Size[0]&0x7F)*0x200000+ (Size[1]&0x7F)*0x400 + (Size[2]&0x7F)*0x80 +(Size[3]&0x7F)

当中。size[0~3]。各自是表1中的6~9字节。

须要注意的是。这个公司计算的长度并不包含ID3V210个字节的头部。

ID3V2头部之后的若干标签帧每一帧结构分为标签ID4字节)、帧内容大小(4字节。不包含标签帧帧头)、存放标志位(2字节)、内容。

当中标签ID的含义例如以下:

TEXT: 歌词作者    TENC: 编码        WXXX URL链接(URL)        TCOP: 版权(Copyright)   TOPE: 原艺术家

TCOM: 作曲家      TDAT: 日期        TPE3: 指挥者              TPE2: 乐队               TPE1: 艺术家相当于ID3v1Artist

TPE4: 翻译(记录员、改动员)          TYER: 即ID3v1Year      USLT: 歌词               TSIZ: 大小

TALB: 专辑相当于ID3v1Album         TIT1: 内容组描写叙述          

TIT2: 标题相当于ID3v1Title       TIT3: 副标题

TCON: 流派(风格)相当于ID3v1Genre AENC: 音频加密技术        

TBPM: 每分钟节拍数COMM: 凝视相当于ID3v1Comment   

TDLY: 播放列表返录                  TRCK: 音轨(曲号)相当于ID3v1Track

TFLT: 文件类型                      TIME: 时间       

TKEY: 最初keyword                    TLAN: 语言                

TLEN: 长度                         TMED: 媒体类型    

TOAL: 原唱片集                      TOFN: 原文件名称            

TOLY: 原歌词作者                    TORY: 最初发行年份

TOWM: 文件全部者(许可证者)          TPOS: 作品集部分          

TPUB: 发行人                        TRDA: 录制日期

TRSN Intenet电台名称                 TRSO Intenet电台全部者   UFID: 唯一的文件标识符  

TSRC ISRC(国际的标准记录代码)     TSSE: 编码使用的软件(硬件设置)

读取MP3文件ID3V2信息的函数可例如以下:

//定义头部和标签帧

typedefstruct ID3v2Header{

   char Identify[3];         // ID3v2固定标志:ID3

   char Ver;              //主版本,ID3v2就是3

   char Rever;            //副版本。一般都为0

   char Flag;             //标志位,一般为0。字义为abc00000

   char Size[4];             // 标签大小,一共四个字节,但每一个字节仅仅使用7位,最高位不使用恒为0,所以格式: 0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx

}ID3v2Header;

 

typedefstruct ID3v2Frame//标签帧,10个字节

{

   char FrameID[4];          // 标志对比符。如TEXTTOPETDAT....

   char Size[4];             // 帧体的大小。依照正常的8位存储的,FSize = Size[0]*0x100000000 + Size[1]*0x10000 + Size[2]*0x100 + Size[3];

   char Flag[2];             // 存放标志

}ID3v2Frame;

 

//输出信息并返回ID3V2大小

int ReadID3v2(FILE *pf)

{

   ID3v2Headermp3header;

   ID3v2Frame mp3Frame;

   int FSize      = 0;

   char str[4096] = {0};

   char str2[5]   = {0};

   int ID3size;

   inthead_size = 0;

   inti;

   if(!pf)

       return -1;

   fseek(pf,0,SEEK_SET);

   fread(&mp3header,sizeof(mp3header),1,pf);

   if (mp3header.Identify[0]!='I' || mp3header.Identify[1]!='D' || mp3header.Identify[2]!='3' ){

       printf("此歌曲不支持ID3v2标准!\n");

       //文件复位

       rewind(pf);

       return -2;

   }

   printf("ID3v2标志:%.3s\n",mp3header.Identify);

   printf("ID3v2版本号:%d\n",  mp3header.Ver);

   ID3size= (mp3header.Size[0]& 0x7F)<< 21|(mp3header.Size[1]& 0x7F)<< 14|(mp3header.Size[2] & 0x7F) << 7|(mp3header.Size[3] & 0x7F);

   printf("标签大小:%d\n***********\n",ID3size);

   for (i=0;i<ID3size;i=i+11+FSize){

       memset(&mp3Frame,0,sizeof(mp3Frame));

       memset(&str,0,sizeof(str));

       fseek(pf,10+i,SEEK_SET);               //移动到标签帧头

       fread(&mp3Frame,sizeof(mp3Frame),1,pf);

       //原则上是不用-1的,可是实际发现,总有一个字节的差距,为了计算方便-1。所以出现-1时标明此区块无内容

       FSize  = (int)(mp3Frame.Size[0]*0x100000000 + mp3Frame.Size[1]*0x10000+ mp3Frame.Size[2]*0x100 + mp3Frame.Size[3]-1);

       if (FSize>0)   {

           fseek(pf,10+11+i,SEEK_SET);//移动到内容区           

           fread(str,FSize,1,pf);

           GetStr(mp3Frame.FrameID,str2);

           printf("%s-%s:\t%s\n",str2,mp3Frame.FrameID,str);

           head_size+=11;

       }else{

           return ID3size+10;

       }

   }

   return ID3size+10;

}

 

//通过FrameID获取相应的中文名

void GetStr(char* oldstr,char* str)

{

   if (0==memcmp((LPCTSTR)"TIT2",oldstr,4))

   {

       memcpy(str,"标题",4);

   }elseif(0==memcmp((LPCTSTR)"TPE1",oldstr,4)){

       memcpy(str,"作者",4);

   }elseif(0==memcmp((LPCTSTR)"TALB",oldstr,4)){

       memcpy(str,"专辑",4);

   }elseif(0==memcmp((LPCTSTR)"TRCK",oldstr,4)){

       memcpy(str,"音轨",4);

   }elseif(0==memcmp((LPCTSTR)"TYER",oldstr,4)){

       memcpy(str,"年代",4);

   }elseif(0==memcmp((LPCTSTR)"COMM",oldstr,4)){

       memcpy(str,"备注",4);

   }elseif(0==memcmp((LPCTSTR)"TCON",oldstr,4)){

       memcpy(str,"类型",4);

   }else{

       memcpy(str,"未知",4);  //其它的不是非常重要,所以省略了

   }

}

MP3文件数据结构及处理流程

MP3数据解码流程借用图1描写叙述。

1

MP3文件的音频数据部分。是分为非常多数据帧存放。每一帧数据播放的时间长度计算公式:

   每帧持续时间(毫秒) =每帧採样数 /採样频率 * 1000

如果每帧採样数为1152,採样频率为44.1K,则每帧数据播放的时间约为26ms

   没帧数据的结构包含帧头(header)、帧边信息(side)、主数据(main data)。

帧头(header

        数据帧帧头长度为4字节,结构如图2所看到的。

2

        由图可知。同步信息(synchronizationword11位皆为1,其它位信息如表

版本号(ID

2bit

00-MPEG 2.5  01-没有定义    10-MPEG 2    11-MPEG 1

层(layer

2bit

00-没有定义     01-Layer 3    10-Layer 2     11-Layer 1

CRC校验

1bit

0-校验       1-不校验

位率索引

4bit

bits

V1,L1

V1,L2

V1,L3

V2,L1

V2,L2

V2,L3

0000

free

free

free

free

free

free

0001

32

32

32

32(32)

32(8)

8 (8)

0010

64

48

40

64(48)

48(16)

16 (16)

0011

96

56

48

96(56)

56(24)

24 (24)

0100

128

64

56

128(64)

64(32)

32 (32)

0101

160

80

64

160(80)

80(40)

64 (40)

0110

192

96

80

192(96)

96(48)

80 (48)

0111

224

112

96

224(112)

112(56)

56 (56)

1000

256

128

112

256(128)

128(64)

64 (64)

1001

288

160

128

288(144)

160(80)

128 (80)

1010

320

192

160

320(160)

192(96)

160 (96)

1011

352

224

192

352(176)

224(112)

112 (112)

1100

384

256

224

384(192)

256(128)

128 (128)

1101

416

320

256

416(224)

320(144)

256 (144)

1110

448

384

320

448(256)

384(160)

320 (160)

1111

bad

bad

bad

bad

bad

bad

V1 - MPEG 1    V2 - MPEG 2 and MPEG 2.5

L1 - Layer 1   L2 - Layer 2    

L3 - Layer 3

"free"表示位率可变   

"bad" 表示不同意值

採样频率

2bit

MPEG-1 00-44.1kHz   01-48kHz   10-32kHz     11-没有定义

MPEG-2 00-22.05kHz  01-24kHz   10-16kHz     11-没有定义

MPEG-2.5 00-11.025kHz 01-12kHz   10-8kHz      11-没有定义

是否填充

1bit

0-无需调整,1-调整

保留(reserved

1bit

 

声道模式

2bit

00-立体声Stereo   01-Joint Stereo   10-双声道       11-单声道

保留(reserved

2bit

 

版权标志

1bit

0-不合法  1-合法

原版标志

1bit

0-非原版  1-原版

强调方式

2bit

00-没有定义    01-50/15ms    10-保留      11-CCITT J.17

2

数据帧大小计算公式:

Size=((採样个数 * (1 / 採样率))*帧的比特率)/8 +帧的填充大小

对于Mp3格式:

   Size=((1152 * (1 /採样率))*帧的比特率)/8 +帧的填充大小= 144*帧的比特率/採样率+帧的填充大小

当中:帧的填充大小便是23bit,不是0则为1

帧边信息(side

帧边信息解码的主要目的在于找出解这帧的各个參数。包含主数据開始位置,尺度因子长度等。

帧边信息如图3所看到的。

3

当中main_data_begin(主数据開始)是一个偏移值。指出主数据是在同步字之前多少个字节開始。

须要注意的是。1.帧头不一定是一帧的開始,帧头CRC校验字和帧边信息在帧数据中是滑动的。

2.这个数值忽略帧头和帧边信息的存在,假设main_data_begin = 0, 则主数据从帧边信息的下一个字节開始,示意图如图4.

4

        块类型(block_type)分为三种类型:

block_type = 0长块

block_type = 1開始块

block_type = 3结束块

block_type = 2短块

在编码过程中进行IMDCT变换时。针对不同信号为同一时候得到较好的时域和频域分辨率定义了两种不同的块长:长块的块长为18个样本,短块的块长为6个样本。这使得长块对于平稳的声音信号能够得到更高的频率分辨率,而短块对跳变信号能够得到更高的时域分辨率。由于在短块模式下。3个短块取代1个长块,而短块的大小恰好是一个长块的1/3。所以IMDCT的样本数不受块长的影响。

对于给定的一帧声音信号,IMDCT能够所有使用长块或所有使用短块,也能够长短块混合使用。

由于低频区的频域分辨率对音质有重大影响,所以在混合块模式下,IMDCT对最低频的2个子带使用长块,而对其余的30个子带使用短块。

这样,既能保证低频区的频域分辨率。又不会牺牲高频区的时域分辨率。

长块和短块之间的切换有一个过程。一般用一个带特殊长转短(即,起始块block_type = 1)或短转长(即终止块,block_type = 3)数据窗体的长块来完毕这个长短块之间的切换。

因此长块也就是包括正常窗,起始块和终止块数据窗体的数据块;短块也包括18个数据,可是是由6个数据独立加窗后在经过连接计算得到的。

主数据(main_data

        main_data中有两粒度组。没个粒度组分为两个声道,取数据存储结构如图5

5

当中,每一个通道(chN_data)的结构图6.

6



转载于:https://www.cnblogs.com/blfshiye/p/5177892.html

你可能感兴趣的文章
oracle 创建暂时表
查看>>
201421410014蒋佳奇
查看>>
导入导出数据库和导入导出数据库表
查看>>
linux下操作mysql
查看>>
【03月04日】A股滚动市盈率PE历史新低排名
查看>>
Xcode5和ObjC新特性
查看>>
jvm slot复用
查看>>
高并发系统数据库设计
查看>>
hdu 1875 畅通工程再续
查看>>
CentOs6和Centos7安装docker
查看>>
TCP/ip协议栈之内核调优
查看>>
6 spark 存储体系 --内存管理
查看>>
PDF/WORD/EXCEL 图片预览
查看>>
onRetainNonConfigurationInstance方法状态保存
查看>>
DevExpress组件之——TreeList组件
查看>>
P2916 [USACO08NOV]安慰奶牛Cheering up the Cow
查看>>
PV操作(转)
查看>>
软考笔记第六天之各排序算法的实现
查看>>
修补PHPRPC_Client中(JAVA版本),创建Socket连接时Timeout不起作用
查看>>
第五次作业160809308周子济
查看>>