是否可以在不实际下载整个文件的情况下读取在线存储的 MP3 的 ID3 标签?
我使用过 TagLib Sharp,但据我所知,您实际上必须打开文件才能读取 ID3 标签。
正如 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) 文件的同步代码。只有他们忘记做一些关于0xFF
在 PNG 和 JPEG 图像中发现的事情......无论如何......
计算大小的方法是这样的:
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 标头中请求的范围。