如何从Mp3里读取ID3 tag Ver2(50分)

  • 主题发起人 主题发起人 wukw
  • 开始时间 开始时间
W

wukw

Unregistered / Unconfirmed
GUEST, unregistred user!
如何从Mp3里读取ID3 tag Ver2,本人急需。有肯赐教者,请发送邮件到
wukw@263.net.cn
将不胜感谢。
 
用这个控件试试:
http://www.playicq.com/dispdoc.php?t=&id=943
 
多谢楼上的兄弟,其实我是用VC的,Delphi的用不上。
而且是读取ID3 tag Ver2没法搞定,读取ID3 tag Ver1已经完全搞定了。

感觉分数给的太少了,兄弟们帮忙,分数小弟一定加!
 
既然你用c,为什么不看看linux下的mp3播放器(如xmms)的源代码,我想你需要的东西
肯定都在里面了.
 
这里有你想要的Delphi程序代码:
http://www.dv.co.yu/mpgscript/download.htm
 
看看sourceforge的开放源码项目,很多东西人家都已经做了,没必要重复工作:

Edit MP3 ID3 and Ogg tags easily. Create support files for audiobook NFO,
SFV, PAR, M3U. Test file base on SFV and PAR.

http://sourceforge.net/projects/mp3bookhelper/
 
要C代码? 这是delphi版吧?
如果没有现成的,直接把ID3v2.pas转成C就行了,几百行代码,很快就转过去了。
 
兄弟们,我找到Delphi版的答案了:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1476517

哪位大侠愿意和我一起把TID3V2的代码翻译成C++的语法??(我不懂Delphi,对C++还可以)
这段看上去很长,其实去掉变量声明,实际也不长。

如果愿意,请尽快与我联系:
QQ:76628305
Msn:nevergrief@hotmail.com
拜托了!
 
C++版本的代码:
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/massid3lib/mp3tagtools/
 
做个标记,以后用得着。
 
to xianjun
感谢您提供的网址,可是那个网址上面,有无数的.h和.cpp文件,居然只能一个个下载。我试了几个,看着名字像ID3V2的class,结果都不行(都包含了其他一堆.h文件,也没找到涉及核心读取数据部分的代码)。
因为着急,所以硬着头皮,花了整整4个小时(打字累得都想吐血),把ID3v2.pas代码写成了C++文件。
可是我不懂Delphi,所以只是初步翻译,里面有无数的错误。有些Delphi的语法我也看不懂。
大哥,您能帮我改一下吗?看您有40000多专家分,一定是大侠了。

求求您,帮忙改一下。我打那么多翻译的源代码,知道根本不可能使用的,只是为了让帮助我的人不用辛苦打那么多C++的源代码。
如果愿意,请尽快与我联系:
QQ:76628305
Msn:nevergrief@hotmail.com
拜托了!
 
这主要是头文件的内容,帮忙看看有没有错:
CID3V2Info();
virtual ~CID3V2Info();

void FSetTitle(const CString NewTitle);
void FSetArtist(const CString NewArtist);
void FSetAlbum(const CString NewAlbum);
void FSetTrack(const WORD NewTrack);

void FSetTrackString(const CString NewTrack);
void FSetYear(const CString NewYear);
void FSetGenre(const CString NewGenre);
void FSetComment(const CString NewComment);
void FSetComposer(const CString NewComposer);
void FSetEncoder(const CString NewEncoder);
void FSetCopyright(const CString NewCopyright);
void FSetLanguage(const CString NewLanguage);
void FSetLink(const CString NewLink);
BOOL ProcessRead(CFile &SourceFile);

BOOL ReadFromFile(const CString FileName);
BOOL ReadFromFile(CFile &SourceFile);
BOOL SaveToFile(const CString FileName);
BOOL RemoveFromFile(const CString FileName);

/****************************************************/
BOOL IsExist();
BYTE GetVersion();
Int GetFileSize();

void SetSongTitle(const CString&
strTitle);
CString GetSongTitle();

void SetSongArtist(const CString&
strArtist);
CString GetSongArtist();

CString GetAlbum();
BOOL SetAlbum(const CString&
strAlbum);

