在 Uint8Array 中搜索多字节模式

问题描述 投票:0回答:2

我有一个nodejs 脚本,我想在其中解析MP3 帧。这些帧很容易检测,因为每个帧都以两个字节开始

0xff 0xfb

我正在使用

Uint8Array
来访问该文件的字节。使用
[].indexOf.call(data, 0xff)
我可以轻松搜索单个字节,但不能搜索两个字节。显然我可以手动检查第二个字节,但我想知道是否有一种干净的方法来获取特定字节序列的索引。

javascript typed-arrays
2个回答
9
投票

显然,如果不编写自定义代码,就没有什么好的方法可以做到这一点,所以这就是我所做的:

Uint8Array.prototype.indexOfMulti = function(searchElements, fromIndex) {
    fromIndex = fromIndex || 0;

    var index = Array.prototype.indexOf.call(this, searchElements[0], fromIndex);
    if(searchElements.length === 1 || index === -1) {
        // Not found or no other elements to check
        return index;
    }

    for(var i = index, j = 0; j < searchElements.length && i < this.length; i++, j++) {
        if(this[i] !== searchElements[j]) {
            return this.indexOfMulti(searchElements, index + 1);
        }
    }

    return(i === index + searchElements.length) ? index : -1;
};

0
投票

我知道这是一个 11 年前的问题,你找到了一些对你有用的东西并回答了你自己的问题,但我一直在寻找这个基本上相同的原因(解析 mpeg 音频帧)并意识到这并不总是为此而努力。

MP3 帧通常以

0xff 0xfb
开头,但其他 mpeg 音频则不然(请参阅有关 MPEG 音频帧标头的信息)。

MPEG 音频帧的前两个字节分解如下表所示(从上面的链接逐字复制,但包括在内,以防文章出现问题)。

位置 长度(位) 意义 示例
0 11 帧同步以查找标头(所有位始终设置) 1111 1111 111
11 2 音频版本 ID(另请参见表 3.2)
00 - MPEG 版本 2.5(MPEG 2 的非官方扩展)
01 - 保留
10 - MPEG 版本 2 (ISO/IEC 13818-3)
11 - MPEG 版本 1 (ISO/ IEC 11172-3)
11
13 2 层索引
00 - 保留
01 - 第 III 层
10 - 第 II 层
11 - 第 I 层
01
15 1 保护位
0 - 由标头后面的 16 位 CRC 保护
1 - 无 CRC
1

鉴于这些信息,您最终得到的解决方案感觉有点缺乏,因为如果我遇到一个带有 CRC 位设置的罕见 mp3(

0xfa
而不是
0xfb
),我的代码可以轻松跳过 CRC 并正常工作,但前提是它首先找到 mp3 帧 - 使用
indexOfMulti
,我可能必须多次循环遍历(至少部分)整个缓冲区/数组,以支持解析可能的 MP3 帧的变化(
indexOfMulti([0xff, 0xfb])
会得到我
-1
,所以我必须在之后运行
indexOfMulti([0xff, 0xfa])
),或者更有可能的是它会在我没有意识到的情况下跳到下一帧。


如上表所示,MPEG 音频以

1111 1111 111
开头,因此为了搜索它,我最终做了类似下面的代码的操作。

let offset = 0;

while (offset < srcBuffer.length) {

    let buffer = srcBuffer.read(10) // length of ID3 frame header

    // ... (skipped code where I parse ID3 tags and
    //      increase the offset and 
    //      read more data into the buffer)

    // this is the key line, 
    // I'm not searching for the byte `0xe0`, 
    // I'm searching for the bit pattern fff* ****
    if (
        buffer[offset] === 0xff && 
        (buffer[offset + 1] & 0xe0) === 0xe0 
    ) { 

        // ... (skipped parsing the mp3 frame header)

    }

    // ... (skipped rest of code for brevity)

}
© www.soinside.com 2019 - 2024. All rights reserved.