响度计算方法之EBU R.128

响度测量算法主要有三种:

Peak:只检测峰值

RMS:均方根运算,输出 平均响度 和 最大响度(最大刻度为 零),即使音频的峰值响度超过了 零,依然显示为 零;适用于正态分布模型(否则会有失真)

EBU R.128:主要特点:1. 用两个 Gate 过滤了音频中的 “静默” 场景;2. 检测方法更符合人类听觉感知;3. 算法不是很复杂,避免对设备造成过大负担;4. 未来随着技术的革新与设备的升级,会有更加优秀的算法出现。

本篇主要介绍EBU R.128响度测量原理和怎样使用ffmpeg进行响度测量

EBU R.128方法介绍

EBU R128是一个基于欧洲广播联盟 (EBU) R128标准的响度测量算法。这个标准旨在提供一种统一的、国际性的音频响度测量方法,以解决由于广播内容响度差异大造成的听觉不一致问题。EBU R128的主要特点包括:

响度单位:EBU R128使用响度单位(Loudness Unit,简称LU)来衡量音频的感知响度,其中1 LU等于1 分贝。标准还定义了LUFS(Loudness Units relative to Full Scale),一种相对于满量程的响度单位,用于数字音频。

K权重滤波器:EBU R128使用K权重滤波器来模拟人耳对不同频率声音的感知敏感度。这是一种频率加权滤波器,强调人耳对某些频率范围的敏感度。

综合响度(Integrated Loudness,I):这是整个节目或音频段的平均响度。它是基于整个音频内容的长期平均值计算出来的。

短期响度(Short-term Loudness,S):它是在较短的时间窗口(例如3秒)内计算的响度。这有助于识别音频中的短暂响度变化。

瞬时响度(Momentary Loudness,M):这是基于更短的时间窗口(例如400毫秒)计算的响度,用于捕捉音频的即时变化。

响度范围(Loudness Range,LRA):这是一个衡量音频响度变化范围的指标,通常用于评估音频的动态范围。

真峰值(True Peak):这是测量音频波形的最大振幅,以确保音频不会超过特定的峰值限制,从而避免失真。

在实际应用中,ebur128算法会对音频信号进行K权重滤波,然后基于定义的时间窗口计算响度。这通常涉及取样本的平方,应用时间加权,然后计算对数平均值以获取响度值。这个过程会根据音频的持续时间和内容的动态范围反复进行,以生成综合响度、短期响度、瞬时响度和响度范围等指标。

ffmpeg怎样分析响度

ffmpeg命令打印分析EBU R.128

ffmpeg -i input_audio.wav -filter_complex ebur128 -f null -

在这个例子中:

-i input_audio.wav

-filter_complex ebur128,使用ebur128算法进行响度分析


下面是ffmpeg的输出结果:

t:时间,单位是秒;

M:瞬时响度(Momentary Loudness, M),单位是lufs

I:综合响度(Integrated Loudness, I),单位是lufs

LRA:响度范围(Loudness Range, LRA),单位lu

ffmpeg命令打印分析音量

ffmpeg -nostats -i  input_audio.wav  -af "volumedetect"  -f null -

ffplay 可视化的方法

ffplay -f lavfi -i "amovie=input_audio.wav,ebur128=video=1:meter=18 [out0][out1]"

主绘图区域包含短期响度(3秒分析),右侧的刻度用于瞬时响度(400毫秒)

EBU R.128算法详解

原理

综合响度 的计算:

综合响度 的计算分两个阶段,由两个门限(Gate)控制。

第一阶段:若 瞬时响度 (即400ms 的 “块”)大于 绝对门限阈值(-70 LUFS),则此 “块” 获准通过 绝对门限 ,参与下一步的计算,这些 “块” 的综合响度为 一阶综合响度 ,即上图中的 绿线 Lk,no gate = -26 LUFS,将此 一阶综合响度 减去 10 LU 后的值设为 相对门限阈值(-36 LUFS),即上图中的 红线 。

第二阶段:若 瞬时响度 (即400ms 的 “块”)大于 相对门限阈值 (-36 LUFS),则此 “块” 获准通过 相对门限 ,参与下一步的计算,这些 “块” 的综合响度为 二阶综合响度 ,即上图中的 黄线 Lk,gated = -25.2 LUFS,此为最终 综合响度。