Word GetTrack();
void SetTrack(const Word wTrack);

CString GetTrackString();

CString GetYesr();
void SetYear(const CString&
strYear);

CString GetGenre();
void SetGenre(const CString&
strGenre);

CString GetComment();
void SetComment(const CString&
strComment);

CString GetComposer();
void SetComposer(const CString&
strComposer);

CString GetEncoder();
void SetEncoder(const CString&
strEncoder);

CString GetCopyright();
BOOL SetCopyright(const CString&
strCopyright);

CString GetLanguage();
void SetLanguage(const CString&
strLanguage);


CString GetLink();
void SetLink(const CString&
strLink);


private:
BOOL FExists;
byte FVersionID;
int FSize;
CString FTitle;
CString FArtist;
CString FAlbum;
WORD FTrack;
CString FTrackString;
CString FYear;
CString FGenre;
CString FComment;
CString FComposer;
CString FEncoder;
CString FCopyright;
CString FLanguage;
CString Flink;

};
 
这是主体文件(里面包含有无数错误)
BOOL ReadHeader(CFile &SourceFile, TagInfo Tag);
{
int Transferred;

// Result = TRUE;
Seek(SourceFile, 0);
// Read header and get file size
BlockRead(SourceFile, Tag, 10, Transferred);
Tag.Filesize = Filesize(SourceFile);
if (Transferred<9) // warning!!!
{
// Result = FALSE;
return TRUE;
}
return FALSE;
}

BOOL ReadHeader(const CString FileName, TagInfo &amp;Tag)
{
// Set read-access and open file
CFile SourceFile;
AssignFile(SourceFile, FileName);
FileMode = 0;
Reset(SourceFile, 1);
// Read header and get file size
BOOL Result = ReadHeader(SourceFile, Tag);
CloseFile(SourceFile);
return Result;
}

int GetTagSize(const TagInfo &amp;Tag)
{
// Get total tag size
int Result =
Tag.Size[1] * 0x200000 +
Tag.Size[2] * 0x4000 +
Tag.Size[3] * 0x80 +
Tag.Size[4] + 10;
if (Result>Tag.Filesize)
{
Result = 0;
}
return Result;
}

void SetTagItem(const ID, CString Data, TagInfo &amp;Tag)
{
byte Iterator;
CString FrameID;
for (Iterator=1;
ID3V2_FRAME_COUNT;
)
{
if (Tag.Version>TAG_VERSION_2_2)
FrameID = ID3V2_FRAME_NEW[Iterator];
else

FrameID = ID3V2_FRAME_OLD[Iterator];
if (FrameID==ID &amp;&amp;
Data[1]<=UNICODE_ID)
Tag.Frame[Iterator] = Data;
}
}

int Swap32(const int Figure)
{
byte[4] ByteArray;
// swap 4 bytes
int Result =
ByteArray[0] * 0x1000000 +
ByteArray[1] * 0x10000 +
ByteArray[2] * 0x100 +
ByteArray[3];

return Result;

}

