2011-02-15 145 views

回答

2

什么样的音频数据?原始解码的PCM流?个别MP3帧?如果它是封装在.wav中的MP3,会怎样?它仍然可以有一个.mp3扩展名,但是它有完整的.wav包装。

剥离ID3v1标签很简单 - 它只是在文件末尾128个字节。 ID3v2有点难度 - 它是可变长度的,并且在MP3开始之前,你必须解析出长度字段(这是4字节,其中只有最低的7位被使用,给出标签的28位最大长度)。 .wav包装会更加困难 - 我不知道什么.wav强加为元数据的任何细节。

+0

嗯,我没有,甚至认为MP3可能是在包装的.wav ...我想提取个人MP3框架,我想。这将离开id3 v1和v2标签,所以我应该能够得到一个标签独立的哈希出来...对吧? – Jeff 2011-02-15 15:34:29

3

您可以直接使用ffmpeg至通过使用副本模式访问音频内容。它的格式无关紧要,因为API会为您提供一个包含原始数据的容器(仅在复制模式下)。如果您有视频或者您想处理解码的音频数据,您也可以解复用和解码。

查看ffmpeg的示例,了解如何执行此操作的快速介绍。通过使用ffmpeg我的意思是不使用该工具,但使用libffmpeg(libavformat,libavcodec)从C++/c中,尽管我认为你也可以使用ffmpeg工具从cmdline做到这一点,通过发送你的输出到标准输出并将其管道到md5sum或等价的东西(如果你是unix用户,那就是)。

特殊情况“-acodec copy”告诉ffmpeg使用相同的编码解码器进行编码。换句话说,不会发生音频的转码。

6

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

如果不解压缩音频数据,就不能提取音频数据 - 它已经被压缩了!但是,如果您只需要原始压缩流,请继续阅读!

典型的mp3音频文件,将其分为几个部分:
[可能的元标记]
[可能的垃圾]
[可能XING/LAME标签[可能更多的垃圾]
[MP3音频帧]
[可能的元标记]

可能的元标记:大多数MP3音频文件将在他们头上的id3标签。请注意,有些用户可能会使用不同的标记格式标记其mp3文件,例如APE,因此您也需要对其进行说明。

可能的垃圾:某些MP3音频文件已标记,重新标记,并转换了这么多次的元标记头可能无法提供你一个准确的偏移的第一音频帧,如先前标签的残余可以留下。foobar2000有一个选项来解决这个问题。

可能的XING/LAME标签:这些包含在mp3音频帧中,但它们不包含实际的音频。 madplay有代码向你展示如何读取和解析这些帧。 XING/LAME标题可能有一个帧数,所以值得分析这些标题。同样,如果文件已经通过许多不同的标签和编辑器,可能会在这里找到几个格式不正确的无效音频帧。

MP3音频帧:实际压缩流,分成'帧'。每帧将以同步位模式0xFFE开始。

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

要查找的音频帧偏移,则需要分析任何元标记头,然后开始寻找同步位模式。你不能只是开始寻找从文件开始同步模式,因为不是所有的标注器正确支持unsynchronization,所以元标记本身可能包含0xFFE模式。

一旦有了偏移到第一音频帧,你应该看看文件的末尾,并计算出多少非音频数据是有那么你知道什么时候停止解析音频。一旦你获得了音频数据开始的偏移量和音频数据末尾的偏移量,就可以通过散列/校验和功能传递音频数据!

1

我最近需要解决这个问题,以及(检测其中有不同的ID3标签重复的MP3文件)。最简单的方法是使用ffmpeg制作一个带有所有ID3标签的mp3文件的副本,然后取一个md5的总和。

参见单独https://github.com/pepaslabs/mp3md5sum

1

的ffmpeg可以计算一个音频文件的音频段,即SANS元数据的MD5哈希值。

用途:

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

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

0

我写了这个裸露的骨头小片段的Linux机器与旧的MP3播放器无法处理的标签。剩下的只是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; 
     } 
    } 
}