FFmpeg在libavfilter模块提供音视频滤镜。所有的音频滤镜都注册在libavfilter/allfilters.c。我们也可以使用ffmpeg -filters命令行来查看当前支持的所有滤镜,前面-a代表音频。本篇文章主要介绍音频滤镜,包括:压缩器、淡入淡出、移除噪声、延时、回声、噪声门。

关于音频滤镜的详细介绍,可查看官方文档:音频滤镜。

1、acompressor

压缩器,主要用于减小信号的动态范围。尤其是现代音乐,大多数以高压缩比,提高整体响度。压缩原理是通过检测信号超过所设定阈值,将其除以比例因子。参数选项如下:

  • level_in:输入增益,默认为1,范围[0.015625, 64]
  • mode:压缩模式,有 upward和downward两种模式, 默认为downward
  • threshold:如果媒体流信号达到此阈值,会引起增益减少。默认为0.125,范围[0.00097563, 1]
  • ratio:信号压缩的比例因子,默认为2,范围[1, 20]
  • attack:信号提升到阈值所用的毫秒数,默认为20,范围[0.01, 2000]
  • release:信号降低到阈值所用的毫秒数,默认为250,范围[0.01, 9000]
  • makeup:在处理后,多少信号被放大. 默认为1,范围[1, 64]
  • knee:增益降低的阶数,默认为2.82843,范围[1, 8]
  • link:信号衰减的averagemaximum两种模式, 默认为average
  • detection:采用peak峰值信号或rms均方根信号,默认采用更加平滑的rms
  • mix:输出时使用多少压缩信号, 默认为1,范围[0, 1]

2、acrossfade

淡入淡出效果,将该效果应用到从一个音频流到另一个音频流的切换过程。参数选项如下:

  • nb_samples, ns:指定淡入淡出效果的采样数, 默认为44100
  • duration, d:指定淡入淡出的持续时间
  • overlap, o:第一个流结束是否与第二个流无缝衔接,默认开启
  • curve1:设置第一个流淡入淡出的过渡曲线
  • curve2:设置第二个流淡入淡出的过渡曲线

参考命令如下:

ffmpeg -i first.flac -i second.flac -filter_complex acrossfade=d=10:c1=exp:c2=exp output.flac

3、afade

淡入淡出效果,与acrossfade效果类似。参数列表如下:

type, t:效果类型in或者out,默认为in

start_sample, ss:开始采样数,默认为0

nb_samples, ns:淡入淡出的采样个数,默认为44100

start_time, st:开始时间,默认为0

duration, d:淡入淡出效果持续时长

curve:淡入淡出的过渡曲线,包括以下选项:

  • tri:三角形,默认为线性斜率
  • qsin:四分之一正弦波
  • hsin:二分之一正弦波
  • esin:指数正弦波
  • log:对数
  • ipar:反抛物线
  • qua:二次插值
  • cub:三次插值
  • squ:平方根
  • cbr:立方根
  • par:抛物线
  • exp:指数
  • iqsin:反四分之一正弦波
  • ihsin:反二分之一正弦波
  • dese:双指数
  • desi:双指数曲线
  • losi:回归曲线
  • sinc:正弦基数函数
  • isinc:反正弦基数函数
  • nofade:无淡入淡出

同样地,采用宏定义给不同采样格式设置淡入淡出效果,代码位于af_afade.c,分为FADE_PLANAR(平面存储)和FADE(交错存储)两种形式:

