PHP读取MP3文件ID3标签信息

时间:2022-10-24 11:37:15

PHP读取MP3文件ID3标签信息

摘要:该文介绍了MP3文件及ID3标签基本结构以及基于PHP语言对MP3文件ID3标签信息的读取的几种方法。

关键词:MP3;PHP;ID3

中图分类号:TP317.4文献标识码:A文章编号:1009-3044(2008)35-2184-04

Use PHP to Read MP3 Files ID3 Tag Information

SHEN Yu-bao1,2

(1. Hefei University of Technology, Hefei 230009, China; 2. Hefei Nursery Teachers Training School, Hefei 230011, China)

Abstract: In this paper, introduce the basic structure of MP3 files and ID3 tags, as well as several ways of reading MP3 files ID3 tag information by php.

Key words: MP3; PHP; ID3

1 MP3文件

1.1 MP3文件简介

MP3全称是动态影像专家压缩标准音频层面3(Moving Picture Experts Group Audio Layer III)。是当今较流行的一种数字音频编码和有损压缩格式,它设计用来大幅度地降低音频数据量,它是在1991年由位于德国埃尔朗根的研究组织Fraunhofer-Gesellschaft的一组工程师发明和标准化的。

MP3就是一种音频压缩技术,由于这种压缩方式的全称叫MPEG Audio Layer3,所以人们把它简称为MP3。MP3是利用 MPEG Audio Layer 3 的技术,将音乐以 1:10 甚至 1:12 的压缩率,压缩成容量较小的文件,换句话说,能够在音质丢失很小的情况下把文件压缩到更小的程度。而且还非常好的保持了原来的音质。正是因为MP3体积小,音质高的特点使得MP3格式几乎成为网上音乐的代名词。每分钟音乐的MP3格式只有1MB左右大小,这样每首歌的大小只有3-4兆字节。使用MP3播放器对MP3文件进行实时的解压缩(解码),这样,高品质的MP3音乐就播放出来了。MP3文件格式也是当今互联网上最常见的音频文件格式。

2 MP3文件ID3标签信息及其格式

2.1 ID3简介

ID3标签是MP3音乐档案中的歌曲附加信息,它能够在MP3中附加曲子的演出者、作者以及其它类别资讯,方便众多乐曲的管理。缺少ID3标签并不会影响 MP3的播放,但若没有的话,管理音乐文件也会相当的麻烦。

ID3,一般是位于一个MP3文件的开头或末尾的若干字节内,附加了关于该MP3的歌手,标题,专辑名称,年代,风格等信息,该信息就被称为ID3信息,ID3信息分为两个版本,v1和v2版。

其中:v1版的ID3在MP3文件的末尾128字节,以TAG三个字符开头,后面跟上歌曲信息。

v2版一般位于MP3的开头,可以存储歌词,该专辑的图片等大容量的信息。

此外,ID3也就是ID3Tags,其中的“Tag”在英文中名词的一个意思是“标签”,所以“ID3Tags”也就是“MP3文件曲目标签”的意思。有些地方以“ID3”这样的简称来代表“ID3Tags”,二者本质是一样的。

2.2 ID3格式

ID3V1比较简单,它是存放在MP3文件的末尾,用16进制的编辑器打开一个MP3文件,查看其末尾的128个顺序存放字节,数据结构定义如下:

char Header[3];/*标签头必须是"TAG"否则认为没有标签*/

char Title[30];/*标题*/

char Artist[30]; /*作者*/

char Album[30];/*专集*/

char Year[4];/*出品年代*/

char Comment[30];/*备注*/

char Genre;/*类型*/

ID3V1的各项信息都是顺序存放,没有任何标识将其分开,比如标题信息不足30个字节,则使用'\0'补足,否则将造成信息错误。

ID3V2到现在一共有4个版本,但流行的播放软件一般只支持第3版,既ID3v2.3。由于ID3V1记录在MP3文件的末尾,ID3V2就只好记录在MP3文件的首部了。也正是由于这个原因,对ID3V2的操作比ID3V1要慢。而且ID3V2结构比ID3V1的结构要复杂得多,但比前者全面且可以伸缩和扩展。

例如ID3V2.3:每个ID3V2.3的标签都一个标签头和若干个标签帧或一个扩展标签头组成。关于曲目的信息如标题、作者等都存放在不同的标签帧中,扩展标签头和标签帧并不是必要的,但每个标签至少要有一个标签帧。标签头和标签帧一起顺序存放在MP3文件的首部。这里由于篇幅限制,详细介绍可以参见网站。

