MP3文件的ID3V1信息与ID3V2信息结构的分析

2024-01-29 09:48

本文主要是介绍MP3文件的ID3V1信息与ID3V2信息结构的分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

MP3文件的ID3V1信息与ID3V2信息结构的分析

 

——吴俊涛2005/05/05

E-mail:bo_tao@126.com  QQ:29248671

主 页:http://wjt276.home4u.china.com(有源代码)

 本人是一位编程爱好者,想通过VB。NET编写一个可以读取MP3文件的信息的不程序,可以不知道文件结构,呀我在网上找了好长时间(好几个月)都没有找到VB的。后来看到一个VC的,还附有结构分析,太好了,动手了。

一:“ID3v1”信息的分析

MP3的基本歌曲信息存在了MP3文件的最后128个字节里,其结构是:
Public Structure ID3v1Info

Dim ID3v1TAG As String 'TAG三个字母,ID3V1的标识

Dim Title As String '存储标题信息,30个字节

Dim Artist As String '存储歌手信息,30个字节

Dim Album As String '存储专辑信息,30个字节

Dim Year As String '存储年代信息,4个字节

Dim Comments As String '存储备注信息,28个字节(有时为30字节)

Dim Genre As String '存储音乐风格信息,保留位,1个字节 

Dim Reserved As String '保留位,1个字节(有时没有意思

Dim Track As String '音轨(曲号)保留位,1个字节(有时没有)

End Structure

ID3V1信息存储结构如下(如图1):

图 1 一个MP3文件的ID3v1信息


1-3 TAG

4-33 歌曲名(Take Me To Your Heart )

34-63 歌手名(Michael Learns to Rock)

64-93 专辑名(Take Me to Your Heart)

94-97 年(2004)