#define FADE_PLANAR(name, type)                                             \
static void fade_samples_## name ##p(uint8_t **dst, uint8_t * const *src,   \int nb_samples, int channels, int dir, \int64_t start, int64_t range, int curve) \
{                                                                           \int i, c;                                                               \\for (i = 0; i < nb_samples; i++) {                                      \double gain = fade_gain(curve, start + i * dir, range);             \for (c = 0; c < channels; c++) {                                    \type *d = (type *)dst[c];                                       \const type *s = (type *)src[c];                                 \\d[i] = s[i] * gain;                                             \}                                                                   \}                                                                       \
}#define FADE(name, type)                                                    \
static void fade_samples_## name (uint8_t **dst, uint8_t * const *src,      \int nb_samples, int channels, int dir,    \int64_t start, int64_t range, int curve)  \
{                                                                           \type *d = (type *)dst[0];                                               \const type *s = (type *)src[0];                                         \int i, c, k = 0;                                                        \\for (i = 0; i < nb_samples; i++) {                                      \double gain = fade_gain(curve, start + i * dir, range);             \for (c = 0; c < channels; c++, k++)                                 \d[k] = s[k] * gain;                                             \}                                                                       \
}

4、adeclick

从输入信号移除脉冲噪声。使用自回归模型将检测为脉冲噪声的样本替换为插值样本。参数选项如下:

  • window, w:设置窗函数大小,单位为ms。默认为55,范围[10, 100]
  • overlap, o:设置窗体重叠比例,默认为75,范围[50, 95]
  • arorder, a:设置自回归阶数,默认2,范围[0, 25]
  • threshold, t:设置阈值,默认为2,范围[1, 100]
  • burst, b:设置聚变系数,默认为2,范围[0, 10]
  • method, m:设置重叠方法,可以为add, a或save, s

5、adelay

延迟效果,声道的延迟采样使用静音填充。代码位于libavfilter/af_adelay.c,采用宏定义把对应采样格式填充为静音。如果是u8类型填充为0x80,其他类型填充为0x00,核心代码如下:

#define DELAY(name, type, fill)                                           \
static void delay_channel_## name ##p(ChanDelay *d, int nb_samples,       \const uint8_t *ssrc, uint8_t *ddst) \
{                                                                         \const type *src = (type *)ssrc;                                       \type *dst = (type *)ddst;                                             \type *samples = (type *)d->samples;                                   \\while (nb_samples) {                                                  \if (d->delay_index < d->delay) {                                  \const int len = FFMIN(nb_samples, d->delay - d->delay_index); \\memcpy(&samples[d->delay_index], src, len * sizeof(type));    \memset(dst, fill, len * sizeof(type));                        \d->delay_index += len;                                        \src += len;                                                   \dst += len;                                                   \nb_samples -= len;                                            \} else {                                                          \*dst = samples[d->index];                                     \samples[d->index] = *src;                                     \nb_samples--;                                                 \d->index++;                                                   \src++, dst++;                                                 \d->index = d->index >= d->delay ? 0 : d->index;               \}                                                                 \}                                                                     \
}DELAY(u8,  uint8_t, 0x80)
DELAY(s16, int16_t, 0)
DELAY(s32, int32_t, 0)
DELAY(flt, float,   0)
DELAY(dbl, double,  0)

6、aecho

回声效果,添加回声到音频流。回声是反射声音,在山间或房间内会形成自然反射声。数字回声信号可以模拟这种效果,通过调节原始声与反射声的延迟时间与衰减系数。其中原始声又称为干声,反射声称为湿声。参数选项如下:

  • in_gain:反射声的输入增益,默认为 0.6
  • out_gain:反射声的输出增益,默认为0.3
  • delays:每次反射声的延迟间隔,使用'|'分隔,默认为1000,范围为(0, 90000.0]
  • decays:每次反射声的衰减系数,使用'|'分隔,默认为0,范围为(0, 1.0]

比如,模拟在山间的回声,参考命令如下:

aecho=0.8:0.9:1000:0.3

代码位于af_aecho.c,采用宏定义来设置不同采样格式的回声:

