From fb05bc8eee95e1b08b6d30fbb611161c4feaf76b Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 25 Aug 2023 10:44:09 +0200 Subject: [PATCH] avfilter/af_astats: extend and improve bit depth output --- libavfilter/af_astats.c | 95 +++++++++++++++++++++++++++-------------- 1 file changed, 64 insertions(+), 31 deletions(-) diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c index c47bd768cc..38d67175fa 100644 --- a/libavfilter/af_astats.c +++ b/libavfilter/af_astats.c @@ -76,7 +76,7 @@ typedef struct ChannelStats { double diff1_sum; double diff1_sum_x2; double abs_peak; - uint64_t mask, imask; + uint64_t mask[4]; uint64_t min_count, max_count; uint64_t abs_peak_count; uint64_t noise_floor_count; @@ -88,6 +88,7 @@ typedef struct ChannelStats { double *win_samples; double *sorted_samples; uint64_t ehistogram[HISTOGRAM_SIZE]; + int64_t lasti; int sorted_front; int sorted_back; int win_pos; @@ -178,8 +179,10 @@ static void reset_stats(AudioStatsContext *s) p->max_runs = 0; p->diff1_sum = 0; p->diff1_sum_x2 = 0; - p->mask = 0; - p->imask = 0xFFFFFFFFFFFFFFFF; + p->mask[0] = 0; + p->mask[1] = 0; + p->mask[2] =~0; + p->mask[3] = 0; p->min_count = 0; p->max_count = 0; p->abs_peak_count = 0; @@ -239,20 +242,28 @@ static int config_output(AVFilterLink *outlink) return 0; } -static void bit_depth(AudioStatsContext *s, uint64_t mask, uint64_t imask, AVRational *depth) +static void bit_depth(AudioStatsContext *s, const uint64_t *const mask, uint8_t *depth) { unsigned result = s->maxbitdepth; + uint64_t amask = mask[1] & (~mask[2]); - mask = mask & (~imask); + depth[0] = 0; + for (int i = 0; i < result; i++) + depth[0] += !!(mask[0] & (1ULL << i)); - for (; result && !(mask & 1); --result, mask >>= 1); + depth[1] = 0; + for (int i = 0; i < result; i++) + depth[1] += !!(mask[1] & (1ULL << i)); - depth->den = result; - depth->num = 0; + depth[2] = result; + for (int i = 0; i < result && !(amask & 1); i++) { + depth[2]--; + amask >>= 1; + } - for (; result; --result, mask >>= 1) - if (mask & 1) - depth->num++; + depth[3] = 0; + for (int i = 0; i < result; i++) + depth[3] += !!(mask[3] & (1ULL << i)); } static double calc_entropy(AudioStatsContext *s, ChannelStats *p) @@ -389,9 +400,13 @@ static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d, p->diff1_sum += fabs(d - p->last); p->diff1_sum_x2 += (d - p->last) * (d - p->last); } + p->mask[0] |= (i < 0) ? -i : i; + p->mask[1] |= i; + p->mask[2] &= i; + if (!isnan(p->last)) + p->mask[3] |= i ^ p->lasti; + p->lasti = i; p->last = d; - p->mask |= i; - p->imask &= i; drop = p->win_samples[p->win_pos]; p->win_samples[p->win_pos] = nd; @@ -462,7 +477,7 @@ static void set_meta(AVDictionary **metadata, int chan, const char *key, static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) { - uint64_t mask = 0, imask = 0xFFFFFFFFFFFFFFFF, min_count = 0, max_count = 0, nb_samples = 0, noise_floor_count = 0; + uint64_t mask[4], min_count = 0, max_count = 0, nb_samples = 0, noise_floor_count = 0; uint64_t nb_nans = 0, nb_infs = 0, nb_denormals = 0; uint64_t abs_peak_count = 0; double min_runs = 0, max_runs = 0, @@ -476,9 +491,14 @@ static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) entropy = 0, min_sigma_x2 = DBL_MAX, max_sigma_x2 =-DBL_MAX; - AVRational depth; + uint8_t depth[4]; int c; + mask[0] = 0; + mask[1] = 0; + mask[2] =~0; + mask[3] = 0; + for (c = 0; c < s->nb_channels; c++) { ChannelStats *p = &s->chstats[c]; @@ -505,8 +525,10 @@ static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) abs_peak_count += p->abs_peak_count; min_runs += p->min_runs; max_runs += p->max_runs; - mask |= p->mask; - imask &= p->imask; + mask[0] |= p->mask[0]; + mask[1] |= p->mask[1]; + mask[2] &= p->mask[2]; + mask[3] |= p->mask[3]; nb_samples += p->nb_samples; nb_nans += p->nb_nans; nb_infs += p->nb_infs; @@ -551,9 +573,11 @@ static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) if (s->measure_perchannel & MEASURE_ENTROPY) set_meta(metadata, c + 1, "Entropy", "%f", p->entropy); if (s->measure_perchannel & MEASURE_BIT_DEPTH) { - bit_depth(s, p->mask, p->imask, &depth); - set_meta(metadata, c + 1, "Bit_depth", "%f", depth.num); - set_meta(metadata, c + 1, "Bit_depth2", "%f", depth.den); + bit_depth(s, p->mask, depth); + set_meta(metadata, c + 1, "Bit_depth", "%f", depth[0]); + set_meta(metadata, c + 1, "Bit_depth2", "%f", depth[1]); + set_meta(metadata, c + 1, "Bit_depth3", "%f", depth[2]); + set_meta(metadata, c + 1, "Bit_depth4", "%f", depth[3]); } if (s->measure_perchannel & MEASURE_DYNAMIC_RANGE) set_meta(metadata, c + 1, "Dynamic_range", "%f", LINEAR_TO_DB(2 * FFMAX(FFABS(p->min), FFABS(p->max))/ p->min_non_zero)); @@ -604,9 +628,11 @@ static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) if (s->measure_overall & MEASURE_ENTROPY) set_meta(metadata, 0, "Overall.Entropy", "%f", entropy / (double)s->nb_channels); if (s->measure_overall & MEASURE_BIT_DEPTH) { - bit_depth(s, mask, imask, &depth); - set_meta(metadata, 0, "Overall.Bit_depth", "%f", depth.num); - set_meta(metadata, 0, "Overall.Bit_depth2", "%f", depth.den); + bit_depth(s, mask, depth); + set_meta(metadata, 0, "Overall.Bit_depth", "%f", depth[0]); + set_meta(metadata, 0, "Overall.Bit_depth2", "%f", depth[1]); + set_meta(metadata, 0, "Overall.Bit_depth3", "%f", depth[2]); + set_meta(metadata, 0, "Overall.Bit_depth4", "%f", depth[3]); } if (s->measure_overall & MEASURE_NUMBER_OF_SAMPLES) set_meta(metadata, 0, "Overall.Number_of_samples", "%f", nb_samples / s->nb_channels); @@ -724,7 +750,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) static void print_stats(AVFilterContext *ctx) { AudioStatsContext *s = ctx->priv; - uint64_t mask = 0, imask = 0xFFFFFFFFFFFFFFFF, min_count = 0, max_count = 0, nb_samples = 0, noise_floor_count = 0; + uint64_t mask[4], min_count = 0, max_count = 0, nb_samples = 0, noise_floor_count = 0; uint64_t nb_nans = 0, nb_infs = 0, nb_denormals = 0, abs_peak_count = 0; double min_runs = 0, max_runs = 0, min = DBL_MAX, max =-DBL_MAX, min_diff = DBL_MAX, max_diff = 0, @@ -737,9 +763,14 @@ static void print_stats(AVFilterContext *ctx) entropy = 0, min_sigma_x2 = DBL_MAX, max_sigma_x2 =-DBL_MAX; - AVRational depth; + uint8_t depth[4]; int c; + mask[0] = 0; + mask[1] = 0; + mask[2] =~0; + mask[3] = 0; + for (c = 0; c < s->nb_channels; c++) { ChannelStats *p = &s->chstats[c]; @@ -769,8 +800,10 @@ static void print_stats(AVFilterContext *ctx) noise_floor_count += p->noise_floor_count; min_runs += p->min_runs; max_runs += p->max_runs; - mask |= p->mask; - imask &= p->imask; + mask[0] |= p->mask[0]; + mask[1] |= p->mask[1]; + mask[2] &= p->mask[2]; + mask[3] |= p->mask[3]; nb_samples += p->nb_samples; nb_nans += p->nb_nans; nb_infs += p->nb_infs; @@ -818,8 +851,8 @@ static void print_stats(AVFilterContext *ctx) if (s->measure_perchannel & MEASURE_ENTROPY) av_log(ctx, AV_LOG_INFO, "Entropy: %f\n", p->entropy); if (s->measure_perchannel & MEASURE_BIT_DEPTH) { - bit_depth(s, p->mask, p->imask, &depth); - av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u\n", depth.num, depth.den); + bit_depth(s, p->mask, depth); + av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u/%u/%u\n", depth[0], depth[1], depth[2], depth[3]); } if (s->measure_perchannel & MEASURE_DYNAMIC_RANGE) av_log(ctx, AV_LOG_INFO, "Dynamic range: %f\n", LINEAR_TO_DB(2 * FFMAX(FFABS(p->min), FFABS(p->max))/ p->min_non_zero)); @@ -876,8 +909,8 @@ static void print_stats(AVFilterContext *ctx) if (s->measure_overall & MEASURE_ENTROPY) av_log(ctx, AV_LOG_INFO, "Entropy: %f\n", entropy / (double)s->nb_channels); if (s->measure_overall & MEASURE_BIT_DEPTH) { - bit_depth(s, mask, imask, &depth); - av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u\n", depth.num, depth.den); + bit_depth(s, mask, depth); + av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u/%u/%u\n", depth[0], depth[1], depth[2], depth[3]); } if (s->measure_overall & MEASURE_NUMBER_OF_SAMPLES) av_log(ctx, AV_LOG_INFO, "Number of samples: %"PRId64"\n", nb_samples / s->nb_channels);