MP3文件——测试工程师Python开发实战(18)

发表于:2023-9-08 09:30

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:胡通    来源:51Testing软件测试网原创

#
Python
  7.2.1  MP3文件
  MPEG音频文件是MPEG1标准中的声音部分,它根据压缩质量和编码复杂程度划分为3层,即Layer1、Layer2、Layer3,分别对应MP1、MP2、MP3这3种音频文件,音频编码的层次越高,编码器越复杂,压缩率也越高,MP1和MP2的压缩率分别为4:1和6:1~8:1,而MP3的压缩率可达10: 1甚至12:1。MP3属于有损失的格式,牺牲音乐文件的质量以换取较小的文件体积,因为人耳只能听到一定频段内的声音(20~20 000 Hz),而其他更高或更低频率的声音对人耳是无法感知的,所以MP3技术就把这部分声音去掉了,从而使得文件体积大为缩小,且在人耳听起来并没有失真。
  MP3的文件构成都是由帧构成的,一般包含3部分:ID3V2、数据帧和ID3V1。MP3帧结构如图7-1所示。
图7-1  MP3帧结构
  ID3V2包含作者、作曲、专辑等信息,存在文件头部,长度不固定,扩展了ID3V1的信息量。ID3V2一共有4个版本—ID3V2.1/2.2/2.3/2.4,目前流行的播放软件一般只支持第3版,即ID3V2.3。
  数据帧个数由文件大小和帧长决定,每个帧的长度可能不固定,也可能固定,由码率决定,每个帧又分为帧头和数据实体两部分,帧头记录了MP3的码率、采样率、版本等信息,每个帧之间相互独立。ID3V1存在文件尾部,长度为128字节。
  如果MP3音频文件存在ID3V2标签的话,在文件的首部顺序会记录10字节的ID3V2的头部,即标签头。之后则为ID3V2标签的标签帧,ID3V2由一个标签头和若干个标签帧或者一个扩展标签头组成,至少要有一个标签帧,每一个标签帧记录一种信息。ID3V2标签帧帧头的数据结构如下:
char Header[3]; /* 字符串"ID3" */
char Ver;       /* 版本号ID3V2.3就记录为3 */
char Revision;  /* 副版本号此版本记录为0 */
char Flag;      /* 存放标志的字节,这个版本只定义了3位,很少用到,可以忽略 */
char Size[4];   /* 标签大小,除了标签头的10字节的标签帧的大小 */
  ID3V1长度为128字节,位于文件尾部,其数据结构如下:
char Header[3];    /* 标签头必须是"TAG"否则认为没有标签 */
char Title[30];    /* 标题,可以看到上面选择部分确实是30字节*/
char Artist[30];   /* 作者 */
char Album[30];    /* 专集 */
char Year[4];      /* 出品年代 */
char Comment[28];  /* 备注 */
char reserve;      /* 保留 */
char track;        /* 音轨 */
char Genre;        /* 类型 */
  接下来是音频数据,每个数据帧都有一个帧头,长度是4字节(32位),帧头后面可能有2字节的CRC(cyclic redundancy check,循环冗余校验),这2字节是否存在取决于帧头信息的第16位,第16位为0则帧头后无CRC校验,为1则有CRC校验,校验值长度为2字节,之后就是帧的实体数据了,格式如图7-2所示。
图7-2  MP3音频数据帧的格式
  而帧头格式如表7-2所示,帧头长4字节(32位)。
表7-2  MP3帧头格式
  大小端模式
  编程中,有很多大于8位的数据类型,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于1字节,那么必然存在如何安排多字节的顺序问题。因此就导致了大端模式和小端模式。
  大端模式(big-endian)是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。
  小端模式(little-endian)是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。
  例如,数字0x12 34 56 78在内存中的表示形式。在大端模式下:
低地址--------------------------->高地址
0x12  |  0x34  |  0x56  |  0x78

在小端模式下:

低地址--------------------------->高地址
0x78  |  0x56  |  0x34  |  0x12?
  7.2.2  WAV文件
  WAV文件比MP3文件简单,如果对其结构足够熟悉,完全可以通过代码自己写入WAV文件,特别是在对音频进行调试的时候,这能提高效率,降低复杂度。
  以无损WAV格式文件为例,此时文件的音频数据部分为PCM,比较简单,重点在于WAV头部。一个典型的WAV文件头长度为44字节,包含采样率、通道数、样本位数等信息,如表7-3所示。
表7-3  WAV文件头
  表7-3为典型的WAV文件头格式,从0x00到0x2B总共44字节,从0x2C开始一直到文件末尾都是PCM音频数据。所以如果我们已经知道了PCM的采样信息,那么可以直接跳过头部的解析,直接从0x2C开始读取PCM即可。WAV文件头对应的结构体如下:
typedef struct {
    // WAV文件标志,值为“RIFF”,一个固定字符
    // 如果我们想判断一个音频文件是不是WAV格式,那么就看它的前4个字符是不是“RIFF”即可
    char ChunkID[4];
    // ChunkID和ChunkSize都是4字节
    unsigned long ChunkSize;
    // 表示是WAVE文件,值为“WAVE”,一个固定字符 */
    char  Format[4];
    // 波形格式标志,值为“fmt”,一个固定字符
    char  Subchunk1ID[4];
    // 数据格式,一般为16、32等
    unsigned long  Subchunk1Size;
    // 压缩格式,大于1表示有压缩,等于1表示无压缩(PCM格式)
    unsigned short AudioFormat;
    // 声道数量
    unsigned short NumChannels;
    // 采样频率
    unsigned long  SampleRate;
    // 字节率=采样频率*声道数量*采样位数/8
    unsigned long  ByteRate;
    // 块对齐之后的大小,也表示一帧的字节数,即通道数*采样位数/8
    unsigned short BlockAlign;
    // 采样位数,存储每个采样值所用的二进制数的位数,一般是4、8、12、16、24或32
    unsigned short BitsPerSample;
    // 数据标志位,值为“data”,一个固定字符
    char  Subchunk2ID[4];    
    // 实际的音频数据总字节数,即整个音频文件的字节数减去文件头部的字节数
    unsigned long  Subchunk2Size;
} WAVHeader;
版权声明:51Testing软件测试网获得作者授权连载本书部分章节。
任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号