[FFmpeg-cvslog] avfilter/avf_showspectrum: rewrite frequency log axis/bin scaling

Paul B Mahol git at videolan.org
Mon Sep 20 12:15:14 EEST 2021


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sun Sep 19 22:27:07 2021 +0200| [59719a905c5e7a9a98ddc275db3e4aa65b71e14d] | committer: Paul B Mahol

avfilter/avf_showspectrum: rewrite frequency log axis/bin scaling

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=59719a905c5e7a9a98ddc275db3e4aa65b71e14d
---

 libavfilter/avf_showspectrum.c | 90 ++++++++++++++++--------------------------
 1 file changed, 34 insertions(+), 56 deletions(-)

diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c
index 5b5c4dccc9..a33ef71689 100644
--- a/libavfilter/avf_showspectrum.c
+++ b/libavfilter/avf_showspectrum.c
@@ -645,54 +645,37 @@ static char *get_time(AVFilterContext *ctx, float seconds, int x)
     return units;
 }
 
-static float log_scale(const float value, const float min, const float max)
+static float log_scale(const float bin,
+                       const float bmin, const float bmax,
+                       const float min, const float max)
 {
-    if (value < min)
-        return min;
-    if (value > max)
-        return max;
-
-    {
-        const float b = logf(max / min) / (max - min);
-        const float a = max / expf(max * b);
-
-        return expf(value * b) * a;
-    }
+    return exp2f(((bin - bmin) / (bmax - bmin)) * (log2f(max) - log2f(min)) + log2f(min));
 }
 
-static float get_log_hz(const int bin, const int num_bins, const float sample_rate)
+static float get_hz(const float bin, const float bmax,
+                    const float min, const float max,
+                    int fscale)
 {
-    const float max_freq = sample_rate / 2;
-    const float hz_per_bin = max_freq / num_bins;
-    const float freq = hz_per_bin * bin;
-    const float scaled_freq = log_scale(freq + 1, 21, max_freq) - 1;
-
-    return num_bins * scaled_freq / max_freq;
+    switch (fscale) {
+    case F_LINEAR:
+        return min + (bin / bmax) * (max - min);
+    case F_LOG:
+        return min + log_scale(bin, 0, bmax, 20.f, max - min);
+    default:
+        return 0.f;
+    }
 }
 
-static float inv_log_scale(const float value, const float min, const float max)
+static float inv_log_scale(float bin,
+                           float bmin, float bmax,
+                           float min, float max)
 {
-    if (value < min)
-        return min;
-    if (value > max)
-        return max;
-
-    {
-        const float b = logf(max / min) / (max - min);
-        const float a = max / expf(max * b);
-
-        return logf(value / a) / b;
-    }
+    return (min * exp2f((bin * (log2f(max) - log2f(20.f))) / bmax) + min) * bmax / max;
 }
 
-static float bin_pos(const int bin, const int num_bins, const float sample_rate)
+static float bin_pos(const int bin, const int num_bins, const float min, const float max)
 {
-    const float max_freq = sample_rate / 2;
-    const float hz_per_bin = max_freq / num_bins;
-    const float freq = hz_per_bin * bin;
-    const float scaled_freq = inv_log_scale(freq + 1, 21, max_freq) - 1;
-
-    return num_bins * scaled_freq / max_freq;
+    return inv_log_scale(bin, 0.f, num_bins, 20.f, max - min);
 }
 
 static float get_scale(AVFilterContext *ctx, int scale, float a)
@@ -835,8 +818,7 @@ static int draw_legend(AVFilterContext *ctx, int samples)
             }
             for (y = 0; y < h; y += 40) {
                 float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
-                float bin = s->fscale == F_LINEAR ? y : get_log_hz(y, h, inlink->sample_rate);
-                float hertz = s->start + bin * range / (float)h;
+                float hertz = get_hz(y, h, s->start, s->start + range, s->fscale);
                 char *units;
 
                 if (hertz == 0)
@@ -893,8 +875,7 @@ static int draw_legend(AVFilterContext *ctx, int samples)
             }
             for (x = 0; x < w - 79; x += 80) {
                 float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
-                float bin = s->fscale == F_LINEAR ? x : get_log_hz(x, w, inlink->sample_rate);
-                float hertz = s->start + bin * range / (float)w;
+                float hertz = get_hz(x, w, s->start, s->start + range, s->fscale);
                 char *units;
 
                 if (hertz == 0)
@@ -1019,29 +1000,26 @@ static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_j
     AVFilterLink *inlink = ctx->inputs[0];
     const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width;
     const int ch = jobnr;
-    float y, yf, uf, vf;
-    int yy = 0;
+    float yf, uf, vf;
 
     /* decide color range */
     color_range(s, ch, &yf, &uf, &vf);
 
     /* draw the channel */
-    for (y = 0; y < h && yy < h; yy++) {
-        float pos0 = bin_pos(yy+0, h, inlink->sample_rate);
-        float pos1 = bin_pos(yy+1, h, inlink->sample_rate);
-        float delta = pos1 - pos0;
+    for (int yy = 0; yy < h; yy++) {
+        float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2;
+        float pos = bin_pos(yy, h, s->start, s->start + range);
+        float delta = pos - floorf(pos);
         float a0, a1;
 
-        a0 = get_value(ctx, ch, yy+0);
-        a1 = get_value(ctx, ch, FFMIN(yy+1, h-1));
-        for (float j = pos0; j < pos1 && y + j - pos0 < h; j++) {
-            float row = (s->mode == COMBINED) ? av_clipf(y + j - pos0, 0, h - 1) : ch * h + av_clipf(y + j - pos0, 0, h - 1);
-            float *out = &s->color_buffer[ch][3 * lrintf(row)];
-            float lerpfrac = (j - pos0) / delta;
+        a0 = get_value(ctx, ch, av_clip(pos, 0, h-1));
+        a1 = get_value(ctx, ch, av_clip(pos+1, 0, h-1));
+        {
+            int row = (s->mode == COMBINED) ? yy : ch * h + yy;
+            float *out = &s->color_buffer[ch][3 * row];
 
-            pick_color(s, yf, uf, vf, lerpfrac * a1 + (1.f-lerpfrac) * a0, out);
+            pick_color(s, yf, uf, vf, delta * a1 + (1.f - delta) * a0, out);
         }
-        y += delta;
     }
 
     return 0;



More information about the ffmpeg-cvslog mailing list