我该如何从mp3文件中提取音频数据?

3
我需要创建一个元数据无关的mp3文件哈希(即在重新标记后可以计算相同的哈希)。如何仅将音频数据提取到内存中,而不实际通过解压器运行它?
MAD似乎是一个很好的起点 - http://www.underbit.com/products/mad/,但似乎没有明显暴露用于此操作的函数。
任何指针都将不胜感激!
6个回答

6

如何仅将音频数据提取到内存中,而不实际通过解压缩器运行它?

你无法在不解压缩的情况下提取音频数据 - 它已经被压缩了!但是,如果你只想要原始压缩流,请继续阅读!

典型的mp3音频文件将被分成几个部分:
[可能是元标签]
[可能是垃圾]
[可能是XING/LAME标签 [可能还有更多垃圾]]
[mp3音频帧]
[可能是元标签]

可能是元标签:大多数mp3音频文件的开头都会有id3标签。请注意,一些用户可能会使用不同的标记格式(例如APE),因此你需要考虑到这一点。

可能是垃圾信息:一些mp3音频文件经过多次标记、重新标记和转换,元标记头可能无法提供第一个音频帧的准确偏移量,因为之前标记的残留物可能会留下来。foobar2000有一个选项可以解决这个问题。

可能是XING/LAME标签:它们包含在mp3音频帧中,但不包含实际的音频。madplay有代码可以显示如何读取和解析这些帧。XING/LAME头可能有一个帧计数,因此值得解析这些头。同样,如果文件经历了许多不同的标记器和编辑器,则可能会在这里找到几个格式不正确、无效的音频帧。

MP3音频帧:实际的压缩流,分成“帧”。每个帧都以同步位模式0xFFE开头。

可能是元标记:在文件末尾发现更多的元标记并不罕见。id3v1、APE、歌词都可以在这里找到。

为了找到音频帧的偏移量,你需要解析任何元标头,然后开始寻找同步位模式。你不能从文件开头开始寻找同步模式,因为并不是所有标签支持unsynchronization,所以元标头本身可能包含0xFFE模式。
一旦你有了第一个音频帧的偏移量,你应该查看文件末尾并计算出那里有多少非音频数据,这样你就知道何时停止解析音频。一旦你有了音频数据的起始偏移量和结束偏移量,你就可以通过哈希/校验和函数传递音频数据!

3
你可以使用ffmpeg通过复制模式直接访问音频内容。无论格式如何,API都会给你一个包含原始数据的容器(仅在复制模式下)。如果您有视频或想处理解码后的音频数据,您还可以进行分离和解码。
请查看ffmpeg的示例,快速了解如何执行此操作。使用ffmpeg时,我的意思是不要使用工具,而是从c++/c中使用libffmpeg(libavformat,libavcodec)。尽管我认为如果您是Unix用户,也可以使用ffmpeg工具将输出发送到stdout并将其pipe到md5sum或类似的东西。
特殊情况“-acodec copy”告诉ffmpeg使用与解码所使用的相同编解码器进行编码。换句话说,音频不进行转码。

2
什么样的音频数据?原始解码的PCM流?单个MP3帧?如果它是封装在.wav中的MP3,那怎么办?它仍然可能有一个.mp3扩展名,但是周围有完整的.wav包装器。
删除ID3v1标签很简单-它只是文件末尾的128字节。ID3v2则稍微困难一些-它的长度可变,并且预先放置在MP3的开头,您需要解析出长度字段(其中4个字节仅使用最低7位,为标签提供28位最大长度)。.wav包装器则更加困难-我不知道.wav强加的元数据的任何细节。

哦,我甚至没有考虑过MP3可能在.wav包装器中...我想要提取单独的MP3帧。那样就可以去掉id3 v1和v2标签,所以我应该能够得到一个与标签无关的哈希值...对吗? - Jeff
很久以前,我曾尝试过编写一个mp3解码器,甚至还获取了文件的ISO规范副本...有太多小细节需要考虑...除此之外,mp3可以与mpeg视频交错 - mp3格式被设计为可以轻松嵌入到几乎任何东西中,这使得非常难以确定mp3音频帧的确切位置。 - Marc B
我购买了一台Sony数字录音机。我可以在Linux下挂载文件系统,但我还没有找到它存储轨道标记的位置。id3v2向我显示,我的一个mp3录音包含一个2756字节的GEOB帧。在添加轨道标记之前和之后,我想提取这个帧,看看我的轨道标记是否隐藏在这里。因此,我想再次投票支持一个解答,它解释了如何提取特定的帧,而不仅仅是音频帧。 - Allan Stokes

2

ffmpeg可以单独计算音频文件的音频片段的MD5哈希值,即不包括元数据。

使用方法:

ffmpeg -v -i $file -acodec copy -f md5 -

请注意,FLAC已经将MD5哈希存储为元数据。

1
我最近也需要解决这个问题(检测具有不同ID3标签的重复mp3文件)。最简单的方法是使用ffmpeg制作一个剥离了所有ID3标签的mp3文件的副本,然后对其进行md5校验。请参见https://github.com/pepaslabs/mp3md5sum

0
我为一台带有旧的 mp3 播放器的 Linux 系统编写了这个最基本的代码片段,该播放器无法处理标签。现在剩下的只是 mp3 的头文件和数据(按编码输出到标准输出)。你可以使用它计算 md5。
#include <fcntl.h>
#define DUMPTAGS
int main(int argc, char **argv){
   unsigned char buf[4096];
   int len,fd = open(argv[1],O_RDONLY);
   while (len=read(fd,buf,10)){ // handle ID3v2 tags (maybe multiple)
      if (buf[0]=='I' && buf[1]=='D' && buf[2]=='3'){
         len=read(fd,buf,buf[9]|(buf[8] << 7)|(buf[7] << 14)|(buf[6] << 21));
#ifdef DUMPTAGS
         write(2,buf,len);
#endif
      } else break;
   }
   while (write(1,buf,len)){
      unsigned char tag[3] = {'T','A','G'}, *end;
      len=read(fd,buf,4096);
      end=(unsigned char *)memmem(buf,len,&tag,3);
      if (end){ //handle ID3v1 tag (should only be 1)
         write(1,buf,end-buf);
#ifdef DUMPTAGS
         write(2,end,len-(end-buf));
#endif
         break;
      }
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接