添加id3标签html5 filesystem api

时间:2015-06-12 02:56:05

标签: javascript html5 html5-filesystem

我有一个场景,我正在构建一个允许收听和存储.mp3播客文件的播客网络应用程序。

我正在尝试实现一个基本的Web界面,有人可以从客户端添加整个id3标记(该文件将存储在客户端本地:此客户端不像每个人客户端,但只是获得原始播客文件而没有任何id3标签的人最好)。然后他主持这一页本地添加正确的id3标签然后复制这些.mp3做一个WebDav文件夹。

我知道编辑需要在服务器上完成,但如果可以在浏览器本地完成所有操作,那将非常有用。

当然没有现成的库来编辑文件,所以我决定使用HTML5文件系统api,即将文件放入虚拟文件系统,编辑它然后将其复制回本地系统。 (对于复制,有一个现成的库FileSaver.js)。

我能够做到以下几点: 1)使用webkitGetAsEntry

将放置在放置区域的mp3文件关联到文件系统api

2)将此文件复制到文件系统api。

部分代码如下:

function onDrop(e) 
{
    e.preventDefault();
    e.stopPropagation();

    var items = e.dataTransfer.items;
    var files = e.dataTransfer.files;

    for (var i = 0, item; item = items[i]; ++i) 
    {
        // Skip this one if we didn't get a file.
        if (item.kind != 'file') {
            continue;
        }

        var entry = item.webkitGetAsEntry();

        if (entry.isFile) 
        {
            // Copy the dropped entry into local filesystem.
            entry.copyTo(cwd, null, function(copiedEntry) {
            //setLoadingTxt({txt: DONE_MSG});
            renderMp3Writer(entry);

我的困惑是如何添加整个 id3标记? 。我现在迷失了,因为我不确定:

1)我们可以从fileWriter方法将整个id3标签添加到文件中吗? 2)如果是,这将是二进制编辑或如何?

任何帮助都会有用。尝试了以下,但我猜我错了。

var blob1 = new Blob(['ID3hTIT2ga'], {type: 'audio/mp3'});
fileWriter.write(blob1);

1 个答案:

答案 0 :(得分:1)

您需要构建一个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位同步整数(section      6.2),共有28个有效位(最多256MB)。

     

ID3v2标签大小是扩展
的字节长度的总和   标头,填充和不同步后的帧。如果是   页脚存在这等于('总大小' - 20)字节,否则   ('总大小' - 10)字节。

如何构建缓冲区的示例。首先定义一个足以容纳所有数据的缓冲区以及DataView:

var id3buffer = new ArrayBuffer(1024),    // 1kb "space"
    view = new DataView(id3buffer);

DataView默认为big-endian,这是完美的,所以我们现在需要做的就是填写应该在哪里的数据。我们可以制作一些辅助方法来帮助我们在写作的同时移动位置。 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);

如果一切顺利,你现在有一个带有ID3标签的MP3(记得要检查现有的ID3 - 你需要扫描到结束)。

现在,您可以将ArrayBuffer发送到服务器,或者转换为Blob用于IndexedDB,或者如果要提供下载链接(此处未显示,因为答案超出范围),可以将其转换为Object-URL。 / p>

这应该足以让你开始 - 如上所述,你需要研究规格。如果您不熟悉typed array,请查看这些内容。

另请参阅other resources(框架等)的网站。

同步安全值

“MP3”文件使用以11位开头的帧,全部设置为1.如果标题的大小字段恰好包含11位设置为1,则解码器可能会错误地将其解释为声音数据。为避免这种情况,使用同步安全整数的概念,确保每个字节的MSB(最重要的位,位7)始终设置为0.该位移到左侧,下一个字节移位一位,用于ID3标记4次(因此4x%01111111)。

以下是如何使用JavaScript(来自Wikipedia C/C++ source)对同步安全整数进行编码和解码:

// 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;
}

对于上面演示中使用的示例值,sync-safe值将显示如下内容:&b01111111011111110111111101111111