使用Python读取Mp3的标签信息

什么是ID3

MP3是音频文件最流行的格式,它的全称是 MPEG layer III。但是这种格式不支持对于音频内容的描述信息,包括歌曲名称、演唱者、专辑等等。

因此在1996年,Eric Kemp在Studio 3项目中提出了ID3的解决方案。ID3全称是Identity of MP3,其解决方案是在音频文件末尾附加一串数据,包含关于歌曲的名称、歌手、图片的信息。为了方便检测,数据的长度固定为128bytes。这个版本的解决方案称为 ID3v1。

Michael Mutschler 在 1997 对格式进行了微小的调整,压缩了Comment字段,增加了Track信息,这个版本被称为ID3v1.1。

1998年,Martin Nilsson & Michael Mutschler牵头,多个贡献者一起发起了ID3v2的工作。这个班的结构和ID3v1完全不同,数据的长度不再固定,位置也从尾部移到了头部,并且引入了Unicode支持。ID3v2的第一个版本是ID3v2.2,2000年发布了ID3v2.4。

ID3v1

附着在音频数据之后,长度为128bytes,每个字段最大支持30个字符。

具体的字段信息

Song Title

30 characters

Artist

30 characters

Album

30 characters

Year

4 characters

Comment

30 characters

Genre

1 byte

在数据开始之前,总是有三个字符TAG,这样和上面的字段加起来,正好是128bytes。如果Artist字段内容不足30个字符,不足的部分用0填充。

ID3v2

ID3v2是加在音频数据前面的一组数据,每项具体的数据称为frame(例如歌曲名称)。可以包含任意类型的数据,每个frame最大支持16MB,整个tag大小最大支持256MB。存储编码支持Unicode,这样就不会产生乱码问题。

Tag数据放在音频数据之前还有一个好处,对于流式访问可以首先获得歌曲信息并展现给用户。

列举一些特性:

  • The ID3v2 tag is a container format, just like IFF or PNG files, allowing new frames (chunks) as evolution proceeds.
  • Residing in the beginning of the audio file makes it suitable for streaming.
  • Has an 'unsynchronization scheme' to prevent ID3v2-incompatible players to attempt to play the tag.
  • Maximum tag size is 256 megabytes and maximum frame size is 16 megabytes.
  • Byte conservative and with the capability to compress data it keeps the files small.
  • The tag supports Unicode.
  • Isn't entirely focused on musical audio, but also other types of audio.
  • Has several new text fields such as composer, conductor, media type, BPM, copyright message, etc. and the possibility to design your own as you see fit.
  • Can contain lyrics as well as music-synced lyrics (karaoke) in almost any language.
  • Is able to contain volume, balance, equalizer and reverb settings.
  • Could be linked to CD-databases such as CDDB and FreeDB.
  • Is able to contain images and just about any file you want to include.
  • Supports enciphered information, linked information and weblinks.

使用 Python 读取ID3 信息

我写了一个 Python 脚本可以用来读取 ID3v1 的信息。实际操作过程中发现两个问题: 1、ID3v1的信息没有编码字段,所以有的时候同样的Mp3,在不同的系统环境中播放,会显示乱码。针对这个问题,打算再写一篇文章说一下如何探测编码。 2、iTunes应该是优先使用ID3v2的信息

我把脚本放到了 github 上,感兴趣的同学可以通过 https://github.com/cocowool/py-id3 查看。

# Read ID3v1 tag information
import os
import string
import base64
import chardet

def parse(fileObj, version = 'v1'):
fileObj.seek(0,2)
# ID3v1's max length is 128 bytes
if(fileObj.tell() < 128):
return False
fileObj.seek(-128,2)
tag_data = fileObj.read()

if(tag_data[0:3] != b'TAG'):
return False
return getTag(tag_data)

