你需要建立一個ID3緩衝,然後創建大到足以容納兩個ID3和MP3文件的緩衝區,插入ID3和追加MP3數據。
爲此,您需要ID3 specification並使用帶有DataView的類型化數組來構建您的數組。
的ID3整體結構的定義如下(見上面的鏈接):
+-----------------------------+
| Header (10 bytes) |
+-----------------------------+
| Extended Header |
| (variable length, OPTIONAL) |
+-----------------------------+
| Frames (variable length) |
+-----------------------------+
| Padding |
| (variable length, OPTIONAL) |
+-----------------------------+
| Footer (10 bytes, OPTIONAL) |
+-----------------------------+
此時緩衝區長度是未知的,所以你需要做的步驟。有幾種方法可以做到這一點,您可以爲每個字段構建小緩衝區段,然後將它們彙總到單個緩衝區中。或者你可以製作一個更大的緩衝區,你知道可以容納你想要包含的所有字段,並將字段的總和從該緩衝區複製到最後一個。
後者往往更簡單,因爲我們正在處理非常小的尺寸,這可能是最好的方法(考慮到第一種方法中的每個片段都有其開銷)。
所以你需要做的第一件事就是定義標題。頭文件是這樣定義的:
ID3v2/file identifier "ID3"
ID3v2 version $04 00
ID3v2 flags %abcd0000 (note: bit-representation)
ID3v2 size 4 * %0xxxxxxx (note: bit-representation/mask)
ID3和版本是固定值(其他版本當然存在,但讓我們跟隨當前)。
通過將它們設置爲0,您可能會忽略大多數標誌(如果不是全部),但請檢查文檔以查找您的用例,例如,如果要使用擴展標頭。
大小被定義:
的ID3v2標籤尺寸被存儲爲一個32位的整數synchsafe(部分 6.2),總共28個有效位(代表至多256MB)。
ID3v2標籤大小是擴展頭的字節長度,填充和非同步之後的幀之和的總和。如果存在頁腳
,則這等於('總大小'〜20)字節,否則爲 ('總大小'〜10)字節。
舉例說明如何構建緩衝區。首先定義大到足以容納所有的數據,以及一個數據視圖緩衝:
var id3buffer = new ArrayBuffer(1024), // 1kb "space"
view = new DataView(id3buffer);
的數據視圖默認爲大端這是完美的,所以我們現在需要做的是在數據來填充它應該。我們可以提供一些幫助方法來幫助我們在寫作的同時移動位置。對於數據視圖位置是字節綁定:
var pos = 0; // global start position
function setU8(value) {
view.setUint8(pos++, value)
}
function setU16(value) {
view.setUint16(pos, value);
pos += 2;
}
function setU32(value) {
view.setUint32(pos, value);
pos += 4;
}
等可以讓助手來寫文本unicode字符串(見TextEncoder例如)等等。
要定義標題,我們可以寫入「魔術」字ID3。你可以轉換一個字符串,或者因爲它只有3個字節,所以直接寫就可以了。 ID3 = 0x494433十六進制這樣:
setU8(0x49); // at pos 0
setU8(0x44); // at pos 1
setU8(0x33); // at pos 2
由於我們所取得的包裝,我們並不需要擔心緩衝位。
然後在版本寫(根據規範v.2.4.0使用的0x0400沒有使用主要版本(2)):
setU16(0x0400); // default is big-endian so this works
現在你可以用標誌和尺寸(見規格)繼續。
當ID3標頭填滿時pos
現在將保存總長度。所以要對ID3標籤和MP3緩衝區的新緩衝區:
var mp3 = new ArrayBuffer(pos + mp3Buffer.byteLength),
view8 = new Uint8Array(mp3);
的view8視圖將允許我們做一個簡單的複製到目的地:
// create a segment from the tag buffer that will fit target:
var segment = new Uint8Array(view.buffer, 0, n); // replace n with actual length
view8.set(segment, 0);
view8.set(mp3buffer, pos);
如果一切正常,你現在有一個MP3一個ID3標籤(記得檢查現有的ID3 - 你需要掃描到結束)。
現在,您可以將ArrayBuffer發送到服務器,或者如果您希望提供下載鏈接(此處沒有顯示答案正在變得超出範圍),則可以將其轉換爲用於IndexedDB的Blob或Object-URL。
這應該足以讓你開始 - 如上所述,你需要研究規格。如果您對typed array不熟悉,請檢查這些。
另請參閱網站other resources(框架等)。
同步安全值
「MP3」文件使用與11位開始幀,全部設置爲1,如果頭的大小字段會包含設置爲1 11位,解碼器可能錯誤地它作爲聲音數據。爲了避免這種情況,使用同步安全整數的概念,確保每個字節的MSB(最重要的位,第7位)始終設置爲0.該位移動到左側,下一個字節移動一位,對於ID3標記4次(因此是4x%01111111)。
下面是如何(從Wikipedia C/C++ source)編碼和解碼使用JavaScript同步安全整數:
// test values
var value = 0xfffffff,
sync = intToSyncsafe(value);
document.write("<pre>Original size: 0x" + value.toString(16) + "<br>");
document.write("Synch-safe : 0x" + sync.toString(16) + "<br>");
document.write("Decoded value: 0x" + syncsafeToInt(sync).toString(16) + "</pre>");
function intToSyncsafe(value) {
var out, mask = 0x7f;
while(mask^0x7fffffff) {
out = value & ~mask;
out <<= 1;
out |= value & mask;
mask = ((mask + 1) << 8) - 1;
value = out;
}
return out
}
function syncsafeToInt(value) {
var out = 0, mask = 0x7F000000;
while (mask) {
out >>= 1;
out |= value & mask;
mask >>= 8;
}
return out;
}
同步安全值將顯示像的位:&b01111111011111110111111101111111
爲例如在上面的演示中使用的值。
只是對標題標籤的標籤大小有疑問。根據id3規範,它說'ID3v2標籤大小存儲爲32位同步安全整數( 6.2),總共有28位有效位(代表高達256MB)。 ID3v2標籤大小是擴展的 標頭的字節長度,填充和非同步之後的幀之和。如果存在 頁腳,則等於('總大小'〜20)字節,否則爲 ('總大小'〜10)字節。目前,我只對代碼中的標題進行編碼,因此可以將其設置爲默認值:4 *%0xxxxxxx –
它是一個同步安全值(請參閱doc中的6.2)。它需要以特殊的方式進行編碼,以便第7位(MSB)始終爲0.第7位移動到左側,然後該位的第7位執行相同操作,總共4次。在答案中增加了解決方案。 (並且由於我們將一個位設置爲0,所以我們放鬆了4位,因此最大尺寸爲28位)。由於該領域非常重要,因此文件可能會更清晰。 – K3N
只是觀察一個問題。 'view8 = new Uint8Array(mp3); '。當我直接檢查「視圖」的blob,即var id3buffer = new ArrayBuffer(1024); view = new DataView(id3buffer);'正確顯示的十六進制顯示正確:'文件名:YourFileName(13).mp3 mime類型:0000-0010:49 44 33 00-00 00 00 00-00 00 00 00- 00 00 00 00 ID3'。但是對於類型化的數組,它顯示爲全部0'var mp3 = new ArrayBuffer(pos); view8 = new Uint8Array(mp3); view8.set(view.buffer,0);',當我查看mp3 Arraybuffer的值時,它全部爲0。 '文件名:YourFileName(14).mp3 mime類型:0000-0003:00 00 00' –