一、概述
本文分析 FFmpeg
af_silencedetect
的实现。
二、af_silencedetect 的作用及基本原理
af_silencedetect 的作用是获取音频的最大音量、平均音量以及音量直方图。
它只支持 AV_SAMPLE_FMT_S16
、 AV_SAMPLE_FMT_S32
、 AV_SAMPLE_FMT_FLT
和 AV_SAMPLE_FMT_DBL
这四种格式——如果不是当然 FFmpeg 能够自动转换。
多大音量认为是静音由参数 noise
确定,默认是 -60dB
或 0.001
;多长的连续时长认为是静音由参数 duration
确定,默认是 2
秒。参数 mono
为非 0
表示各个声道分别检测,默认是合并在一起检测。
合并在一起检测:比如认为 2 秒连续无声(或小声)认为是静音,那么其中一个声道达标,另一个声道在该时段内不达标也不认为是静音。
三、在调用 ffmpeg 程序时使用 af_silencedetect
使用默认参数:
1 | ffmpeg -i input.mp3 -af "silencedetect" -vn -sn -dn -f null /dev/null |
在 Windows 中使用需将
/dev/null
替换为NUL
-vn
、-sn
和-dn
告知 FFmpeg 忽略非音频流。能够在分析时避免不必要的操作从而更快速.
输出类似于:
1 | [silencedetect @ 0x137f044d0] silence_start: 0 0x |
各个声道分别检测:
1 | ffmpeg -i 0.mp3 -af "silencedetect=mono=1" -vn -sn -dn -f null /dev/null |
输出类似于:
1 | [silencedetect @ 0x152704190] channel: 0 | silence_start: 0 |
四、源码分析
af_silencedetect 源码位于 ffmpg/libavfilter/af_silencedetect.c 中。
分析 filter 一般从 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
函数入手。不过由于要支持多种采样格式,需要在 static int config_input(AVFilterLink *inlink)
根据采样格式设置检测函数。
1 | static int config_input(AVFilterLink *inlink) |
nb_null_samples
用于累加达标的采样数,通过
silencedetect_dbl
、silencedetect_flt
、silencedetect_s32
和 silencedetect_s16
由宏定义:
1 |
|
update
用于检测每一个采样:
1 | static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, |
五、C# 简单实现
1 | public class VolumeUtils |
由于本人需要,对于多声道本方法也只检测第一个声道。在多个声道音量不是交错的情况下有助于提升效率。