#define ECHO(name, type, min, max)                                          \
static void echo_samples_## name ##p(AudioEchoContext *ctx,                 \uint8_t **delayptrs,                   \uint8_t * const *src, uint8_t **dst,   \int nb_samples, int channels)          \
{                                                                           \const double out_gain = ctx->out_gain;                                  \const double in_gain = ctx->in_gain;                                    \const int nb_echoes = ctx->nb_echoes;                                   \const int max_samples = ctx->max_samples;                               \int i, j, chan, av_uninit(index);                                       \\av_assert1(channels > 0); /* would corrupt delay_index */               \\for (chan = 0; chan < channels; chan++) {                               \const type *s = (type *)src[chan];                                  \type *d = (type *)dst[chan];                                        \type *dbuf = (type *)delayptrs[chan];                               \\index = ctx->delay_index;                                           \for (i = 0; i < nb_samples; i++, s++, d++) {                        \double out, in;                                                 \\in = *s;                                                        \out = in * in_gain;                                             \for (j = 0; j < nb_echoes; j++) {                               \int ix = index + max_samples - ctx->samples[j];             \ix = MOD(ix, max_samples);                                  \out += dbuf[ix] * ctx->decay[j];                            \}                                                               \out *= out_gain;                                                \\*d = av_clipd(out, min, max);                                   \dbuf[index] = in;                                               \\index = MOD(index + 1, max_samples);                            \}                                                                   \}                                                                       \ctx->delay_index = index;                                               \
}ECHO(dbl, double,  -1.0,      1.0      )
ECHO(flt, float,   -1.0,      1.0      )
ECHO(s16, int16_t, INT16_MIN, INT16_MAX)
ECHO(s32, int32_t, INT32_MIN, INT32_MAX)

7、agate

噪声门,用于减少低频信号,消除有用信号中的干扰噪声。通过检测低于阈值的信号,将其除以设定的比例因子。参数选项如下:

  • level_in:输入等级,默认为0,范围[0.015625, 64]
  • mode:操作模式upward或downward.,默认为downward
  • range:增益衰减范围,默认为 0.06125,范围[0, 1]
  • threshold:增益提升的阈值,默认为0.125,范围[0, 1]
  • ratio:增益衰减的比例因子,默认为2,范围[1, 9000]
  • attack:信号放大时间,默认为20ms,范围[0.01, 9000]
  • release:信号衰减时间,默认为250ms.,范围[0.01, 9000]
  • makeup:信号放大系数,默认为1,范围[1, 64]
  • detection:探测方式,peak或 rms,默认为 rms
  • link:衰减方式,average或maximum,默认为average

8、alimiter

限幅器,用于防止输入信号超过设定阈值。使用前向预测避免信号失真,意味着信号处理有一点延迟。参数选项如下:

  • level_in:输入增益,默认为1
  • level_out:输出增益,默认为1
  • limit:限制信号不超过阈值,默认为1
  • attack:信号放大时间,默认为5ms
  • release:信号衰减时间,默认为50ms
  • asc:需要减少增益时,ASC负责减少到平均水平
  • asc_level:衰减时间等级, 0代表不需要额外时间,1代表需要额外时间
  • level:自动调整输出信号,默认关闭

限幅器的代码位于af_alimiter.c,核心代码如下:

