2011-02-15 147 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; 
     } 
    } 
}