From 1cac1a13e5142b0eff4acd17aecaac596ae359d4 Mon Sep 17 00:00:00 2001
From: Martin Vignali <martin.vignali@gmail.com>
Date: Sat, 31 Mar 2018 15:53:04 +0200
Subject: [PATCH 5/5] avfilter/showvolume : add persistent max display

WIP
---
 libavfilter/avf_showvolume.c | 63 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c
index 50ff80e022..eee66a54a3 100644
--- a/libavfilter/avf_showvolume.c
+++ b/libavfilter/avf_showvolume.c
@@ -55,6 +55,11 @@ typedef struct ShowVolumeContext {
     float *max;
     float rms_factor;
     int display_scale; /* 0 for linear, 1 for log */
+    int draw_persistent_max;
+    double draw_persistent_duration; /* in second */
+    int persistent_max_frames; /* number of frames to check max value */
+    float *max_persistent; /* max value for draw_persistent_max for each channel */
+    int *nb_frames_max_display; /* number of frame for each channel, for displaying the max value */
 
     void (*meter)(float *src, int nb_samples, float *max, float factor);
 } ShowVolumeContext;
@@ -72,6 +77,8 @@ static const AVOption showvolume_options[] = {
     { "c", "set volume color expression", OFFSET(color), AV_OPT_TYPE_STRING, {.str="PEAK*255+floor((1-PEAK)*255)*256+0xff000000"}, 0, 0, FLAGS },
     { "t", "display channel names", OFFSET(draw_text), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
     { "v", "display volume value", OFFSET(draw_volume), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
+    { "dm", "display persistent max value", OFFSET(draw_persistent_max), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
+    { "dm_duration", "duration for max value display", OFFSET(draw_persistent_duration), AV_OPT_TYPE_DOUBLE, {.dbl=3.}, 0, 9000, FLAGS},
     { "o", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "orientation" },
     {   "h", "horizontal", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "orientation" },
     {   "v", "vertical",   0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "orientation" },
@@ -179,6 +186,11 @@ static int config_input(AVFilterLink *inlink)
     default: return AVERROR_BUG;
     }
 
+    if (s->draw_persistent_max) {
+        s->persistent_max_frames = (int) FFMAX(av_q2d(s->frame_rate) * s->draw_persistent_duration, 1.);
+        s->max_persistent = av_calloc(inlink->channels * s->persistent_max_frames, sizeof(*s->max_persistent));
+        s->nb_frames_max_display = av_calloc(inlink->channels * s->persistent_max_frames, sizeof(*s->nb_frames_max_display));
+    }
     return 0;
 }
 
@@ -330,6 +342,31 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
                     continue;
                 drawtext(s->out, c * (s->h + s->b) + (s->h - 10) / 2, outlink->h - 35, channel_name, 1);
             }
+
+            if (s->draw_persistent_max) {
+                /* update max value for persistent max display */
+                if ((max >= s->max_persistent[c]) || (s->nb_frames_max_display[c] >= s->persistent_max_frames)) { /* update max value for display */
+                    s->max_persistent[c] = max;
+                    s->nb_frames_max_display[c] = 0;
+                } else {
+                    s->nb_frames_max_display[c] += 1; /* incremente display frame count */
+                }
+
+                /*! draw white line 1pix */
+                if (s->display_scale) { /* log display */
+                    max_draw = -1 * (outlink->h * log10(s->max_persistent[c]) * 0.5);
+                } else { /* linear */
+                    max_draw = outlink->h - outlink->h * s->max_persistent[c];
+                }
+
+                uint8_t *dst = s->out->data[0] + max_draw * s->out->linesize[0] + c * (s->b + s->h) * 4;
+                for (k = 0; k < s->h; k++) {
+                    dst[k * 4 + 0] = 255;
+                    dst[k * 4 + 1] = 255;
+                    dst[k * 4 + 2] = 255;
+                    dst[k * 4 + 3] = 255;
+                }
+            }
         }
     } else { /* horizontal */
         for (c = 0; c < inlink->channels; c++) {
@@ -365,6 +402,32 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
                     continue;
                 drawtext(s->out, 2, c * (s->h + s->b) + (s->h - 8) / 2, channel_name, 0);
             }
+
+            if (s->draw_persistent_max) {
+                /* update max value for persistent max display */
+                if ((max >= s->max_persistent[c]) || (s->nb_frames_max_display[c] >= s->persistent_max_frames)) { /* update max value for display */
+                    s->max_persistent[c] = max;
+                    s->nb_frames_max_display[c] = 0;
+                } else {
+                    s->nb_frames_max_display[c] += 1; /* incremente display frame count */
+                }
+
+                /*! draw white line 1pix */
+                if (s->display_scale) { /* log display */
+                    max_draw = s->w + (log10(s->max_persistent[c]) * 0.5 * s->w);
+                } else { /* linear */
+                    max_draw = s->w * s->max_persistent[c];
+                }
+
+                for (j = 0; j < s->h; j++) {
+                    uint8_t *dst = s->out->data[0] + (c * s->h + c * s->b + j) * s->out->linesize[0];
+
+                    dst[max_draw * 4 + 0] = 255;
+                    dst[max_draw * 4 + 1] = 255;
+                    dst[max_draw * 4 + 2] = 255;
+                    dst[max_draw * 4 + 3] = 255;
+                }
+            }
         }
     }
 
-- 
2.14.3 (Apple Git-98)