static int filter_frame(AVFilterLink *inlink, AVFrame *in)
{......// 循环检测每个samplefor (n = 0; n < in->nb_samples; n++) {double peak = 0;for (c = 0; c < channels; c++) {double sample = src[c] * level_in;buffer[s->pos + c] = sample;peak = FFMAX(peak, fabs(sample));}if (s->auto_release && peak > limit) {s->asc += peak;s->asc_c++;}if (peak > limit) {double patt = FFMIN(limit / peak, 1.);double rdelta = get_rdelta(s, release, inlink->sample_rate,peak, limit, patt, 0);double delta = (limit / peak - s->att) / buffer_size * channels;int found = 0;if (delta < s->delta) {s->delta = delta;nextpos[0] = s->pos;nextpos[1] = -1;nextdelta[0] = rdelta;s->nextlen = 1;s->nextiter= 0;} else {for (i = s->nextiter; i < s->nextiter + s->nextlen; i++) {int j = i % buffer_size;double ppeak, pdelta;ppeak = fabs(buffer[nextpos[j]]) > fabs(buffer[nextpos[j] + 1]) ?fabs(buffer[nextpos[j]]) : fabs(buffer[nextpos[j] + 1]);pdelta = (limit / peak - limit / ppeak) / (((buffer_size - nextpos[j] + s->pos) % buffer_size) / channels);if (pdelta < nextdelta[j]) {nextdelta[j] = pdelta;found = 1;break;}}if (found) {s->nextlen = i - s->nextiter + 1;nextpos[(s->nextiter + s->nextlen) % buffer_size] = s->pos;nextdelta[(s->nextiter + s->nextlen) % buffer_size] = rdelta;nextpos[(s->nextiter + s->nextlen + 1) % buffer_size] = -1;s->nextlen++;}}}buf = &s->buffer[(s->pos + channels) % buffer_size];peak = 0;for (c = 0; c < channels; c++) {double sample = buf[c];peak = FFMAX(peak, fabs(sample));}if (s->pos == s->asc_pos && !s->asc_changed)s->asc_pos = -1;if (s->auto_release && s->asc_pos == -1 && peak > limit) {s->asc -= peak;s->asc_c--;}s->att += s->delta;for (c = 0; c < channels; c++)dst[c] = buf[c] * s->att;if ((s->pos + channels) % buffer_size == nextpos[s->nextiter]) {if (s->auto_release) {s->delta = get_rdelta(s, release, inlink->sample_rate,peak, limit, s->att, 1);if (s->nextlen > 1) {int pnextpos = nextpos[(s->nextiter + 1) % buffer_size];double ppeak = fabs(buffer[pnextpos]) > fabs(buffer[pnextpos + 1]) ?fabs(buffer[pnextpos]) :fabs(buffer[pnextpos + 1]);double pdelta = (limit / ppeak - s->att) /(((buffer_size + pnextpos -((s->pos + channels) % buffer_size)) %buffer_size) / channels);if (pdelta < s->delta)s->delta = pdelta;}} else {s->delta = nextdelta[s->nextiter];s->att = limit / peak;}s->nextlen -= 1;nextpos[s->nextiter] = -1;s->nextiter = (s->nextiter + 1) % buffer_size;}if (s->att > 1.) {s->att = 1.;s->delta = 0.;s->nextiter = 0;s->nextlen = 0;nextpos[0] = -1;}if (s->att <= 0.) {s->att = 0.0000000000001;s->delta = (1.0 - s->att) / (inlink->sample_rate * release);}if (s->att != 1. && (1. - s->att) < 0.0000000000001)s->att = 1.;if (s->delta != 0. && fabs(s->delta) < 0.00000000000001)s->delta = 0.;for (c = 0; c < channels; c++)dst[c] = av_clipd(dst[c], -limit, limit) * level * level_out;s->pos = (s->pos + channels) % buffer_size;src += channels;dst += channels;}if (in != out)av_frame_free(&in);return ff_filter_frame(outlink, out);
}