98-125 备注 (http://www.uptu.com)

126 保留位,这时为0,则说明有音轨,下一位就是音轨

127 保留位,为音轨(第几首歌)(OC)

128 保留位 (风格)(66)

 

而在Winamp的ID3v1歌曲信息里(如图1),我们看到的是他都包括:
Title(歌曲名)
Artist(歌手名)
Album(专辑名)
Year(年)
Comment(备注)
Genre(歌曲风格)注,见下面有详细的列表
Track#(歌曲在专辑里的顺序,就是我们经常说的“第几首”)

  Title,Artist,Album,Year,Comment我们都是可以在那个128个字节里得到,Genre和Track哪里去了呢? 有的朋友都重视了那128字节信息的前125个信息了,而这两个信息是却放在了最后的126-128字节里。其实,127那处就是Track信息,而128处就是Genre信息。他们的存储方式都不是字符,我们提取他们的时候需要注意,他们都是数字。比如,就如我们看到的这首歌的126处是0x0D,那么很显然,他就是13。也就是第13号歌曲风格,Pop流行( 下面列表)。

这时,你也该猜到了,127和128都是有意义的,自然126处也是有其意义!ID3v1信息的Comment(注释)一共占用28个字节。这个说法并不是完全的正确。准确的说应该是正确了一部分。有的时候注释也可以超过这个数字的。ID3v1要求注释最多可以到30个字节。那么有的读者会问“MP3的ID3v1就是得有130个字节的信息了嘛?”不是,当然不是。ID3v1是固定的128个字节,这个你不用担心。其实ID3v1是这样安排的:如果MP3的注释是大于28个字节的,那么就要借用126-127两个字节。所以ID3v1的注释部分可能是28个字节也可能是30个字节。那么,怎么区分到底是28个字节还是30个字节呢?很简单,126处就是管这个的,我们只要看看126处是不是0x00,如果是0x00那么注释就有28个字节。如果不等于0x00,那么就是说注释是30个字节。同时别忘了,由于第127字节存储了Track信息,那么如果注释是30个字节的时候,这首歌的ID3v1里的那个127处的信息自然就不是Track信息了。Track自然就是没有地方存了,所以127处变的没有Track意义了,它只是Comment的一部分了。在你决定制作读取ID3v1的程序的时候,请特别注意一下。

我们最终知道了126处是ID3v1信息的注释部分到底是28个字节还是30个字节的标志位。127处是音轨信息(Track),而Reserved3则是歌曲风格(Genre)。现在我们重新再写一次结构

原理2:MP3文件有没有ID3v1信息的错误理解
  那就是到底什么能叫做“MP3文件没有ID3v1信息”。检测的方法是先提取指定的MP3文件的最后128字节信息,然后确定这128个字节的前3个字节是“TAG”。很多朋友都会同意这个方法没有问题的。可是,实际上问题并不是那么简单。

  Winamp或者其他的MP3播放相关的软件都有MP3信息的写入和读取的功能,然而这些写入ID3v1的软件都会不自觉的当你一打开这个MP3文件就会给它加上这128个字节的信息。也就是说当我们用这种软件打开MP3文件的时候,这些软件就会自动的在这个MP3文件尾端添加了一个128字节的ID3v1结构,而且还是以“TAG”开头!(如图3)。那么很显然,光靠检测那“TAG”三个字节的信息,还是不能完全确定MP3到底有没有ID3v1信息的。我们还要确定这“TAG”后的125字节是不是正确的信息。一般情况下,这类软件产生的ID3v1结构都是由一堆00,或者一堆空格组成的,所以我们要判断一下是不是ID3v1的信息是一堆00或者一堆空格。如果是,那么MP3文件虽然有这“TAG”三个字母,却仍然不是一个合法的ID3v1信息。MP3文件仍然应该认为没有ID3v1信息。我觉得这个东西有必要特别提醒大家注意。

二:ID3v2信息的提取
MP3文件的“ID3v1信息”。这个信息结构提取起来非常容易,写入到文件也不是什么难事。但是它的信息安排和可扩展性却非常之差(只能128个字节)。就如你所知,MP3文件还有另外的一个信息结构,这个结构具有更好的可扩展性,而且存储的容量也不受限制(也就是总长度不固定)。这个信息就是ID3v2信息(相对ID3v1而言)。由于ID3v1信息存储在了文件的最后128个字节里,那么ID3v2就不得不放弃选择存储在文件的末尾了,于是它被存储在了文件的起始位置。

ID3v2信息的存储和读取远远要比ID3v1信息复杂的多。这是因为ID3v2信息不再固定,而且由于这段信息存储在了文件的首端,所以重新写入的时候也远比ID3v1麻烦的多。

我用尽可能清楚而且简练的话,给大家讲一下ID3v2信息的读取方法。ID3v2到现在一共有4个版本,不过比较流行的MP3播放软件一般只支持第3版,即ID3v2.3。我们要读取的就是ID3v2.3信息。ID3v2信息包括两个部分,一个部分是标头信息,另一个部分是标体信息。其中标头信息占固定的十个字节,

 每个ID3V2的标签部一个标签头和若干个标签帧或一个扩展标签组成关于曲目的信息如标题、作者等都放在在不同的标签帧中,扩展标签头和标签帧关不是必要的,但每个标签至少要有一个标签头和标签帧一直顺序存放在MP3文件首部。

它的结构如下:

(一)、标签头

Private Structure ID3v2Header

  Dim Header() As Byte'ID3v2标识位,应该是“ID3”三个字母为对

  Dim Ver As Byte'版本号ID3V2就记录3

  Dim Revision As Byte’副版本号此版本记录为0

  Dim Flag As Byte‘存放标志的字节,这个版本只定义了三位,稍后详细解说

  Dim Size() As Byte’标签大小,不包括标签头的10个字节(但是有的文章说包括)我是通过核实 才这样说的,看看源代码就知道了

End Structure

这十个字节的信息作用:

1、Header(2),一般为“ID3”,否则没有ID3V2信息

2、Flag 标志字节:标志字节一般为0,字义为abc00000

a-表示是否使用Unsynchronisation

b-表示是否有扩展头部,一般没有(WINAMP也没有)所以一般不设置

 c-表示是否为测试标签(99.9%的标签都不是测试用的,所以一般不设置)

3、Sixe(3) 标签大小:一共四个字节,但每个字节只使用7位,最高位不使用恒为0,所以格式如下:

  0xxxxxxx 0xxxxxxx 0xxxxxxx 0xxxxxxx

 计算大小时要将0去掉,得到一个28位的二进制数,就是标签的大,计算公式如下

   ①、VC的:ID3size =(Size[0]&0x7F)*0x200000 +(Size[1]&0x7F)*0x400 +(Size[2]&0x7F)*0x80 +(Size[3]&0x7F);

②、VB的:ID3size =Size(0) * (2 ^ 21) + Size(1) * (2 ^ 14) + Size(2) * (2 ^ 7) + Size(3) * (2 ^ 0)

VB的我已在类中声明了一个函数ByteToLong,很方便,直调用就OK了。

通过解析这段标头信息我们可以知道一个MP3文件是不是有ID3v2信息,如果有我们就知道了ID3v2的数据体的总长度。

(二)、标签帧

  接下来我们要解析ID3v2的 标签帧,别担心,虽然复杂,但也没你想象的那么的痛苦。ID3v2的数据体又分为很多相同的数据结构。

  每个标签帧都有一个10个字节的帧头和至少一个字节的不固定长度的内容组成,它们也是顺序存放在文件中,和标签头和其他的标签帧也没有特殊的字符分隔,得到一个完整的帧的内容只有从帧头中的到内容大小 后才能读出,读取时要注意大小,不要将其它的帧的内容或帧头读入。帧的定义如下:

Private Structure ID3v2Frame

  Dim FrameID As String‘用4个字符标识一个帧,说明其内容,常用的标识对照表见附表

  Dim Size() As Byte’4个字节 帧内容的大小,不包括帧头,不得小于1,计算时也用上面的公式计算

  Dim Flags() As Byte’2个字节 存放标志,只定义了6位,稍后详细解说

End Structure 

 1、FrameID 帧标:用四个字符标识一个帧的内容含义,常用的对照如下:

TEXT: 歌词作者 TENC: 编码
WXXX: URL链接(URL) TCOP: 版权(Copyright)
TOPE: 原艺术家 TCOM: 作曲家
TDAT: 日期 TPE3: 指挥者
TPE2: 乐队 TPE1: 艺术家相当于ID3v1的Artist
TPE4: 翻译(记录员、修改员) TYER: 年代相当于ID3v1的Year
USLT: 歌词 TALB: 专辑相当于ID3v1的Album
TIT1: 内容组描述 TIT2: 标题相当于ID3v1的Title
TIT3: 副标题 TCON: 流派(风格)相当于ID3v1的Genre见下表
TBPM: 每分钟节拍数 COMM: 注释相当于ID3v1的Comment
TDLY: 播放列表返录 TRCK: 音轨(曲号)相当于ID3v1的Track
TFLT: 文件类型 TIME: 时间 
TKEY: 最初关键字 TLAN: 语言
TLEN: 长度 TMED: 媒体类型
TOAL: 原唱片集 TOFN: 原文件名
TOLY: 原歌词作者 TORY: 最初发行年份
TOWM: 文件所有者(许可证者) TPOS: 作品集部分
TPUB: 发行人 TRDA: 录制日期
TRSN: Intenet电台名称 TRSO: Intenet电台所有者
TSIZ: 大小   TSRC: ISRC(国际的标准记录代码)
TSSE: 编码使用的软件(硬件设置) UFID: 唯一的文件标识符
AENC: 音频加密技术    

   其中要说明的是这个FrameID,在ID3v1里我们是根据每一个信息所占用的固定的字节数和位置来判断他是哪个信息的。而ID3v2为了提供更好的可扩展性,把这些信息变得“动态”化了,因为长度并不是预先设定好的,而是在size[4]里存储的。这样长度就可以不再固定了。我觉得在我们自己定义文件的时候ID3v2和ID3v1也是值得我们考虑的一个方面。如果结构很小而且存储的量也不大,我们可以采用ID3v1的信息存储方式。如果存储的信息不固定,而且要求有很好的可扩展性,那么ID3v2当然成了首选。实际上,现在很多格式的文件的存储方式都是ID3v2的存储方式非常接近的。

2、Size() 帧内容大小:不再是总标头那样的每个字节只取后7位了,它是按照正常的8位存储的。得到帧内容的大小的格式如下 :

xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

 计算成整形,公式如下:

   ①、VC的: FSize = Size[0]*0x100000000 + Size[1]*0x10000 + Size[2]*0x100 + Size[3];

②、VB的:ID3size =Size(0) * (2 ^ 21) + Size(1) * (2 ^ 14) + Size(2) * (2 ^ 7) + Size(3) * (2 ^ 0)

VB的我已在类中声明了一个函数ByteToLong,很方便,直调用就OK了。

3、Flags() 标志:只定义了6位,另外10位为0 但大部分的情况下16位都为0就可以了,格式如下:

 a-标签保护标志,设置时认为此帧作废

b-文件保护标志,设置时认为此帧作废

c-只读标志,设置时认为此帧不能修改(目前好像没有看到过)

i-压缩标志,设置时一个字节存放两个BCD码表示数字

j-加密标志(好像不太实用)

k-组标志,设置时说明此帧和其它的某帧是一组。


  详细你可能到www.ID3.org去了解一下。

4、帧内容(数据体)


  标头后面就是数据体了,我们提取数据体的前十个字节,我们知道了这个数据结构存储的FrameID是TIT2,查上面的表,说明这个数据结构存储的是歌曲名信息。大小是00 00 00 17,换成十进制就是23。也就是歌曲名是这个子标头后的23个字节的信息。也就是:“Take Me To Your Heart ”。接下来的一个数据结构的FrameID是TPE1,说明是歌手名,而大小是00 00 00 17,说明这个数据体有23个字节,也就是:“Michael Learns to Rock”。依次类推。这里需要大家知道的是一个汉字占用两个字节。在写入时,要计算字节数,我已编写了一个函数ByteSize,大家可以直接使用了。

  还有特别要提醒大家的是,ID3v2的注释信息(FrameID是COMM)的数据体的前四(但经我测试为前5个字节)个字节,并不是注释内容,而是注释使用的自然语言,这个例子里我们看到是:”eng/0”,我们要跳过这四个字节的信息进行解析。此外ID3v2的歌曲类型Genre(FrameID是TCON)的存储也不太一样的。由于很多MP3播放器的写入方式并不是非常一致,而在Genre写入的也不一致。比如,这首歌的ID3v2的Genre是Classic Rock,其实有的还会写入成:(1),或者1,还有(1)Classic Rock,所以格式五花八门,我们要在解析的时候注意一下。还有,值得一提的是winamp在保存和读取帧内容的时候会在内容前面加个'/0',并把这个字节计算在帧内容的大小中。所以前面提到的歌手名“Michael Learns to Rock”本身应该22个字节,可是却占了23个字节。

源代码已发布,你可以到本站点的主页去下载,如有什么问题,请一定联系我呀,不要客气轼呀

您如有什么问题,可以发E-MAIL给我,我们一起来讨论,主页里有源代码和实例,有兴趣的朋友不访去看看 http://wjt276.home4u.china.com

作者:吴俊涛   时间:2005/05/05    

这篇关于MP3文件的ID3V1信息与ID3V2信息结构的分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/656520

相关文章

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

C#实现获取电脑中的端口号和硬件信息

《C#实现获取电脑中的端口号和硬件信息》这篇文章主要为大家详细介绍了C#实现获取电脑中的端口号和硬件信息的相关方法,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 我们经常在使用一个串口软件的时候,发现软件中的端口号并不是普通的COM1,而是带有硬件信息的。那么如果我们使用C#编写软件时候,如

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

通过C#获取PDF中指定文本或所有文本的字体信息

《通过C#获取PDF中指定文本或所有文本的字体信息》在设计和出版行业中,字体的选择和使用对最终作品的质量有着重要影响,然而,有时我们可能会遇到包含未知字体的PDF文件,这使得我们无法准确地复制或修改文... 目录引言C# 获取PDF中指定文本的字体信息C# 获取PDF文档中用到的所有字体信息引言在设计和出

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维

C#读取本地网络配置信息全攻略分享

《C#读取本地网络配置信息全攻略分享》在当今数字化时代,网络已深度融入我们生活与工作的方方面面,对于软件开发而言,掌握本地计算机的网络配置信息显得尤为关键,而在C#编程的世界里,我们又该如何巧妙地读取... 目录一、引言二、C# 读取本地网络配置信息的基础准备2.1 引入关键命名空间2.2 理解核心类与方法

Redis连接失败:客户端IP不在白名单中的问题分析与解决方案

《Redis连接失败:客户端IP不在白名单中的问题分析与解决方案》在现代分布式系统中,Redis作为一种高性能的内存数据库,被广泛应用于缓存、消息队列、会话存储等场景,然而,在实际使用过程中,我们可能... 目录一、问题背景二、错误分析1. 错误信息解读2. 根本原因三、解决方案1. 将客户端IP添加到Re

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实