5

我想以编程方式创建音频文件(MP3、Ogg Vorbis、Flac)的 SHA1 校验和。要求是即使标头(例如 ID3)发生变化,校验和也应该是稳定的。
注意:音频文件没有 CRC

这是我现在尝试的:

1) 使用 Perl 和MPEG::Audio::Frame读取 + 散列所有 MPEG 帧

my $sha1 = Digest::SHA1->new;
while (my $frame = MPEG::Audio::Frame->read(\*FH)) {
    $sha1->add($frame->content());
}

2) 使用 Python 和libmad (pymad)解码 + 散列所有 MPEG 帧

mf = mad.MadFile(path)
sha1 = hashlib.sha1()

while 1:
    buf = mf.read()
    if (buf is None):
        break
    sha1.update(buf)

3) 使用mp3cat

> mp3cat - - < file.mp3 | sha1sum

然而,这些方法都没有提供稳定的校验和。即,在某些情况下,使用picard重新标记文件后校验和会发生变化。

是否有任何图书馆已经提供了我想要的东西?
我不关心编程语言...

更新: 我进一步调试了这个案例。libmad 校验和不一致似乎发生在 libmad 出现一些解码错误的情况下,例如"Huffman data overrun (0x0238)"。由于这确实发生在许多 mp3 文件上,我不确定它是否真的表明文件损坏......</p>

4

5 回答 5

3

如果您正在为实际音乐寻找稳定的哈希值,您可能需要查看libOFA。您当前的方法会给您不同的结果,因为格式可以嵌入标签。此外,如果您希望具有相同歌曲的两个不同文件返回相同的哈希值,您需要考虑比特率和采样频率等因素。

另一方面,libOFA 可以为您提供可以在格式和不同编码之间使用的稳定哈希。可能是你想要的?

于 2009-07-22T11:45:58.540 回答
2

我需要工具来快速检查我的 MP3/OGG​​ 库是否仍然有效。对于 MP3,我发现 mp3md5.py ( http://snipplr.com/view/4025/mp3-checksum-in-id3-tag/ ) 可以完成这项工作,但对于 OGG Vorbis 来说没有简单的工具,但我编写了一些 bash脚本为我执行此操作。这两种工具都应该容忍对评论/ID3Tag 的修改。

#!/bin/bash

# This bash script appends an MD5SUM to the vorbiscomment and/or verifies it if it exists
# Later modification of the vorbis comment does not alter the MD5SUM
# Julian M.K.

FILE="$1"

if [[ ! -f "$FILE" || ! -r "$FILE" || ! -w "$FILE" ]] ; then
  echo "File $FILE" does not exist or is not readable or writable
  exit 1
fi

OLDCRC=`vorbiscomment "$FILE" | grep ^CRC=|cut -d "=" -f 2`
NEWCRC=`ogginfo "$FILE" |grep "Total data length:" |cut -d ":" -f 2 | md5sum |cut -d " " -f 1`

if [[ "$OLDCRC" == "" ]] ; then
  echo "ADDED $FILE  $NEWCRC"
  vorbiscomment -a -t "CRC=$NEWCRC" "$FILE" 
  # rewrite CRC to get proper data length, I dont know why this is necessary
  NEWCRC=`ogginfo "$FILE" |grep "Total data length:" |cut -d ":" -f 2 | md5sum |cut -d " " -f 1`
  vorbiscomment -w -t "CRC=$NEWCRC" "$FILE" 
elif [[ "$OLDCRC" == "$NEWCRC" ]]  ; then
  echo "VERIFIED $FILE"
else
  echo "FAILURE $FILE -- $OLDCRC - $NEWCRC"
fi
于 2011-06-10T11:39:47.877 回答
1

有一种简单稳定的方法可以做到这一点。只需复制文件并从中删除所有标签(例如,使用 mutagen.id3)并获取结果文件的哈希值。

这种方法的唯一缺点是它的性能。

于 2019-01-11T18:12:05.220 回答
0

Bene,如果我是你,(我正在做一些与你想做的非常相似的事情),我会对 mp3 数据块进行哈希处理。(首先将其提取为原始数据,然后将其写入磁盘,这样您就知道自己在处理什么了)。然后,修改 ID3 标签。再次散列您的数据。现在,如果它发生了变化,比较你的两组原始数据并找出它在哪里发生了变化。很有可能,您可能在某个地方越界了。如果我记得,MP3 文件以 FF F8 之类的开头。好吧,至少框架可以。

我对你的发现很感兴趣,因为我仍在编写我所有的代码来处理指纹等,还没有得到实际的散列。

于 2008-12-12T18:37:42.947 回答
0

多年后更新:

请参阅对一个非常相似的问题的回答。事实证明,它ffmpeg实际上支持对各个流进行校验和。要仅获取音频流的 md5 哈希:

ffmpeg -i "$filename" -map 0:a -codec copy -f md5 "$filename.md5"

还支持使用通用-f hash格式的其他哈希格式,或者使用-f framemd5.


我正在尝试做同样的事情。我使用 MD5 而不是 SHA1。我开始使用 mp3tag ( www.mp3tag.de/en/ ) 导出音频校验和;然后制作了一个类似于你的 Perl 脚本来做同样的事情。然后我从测试文件中删除了所有标签,音频校验和保持不变。

这是脚本:

use MPEG::Audio::Frame;
use Digest::MD5 qw(md5_hex);
use strict;

my $file = 'E:\Music\MP3\Russensoul\01 - 5nizza , Soldat (Russensoul - Russensoul).mp3';
my $mp3tag_audio_md5 = lc '2EDFBD62995A46A45CEEC08C1F303486';

my $md5 = Digest::MD5->new;

open(FILE, $file) or die "Cannot open $file : $!\n";
binmode FILE;

while(my $frame = MPEG::Audio::Frame->read(\*FILE)){
    $md5->add($frame->asbin);
}

print '$md5->hexdigest  : ', $md5->hexdigest, "\n",
      'mp3tag_audio_md5 : ', $mp3tag_audio_md5,  "\n",
      ;

是否有可能您用来修改标签的任何东西有时也会修改 mp3 标头?

于 2009-05-22T12:26:34.600 回答