You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-10 06:10:52 +02:00
avfilter/af_astats: drop usage of histogram for noise floor calculation
This commit is contained in:
@@ -86,8 +86,10 @@ typedef struct ChannelStats {
|
|||||||
uint64_t nb_infs;
|
uint64_t nb_infs;
|
||||||
uint64_t nb_denormals;
|
uint64_t nb_denormals;
|
||||||
double *win_samples;
|
double *win_samples;
|
||||||
uint64_t histogram[HISTOGRAM_SIZE];
|
double *sorted_samples;
|
||||||
uint64_t ehistogram[HISTOGRAM_SIZE];
|
uint64_t ehistogram[HISTOGRAM_SIZE];
|
||||||
|
int sorted_front;
|
||||||
|
int sorted_back;
|
||||||
int win_pos;
|
int win_pos;
|
||||||
int max_index;
|
int max_index;
|
||||||
double noise_floor;
|
double noise_floor;
|
||||||
@@ -191,9 +193,12 @@ static void reset_stats(AudioStatsContext *s)
|
|||||||
p->noise_floor_count = 0;
|
p->noise_floor_count = 0;
|
||||||
p->entropy = 0;
|
p->entropy = 0;
|
||||||
p->win_pos = 0;
|
p->win_pos = 0;
|
||||||
|
p->sorted_front = 0;
|
||||||
|
p->sorted_back = 0;
|
||||||
memset(p->win_samples, 0, s->tc_samples * sizeof(*p->win_samples));
|
memset(p->win_samples, 0, s->tc_samples * sizeof(*p->win_samples));
|
||||||
memset(p->histogram, 0, sizeof(p->histogram));
|
|
||||||
memset(p->ehistogram, 0, sizeof(p->ehistogram));
|
memset(p->ehistogram, 0, sizeof(p->ehistogram));
|
||||||
|
for (int n = 0; n < s->tc_samples; n++)
|
||||||
|
p->sorted_samples[n] = -1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +219,10 @@ static int config_output(AVFilterLink *outlink)
|
|||||||
p->win_samples = av_calloc(s->tc_samples, sizeof(*p->win_samples));
|
p->win_samples = av_calloc(s->tc_samples, sizeof(*p->win_samples));
|
||||||
if (!p->win_samples)
|
if (!p->win_samples)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
p->sorted_samples = av_calloc(s->tc_samples, sizeof(*p->sorted_samples));
|
||||||
|
if (!p->sorted_samples)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->mult = exp((-1 / s->time_constant / outlink->sample_rate));
|
s->mult = exp((-1 / s->time_constant / outlink->sample_rate));
|
||||||
@@ -260,6 +269,63 @@ static double calc_entropy(AudioStatsContext *s, ChannelStats *p)
|
|||||||
return -entropy / log2(HISTOGRAM_SIZE);
|
return -entropy / log2(HISTOGRAM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double calc_noise_floor(double *ss, double x, double px,
|
||||||
|
int n, int *ffront, int *bback)
|
||||||
|
{
|
||||||
|
double r, ax = fabs(x);
|
||||||
|
int front = *ffront;
|
||||||
|
int back = *bback;
|
||||||
|
int empty = front == back && ss[front] == -1.0;
|
||||||
|
|
||||||
|
if (!empty && fabs(px) == ss[front]) {
|
||||||
|
ss[front] = -1.0;
|
||||||
|
if (back != front) {
|
||||||
|
front--;
|
||||||
|
if (front < 0)
|
||||||
|
front = n - 1;
|
||||||
|
}
|
||||||
|
empty = front == back;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty && ax >= ss[front]) {
|
||||||
|
while (1) {
|
||||||
|
ss[front] = -1.0;
|
||||||
|
if (back == front) {
|
||||||
|
empty = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
front--;
|
||||||
|
if (front < 0)
|
||||||
|
front = n - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!empty && ax >= ss[back]) {
|
||||||
|
ss[back] = -1.0;
|
||||||
|
if (back == front) {
|
||||||
|
empty = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
back++;
|
||||||
|
if (back >= n)
|
||||||
|
back = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty) {
|
||||||
|
back--;
|
||||||
|
if (back < 0)
|
||||||
|
back = n - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ss[back] = ax;
|
||||||
|
r = ss[front];
|
||||||
|
|
||||||
|
*ffront = front;
|
||||||
|
*bback = back;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void update_minmax(AudioStatsContext *s, ChannelStats *p, double d)
|
static inline void update_minmax(AudioStatsContext *s, ChannelStats *p, double d)
|
||||||
{
|
{
|
||||||
if (d < p->min)
|
if (d < p->min)
|
||||||
@@ -271,7 +337,7 @@ static inline void update_minmax(AudioStatsContext *s, ChannelStats *p, double d
|
|||||||
static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d, double nd, int64_t i)
|
static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d, double nd, int64_t i)
|
||||||
{
|
{
|
||||||
double abs_d = FFABS(d);
|
double abs_d = FFABS(d);
|
||||||
double drop;
|
double drop, noise_floor;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
if (p->abs_peak < abs_d) {
|
if (p->abs_peak < abs_d) {
|
||||||
@@ -331,24 +397,21 @@ static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d,
|
|||||||
p->win_samples[p->win_pos] = nd;
|
p->win_samples[p->win_pos] = nd;
|
||||||
index = av_clip(lrint(av_clipd(FFABS(nd), 0.0, 1.0) * HISTOGRAM_MAX), 0, HISTOGRAM_MAX);
|
index = av_clip(lrint(av_clipd(FFABS(nd), 0.0, 1.0) * HISTOGRAM_MAX), 0, HISTOGRAM_MAX);
|
||||||
p->max_index = FFMAX(p->max_index, index);
|
p->max_index = FFMAX(p->max_index, index);
|
||||||
p->histogram[index]++;
|
|
||||||
p->ehistogram[index]++;
|
p->ehistogram[index]++;
|
||||||
if (!isnan(p->noise_floor))
|
|
||||||
p->histogram[av_clip(lrint(av_clipd(FFABS(drop), 0.0, 1.0) * HISTOGRAM_MAX), 0, HISTOGRAM_MAX)]--;
|
|
||||||
p->win_pos++;
|
p->win_pos++;
|
||||||
|
|
||||||
while (p->histogram[p->max_index] == 0)
|
if (p->win_pos >= s->tc_samples)
|
||||||
p->max_index--;
|
p->win_pos = 0;
|
||||||
if (p->win_pos >= s->tc_samples || !isnan(p->noise_floor)) {
|
|
||||||
double noise_floor = 1.;
|
|
||||||
|
|
||||||
for (int i = p->max_index; i >= 0; i--) {
|
if (p->nb_samples >= s->tc_samples) {
|
||||||
if (p->histogram[i]) {
|
p->max_sigma_x2 = FFMAX(p->max_sigma_x2, p->avg_sigma_x2);
|
||||||
noise_floor = i / (double)HISTOGRAM_MAX;
|
p->min_sigma_x2 = FFMIN(p->min_sigma_x2, p->avg_sigma_x2);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
p->nb_samples++;
|
||||||
|
|
||||||
|
if (p->nb_samples >= s->tc_samples) {
|
||||||
|
noise_floor = calc_noise_floor(p->sorted_samples, nd, drop,
|
||||||
|
s->tc_samples, &p->sorted_front, &p->sorted_back);
|
||||||
if (isnan(p->noise_floor)) {
|
if (isnan(p->noise_floor)) {
|
||||||
p->noise_floor = noise_floor;
|
p->noise_floor = noise_floor;
|
||||||
p->noise_floor_count = 1;
|
p->noise_floor_count = 1;
|
||||||
@@ -361,16 +424,6 @@ static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->win_pos >= s->tc_samples) {
|
|
||||||
p->win_pos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->nb_samples >= s->tc_samples) {
|
|
||||||
p->max_sigma_x2 = FFMAX(p->max_sigma_x2, p->avg_sigma_x2);
|
|
||||||
p->min_sigma_x2 = FFMIN(p->min_sigma_x2, p->avg_sigma_x2);
|
|
||||||
}
|
|
||||||
p->nb_samples++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void update_float_stat(AudioStatsContext *s, ChannelStats *p, float d)
|
static inline void update_float_stat(AudioStatsContext *s, ChannelStats *p, float d)
|
||||||
@@ -847,6 +900,7 @@ static av_cold void uninit(AVFilterContext *ctx)
|
|||||||
ChannelStats *p = &s->chstats[i];
|
ChannelStats *p = &s->chstats[i];
|
||||||
|
|
||||||
av_freep(&p->win_samples);
|
av_freep(&p->win_samples);
|
||||||
|
av_freep(&p->sorted_samples);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
av_freep(&s->chstats);
|
av_freep(&s->chstats);
|
||||||
|
Reference in New Issue
Block a user