Вам нужно создать буфер ID3, затем создать буфер, достаточно большой для хранения файлов ID3 и MP3, вставить ID3 и добавить данные MP3.
Для этого вам понадобится спецификация ID3 и используйте типизированные массивы с 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-битного синхронизируемого целого числа (раздел 6.2), что в сумме составляет 28 эффективных битов (представляющих до 256 МБ).
Размер тега ID3v2 представляет собой сумму длины в байтах расширенного заголовка
, заполнения и кадров после десинхронизации. Если нижний колонтитул
присутствует, он равен ('общий размер' - 20) байтам, в противном случае ('общий размер' - 10) байтам.
Пример того, как вы можете построить свой буфер. Сначала определите буфер, достаточно большой для хранения всех данных, а также DataView:
var id3buffer = new ArrayBuffer(1024), // 1kb "space"
view = new DataView(id3buffer);
DataView по умолчанию использует обратный порядок байтов, что идеально, поэтому все, что нам нужно сделать сейчас, это заполнить данные там, где они должны быть. Мы можем создать несколько вспомогательных методов, которые помогут нам перемещать позицию одновременно с записью. Позиции для DataView привязаны к байтам:
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 на сервер или преобразовать в Blob для IndexedDB или в URL-адрес объекта, если вы хотите предоставить ссылку для загрузки (ни один из показанных здесь ответов не выходит за рамки).
Этого должно быть достаточно для начала — как сказано, вам нужно изучить спецификации. Если вы не знакомы с типизированным массивом, ознакомьтесь с ними. также.
Также см. на сайте другие ресурсы (фреймы и т. д.).
Безопасные для синхронизации значения
В файлах «MP3» используются кадры, начинающиеся с 11 бит, для всех которых установлено значение 1. Если поле размера заголовка содержит 11 бит, для которых установлено значение 1, декодер может ошибочно интерпретировать его как звуковые данные. Чтобы избежать этого, используется концепция безопасных для синхронизации целых чисел, гарантирующая, что каждый байт MSB (самый старший бит, бит 7) всегда установлен в 0. Бит перемещается влево, следующий байт сдвигается на один бит для ID3. тег 4 раза (отсюда и 4x% 01111111).
Вот как кодировать и декодировать безопасные для синхронизации целые числа с помощью JavaScript (из источник Википедии C/C++) :
// 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
для примерного значения, используемого в приведенной выше демонстрации.
person
Community
schedule
12.06.2015