Python读取Ogg Opus文件头CRC校验失败,求排查解决方法
Ogg Opus文件CRC校验失败问题排查
正在研究文件格式,用Python读取Ogg Opus文件,已正确提取文件头所有信息,但CRC校验始终无法通过。根据Ogg官方文档,校验时需将原CRC校验值设为0,再计算整个页(含页头、段表、数据包内容)的CRC。编写的Python代码计算结果与文件中的CRC值不符,求排查遗漏步骤。
import zlib import struct with open("sample3.opus", "rb") as f_: file_data = f_.read() cp, ssv, htf, agp, ssn, psn, pc, ps = struct.unpack_from("<4sBBQIIIB", file_data, 0) offset = struct.calcsize("<4sBBQIIIB") segments = struct.unpack_from(f"<{ps}B", file_data, offset) packet_size = 0 for num in segments: packet_size += num header_size = offset + len(segments) + packet_size # Copying the entire packet then changing the crc to 0. header_copy = bytearray() header_copy.extend(file_data[0:header_size]) struct.pack_into("<I", header_copy, struct.calcsize("<4sBBQII"), 0) print(pc) print(zlib.crc32(header_copy))
运行结果:
277013243 752049619
你的代码主要遗漏了Ogg CRC32算法的初始值设置和结果取反步骤,另外需要注意Python中zlib.crc32返回值的符号处理:
- Ogg的CRC32计算需要从初始值
0xFFFFFFFF开始,而zlib.crc32默认初始值为0 - 计算完成后需要对结果取反(与
0xFFFFFFFF进行异或) - Python的
zlib.crc32返回32位有符号整数,需转换为无符号整数再处理
修正后的代码如下:
import zlib import struct with open("sample3.opus", "rb") as f_: file_data = f_.read() # 解析Ogg页头 cp, ssv, htf, agp, ssn, psn, pc, ps = struct.unpack_from("<4sBBQIIIB", file_data, 0) header_len = struct.calcsize("<4sBBQIIIB") # 解析段表 segments = struct.unpack_from(f"<{ps}B", file_data, header_len) # 计算页内数据包总长度 packet_total = sum(segments) # 整个页的总长度 page_total_len = header_len + ps + packet_total # 复制整个页并将CRC字段设为0 page_copy = bytearray(file_data[:page_total_len]) # CRC字段在页头的偏移是22字节(<4sBBQII的长度:4+1+1+8+4+4=22) struct.pack_into("<I", page_copy, 22, 0) # 按照Ogg标准计算CRC # 初始值0xFFFFFFFF,计算后取反 computed_crc = zlib.crc32(page_copy, 0xFFFFFFFF) & 0xFFFFFFFF computed_crc ^= 0xFFFFFFFF print(f"文件中的CRC值: {pc}") print(f"计算得到的CRC值: {computed_crc}") print(f"校验结果: {computed_crc == pc}")
额外验证项:
- 确认
page_total_len确实覆盖了整个Ogg页:Ogg页的段表中每个字节对应数据包段的长度,所有段长度之和就是页内总数据长度 - 确认CRC字段偏移位置正确:Ogg页头中CRC字段从第22字节(0索引)开始,长度4字节,采用小端字节序
内容的提问来源于stack exchange,提问作者Trykowo
相关产品推荐
相关产品推荐

