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(总刻度数),两者相除得到秒数。

代码要点:

  1. 使用BytesIO将bytes数据转为可寻址的流
  2. 按box结构递归解析:每个box包含大小(4字节)和类型(4字节)
  3. 定位到moovmvhd box,读取版本号确定时间戳格式
  4. 计算时长 = duration_units / timescale

一句话总结: 解析3GP的MP4容器格式,从mvhd box中读取时间刻度和总刻度数来计算时长。


回到顶部