这几天研究 live555,然而蛋疼滴发现它流化的 opus 文件,VLC 居然无法播放,于是想了解一下 opus 文件,看了 live555 的 OggFileParser 代码,发现 checksum 都被无视了,本来 UMU 也应该无视这个细节的,然而随便用自己以前写的 CRC32 代码验证了一下,居然不一样!而这份代码之前是测试过的,和 7-Zip 的 CRC-32 算出来是一致的。
因为 opus 文件是基于 ogg 文件格式的,所以阅读了一下 Ogg Documentation,发现确实不一样,它用的其实是 CRC32_IEEE,于是参考了 libogg 的 framing.c 和 ffmpeg\libavutil\crc.c 把自己的代码库给更新了,使用模版增强功能:
#pragma region "CRC"
// CRC_8_ATM <false, 8, 0x07, 0>
// CRC_16_ANSI <false, 16, 0x8005, 0>
// CRC_16_CCITT <false, 16, 0x1021, 0>
// CRC_24_IEEE <false, 24, 0x864CFB, 0>
// CRC_32_IEEE <false, 32, 0x04C11DB7, 0> -> OggFile's Checksum
// CRC_32_IEEE_LE <true, 32, 0xEDB88320, 0>
// CRC_16_ANSI_LE <true, 16, 0xA001, 0>
// defualt <true, 32, 0xEDB88320, 0xFFFFFFFF>, 7 - Zip's CRC-32
template <bool kIsLE = true, uint8_t kBits = 32, uint32_t kPolynomial = 0xEDB88320, uint32_t kXorOut = 0xFFFFFFFF>
class CRC
{
public:
CRC()
{
static_assert (kBits >= 8 && kBits <= 32 && kPolynomial < (1LL << kBits), "invalid bits");
for (int i = 0; i < 256; ++i) {
if (kIsLE) {
register uint32_t crc = i;
for (int j = 8; j > 0; --j) {
crc = (crc >> 1) ^ (kPolynomial & (-static_cast<int32_t>(crc & 1)));
}
crc32_table_[i] = crc;
} else {
register uint32_t crc = i << 24;
for (int j = 8; j > 0; --j) {
crc = (crc << 1) ^ ((kPolynomial << (32 - kBits)) & (static_cast<int32_t>(crc) >> 31));
}
crc32_table_[i] = be2me_32(crc);
}
}
}
uint32_t GetCRC(uint32_t crcinit, const uint8_t* data, size_t data_size)
{
register uint32_t crc = crcinit ^ kXorOut;
/* process not aligned message head */
for (; (3 & (data - (uint8_t*)0)) && data_size > 0; ++data, --data_size) {
crc = crc32_table_[static_cast<uint8_t>(crc) ^ *data] ^ (crc >> 8);
}
/* fast CRC32 calculation of a DWORD-aligned message */
for (const uint8_t* e = data + (data_size & ~15); data < e; data += 4) {
crc ^= le2me_32(*reinterpret_cast<const uint32_t *>(data));
crc = crc32_table_[crc & 0xFF] ^ (crc >> 8);
crc = crc32_table_[crc & 0xFF] ^ (crc >> 8);
crc = crc32_table_[crc & 0xFF] ^ (crc >> 8);
crc = crc32_table_[crc & 0xFF] ^ (crc >> 8);
}
/* process not aligned message tail */
for (const uint8_t* e = data + (data_size & 15); data < e; ++data) {
crc = crc32_table_[static_cast<uint8_t>(crc) ^ *data] ^ (crc >> 8);
}
return crc ^ kXorOut;
}
private:
uint32_t crc32_table_[256];
};
#pragma endregion