# Detect the encoding and decode
def decodeData(bin_seq):
# print(bin_seq)
result = chardet.detect(bin_seq)
# print(result)
if(result['confidence'] > 0):
try:
return bin_seq.decode(result['encoding'])
except UnicodeDecodeError:
return 'Decode Failed'


# Get ID3v1 tag data
def getTag(tag_data):
# STRIP_CHARS = compat.b(string.whitespace) + b"\x00"
STRIP_CHARS = b"\x00"

tags = {}
tags['title'] = tag_data[3:33].strip(STRIP_CHARS)

if(tags['title']):
tags['title'] = decodeData(tags['title'])

tags['artist'] = tag_data[33:63].strip(STRIP_CHARS)
if(tags['artist']):
tags['artist'] = decodeData(tags['artist'])

tags['album'] = tag_data[63:93].strip(STRIP_CHARS)
if(tags['album']):
tags['album'] = decodeData(tags['album'])

tags['year'] = tag_data[93:97].strip(STRIP_CHARS)
# if(tags['year']):
# tags['year'] = decodeData(tags['year'])

tags['comment'] = tag_data[97:127].strip(STRIP_CHARS)
#@TODO Need to analyze comment to verfiy v1 or v1.1
if(tags['comment']):
tags['comment'] = decodeData(tags['comment'])

tags['genre'] = ord(tag_data[127:128])

return tags

# Set ID3v1 tag data
def setTag():
pass

参考资料: 1、ID3.org

2、Wiki ID3

3、Python open() 函数

4、使用Python读取和写入mp3文件的id3v1信息

5、Python 模块

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏王大锤

iOS中的预编译指令的初步探究

43580
来自专栏PPV课数据科学社区

数据流编程教程:R语言与DataFrame

DataFrame DataFrame 是一个表格或者类似二维数组的结构,它的各行表示一个实例,各列表示一个变量。 一. DataFrame数据流编程 ? 二....

495120
来自专栏walterlv - 吕毅的博客

使用不安全代码将 Bitmap 位图转为 WPF 的 ImageSource 以获得高性能和持续小的内存占用

发布于 2017-11-09 15:25 更新于 2017-11...

9420
来自专栏码生

Swift2转Swift3

接触swift 已经有一年多的时间了,由最初的OC代码转为 swift 代码,然后从 swift 2.3 转为 swift 3。每次的转换都感觉是将项目整个的翻...

17350
来自专栏web前端教室

【蒙圈】自己写的Js,自己不认识了?

但是,下课之前我说,今天的作业,如何如何要求,格式什么样,标明用了多长时间,然后就有同学在学习群里问我,。。原话记不太清了,大概意思就是,自己写的看不明白了,还...

15240
来自专栏章鱼的慢慢技术路

程序员算法时间空间复杂度速查表

21230
来自专栏Python小屋

Python tkinter版猜数游戏

程序启动后,首先需要启动一次游戏并设置数值范围和猜测次数,然后可以猜数并输入,程序会根据实际情况进行大小提示,退出程序时提示战绩,例如共玩几次和成功几次。 im...

41650
来自专栏日常学python

爬取《The Hitchhiker’s Guide to Python!》python进阶书并制成pdf

这是日常学python的第15篇原创文章 前几篇文章我们学习了requests库和正则,还有个urllib库,我上篇文章也用了requests库来教大家去爬那些...

449170
来自专栏小詹同学

爬点重口味的 。

小弟最近在学校无聊的很哪,浏览网页突然看到一张图片,对面的女孩看过来(邪恶的一笑),让人想入非非啊,一看卧槽,左边这妹子彻底赢了,这(**)这么大,还这么漂亮,...

16120
来自专栏祝威廉

Bug剖析篇-"Facebook 60TB+级的Apache Spark应用案例"

Facebook 60TB+级的Apache Spark应用案例,本来上周就准备看的,而且要求自己不能手机看,要在电脑上细细的看。然而终究是各种忙拖到了昨天晚上...

9840

扫码关注云+社区

领取腾讯云代金券