3 使用PHP读取MP3文件ID3标签信息

下面只针对MP3的ID3v1进行了讨论由于在现实应用中,本例以读取id3v1为例,php最大优势就是开源,同样对于MP3文件ID3标签信息读取,我们同样可以采取开源。

3.1 利用pear库中MP3_ID类读取ID3标签信息

PEAR(PHP Extension and Application Repository)由Stig S. Bakken于2000年在PHP开发者会议(PHP Developers' Meeting, PDM) 上提出,目的是实做可以重复使用的函式库来提供PHP社群使用。在今天,有PEAR这个由全世界众多顶尖的PHP高手所共同生a的智慧结晶,可以让我们轻松又有效率地撰写代码,并且克服许多撰写上的困难。在许多方面如:图片处理类(IMAGE)、XML类(XML)、数学类(MATH)等许多方面有着成熟的代码,在读取MP3ID3标签信息有一个Id.php类,具体使用代码如下:

require_once("MP3/Id.php"); //引用pear类中Id.php开源代码

$file = "beijing.MP3";//读取MP3文件名称

$id3 = &new MP3_Id(); //新建类

$id3->read($file);//读取id3v1

print_r($id3);//输出id3v1结果

?>

执行结果如图1所示:

图1

3.2 利用getid3读取ID3标签信息

getid3是一套脚本从各种多媒体文件中读写有用的信息,它支持多种格式,如id3v1, id3v2, ogg, mpc, avi, Lyrics3等,支持媒体格式且支持目录的读取。

主页为:/ 可以免费下载使用。读取代码如下:

require_once('../getid3/getid3/getid3.php');

$filename="beijing.MP3";

$getID3 = new getID3;

$ThisFileInfo = $getID3->analyze($filename);

getid3_lib::CopyTagsToComments($ThisFileInfo);

print_r($ThisFileInfo);

?>

执行结果部分如图2所示:

图2

3.3 编写PHP代码读取ID3信息

$genres = Array('Blues','Classic Rock','Country','Dance','Disco','Funk',

'Grunge','Hip-Hop','Jazz' ......)//设置类型数组部分代码略

$genreids = Array("Blues" => 0,"Classic Rock" => 1,"Country" => 2,"Dance" => 3,

"Disco" => 4, ......)//设置类型数组部分代码略

$version=Array("00"=>2.5, "10"=>2, "11"=>1);//id3版本

$layer=Array("01"=>3, "10"=>2, "11"=>1);//音频采用压缩技术

$crc=Array("Yes", "No");

$bitrate["0001"]=Array(32,32,32,32,8,8);

$bitrate["0010"]=Array(64,48,40,48,16,16);

$bitrate["0011"]=Array(96,56,48,56,24,24);

$bitrate["0100"]=Array(128,64,56,64,32,32);

$bitrate["0101"]=Array(160,80,64,80,40,40);

$bitrate["0110"]=Array(192,96,80,96,48,48);

$bitrate["0111"]=Array(224,112,96,112,56,56);

$bitrate["1000"]=Array(256,128,112,128,64,64);

$bitrate["1001"]=Array(288,160,128,144,80,80);

$bitrate["1010"]=Array(320,192,160,160,96,96);

$bitrate["1011"]=Array(352,224,192,176,112,112);

$bitrate["1100"]=Array(384,256,224,192,128,128);

$bitrate["1101"]=Array(416,320,256,224,144,144);

$bitrate["1110"]=Array(448,384,320,256,160,160);

$bitindex=Array("1111"=>"0","1110"=>"1","1101"=>"2",

"1011"=>"3","1010"=>"4","1001"=>"5","0011"=>"3","0010"=>4,"0001"=>"5");

$freq["00"]=Array("11"=>44100,"10"=>22050,"00"=>11025);

$freq["01"]=Array("11"=>48000,"10"=>24000,"00"=>12000);

$freq["10"]=Array("11"=>32000,"10"=>16000,"00"=>8000);

$mode=Array("00"=>"Stereo","01"=>"Jointstereo","10"=>"Dual channel","11"=>"Mono");

$copy=Array("No","Yes");

function strip_nulls( $str ) {

$res = explode( chr(0), $str );

return chop( $res[0] );}

function MP3_id($file) {

global $version, $layer, $crc, $bitrate, $bitindex, $freq, $mode, $copy, $genres;//设置全局变量

if(!$f=@fopen($file, "r")) { return -1; break; } else {

$tmp=fread($f,4);

if($tmp=="RIFF") {

$idtag["ftype"]="Wave";

fseek($f, 0);

$tmp=fread($f,128);

$x=StrPos($tmp, "data");

fseek($f, $x+8);

$tmp=fread($f,4);}

for($y=0;$y

$x=decbin(ord($tmp[$y]));

for($i=0;$i

$bajt.=$x;}

if(substr($bajt,1,11)!="11111111111") {

fseek($f, 4);

$tmp=fread($f,2048);

for($i=0;$i

if(ord($tmp[$i])==255 && substr(decbin(ord($tmp[$i+1])),0,3)=="111") {

$tmp=substr($tmp, $i,4);

$bajt="";

for($y=0;$y

$x=decbin(ord($tmp[$y]));

for($i=0;$i

$bajt.=$x;}

break;}}}

if($bajt=="") {

return -1;

break;}

$len=filesize($file);//取得文件大小

$idtag["version"]=$version[substr($bajt,11,2)]; //取得ID标签版本

$idtag["layer"]=$layer[substr($bajt,13,2)];

$idtag["crc"]=$crc[$bajt[15]];

$idtag["bitrate"]=$bitrate[substr($bajt,16,4)][$bitindex[substr($bajt,11,4)]];

$idtag["frequency"]=$freq[substr($bajt,20,2)][substr($bajt,11,2)];

$idtag["padding"]=$copy[$bajt[22]];

$idtag["mode"]=$mode[substr($bajt,24,2)];

$idtag["copyright"]=$copy[$bajt[28]];

$idtag["original"]=$copy[$bajt[29]];

//取得文件存储大小

if($idtag["layer"]==1) { $fsize=(12*($idtag["bitrate"]*1000)/$idtag["frequency"]+$idtag["padding"])*4; }

else { $fsize=144*(($idtag["bitrate"]*1000)/$idtag["frequency"]+$idtag["padding"]);}

$idtag["lenght_sec"] = @round($len/Round($fsize)/38.37);

$idtag["length"]=(Round($fsize))? @date("i:s",round($len/Round($fsize)/38.37)) : 0;

if(!$len) $len=filesize($file);

fseek($f, $len-128);

$tag = fread($f, 128);

if(Substr($tag,0,3)=="TAG") {

$idtag["file"]=$file;

$idtag["tag"]=-1;

$idtag["title"]=strip_nulls( Substr($tag,3,30) );

$idtag["artist"]=strip_nulls( Substr($tag,33,30) );

$idtag["album"]=strip_nulls( Substr($tag,63,30) );

$idtag["year"]=strip_nulls( Substr($tag,93,4) );

$idtag["comment"]=strip_nulls( Substr($tag,97,30) );

if (strlen( $idtag["comment"]) < 29 ) {

if (Ord(Substr($tag,125,1)) == chr(0)) // If char 125 is null then track (maybe) is present

$idtag["track"]=Ord(Substr($tag,126,1));

else $idtag["track"]=0;

} else { // If the comment is 29 or 30 chars long, there's no way to put track #

$idtag["track"]=0;}

$idtag["genreid"]=Ord(Substr($tag,127,1));

$idtag["genre"]=$genres[$idtag["genreid"]];

$idtag["filesize"]=$len;

} else {

$idtag["tag"]=0;}

if(!$idtag["title"]) {

$idtag["title"]=Str_replace("\\","/", $file);

$idtag["title"]=substr($idtag["title"],strrpos($idtag["title"],"/")+1, 255);}

fclose($f); //关闭文件

return $idtag;//返回参数

}}

print_r(MP3_id("beijing.MP3")); //输出MP3_id信息

?>

执行结果如图3所示:

4 总结

以上程序代码在Apache2.0 + Windows XP + PHP5环境下测试通过,利用pear库中MP3_ID类和getid3开源不仅仅可以读取ID3标签信息、也可以对其信息进行写入,getid3可以进行目录的读取,同时也支持多种音频文件格式,甚至可以自动读取数据写入到MYSQL数据库中,其应用有很大挖掘潜力,但是其对中文编码的支持存在一定的缺陷,希望本文能够对音频点播等应用方面具有一定积极的意义。

参考文献:

[1] Davis M E,Pblilips J A. Learning PHP & MySQL[M]. 北京:中国电力出版社,2007.

上一篇:一种基于SAT的FPGA映射优化算法 下一篇:基于第二代端口VLAN技术的交换机管理