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

avatar
作者
筋斗云
阅读量:0

一、引言

通过FFmpeg命令:

./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中:

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中:

/**  * 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格式:

/* 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格式时产生的冲突:

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当成一种文件格式来处理:

else if ((!memcmp(p->buf,      "RF64", 4) ||                   !memcmp(p->buf,      "BW64", 4)) &&                  !memcmp(p->buf + 12, "ds64", 4))             return AVPROBE_SCORE_MAX;

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!