FFmpeg源码分析:音频滤镜介绍(上)相关推荐

  1. FFmpeg源码分析:视频滤镜介绍(上)

    FFmpeg在libavfilter模块提供音视频滤镜.所有的视频滤镜都注册在libavfilter/allfilters.c.我们也可以使用ffmpeg -filters命令行来查看当前支持的所有滤 ...

  2. ffmpeg源码分析-parse_optgroup

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

  3. ffmpeg源码分析-ffmpeg_parse_options

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

  4. ffmpeg源码分析-transcode_step

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

  5. FFMPEG源码分析(一)

    FFMPEG源码分析(一) ffmpeg之前公司项目中就使用过,但是多停留于应用层面,实现某个功能时,需要哪些结构体以及调用哪些函数.最近想系统的学习一下ffmpeg,于是开始看雷霄骅https:// ...

  6. FFMPEG源码分析(二)

    ffmpeg源码分析之数据流 本文主要介绍ffmpeg的数据流,在ffmpeg中主要分有三个主要用途用于媒体流的解码播放,媒体流的转换(解码之后再编码)和媒体流录制. 媒体流的解码播放 在ffmpeg ...

  7. FFMPEG 源码分析

    FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库.FFMPEG是在linux下开发的,但也有windows下的编译版本. ffmpeg项目由以下几部分组 ...

  8. 【SemiDrive源码分析】【X9芯片启动流程】08 - X9平台 lk 目录源码分析 之 目录介绍

    [SemiDrive源码分析][X9芯片启动流程]08 - X9平台 lk 目录源码分析 之 目录介绍 一./rtos/lk/ 目录结构分析 1.1 /rtos/lk_boot/ 目录结构分析 1.2 ...

  9. 集合底层源码分析之HashMap《上》(三)

    集合底层源码分析之HashMap<上>(三) 前言 源码分析 HashMap主要属性及构造方法分析 tableSizeFor()方法源码分析 Node类源码分析 TreeNode类源码分析 ...

  10. FFmpeg源码分析-直播延迟-内存泄漏

    FFmpeg源码分析-直播延迟-内存泄漏|FFmpeg源码分析方法|ffmpeg播放为什么容易产生延迟|解复用.解码内存泄漏分析 专注后台服务器开发,包括C/C++,Linux,Nginx,ZeroM ...

最新文章

  1. QT的QWGLNativeContext类的使用
  2. ORA-01810: 格式代码出现两次
  3. 盘点那些面试中最常问的MySQL问题
  4. 会java的鸭子_鸭子在Java中打字? 好吧,不完全是
  5. 列举网络芳邻的网络资源
  6. 处理硬件设备访问权限问题
  7. 【转】刨根究底字符编码之十二——UTF-8究竟是怎么编码的
  8. 老罗Android开发视频教程( android解析json数据 )4集集合
  9. mysql 覆盖式索引_【MySQL】性能优化之 覆盖索引
  10. 一文告诉你市面上最火的游戏都是用什么引擎做的!!!
  11. 旧视频调整为4k视频提高分辨率Topaz Video Enhance AI
  12. 计算机组成原理(第三版)唐朔飞-第四章存储器-课后习题
  13. nodejs 定时任务
  14. 云原生爱好者周刊:炫酷的 Grafana 监控面板集合
  15. 一个矩阵与单位矩阵相乘等于本身吗?并且符合交换律吗?
  16. win系统下设置小鹤双拼
  17. mysql 1093 you can_mysql中错误:1093-You can’t specify target table for update in FROM clause的解决方法...
  18. excel表格汇总软件
  19. 大数据因果推理与学习入门综合概述
  20. Wallystech|802.11r Fast Roaming hardware IPQ4019 IPQ4029 routerboard

热门文章

  1. 微信怎么屏蔽他人的朋友圈?图文教学,1分钟学会
  2. Linux下编译pjproject-2.6并运行例程simple_pjsua
  3. jdk安装,提示错误1335
  4. 1.设计一个长方形的类,成员变量有长与宽,成员函数有求周长与面积,然后进行测试。要求有构造函数、析造函数和复制构造函数。
  5. 费雪分离定理的证明与评价
  6. abp zero mysql_ABP从入门到精通(2):aspnet-zero-core 使用MySql数据库
  7. 运行mysql时,提示Table ‘performance_schema.session_variables’ doesn’t exis
  8. web前端期末大作业网页设计与制作 ——汉口我的家乡旅游景点 5页HTML+CSS+JavaScript
  9. Prometheus配置企业微信报警
  10. 电脑作为文件服务器,把电脑做成一个云文件服务器