正如 Florian 上面所说,您可以使用 HTTP 范围读取文件的一小部分并查看是否存在 ID3,然后读取标签的其余部分(如果存在/必要)。例如:
Range: bytes=0-65535
ID3 标记可能包含图像,因此它可能非常大(我见过一些是 500Kb)。但是,大多数有用的信息,例如标题、描述等,很可能会在前几个 Kb 中提供。根据您的连接(或预期的客户端连接),我会选择要下载的第一个 Kb 数。对于大多数连接来说,现在 64Kb 的速度会非常快(也许 2014 年的速度会降低)。
请注意,整个文件的总大小也可能小于 64Kb。 Range 请求应该仍然有效,只是它会返回文件大小。在这种情况下,您将永远不会再发送更多数据请求。
带有 ID3 标签的 MP3 文件开头如下:
0x49 0x44 0x33 ID3
0x03 0x00 major.revision (2.0 or 3.0)
0x00 flags
0xSS 0xSS 0xSS 0xSS size
版本说明:
- 标签是 ID3,
3 不是版本的一部分
- 第一个版本是
2,因为 MP3 已经具有TAG 功能,并且被认为是版本1(在某些情况下是1.1)。
- 目前,除了
0,我没有看到任何修订版。这就是为什么我们将标签称为 ID3v1 (TAG)、ID3v2 (ID3 + 0x02) 和 ID3v3 (ID3 + 0x03)。
0xSS 代表大小。这是一个有趣的问题,因为在每个字节中只使用了 7 位以避免0xFF 这是 MP3 (MPEG) 文件的同步代码。只是他们忘记对 PNG 和 JPEG 图像中的0xFF 做点什么……反正……
大小的计算方法是这样的:
size = (buffer[pos + 6] << 21) +
(buffer[pos + 7] << 14) +
(buffer[pos + 8] << 7) +
(buffer[pos + 9] << 0)
重要提示:您应该确认没有在这些字节中设置第 7 位。如果设置,则它不是有效的 ID3 标签。这就是我不做 (buffer[pos + n] & 0x7F) 的原因,如果您尽早正确验证大小,则不需要 & 0x7F 部分。
请注意,此size 不包括标题的大小。所以请记住,标头有 10 个字节。
缓冲区的其余部分组织在帧中。这些是 3 个字母、一个大小和该帧的数据,或者是 4 个字母、一个大小、标志和数据。每帧的标头由版本(2 或 3)决定。
无论如何,一旦你有了size,如果你想读取整个 ID3,你可以对 HTTP 服务器执行另一个 GET 并检索剩余的数据,如果前 64Kb(或你首先使用的任何大小)不是已经大于或等于必要的大小。
Range: bytes=65536-<size + 10 - 1>
大小是ID3内的数据。 +10 用于标题。 -1 是因为 HTTP 范围是包容性的(不是大小,而是位置)。
重要提示:所有服务器都不接受Range 标头。如果您可以控制并且您的服务器不支持范围请求,您可能需要考虑在服务器前面添加一个代理。 nginx 在这方面真的很擅长。它可以缓存整个文件并仅返回 HTTP 标头中请求的范围。