使用 Delphi 7 从 MP3 文件中删除或编辑 ID3Tag 版本 2

Posted

技术标签:

【中文标题】使用 Delphi 7 从 MP3 文件中删除或编辑 ID3Tag 版本 2【英文标题】:Remove or edit ID3Tag version 2 from MP3 file using Delphi 7 【发布时间】:2013-01-03 21:18:04 【问题描述】:

我正在使用旧的 MPGTools 和自己的在我的 MP3 文件中设置 ID3 标签的简单方法。但是这两种方法都太旧了,无法支持 ID3Tag 版本 2。我正在寻找任何解决方案,允许我的应用程序(用 Delphi 7 编写)从它处理的每个文件中删除 ID3Tag 或将其设置为与 ID3Tag 完全相同的值版本 1 已设置。

目前我正在手动删除 ID3Tagv2,使用 Winamp 中的快速键盘组合。

我不使用 v2 或专辑封面或所有这些“新”添加,因此我只需要摆脱 ID3Tagv2(如果它存在于特定文件中)的最快方法。

当然,我曾尝试使用 Google 搜索互联网,但要么我遇到了糟糕的一天,要么我问错了问题,因为我在上述问题上得到的所有结果都是来自搜索引擎的虚假结果Software Informer 等窃取者。

【问题讨论】:

【参考方案1】:

碰巧,我坐在这里的一个项目正在等待完成(大约 80%,当谈到 Delphi 时,我更像是一个业余爱好者,并且有更多紧迫的事情出现,然后我找到了一个我能够完成的程序完全符合我的要求的下载)是一个完整的 MP3 文件的 ID3 标签编辑器。虽然 v1 超级简单,但 v2 更难。您可以参考standard document for v2.3 here。 但我将仅限于这里提到的几点。

您可能需要 ID3v2 标记,具体取决于应用程序。我的便携式 MP3 播放器只接受 v2 标签,这就是促使我首先做这个项目的原因。

ID3v2 标签以可变长度方式写入文件的开头,其中可能存在或不存在可变数量的标签。幸运的是,如果是 ID3v2 标记文件,则数据的全长应该在第一条记录中。因此,读取文件找到ID3v2数据的长度,然后重写没有ID3v2数据的文件并删除标签。在一开始就拥有数据使得这很有必要,而且确实令人沮丧。我将来对代码所做的任何事情都将涉及尝试更改数据。下面是一些非常脏的代码,AFAIR 工作,但如果你使用,你将需要清理(我相信这里的一些内容会满足于准确指出我应该如何)。但为了确定,好好测试一下。也一定要问我是否遗漏了我复制出来的单元中的任何内容(这是一个 19.3KB 的 pas 文件),您需要:

type
  sarray = array[0..3] of byte;
  psarray = ^sarray;

  ID3v2Header = packed record
     identifier: array[0..2] of char;
     major_version: byte;
     minor_version: byte;
     flags: byte;
     size: DWord;
  end;

 function size_decodeh(insize: DWord): DWord;
    decodes the size headers only, which does not use bit 7 in each byte,
     requires MSB conversion as well 
   var
     outdval: DWord;
     outd, ind: psarray;
     tnext2, pnext2: byte;

   begin
     outdval := 0;
     outd := @outdval;
     ind := @insize;
     tnext2 := ind^[2] shr 1;
     pnext2 := ind^[1] shr 2;

     outd^[0] := ind^[3] or ((ind^[2] and $01) shl 7);
     outd^[1] := tnext2 or ((ind^[1] and $03) shl 6);
     outd^[2] := pnext2 or ((ind^[0] and $07) shl 5);
     outd^[3] := ind^[0] shr 3;
     Result := outdval;
   end;

procedure ID3v2_LoadData(filename: string; var memrec: pointer;
                       var outsize: integer);
   procedure loads ID3v2 data from "filename".  Returns outsize = 0 if
    there is no ID3v2 data 

var
  infile: file;
  v1h: ID3V2Header;
begin
  assign(infile, filename);
  reset(infile, 1);
// read main header to get id3v2 size
  blockread(infile, v1h, sizeof(v1h));
