2016-06-12 84 views
0

我的semestral項目將於本週四發佈,並且我在閱讀MP3文件時遇到重大問題(該項目關於聲音分析,不要問我究竟是什麼,這麼晚了)。正確閱讀由ID3標籤中斷的MP3文件

首先,我讀了前10個字節來檢查ID3標籤。如果他們在場,我只會跳到第一個MP3頭 - 或者至少這是個大想法。這裏是我怎麼算ID3標籤尺寸:

if (inbuf[0] == 'I' && inbuf[1] == 'D' && inbuf[2] == '3') //inbuf contains first 10 bytes from file 
{ 
    int size = inbuf[3] * 2097152 + inbuf[4] * 16384 + inbuf[5] * 128 + inbuf[6]; //Will change to binary shifts later 
    //Do something else with it - skip rest of ID3 tags etc 
} 

它工作正常的文件沒有ID3標籤,並與他們的一些文件,但對於一些其他文件的ffmpeg(我使用的解碼)返回「無頭」錯誤,這意味着它沒有正確捕獲MP3頭。我知道,因爲如果我從該.mp3文件(例如Winamp)中刪除ID3,則不會發生錯誤。結論是大小計算算法並不總是有效的。

所以問題是:我如何才能知道.mp3文件(所有可能的標籤,專輯圖片和其他)的整個ID3部分有多大?我正在尋找它,但我只是繼續找到上面發佈的這個算法。有時候我也需要考慮一些關於10個字節的頁腳,但它似乎經常會獲得10個以上的字節,因此它最終能夠獲得正確的MP3幀。

+0

當讀ID3的大小就意味着數據的量** ID3頭之後**所以佔10頭部的字節,我們添加「+ 10」的大小。如果大小不正確(檢查十六進制編輯器?),然後考慮查看**同步安全整數**並通過這樣的函數傳遞您的值以獲得正確的大小返回。 –

+0

PS:從十六進制編輯器複製並粘貼到此處...只顯示有問題的ID3標頭的10個字節。你通過代碼獲得了多大的尺寸?和(來自十六進制編輯器)也會告訴我們第一個mp3幀的字節'FF FB'的顯示偏移量。 –

回答

1

ID3v1標籤的大小始終固定爲128字節。

我會發現下面的描述

如果一個總和的所有這些領域,我們看到,30 + 30 + 30 + 4 + 30 + 1等於125個字節,而不是128字節的大小。在歌曲標題之前,可以在標籤的最開始處找到缺少的三個字節。這三個字節總是「TAG」,並且是這確實是ID3標籤的標識。查找ID3v1/1.1標籤的最簡單方法是從文件末尾查找128個字節的單詞「TAG」。

來源:http://id3.org/ID3v1

還有另外一個版本,叫做ID3v2的:

其中一個設計目標是將ID3v2的應該是非常靈活的,可擴展的... 由於每架可是16MB,整個標籤可以是256MB,那麼當您嘗試在舊ID3中寫入一個有用的評論時,它可能永遠不會再次處於相同的情況,而舊ID3限制爲30個字符。

這ID3v2的總是開始於開始的音頻文件,你可以在這裏閱讀:http://id3.org/ID3v2Easy

ID3v2/file identifier "ID3" 
ID3v2 version   $03 00 
ID3v2 flags    %abc00000 
ID3v2 size    4 * %0xxxxxxx 

的ID3v2標籤尺寸編碼有四個字節,其中最顯著位(第7位)在每個字節中被設置爲零,總共28位。經過檢查的比特被忽略,因此一個257個字節長標籤被表示爲$ 00 00 02 01

+0

我已經知道了這一切。問題是,即使我用這種方法實現讀取ID3v2標籤大小並將其保存到某個x變量,讀取這些x字節後,解碼器幾乎無法識別文件中接下來的內容爲合適的MP3幀。我的問題不在於如何計算這個大小,而是爲什麼在計算它並讀取ID3的其餘部分後,似乎仍然有一些數據留在文件中。 – PookyFan

0
bool LameDecoder::skipDataIfRequired() 
{ 
    auto data = m_file.read(3); 
    Q_ASSERT(data.size() == 3); 
    if (data.size() != 3) 
     return false; 
    if (memcmp(data.constData(), "ID3", 3)) 
    { 
     m_file.seek(0); 
     return true; 
    } 

    // ID3v2 tag is detected; skip it 

    m_file.seek(3+2+1); 
    data = m_file.read(4); 
    if (data.size() != 4) 
     return false; 

    qint32 size = (data[0] << (7*3)) | (data[1] << (7*2)) | 
      (data[2] << 7) | data[3]; 

    m_file.seek(3+2+1+4+size); 

    return true; 
}