时间:2022-10-24 11:37:15
摘要:该文介绍了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.