// detect if there is id3v2 data
  if v1h.identifier = 'ID3' then
    begin
      outsize := size_decodeh(v1h.size);
      // read ID3v2 header data
      getmem(memrec, outsize);
      blockread(infile, memrec^, outsize);
      Close(infile);
    end
  else
    outsize := 0;
  end;

 function id3v2_erase(infilestr: string): boolean;
   erase all ID3v2 data.  Data are stored at the beginning of file, so file
    must be rewritten 
   const
     tempfilename = 'TMp@!0X.MP3';
   var
     memrec: pointer;
     outsize, dataread: integer;
     IsID3v2: boolean;
     databuffer: array[1..32768] of byte;
     newfile, origfile: file;
   begin
  // reuse service routine to get information
     Id3v2_loaddata(infilestr, memrec, outsize);
  // is there ID3v2 data?
     if outsize > 0 then
       begin
        // need to clean up after the service routine
         freemem(memrec);
        // get amount of data to erase
        outsize := outsize + sizeof(Id3v2Header);
        writeln('Data to delete is: ', outsize, ' bytes.');
        // now rewrite the file
        AssignFile(origfile, infilestr);
        reset(origfile, 1);
        AssignFile(newfile, tempfilename);
        rewrite(newfile, 1);
        Seek(origfile, outsize);
        repeat
          blockread(origfile, databuffer, sizeof(databuffer), dataread);
          blockwrite(newfile, databuffer, dataread);
        until dataread = 0;
        CloseFile(origfile);
        CloseFile(newfile);
       // rename temp file and delete original
        DeleteFile(infilestr);
        RenameFile(tempfilename, infilestr);
        IsID3v2 := true;
      end
  else
     IsID3v2 := false;
  Result := IsID3v2;
end;

适用于大多数情况的完整编辑功能显然比这更难攀登,但所有细节都在我链接到的那个文档中。希望这对您有所帮助。

【讨论】:

我刚刚重读了这篇文章,发现了许多风格问题(就像我说的,它需要清理很多)。但我对 MP3 进行了快速检查,它起作用了——它的输出的 SHA1 与 Winamp 的输出相同。无论如何,希望它有所帮助。 Glenn1234:我不仅非常惊讶!我只是在寻求建议,从哪里寻找或从哪里开始,你给了我我需要的整个解决方案(不管代码是否 100% 使用最新标准编写)。所以,万分感谢,真的很遗憾,我只能选择一次你的答案。【参考方案2】:

很少有库可以与 ID3V2 一起正常工作。早在 2006 年,我进行了一项大型研究,以找到支持 Delphi 7 的大部分 Id3V2 规范的 Delphi 库。 我找到了这 2 个:

    Audio Tools Library(那一刻是最好的)。我认为它甚至可以用 Unicode 读/写标签。这里是单位Id3V2.pas JVCL 具有使用 Id3V2 标记的组件。但它在 2006 年没有对非 unicode Delphi 的 Unicode 支持。

顺便说一句,如果您还没有使用 JVCL,那么为了获得 Id3V2 支持而安装超过 600 个组件是不值得的。 所以,看看音频工具库

【讨论】:

非常感谢您的回答。是的,音频工具库看起来很酷。我选择了上面的答案(Glenn1234's),因为我是那种喜欢纯代码解决方案而不是即用型库的极客(疯子)。我知道,这违反了标准和良好的编码实践,但这只是我,我能做些什么呢? :] 此外,Glenn1234 的解决方案已经为我准备好了,因为我确实想删除 ID3Tagv2。如果我曾经考虑完整的编辑功能,那么我肯定会更喜欢您的图书馆之一。再次感谢您!

以上是关于使用 Delphi 7 从 MP3 文件中删除或编辑 ID3Tag 版本 2的主要内容,如果未能解决你的问题,请参考以下文章

从 mp3 文件中删除特定频率

Delphi:如何创建具有特定秒数的静音 MP3 文件?

如何防止我的用户从 iPod 中删除 MP3 文件

delphi如何获取文件夹内的MP3文件数量

如何在 Delphi 中播放资源中的 mp3 内容?

MP3/wav 音频文件的持续时间