void ReadFramesNewSlow(CFile &amp;SourceFile, TagInfo &amp;Tag)
{
FrameHeaderNew Frame;
char[500] Data;
int DataPosition, DataSize;
// Get information from frames (ID3v2.3.x &amp;
ID3v2.4.x)
Seek(SourceFile, 10);
while( FilePos(SourceFile)<GetTagSize(Tag)) &amp;&amp;
!(SourceFile)) //do
n't know how to translate
{
FillChar(Data, sizeof(Data), 0);
// Read frame header and check frame ID
if (!(Frame.ID[1]>'A' &amp;&amp;
Frame.ID[1]<'Z'))
break;
// Note data position and determine significant data size
DataPositon = FilePos(SourceFile);
if (Swap32(Frame.Size)>sizeof(Data))
DataSize = sizeof(Data);
else

DataSize = Swap32(Frame.Size);
// Read frame data and set tag item if frame supported
BlockRead(Source, Data, DataSize);
SetTagItem(Frame.ID, Data, Tag);
Seek(SourceFile, DataPosition + Swap(Frame.Size));
}
}
// {orig Read ID3v2 2600 files, 50 folders, 1.302 sec, 0.0005008 sec/per file}
// {buff Read ID3v2 2600 files, 50 folders, 1.252 sec, 0.0004815 sec/per file}
void ReadFramesNew(CFile &amp;SourceFile, TagInfo &amp;Tag)
{
FrameHeaderNew Frame;
char[500] Data;
int DataSize;
int tagSIZE, AmtTransferred;
char* Buffer;
int BufferPos;
char* Bptr;

tagSIZE = GetTagSize(Tag);
Buffer = AllocMem(tagSIZE);
// Get information from frames (ID3v2.3.x &amp;
ID3v2.4.x)
Seek(SourceFile, 10)
BlockRead(SourceFile, Buffer, tagSIZE, AmtTransferred);
if (tagSIZE!=AmtTransferred)
ReadFramesNewSlow(SourceFile, Tag);
else
{
BufferPos = 0;
while (BufferPos <tagSIZE &amp;&amp;
BufferPos<AmtTransferred)
{
FillChar(Data, sizeof(Data), 0);
Bptr = Buffer + BufferPos;
// Read frame header and check frame ID
Move(Bptr^, Frame, 10);
Bptr = Buffer + BuffePos + 10;
if (!(Frame.ID[0]>'A' &amp;&amp;
(Frame.ID[0]<'Z'))
break;
// Note data position and determine significant data size
if (Swap32(Frame.Size)>sizeof(Data)
DataSize = sizeof(Data);
else

DataSize = Swap32(Frame.Size);
// Read frame data and set tag item if frame supported
memcpy(Bptr, Data, DataSize);
SetTagItem(Frame.ID, Data, Tag);
Inc(BufferPos, 10+Swap32(Frame.Size));
}
}
FreeMem(Buffer);
}

void ReadFramesOld(CFile &amp;SourceFile, TagInfo &amp;Tag)
{
FrameHeaderOld Frame;
char Data[500];
int DataPosition, FrameSize, DataSize;
// Get information from frames (ID3v2.2.x)
Seek(SourceFile, 10);
while ( FilePos(SourceFile)<GetTagSize(Tag) &amp;&amp;
(!EOF(SourceFile)) //do
n't know how to translate
{
FillChar(Data, sizeof(Data), 0);
// Read frame header and check frame ID
BlockRead(Source, Frame, 6);
if (!(Frame.ID[0]>'A' &amp;&amp;
Frame.ID[0]<'Z'))
break;
// Note data position and determine significant data size
DataPosition = FilePos(SourceFile);
FrameSize = Frame.Size[0]<<16 + Frame.Size[1]<<8 + Frame.Size[3];
if (FrameSize>sizeof(Data))
DataSize = sizeof(Data);
else

DataSize = FrameSize;
// Read frame data and set tag item if frame supported
BlockRead(SourceFile, Data, DataSize);
SetTagItem(Frame.ID, Data, Tag);
Seek(SourceFile, DataPosition+FrameSize);
}
}

CString GetANSI(const CString &amp;Source)
{
int Index;
byte FirstByte, SecondByte;
TChar UnicodeChar;

// Convert string from unicode if needed and trim spaces
if (strlen(Source)>0 &amp;&amp;
Source[0] = UNICODE_ID)
{
result = "";
for (Index=1;
Index<(strlen(Source)-1)/2 ;
Index++)
{
FirstByte = Ord(Source[Index*2]);
SecondByte = Ord(Source[Index*2+1]);
UnicodeChar = WideChar(FirstByte || (Seconde<<8));
if (UnicodeChar=0)
break;
if (FirstByte<0xFF)
Result = Result + UnicodeChar;
}
Result.TrimLeft();
Result.TrimRight();
}
else
{
Source.TrimLeft();
Source.TrimRight();
}
}

CString GetContent(const CString Content1, const CString Content2)
{
// Get content preferring the first content
Result = GetANSI(Content1);
if (Result=="")
GetANSI(Content2);
}

WORD ExtractTrack(const CString TrackString)
{
CString Track;
int Index, Value, Code;
// Extract track from string
Track = GetANSI(TrackString);
// Extract track from string like [02/20]
Index = Track.Find('/');
// vlads fix: Extract track from string like [02 of 20]
if (Index ==0)
Val(Track, Value, Code)
else

Val(Copy(Track, 1, Index-1), Value, Code);
if (Code==0)
Result = Value;
else

Result = 0;
}

CString ExtractYear(const CString YearString, const CString DataString)
{
// Extract year from strings
Result = GetANSI(YearString);
if (Result=="")
Result = GetANSI(DataString).Mid(0, 4);
}

CString ExtractGenre(const CString GenreString)
{
// Extract genre from string
Result = GetANSI(GenreString);
if (Result.Find(')')>0)
Delete(Result, 1, LastDelimiter(')', Result));
// 不会翻译,照抄
}

CString ExtractText(const CString SourceString, BOOL LanguageID)
{
CString Source, Separator;
char EncodingID;
// Extract significant text data from a complex field
Source = SourceString;
Result = "";
if (Source.GetLength()>0)
{
EncodingID = Source[0];
if (EncodingID==UNICODE_ID)
Separator = #0#0l;
else

Separator = #0;
if (LanguageID)
Delete(Source, 1, 4);
else

Delete(Source, 1, 4);
Delete(Source, 1, Pos(Separator, Source) + Length(Separator) - 1);
// 不会翻译,照抄
Result = GetANSI(EncodingID + Source);
}
}

void BuildHeader(TagInfo &amp;Tag)
{
int Iterator, tagSIZE;
// Calculate new tag size (without padding)
tagSIZE = 10;
for (Iterator=1;
Iterator<ID3V2_FRAME_COUNT ;
Iterator++ )
if (Tag.Frame[Interator]!="")
Inc(tagSIZE, Tag.Frame[Iterator].GetLength()+ 11);
// Check for ability to change existing tag
Tag.NeedRewrite =
(Tag.ID != ID3V2_ID) ||
(GetTagSize(Tag) < tagSIZE) ||
(GetTagSize(Tag) > ID3V2_MAX_SIZE);
// Calculate padding size and set padded tag size
if (Tag.NeedRewrite)
Tag.PaddingSize = ID3V2_MAX_SIZE - tagSIZE;
else

Tag.PaddingSize = GetTagSize(Tag) - tagSIZE;
Inc(tagSIZE, Tag.PaddingSize);
// Build tag header
Tag.ID = ID3V2_ID;
Tag.Version = TAG_VERSION_2_3;
Tag.Revision = 0;
Tag.Flags = 0;
// Convert tag size
for (Iterator=1;
Iterator<=4;
Iterator++ )
Tag.Size[Iterator] = ((tagSIZE-10) << ((4-Iterator)) &amp;
0x7F;
}

function ReplaceTag(const FileName: string;
TagData: TStream): Boolean;
// 碰到TStream,不会翻译,整个函数照抄
var
Destination: TFileStream;
begin

{ Replace old tag with new tag data }
Result := False;
if (not FileExistsUnsetReadOnly(FileName)) then

Exit;
try
TagData.Position := 0;
Destination := TFileStream.Create(FileName, fmOpenReadWrite);
Destination.CopyFrom(TagData, TagData.Size);
Destination.Free;
Result := True;
except
{ Access error }
end;

end;


function RebuildFile(const FileName: string;
TagData: TStream): Boolean;
// 碰到TStream,不会翻译,整个函数照抄
var
Tag: TagInfo;
Source, Destination: TFileStream;
BufferName: string;
begin

{ Rebuild file with old file data and new tag data (optional) }
Result := False;
if (not FileExistsUnsetReadOnly(FileName)) then

Exit;
if not ReadHeader(FileName, Tag) then

Exit;
if (TagData = nil) and (Tag.ID <> ID3V2_ID) then

Exit;
try
{ Create file streams }
BufferName := FileName + '~';
Source := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
Destination := TFileStream.Create(BufferName, fmCreate);
{ Copy data blocks }
if Tag.ID = ID3V2_ID then

Source.Seek(GetTagSize(Tag), soFrombegin
ning);
if TagData <> nil then

Destination.CopyFrom(TagData, 0);
Destination.CopyFrom(Source, Source.Size - Source.Position);
{ Free resources }
Source.Free;
Destination.Free;
{ Replace old file and delete temporary file }
if (DeleteFile(FileName)) and (RenameFile(BufferName, FileName)) then

Result := True
else

raise Exception.Create('');
except
{ Access error }
if FileExists(BufferName) then

DeleteFile(BufferName);
end;

end;


function SaveTag(const FileName: string;
Tag: TagInfo): Boolean;
// 碰到TStream,不会翻译,整个函数照抄
var
TagData: TStringStream;
Iterator, FrameSize: Integer;
Padding: array[1..ID3V2_MAX_SIZE] of Byte;
begin

{ Build and write tag header and frames to stream }
TagData := TStringStream.Create('');
BuildHeader(Tag);
TagData.Write(Tag, 10);
for Iterator := 1 to ID3V2_FRAME_COUNTdo

if Tag.Frame[Iterator] <> '' then

begin

TagData.WriteString(ID3V2_FRAME_NEW[Iterator]);
FrameSize := Swap32(Length(Tag.Frame[Iterator]) + 1);
TagData.Write(FrameSize, SizeOf(FrameSize));
TagData.WriteString(#0#0#0 + Tag.Frame[Iterator]);
end;

{ Add padding }
FillChar(Padding, SizeOf(Padding), 0);
if Tag.PaddingSize > 0 then

TagData.Write(Padding, Tag.PaddingSize);
{ Rebuild file or replace tag with new tag data }
if Tag.NeedRewrite then

Result := RebuildFile(FileName, TagData)
else

Result := ReplaceTag(FileName, TagData);
TagData.Free;
end;


void FSetTitle(const CString NewTitle)
{
// Set song title
NewTitle.TrimLeft();
NewTitle.TrimRight();
FTitle = NewTitle;
}

void FSetArtist(const CString NewArtist)
{
// Set artist name
NewArtist.TrimLeft();
NewArtist.TrimRight();
FArtist = NewArtist;
}

void FSetAlbum(const CString NewAlbum)
{
// Set album title
NewAlbum.TrimLeft();
NewAlbum.TrimRight();
FAlbum = NewAlbum;
}

void FSetTrack(const WORD NewTrack)
{
// Set track number
// This will set a number value but String would be used when stored
FTrack = NewTrack;
FTrackString.Format("%d", FTrack);
}

void FSetTrackString(const CString NewTrack)
{
// Set track number
FTrackString = NewTrack;
// This will set a number value but Sting would be used when stored
FTrack = ExtractTrack(FTrackString);
}

void FSetYear(const CString NewYear)
{
// Set release year
NewYear.TrimLeft();
NewYear.TrimRight();
FYear = NewYear;
}

void FSetGenre(const CString NewGenre)
{
// Set genre name
NewGenre.TrimLeft();
NewGenre.TrimRight();
FGenre = NewGenre;
}

void FSetComment(const CString NewComment)
{
// Set comment
NewComment.TrimLeft();
NewComment.TrimRight();
FComment = NewComment;
}

void FSetComposer(const CString NewComposer)
{
// Set composer name
NewComposer.TrimLeft();
NewComposer.TrimRight();
FComposer = NewComposer;
}

void FSetEncoder(const CString NewEncoder)
{
// Set encoder name
NewEncoder.TrimLeft();
NewEncoder.TrimRight();
FEncoder = NewEncoder;
}

void FSetLanguage(const CString NewLanguage)
{
// Set language
NewLanguage.TrimLeft();
NewLanguage.TrimRight();
FLanguage = NewLanguage;
}

void FSetLink(const CString NewLink)
{
// Set URL link
NewLink.TrimLeft();
NewLink.TrimRight();
FLink = NewLink;
}

// {********************** Public functions &amp;
procedures ********************** }
constructor TID3v2.Create;
// 不会翻译,照抄
begin

{ Create object }
inherited;
ResetData;
end;


void ResetData()
{
FExists = FALSE;
FVersionID = 0;
FSize = 0;
FTitle = "";
FArtist = "";
FAlbum = "";
FTrack = 0;
FTrackString = "";
FYear = "";
FGenre = "";
FComment = "";
FComposer = "";
FEncoder = "";
FCopyright = "";
FLanguage = "";
Flink = "";
}

BOOL ReadFromFile(const CString FileName)
{
CFile SourceFile;
// Reset data and load header from file to variable
ResetData();
AssignFile(SourceFile, FileName);
FileMode = 0;
Reset(SourceFile, 1);

Result = ProcessRead(SourceFile);
CloseFile(SourceFile);
}

BOOL ProcessRead(CFile &amp;SourceFile)
{
TagInfo Tag;
Result = ReadHeader(SourceFile, Tag);
// Process data if loaded and header valid
if (Result &amp;&amp;
Tag.ID==ID3V2_ID)
{
FExist = TRUE;
// Fill properties with header data
FVersionID = Tag.Version;
FSize = GetTagSize(Tag);
// Get information from frames if version supported
if ((FVersionID ==TAG_VERSION_2_2 || FVersionID ==TAG_VERSION_2_3 || FVersionID ==TAG_VERSION_2_4) &amp;&amp;
(FSize>0))
{
if (FVersionID>TAG_VERSION_2_2)
ReadFramesNew(SourceFile, Tag);
else

ReadFramesOld(SourceFile, Tag);
FTitle := TruncateToZerro(GetContent(Tag.Frame[1], Tag.Frame[15]));
// 不懂TruncateToZerro是干什么的
FArtist := TruncateToZerro(GetContent(Tag.Frame[2], Tag.Frame[14]));
FAlbum := TruncateToZerro(GetContent(Tag.Frame[3], Tag.Frame[16]));
FTrack := ExtractTrack(Tag.Frame[4]);
FTrackString := TruncateToZerro(GetANSI(Tag.Frame[4]));
FYear := TruncateToZerro(ExtractYear(Tag.Frame[5], Tag.Frame[13]));
FGenre := TruncateToZerro(ExtractGenre(Tag.Frame[6]));
FComment := TruncateToZerro(ExtractText(Tag.Frame[7], True));
FComposer := TruncateToZerro(GetANSI(Tag.Frame[8]));
FEncoder := TruncateToZerro(GetANSI(Tag.Frame[9]));
FCopyright := TruncateToZerro(GetANSI(Tag.Frame[10]));
FLanguage := TruncateToZerro(GetANSI(Tag.Frame[11]));
Flink := TruncateToZerro(ExtractText(Tag.Frame[12], False));
}
}
}

BOOL SaveToFile(const CString FileName)
{
TagInfo Tag;
// Check for existing tag
FillChar(Tag, sizeof(Tag), 0);
ReadHeader(FileName, Tag);
// Prepare tag data and save to file
Tag.Frame[1] = FTitle;
// 在C++里,似乎应该从0开始
Tag.Frame[2] = FArtist;
Tag.Frame[3] = FAlbum;
// vlads fix: Save Track as Sting not as Number
// if FTrack > 0 then
Tag.Frame[4] := IntToStr(FTrack);
Tag.Frame[4] = FTrackString;
Tag.Frame[5] = FYear;
Tag.Frame[6] = FGenre;
if (FComment!="")
Tag.Frame[7] = "eng" + #0 + FComment;
Tag.Frame[8] = FComposer;
Tag.Frame[9] = FEncoder;
Tag.Frame[10] = FCopyright;
Tag.Frame[11] = FLanguage;
if (FLink!="")
Tag.Frame[12] = #0 + Flink;
Result = SaveTag(FileName, Tag);
}

BOOL RemoveFromFile(const CString FileName)
{
// Remove tag from file
Result = RebuildFile(FileName, NULL);
}
 
做完了整个Class,我一定把它放在网上造福天下苍生,不要都像我这么傻~~~
 
首先,真是不好意思,没有把下载页面贴出来:
http://sourceforge.net/project/showfiles.php?group_id=35632&amp;release_id=63231
里面有两个,一个是 Mp3 Tag Tools,一是massid3lib
我下载来看了,是可以使用的
你先看看吧,如果实在不行我再帮你翻译那个PAS文件好了。 [:)]
 
http://www.id3.org/

有文档,有代码
 
有没有人知道OGG的TAG 信息怎么写!!!!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部