MP3文件结构及解码概述
Layer-3音频文件。MPEG(MovingPicture Experts Group)在汉语中译为活动图像专家组,特指活动影音压缩标准,MPEG音频文件是MPEG1标准中的声音部分。也叫MPEG音频层,它依据压缩质量和编码复杂程度划分为三层,即Layer-1、Layer2、Layer3。且分别相应MP1、MP2、MP3这三种声音文件,并依据不同的用途,使用不同层次的编码。MPEG音频编码的层次越高,编码器越复杂,压缩率也越高。MP1和MP2的压缩率分别为4:1和6:1-8:1,而MP3的压缩率则高达10:1-12:1。
MP3文件大体分为三部分:TAG_V2(ID3V2),音频数据。TAG_V1(ID3V1),当中ID3V2是ID3V1的补充,并非全部的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
由于3、4、5字节所代表的意义并非MP3解码的重点,故此仅仅讲解前三字节和后四字节:
从表1可看出推断MP3文件是否存在ID3V2。仅仅须要推断文件前三个字节是否是”ID3”。
ID3V2数据大小计算公司:
total_size = (Size[0]&0x7F)*0x200000+ (Size[1]&0x7F)*0x400 + (Size[2]&0x7F)*0x80 +(Size[3]&0x7F) |
当中。size[0~3]。各自是表1中的6~9字节。
须要注意的是。这个公司计算的长度并不包含ID3V2的10个字节的头部。
ID3V2头部之后的若干标签帧每一帧结构分为标签ID(4字节)、帧内容大小(4字节。不包含标签帧帧头)、存放标志位(2字节)、内容。
当中标签ID的含义例如以下:
TEXT: 歌词作者 TENC: TCOM: 作曲家 TDAT: TPE4: 翻译(记录员、改动员) TYER: TALB: 专辑相当于ID3v1的Album TIT1: TIT2: 标题相当于ID3v1的Title TIT3: TCON: 流派(风格)相当于ID3v1的Genre AENC: TBPM: 每分钟节拍数COMM: TDLY: 播放列表返录 TFLT: 文件类型 TKEY: 最初keyword TLEN: 长度 TOAL: 原唱片集 TOLY: 原歌词作者 TOWM: 文件全部者(许可证者) TPOS: TPUB: 发行人 TRSN: Intenet电台名称 TRSO: TSRC: ISRC(国际的标准记录代码) TSSE: |
读取MP3文件ID3V2信息的函数可例如以下:
//定义头部和标签帧 typedefstruct ID3v2Header{ char Identify[3]; // ID3v2固定标志:ID3 。字义为abc00000 char Size[4]; // }ID3v2Header; typedef个字节 { char FrameID[4]; // char Size[4]; // 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' 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* { 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文件的音频数据部分。是分为非常多数据帧存放。每一帧数据播放的时间长度计算公式:
每帧持续时间(毫秒) 如果每帧採样数为1152,採样频率为44.1K,则每帧数据播放的时间约为26ms。 |
没帧数据的结构包含帧头(header)、帧边信息(side)、主数据(main
data)。
帧头(header)
数据帧帧头长度为4字节,结构如图2所看到的。
图2
由图可知。同步信息(synchronizationword)11位皆为1,其它位信息如表
版本号(ID) |
2bit |
00-MPEG 2.5 01-没有定义 10-MPEG |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
层(layer) |
2bit |
00-没有定义 01-Layer |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
CRC校验 |
1bit |
0-校验 1-不校验 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
位率索引 |
4bit |
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 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
保留(reserved) |
2bit |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
版权标志 |
1bit |
0-不合法 1-合法 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
原版标志 |
1bit |
0-非原版 1-原版 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
强调方式 |
2bit |
00-没有定义 01-50/15ms 10-保留 11-CCITT |
表2
数据帧大小计算公式:
Size=((採样个数 * 对于Mp3格式: Size=((1152 * (1 /採样率))*帧的比特率)/8 +帧的填充大小= 当中:帧的填充大小便是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
MP3文件结构及解码概述的更多相关文章
- 多媒体文件格式分析 MP3文件结构及编解码流程
多媒体文件格式分析 http://blog.csdn.net/taniya001/article/details/7962864 多媒体文件格式分析 MP3文件结构及编解码流程 http://www. ...
- MP3文件结构解析(超详细)
转自:http://blog.csdn.net/u010650845/article/details/53520426 MP3文件结构解析(超详细) 1. MP3文件结构解析 1.1. 概述 1.1. ...
- 转载:AAC编解码概述
转自:http://www.cnblogs.com/gaozehua/archive/2012/05/03/2479960.html 编码概述 其整体AAC 编解码系统,如图所示,其编码流程概述如下: ...
- jpeg编解码概述
本博文为概览性介绍.后面有空了再分几篇博文分别介绍所用到的技术细节. 1.编解码目标 编码和解码是个逆过程.jpeg编码的目的在于图形去冗余,进行数据压缩,解码的目的在于还原图像,使能够进行预览. 2 ...
- 一、MP3文件概述
一.概述 MP3 文件是由帧(frame)构成的,帧是 MP3 文件最小的组成单位.MP3 的全称应为 MPEG1 Layer-3 音频文件,MPEG(Moving Picture Experts G ...
- MP3格式音频文件结构解析
MP3的全称是MPEG Audio Layer3,它是一种高效的计算机音频编码方案,它以较大的压缩比将音频文件转换成较小的扩展名为.MP3的文件,基本保持原文件的音质.MP3是ISO/MPEG标准的一 ...
- android MediaCodec 音频编解码的实现——转码
原文地址:http://blog.csdn.net/tinsanmr/article/details/51049179 从今天开始 每周不定期更新博客,把这一周在工作与学习中遇到的问题做个总结.俗话说 ...
- MP3 信息读取
MP3 信息读取 运行环境:Window7 64bit,.NetFramework4.61,C# 7.0: 编者:乌龙哈里 2017-03-13 参考: MP3-wikipedia ID3v1 MPE ...
- MP3文件头格式
MP3文件结构及编解码流程 http://blog.sina.com.cn/s/blog_67b7cb7b01018i2l.html http://blog.csdn.net/liuyan4794/a ...
随机推荐
- iOS应用性能调优的25个建议和技巧【转】
转载自:http://blog.jobbole.com/37984/ 首页 最新文章 资讯 程序员 设计 IT技术 创业 在国外 营销 趣文 特别分享 更多 > - Navigation - ...
- 使用hbase的api创建表时出现的异常
/usr/lib/jvm/java-7-openjdk-amd64/bin/java -Didea.launcher.port=7538 -Didea.launcher.bin.path=/usr/l ...
- eclipse 汉化
对于: Eclipse Standard/SDK Version: Luna Release (4.4.0) 对应的网络地址:http://download.eclipse.org/technolog ...
- (转) .NET实现Repeater控件+AspNetPager控件分页
SqlConnection (.NET C#) 连接及分页 .net的访问数据机制决定了访问大量数据时会致使客户端机器消耗大量资源,因此有必要对数据进行分页显示,开发工具vs.net+sqlserve ...
- (搬运工)国内顺利使用Google的另类技巧
在特殊的地方和特殊的时间,流畅顺利使用Google的方法也会变得很特殊.分享一些奇葩的Google使用方法,通过下列网址也可以使用Google来搜索:http://www.GoogleStable.c ...
- include 和 require 的区别
1. 首先不去介绍大家都知道的区别,百度上都进行了详细的说明,对于返回值的方面大家都很少提到. include 和 require 还有一个区别就是是否具有返回值.参见手册 对include 加载文件 ...
- iOS学习之视图加载过程中会触发的方法(loadView/viewDidLoad/didReceiveMemoryWarning)
1.loadView 这是视图控制器用来加载根视图的方法; 如果需要将自定义的视图作为根视图,则不需要调用父类对该方法的实现([super loadView]);直接将自定义视图通过self.view ...
- gulp编译less简单demo
写个简单的less.watch任务的demo分享———— 1.准备: 安装全局node.npm,这个教程很多不作详细介绍: 安装全局gulp npm install -g gulp 新建getstar ...
- [HDU] 2094 产生冠军(拓扑排序+map)
题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=2094 注意每组数据处理前,map要清空. #include<cstdio> #includ ...
- 采购术语PR、PO、RFQ、RFI、SOW、BOM、JIT、VMI、MRO 是什么意思
PO:Purchase Order Form 采购订单,公司对外使用,还有个PR: ,公司内部使用的采购申请单 PR (Purchase Requirent) 请购单,采购申请单,代表企业内部的申请需 ...