音视频入门基础:WAV专题(3)——FFmpeg源码中,判断某文件是否为WAV音频文件的实现

一、引言

通过FFmpeg命令:

cpp 复制代码
./ffmpeg -i XXX.wav

可以判断出某个文件是否为WAV格式的音频文件:

所以FFmpeg是怎样判断出某个文件是否为WAV格式的音频文件呢?它内部其实是通过wav_probe函数来判断的。从文章《FFmpeg源码:av_probe_input_format3函数分析》中我们可以知道:

FFmpeg中实现容器格式检测的函数是av_probe_input_format3函数,其内部通过循环while ((fmt1 = av_demuxer_iterate(&i))) 拿到所有容器格式对应的AVInputFormat结构,然后通过score = fmt1->read_probe(&lpd)语句执行不同容器格式对应的解析函数,根据是否能被解析,以及匹配程度,来判断出这是哪种容器格式。而WAV格式的音频文件对应的解析函数就是wav_probe函数。

二、wav_probe函数的定义

wav_probe函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为5.0.3)的源文件libavformat/wavdec.c中:

cpp 复制代码
static int wav_probe(const AVProbeData *p)
{
    /* check file header */
    if (p->buf_size <= 32)
        return 0;
    if (!memcmp(p->buf + 8, "WAVE", 4)) {
        if (!memcmp(p->buf, "RIFF", 4) || !memcmp(p->buf, "RIFX", 4))
            /* Since the ACT demuxer has a standard WAV header at the top of
             * its own, the returned score is decreased to avoid a probe
             * conflict between ACT and WAV. */
            return AVPROBE_SCORE_MAX - 1;
        else if ((!memcmp(p->buf,      "RF64", 4) ||
                  !memcmp(p->buf,      "BW64", 4)) &&
                 !memcmp(p->buf + 12, "ds64", 4))
            return AVPROBE_SCORE_MAX;
    }
    return 0;
}

其作用就是检测某个文件是否为WAV格式的音频文件。

形参pd:输入型参数,为AVProbeData类型的指针。

AVProbeData结构体声明在libavformat/avformat.h中:

cpp 复制代码
/**
 * This structure contains the data a format has to probe a file.
 */
typedef struct AVProbeData {
    const char *filename;
    unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */
    int buf_size;       /**< Size of buf except extra allocated bytes */
    const char *mime_type; /**< mime_type, when known. */
} AVProbeData;

p->filename为:需要被推测格式的文件的路径。

p->buf:指向"存放从路径为p->filename的文件中读取出来的二进制数据"的缓冲区。

p->buf_size:缓冲区p->buf的大小,单位为字节。注:FFmpeg判断某个文件的格式时不会读取完整个文件,只会读取它前面的一部分,比如最开始的2048个字节。只要根据前面的这些字节就足够判断出它的格式了,所以p->buf_size的值一般就是2048。

p->mime_type:一般为NULL,可忽略。

返回值:返回一个类型为整形的分值。返回0表示该文件完全不符合WAV格式。返回一个大于0的值表示该文件比较符合WAV格式,但还需要在av_probe_input_format3函数中执行其它容器格式对应的解析函数来进行对比,最终通过最高分来确定到底是哪种容器格式。

三、wav_probe函数的内部实现原理

wav_probe函数中,首先有如下判断逻辑:如果能读取到的文件中的二进制数据量小于32个字节,远远小于WAV Header中必须包含的数据量,wav_probe函数返回0,表示该文件完全不符合WAV格式:

cpp 复制代码
/* check file header */
    if (p->buf_size <= 32)
        return 0;

由《音视频入门基础:WAV专题(2)------WAV格式简介》可以知道,WAV文件的第0到3字节为"区块编号",内容必须为"RIFF"或"RIFX";第8到11字节为"档案格式",内容必须固定为"WAVE"。所以通过下面代码来判断该文件是否符合上述条件,如果符合返回AVPROBE_SCORE_MAX - 1(也就是返回99分),意味着该文件比较符合WAV格式。 从文章《FFmpeg源码:av_probe_input_format3函数分析》中我们可以知道容器格式探测函数的分值最高为100分,100分才是完全符合这种格式。所以为什么下面代码中不是返回100分只是返回99分呢?因为ACT音频格式可能会包含一个标准的WAV文件头,所以FFmpeg将分值减小来避免探测ACT和WAV格式时产生的冲突:

cpp 复制代码
f (!memcmp(p->buf + 8, "WAVE", 4)) {
        if (!memcmp(p->buf, "RIFF", 4) || !memcmp(p->buf, "RIFX", 4))
            /* Since the ACT demuxer has a standard WAV header at the top of
             * its own, the returned score is decreased to avoid a probe
             * conflict between ACT and WAV. */
            return AVPROBE_SCORE_MAX - 1;

如果不符合上述的判断,通过下面代码判断该文件是否为WAVE 64位扩展格式Wave64,如果符合,返回AVPROBE_SCORE_MAX(也就是返回100分),意味着该文件完全符合WAV格式。FFmpeg内部把WAV和Wave64当成一种文件格式来处理:

cpp 复制代码
else if ((!memcmp(p->buf,      "RF64", 4) ||
                  !memcmp(p->buf,      "BW64", 4)) &&
                 !memcmp(p->buf + 12, "ds64", 4))
            return AVPROBE_SCORE_MAX;
相关推荐
批量小王子5 分钟前
2025-06-13【视频处理】基于视频内容转场进行分割
音视频
Jay Kay14 小时前
MemVid:信息存储的未来?创新还是“视频噱头”?
音视频
昨日之日200616 小时前
LatentSync V8版 - 音频驱动视频生成数字人说话视频 更新V1.6版模型 支持50系显卡 支持批量 一键整合包下载
人工智能·音视频
知舟不叙17 小时前
基于OpenCV实现视频运动目标检测与跟踪
opencv·目标检测·目标跟踪·音视频
allnlei19 小时前
修改FFMpeg的日志函数av_log,使其在记录日志时能显示调用该函数的位置(文件名和行号)
ffmpeg
sukalot21 小时前
window 显示驱动开发-处理视频帧
驱动开发·音视频
Sherlock Ma21 小时前
Seedance:字节发布视频生成基础模型新SOTA,能力全面提升
人工智能·深度学习·计算机视觉·aigc·音视频·扩散模型·视频生成
Everbrilliant891 天前
音视频之H.264/AVC编码器原理
音视频·h.264·h.264编解码·h.264帧内预测·h.264帧间预测·h.264的sp/si帧技术·h.264码率控制
s_little_monster1 天前
【Linux开发】海思摄像头内部视频处理模块
linux·运维·经验分享·学习·音视频·嵌入式开发·海思
vfvfb1 天前
视频音频去掉开头结尾 视频去掉前n秒后n秒 电视剧去掉开头歌曲
音视频·批量去掉视频开头·批量去掉崇·去掉mp3开头几秒·批量去掉视频结尾歌曲