Python中如何从3gp音频的bytes流中抽取音频时长?
不进行全文扫描 的库有那些,话说找了几个库 不太靠谱啊。。。
有呒有大佬 指点下
Python中如何从3gp音频的bytes流中抽取音频时长?
2 回复
import struct
from io import BytesIO
def get_3gp_duration_from_bytes(data_bytes):
"""
从3GP文件的bytes数据中提取音频时长(单位:秒)
参数:
data_bytes: bytes类型的3GP音频数据
返回:
float: 音频时长(秒),解析失败返回0.0
"""
if not isinstance(data_bytes, bytes):
raise TypeError("输入必须是bytes类型")
stream = BytesIO(data_bytes)
duration = 0.0
try:
# 读取文件大小
stream.seek(0, 2)
file_size = stream.tell()
stream.seek(0)
while stream.tell() < file_size:
# 读取box大小和类型
size_data = stream.read(4)
if len(size_data) < 4:
break
box_size = struct.unpack('>I', size_data)[0]
box_type = stream.read(4).decode('ascii', errors='ignore')
if box_size < 8: # 无效的box
break
if box_type == 'moov':
# 进入moov box
moov_start = stream.tell() - 8
while stream.tell() < moov_start + box_size:
# 读取子box
sub_size_data = stream.read(4)
if len(sub_size_data) < 4:
break
sub_size = struct.unpack('>I', sub_size_data)[0]
sub_type = stream.read(4).decode('ascii', errors='ignore')
if sub_size < 8:
break
if sub_type == 'mvhd':
# 读取mvhd box内容
version = struct.unpack('B', stream.read(1))[0]
stream.read(3) # 跳过flags
if version == 0:
# 32位时间戳
stream.read(8) # 跳过creation_time和modification_time
timescale = struct.unpack('>I', stream.read(4))[0]
duration_units = struct.unpack('>I', stream.read(4))[0]
elif version == 1:
# 64位时间戳
stream.read(16) # 跳过creation_time和modification_time
timescale = struct.unpack('>I', stream.read(4))[0]
duration_units = struct.unpack('>Q', stream.read(8))[0]
else:
break
if timescale > 0:
duration = duration_units / timescale
return duration
# 移动到下一个box
stream.seek(sub_size - 8, 1)
# 移动到下一个box
if box_size == 0: # box到文件结尾
break
elif box_size == 1: # 扩展大小
# 读取64位大小
size_data = stream.read(8)
if len(size_data) < 8:
break
box_size = struct.unpack('>Q', size_data)[0]
stream.seek(box_size - 16, 1)
else:
stream.seek(box_size - 8, 1)
except Exception as e:
print(f"解析错误: {e}")
return 0.0
return 0.0
# 使用示例
def example_usage():
# 假设我们有一个3GP文件的bytes数据
# 这里用读取文件的方式模拟
with open('audio.3gp', 'rb') as f:
audio_data = f.read()
# 获取时长
duration = get_3gp_duration_from_bytes(audio_data)
print(f"音频时长: {duration:.2f} 秒")
# 或者直接处理bytes流
# duration = get_3gp_duration_from_bytes(your_bytes_data)
if __name__ == "__main__":
example_usage()
核心原理:
3GP文件使用MP4容器格式(基于ISO BMFF标准),通过解析moov box中的mvhd box获取时长信息。mvhd box包含timescale(时间刻度,单位:每秒刻度数)和duration(总刻度数),两者相除得到秒数。
代码要点:
- 使用
BytesIO将bytes数据转为可寻址的流 - 按box结构递归解析:每个box包含大小(4字节)和类型(4字节)
- 定位到
moov→mvhdbox,读取版本号确定时间戳格式 - 计算时长 = duration_units / timescale
一句话总结: 解析3GP的MP4容器格式,从mvhd box中读取时间刻度和总刻度数来计算时长。
人呢

