Python 实现 MP3 格式真伪校验:基于 ID3 与帧头解析

Finn
Finn
发布时间:2026-10-12 | 3人浏览过
原创

本文介绍如何使用 Python 判断音频文件是否为真正的 MP3 格式。由于仅靠后缀名不可靠,需通过解析文件结构来验证。MP3 文件通常包含 ID3V2 标签、音频帧和 ID3V1 标签。通过检测文件头部的 'ID3' 标识、结尾的 'TAG' 标识或帧头以 'FFF'(ASCII 255)开头,可有效区分真实 MP3 与伪装文件。

在项目中利用 MP3 格式播放音效时,曾遇到一个文件虽然以 .mp3 结尾,但在程序中无法播放声音。经排查发现,该文件实际为 WAV 格式,仅被错误地重命名。为了对资源进行准确的 MP3 格式判断,仅依赖文件后缀名是不可靠的,必须从编码格式层面进行判断。具体方法如下:

1. MP3 编码结构分析

MP3 文件属于流媒体文件格式,因此它没有像 AVI 或 WAV 那样统一的文件头(RIFF 结构)。对于 AVI 和 WAV 格式,可以通过对比 RIFF 字符串来快速识别,但 MP3 只能通过分析其内部编码结构来判断。这里简要说明 MP3 的编码规则,如需详细了解可参考相关技术文章。

一个标准的 MP3 文件大体由三个部分组成:TAG_V2(即 ID3V2)、音频数据帧、以及 TAG_V1(即 ID3V1)。

a). ID3V2 位于文件起始位置,以 'ID3' 字符串开头,存储了作者、作曲者、专辑等元数据。其长度不固定,是对 ID3V1 信息量的扩展,但并非所有 MP3 文件都包含此部分。

b). 一系列音频数据帧位于文件中间,帧的数量由文件大小和单帧长度决定。每个帧以 'FFF' 开头(对应 ASCII 码 255),帧长度可能固定也可能不固定,具体取决于位率(bitrate)。每个帧由帧头和数据实体两部分组成,帧头记录了 MP3 的位率、采样率和版本等信息,且各帧之间相互独立。

c). ID3V1 位于文件末尾,以 'TAG' 字符串开头,同样包含作者、作曲者、专辑等信息,其长度固定为 128 Byte。此部分也是可选的。

ID3V2

包含了作者,作曲,专辑等信息,长度不固定,扩展了ID3V1的信息量。

Frame

.

.

.

Frame

一系列的帧,个数由文件大小和帧长决定

每个FRAME的长度可能不固定,也可能固定,由位率bitrate决定

每个FRAME又分为帧头和数据实体两部分

帧头记录了mp3的位率,采样率,版本等信息,每个帧之间相互独立。

ID3V1

包含了作者,作曲,专辑等信息,长度为128BYTE。 

综上所述,通过检测上述三个结构(TAG_V2、音频数据帧、TAG_V1)中的特定开头标识,即可判断文件是否具备 MP3 编码特征。

2. Python 实现代码

# coding: utf-8

'''
@author: BigFengFeng
@time: 16/12/21 下午6:10
@license: Apache Licence
@description:

'''

import os

#mp3filePath是否是mp3格式的
def isMp3Format(mp3filePath):
 #读取文件内字符串
 f = open(mp3filePath, "r");
 fileStr = f.read();
 f.close();
 head3Str = fileStr[:3];

 #判断开头是不是ID3
 if head3Str == "ID3":
  return True;

 #判断结尾有没有TAG
 last32Str = fileStr[-32:];
 if last32Str[:3] == "TAG":
  return True;

 #判断第一帧是不是FFF开头, 转成数字
 # fixme 应该循环遍历每个帧头,这样才能100%判断是不是mp3
 ascii = ord(fileStr[:1]);
 if ascii == 255:
  return True;

 return False;


#遍历folderPath看看是不是都是mp3格式的,
#是就true,不是就是false, 并返回是mp3的list,不是MP3的list
def isMp3FolderTraverse(folderPath):
 mp3List = [];
 notMp3List = [];
 isAllMpFormat = True;
 for dirpath, dirnames, filenames in os.walk(folderPath):
  for filename in filenames:
   path = dirpath + os.sep + filename;
   isMp3 = isMp3Format(path);
   #判断是不是mp3结尾的 并且 是mp3格式的
   if isMp3 == False and str.endswith(path, ".mp3") == True:
    # print("--warning: file " + path + " is not mp3 format!--");
    notMp3List.append(path);
    isAllMpFormat = False;
   else:
    mp3List.append(path);
 return isAllMpFormat, mp3List, notMp3List;


if __name__ == '__main__':
 isMp3Format("s_com_click1.mp3");
 isAllMp3, mp3List, notMp3List = isMp3FolderTraverse("sound");
 print isAllMp3;
 print mp3List;
 print notMp3List;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表