音视频入门基础: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;
相关推荐
骄傲的心别枯萎2 小时前
RV1126 NO.57:ROCKX+RV1126人脸识别推流项目之读取人脸图片并把特征值保存到sqlite3数据库
数据库·opencv·计算机视觉·sqlite·音视频·rv1126
好游科技2 小时前
IM即时通讯系统:安全可控、功能全面的社交解决方案全解析
安全·音视频·webrtc·im即时通讯·私有化部署im即时通讯·社交app
EasyDSS3 小时前
视频直播点播平台EasyDSS构建高并发、低延迟的远程教学直播新模式
音视频
GIOTTO情3 小时前
多模态舆情监测技术深度解析:Infoseek 如何实现 AI 造假与短视频舆情的精准捕捉?
人工智能·音视频
音视频牛哥3 小时前
C# 开发工业级 RTSP/RTMP 播放器实战:基于 SmartMediakit 的低延迟与高可靠性设计
音视频·rtsp播放器·rtmp播放器·windows rtsp播放器·windows rtmp播放器·c# rtsp播放器·c# rtmp播放器
JellyDDD3 小时前
【悬赏】Android WebRTC 数字人项目回声问题排查(AEC / AudioMode)
音视频·webrtc
于是我说4 小时前
如何判断一个视频到底是真实 MP4 直链,还是流媒体M3U8
网络·音视频
gf13211114 小时前
剪映草稿位置坐标换算
音视频
ACP广源盛139246256734 小时前
GSV1011@ACP#1011产品规格详解及产品应用分享
嵌入式硬件·计算机外设·音视频
阿道夫小狮子5 小时前
android 音频抢占问题
android·音视频