FFmpeg源码分析:音频滤镜介绍(下)
2021/12/21 11:19:54
本文主要是介绍FFmpeg源码分析:音频滤镜介绍(下),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
FFmpeg在libavfilter模块提供音视频滤镜。所有的音频滤镜都注册在libavfilter/allfilters.c。我们也可以使用ffmpeg -filters命令行来查看当前支持的所有滤镜,前面-a代表音频。本篇文章主要介绍音频滤镜,包括:混音、静音填充、哈斯效应、合唱效果、均衡器、iir与fir滤波器、低通滤波器、带通滤波器、高通滤波器、变速变调、音量调节、静音检测。
关于音频滤镜的详细介绍,可查看官方文档:音频滤镜。上半部分的音频滤镜,可查看:音频滤镜介绍(上)。
1、amerge
合并,把两个或多个音频流合并到一个多通道的输出流。假如输入声道布局是交错的,那么输出声道布局相应地设置,声道根据需要进行重新排序。相反,假如输入声道布局不是交错的,那么先是第一个输入流的所有声道,然后是第二个输入流,依次类推。
比如合并两个音频流,参考命令如下:
ffmpeg -i one.mp3 -i two.mp3 -filter_complex [0:a][1:a]amerge=inputs=2[aout] -map [aout] out.mp3
2、amix
混音,把所有输入音频流混合成单个音频流。该滤镜仅支持浮点采样格式。如果是整型采样格式,会自动转换成浮点采样格式。参数选项如下:
- inputs:输入音频数,默认为2
- duration:混音后的音频时长
- longest:使用最长的输入流时长(默认)
- shortest:使用最短的输入流时长
- first:使用第一个输入流时长
- dropout_transition:过渡时间,默认为2秒
- weights:每个音频流的占比权重,默认所有音频流权重相同
- normalize:是否开启归一化,默认开启
混音代码位于libavfilter/af_amix.c,核心代码如下:
// 从FIFO队列读取若干采样数据,然后混音,写到输出缓冲区 static int output_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; MixContext *s = ctx->priv; AVFrame *out_buf, *in_buf; int nb_samples, ns, i; if (s->input_state[0] & INPUT_ON) { nb_samples = frame_list_next_frame_size(s->frame_list); for (i = 1; i < s->nb_inputs; i++) { if (s->input_state[i] & INPUT_ON) { ns = av_audio_fifo_size(s->fifos[i]); if (ns < nb_samples) { if (!(s->input_state[i] & INPUT_EOF)) return 0; nb_samples = ns; } } } s->next_pts = frame_list_next_pts(s->frame_list); } else { nb_samples = INT_MAX; for (i = 1; i < s->nb_inputs; i++) { if (s->input_state[i] & INPUT_ON) { ns = av_audio_fifo_size(s->fifos[i]); nb_samples = FFMIN(nb_samples, ns); } } if (nb_samples == INT_MAX) { ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts); return 0; } } frame_list_remove_samples(s->frame_list, nb_samples); calculate_scales(s, nb_samples); if (nb_samples == 0) return 0; out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) return AVERROR(ENOMEM); in_buf = ff_get_audio_buffer(outlink, nb_samples); if (!in_buf) { av_frame_free(&out_buf); return AVERROR(ENOMEM); } for (i = 0; i < s->nb_inputs; i++) { if (s->input_state[i] & INPUT_ON) { int planes, plane_size, p; // 从FIFO队列读取采样数据 av_audio_fifo_read(s->fifos[i], (void **)in_buf->extended_data, nb_samples); planes = s->planar ? s->nb_channels : 1; plane_size = nb_samples * (s->planar ? 1 : s->nb_channels); plane_size = FFALIGN(plane_size, 16); // 开始混音,判断是float类型还是double类型 if (out_buf->format == AV_SAMPLE_FMT_FLT || out_buf->format == AV_SAMPLE_FMT_FLTP) { for (p = 0; p < planes; p++) { s->fdsp->vector_fmac_scalar((float *)out_buf->extended_data[p], (float *) in_buf->extended_data[p], s->input_scale[i], plane_size); } } else { for (p = 0; p < planes; p++) { s->fdsp->vector_dmac_scalar((double *)out_buf->extended_data[p], (double *) in_buf->extended_data[p], s->input_scale[i], plane_size); } } } } av_frame_free(&in_buf); out_buf->pts = s->next_pts; if (s->next_pts != AV_NOPTS_VALUE) s->next_pts += nb_samples; return ff_filter_frame(outlink, out_buf); }
混音时,如果是浮点数据调用vector_fmac_scalar函数指针,来自libavutil/float_dsp.h的AVFloatDSPContext结构体一个成员变量。将源数据乘以标量,然后相加到目标矢量:
/** * Multiply a vector of floats by a scalar float and add to * destination vector. Source and destination vectors must * overlap exactly or not at all. * * @param dst result vector * constraints: 32-byte aligned * @param src input vector * constraints: 32-byte aligned * @param mul scalar value * @param len length of vector * constraints: multiple of 16 */ void (*vector_fmac_scalar)(float *dst, const float *src, float mul, int len);
在float_dsp.c源代码中,avpriv_float_dsp_alloc()对函数指针进行赋值:
av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) { AVFloatDSPContext *fdsp = av_mallocz(sizeof(AVFloatDSPContext)); if (!fdsp) return NULL; fdsp->vector_fmac_scalar = vector_fmac_scalar_c; fdsp->vector_fmul_scalar = vector_fmul_scalar_c; return fdsp; }
让我们看看vector_fmac_scalar_c()方法的实现:
static void vector_fmac_scalar_c(float *dst, const float *src, float mul, int len) { int i; for (i = 0; i < len; i++) dst[i] += src[i] * mul; }
3、apad
填充,将音频流结尾填充为静音。参数选项如下:
- packet_size:静音数据包大小,默认为4096
- pad_len:填充为静音的采样数
- whole_len:指定最少的输出采样数
- pad_dur:指定填充时长
- whole_dur:指定最小的输出时长
4、atempo
变速,调节音频播放速度。只接受一个参数atempo,取值范围[0.5, 100.0],默认为1.0。需要注意的是,如果atempo大于2,将会跳过一些采样数据。
音频改为2倍速,参考命令如下:
ffmpeg -i in.mp3 -filter_complex atempo=2.0 out.mp3
5、chorus
合唱,添加合唱效果到音频流。合唱类似于具有短延迟的回声效果,但回声的延迟是恒定的,而合唱则使用正弦波或三角形波调制来改变延迟。因此,延迟的声音听起来会更慢或更快,即延迟的声音会围绕原始声音进行调谐。参数选项如下:
- in_gain:输入增益,默认为0.4
- out_gain:输出增益,默认为0.4
- delays:延迟时间,一般为40ms到60ms
- decays:衰减系数
- speeds:设置速度
- depths:设置深度
6、haas
哈斯,应用哈斯效应到音效中。需要注意的是,这主要作用于单声道信号。将此滤波器应用单声道信号时,会提供方向感,并且转换为立体声。参数选项如下:
- level_in:输入等级,默认为1
- level_out:输出等级,默认为1
- side_gain:侧边增益,默认为1
- middle_source:中间声源类型,包括以下参数:
- ‘left’:选择左声道
- ‘right’:选择右声道
- ‘mid’:中间立体声道
- ‘side’:侧边立体声道
- middle_phase:是否改变中间相位,默认关闭
- left_delay:左声道延迟,默认为2.05 ms
- left_balance:左声道均衡,默认为-1
- left_gain:左声道增益,默认为1
- left_phase:改变左相位,默认关闭
- right_delay:右声道延迟,默认为2.12 ms
- right_balance:右声道均衡,默认为1
- right_gain:右声道增益,默认为1
- right_phase:改变右声道相位,默认开启
7、silencedetect
静音检测,检测音频流的静音部分。当该过滤器检测到输入音频音量小于或等于噪声容限值,且持续时间大于或等于检测到的最小噪声持续时间时,认定为静音。参数选项如下:
- noise, n:噪声容忍值,单位为dB, 默认为-60dB
- duration, d:设置静音时长,默认为2s
- mono, m:独立处理每个声道,默认关闭
检测静音的参考命令如下:
ffmpeg -i hello.mp3 -af silencedetect=noise=0.0001 -f null -
输出结果以silence_start开始,silence_end结束,silence_duraition为静音时长:
[silencedetect @ 0000020c67936fc0] silence_start: 268.82 [silencedetect @ 0000020c67936fc0] silence_end: 271.048 | silence_duration: 2.22796
这篇关于FFmpeg源码分析:音频滤镜介绍(下)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南