响度范围 的计算需要使用到 “ 综合响度 的计算的第一阶段生成的 一阶综合响度 ”,上图中 绿线,减去 20 LU 得到 紫线(-41.8 LUFS),以 紫线 为 响度范围的相对门限阈值,剔除前 10% 和 后 5%,所遗留区域的范围即为 响度范围,上图中 橙色区域 。

ffmpeg中ebur算法实现详解

代码路径

“libavfilter/f_ebur128.c”

代码结构解析

数据结构解析

宏定义和常量:

定义了用于预滤波器和RLB滤波器的系数

// 预滤波器的系数定义

#definePRE_B0 1.53512485958697

#definePRE_B1 -2.69169618940638

#definePRE_B2 1.19839281085285

#definePRE_A1 -1.69065929318241

#definePRE_A2 0.73248077421585

// RLB滤波器的系数定义

#defineRLB_B0 1.0

#defineRLB_B1 -2.0

#defineRLB_B2 1.0

#defineRLB_A1 -1.99004745483398

#defineRLB_A2 0.99007225036621

定义了其他的常量,如最大通道数、静音门限和直方图的大小

// 定义静音门限(LUFS)

#defineABS_THRES -70

// 定义上限响度门限

#defineABS_UP_THRES 10

// 定义直方图精度

#defineHIST_GRAIN 100

// 计算直方图大小

#defineHIST_SIZE ((ABS_UP_THRES - ABS_THRES) * HIST_GRAIN + 1)

结构体定义:

hist_entry:存储响度直方图的条目

// 直方图条目的结构体定义

struct hist_entry {    int count;      // 对应值出现的次数  

  double energy;  // 能量 E = 10^((L + 0.691) / 10)    

  double loudness; // 响度 L = -0.691 + 10 * log10(E)

};

integrator:存储集成响度计算所需的各种参数和缓存。

// 积分器结构体定义

struct integrator { 

 double *cache[MAX_CHANNELS]; // 滤波后样本的窗口(N毫秒)

 int cache_pos; // 缓存数组中最后添加的元素位置 

 double sum[MAX_CHANNELS]; // 最后N毫秒滤波后样本的和(缓存内容)

 int filled; // 如果缓存完全填满则为1,否则为0 

 double rel_threshold; // 相对阈值 

 double sum_kept_powers; // 高于绝对阈值的功率和 

 int nb_kept_powers; // 高于绝对阈值的求和次数 

 structhist_entry*histogram; // 功率的直方图,用于计算LRA和I

};

EBUR128Context:主结构体,包含所有滤波器状态、配置和缓存。

// EBU R128上下文结构体定义

typedef struct{ 

 const AVClass *class; // AVClass上下文,用于日志和选项 ...

...

    // 视频相关的字段

 int do_video;                  // 如果启用视频输出则为1,否则为0   

 int w, h;                      // 视频输出的大小    

struct rect text;              // 左侧LU图例的矩形    

struct rect graph;              // 中心主图的矩形   

struct rect gauge;              // 右侧计量器的矩形    

AVFrame *outpicref;            // 视频输出的参考帧,定期更新    ...

...

// 音频相关的字段

 int nb_channels;                // 输入的通道数    

double *ch_weighting;          // 通道加权映射  

  ...

 // 滤波器缓存    

double x[MAX_CHANNELS * 3];    // 每个通道的3个输入样本缓存    

...

// 积分器实例    

struct integratori400;        // 400ms积分器,用于瞬时响度(M)和综合响度(I)    

struct integratori3000;        // 3秒积分器,用于短期响度(S)和响度范围(LRA)    ...

} EBUR128Context;

功能函数:

包括绘制文本、绘制线条、配置视频输出等辅助函数。

核心处理函数:

filter_frame:这是核心处理函数,负责处理每一帧音频,计算响度,并更新视频输出(如果启用)。

初始化和清理函数:

init:初始化滤波器,设置相关参数。

uninit:释放分配的资源。

格式和配置函数:

query_formats:设置支持的音频格式和采样率。

config_audio_input和config_audio_output:配置音频输入和输出链接的属性。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容