diff options
author | Martin Vignali <martin.vignali@gmail.com> | 2018-04-16 11:32:48 +0200 |
---|---|---|
committer | Martin Vignali <martin.vignali@gmail.com> | 2018-04-16 11:35:03 +0200 |
commit | fd10a6e2f21f9cadc44a0415e204ea82940cd089 (patch) | |
tree | dc493c9626e6e6cf7712dd917881c1bb3274734c | |
parent | cb2f52b6a70971c902ea2aaa989d141973472125 (diff) | |
download | ffmpeg-fd10a6e2f21f9cadc44a0415e204ea82940cd089.tar.gz |
avfilter/showvolume : add persistent max display
draw a color line for the max level in the given duration
-rw-r--r-- | doc/filters.texi | 10 | ||||
-rw-r--r-- | libavfilter/avf_showvolume.c | 52 |
2 files changed, 62 insertions, 0 deletions
diff --git a/doc/filters.texi b/doc/filters.texi index d95b377bd7..f267d26b9d 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -20018,6 +20018,16 @@ default is @code{p}. @item ds Set display scale, can be linear: @code{lin} or log: @code{log}, default is @code{lin}. + +@item dm +In second. +If set to > 0., display a line for the max level +in the previous seconds. +default is disabled: @code{0.} + +@item dmc +The color of the max line. Use when @code{dm} option is set to > 0. +default is: @code{orange} @end table @section showwaves diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c index da8b4088bd..fe8a95a07b 100644 --- a/libavfilter/avf_showvolume.c +++ b/libavfilter/avf_showvolume.c @@ -57,6 +57,12 @@ typedef struct ShowVolumeContext { float rms_factor; int display_scale; + double draw_persistent_duration; /* in second */ + uint8_t persistant_max_rgba[4]; + 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; @@ -73,6 +79,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", "duration for max value display", OFFSET(draw_persistent_duration), AV_OPT_TYPE_DOUBLE, {.dbl=0.}, 0, 9000, FLAGS}, + { "dmc","set color of the max value line", OFFSET(persistant_max_rgba), AV_OPT_TYPE_COLOR, {.str = "orange"}, CHAR_MIN, CHAR_MAX, 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" }, @@ -180,6 +188,11 @@ static int config_input(AVFilterLink *inlink) default: return AVERROR_BUG; } + if (s->draw_persistent_duration > 0.) { + 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; } @@ -276,6 +289,33 @@ static inline int calc_max_draw(ShowVolumeContext *s, AVFilterLink *outlink, flo } } +static inline void calc_persistent_max(ShowVolumeContext *s, float max, int channel) +{ + /* update max value for persistent max display */ + if ((max >= s->max_persistent[channel]) || (s->nb_frames_max_display[channel] >= s->persistent_max_frames)) { /* update max value for display */ + s->max_persistent[channel] = max; + s->nb_frames_max_display[channel] = 0; + } else { + s->nb_frames_max_display[channel] += 1; /* incremente display frame count */ + } +} + +static inline void draw_max_line(ShowVolumeContext *s, int max_draw, int channel) +{ + int k; + if (s->orientation) { /* vertical */ + uint8_t *dst = s->out->data[0] + max_draw * s->out->linesize[0] + channel * (s->b + s->h) * 4; + for (k = 0; k < s->h; k++) { + memcpy(dst + k * 4, s->persistant_max_rgba, sizeof(s->persistant_max_rgba)); + } + } else { /* horizontal */ + for (k = 0; k < s->h; k++) { + uint8_t *dst = s->out->data[0] + (channel * s->h + channel * s->b + k) * s->out->linesize[0]; + memcpy(dst + max_draw * 4, s->persistant_max_rgba, sizeof(s->persistant_max_rgba)); + } + } +} + static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { AVFilterContext *ctx = inlink->dst; @@ -341,6 +381,12 @@ 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_duration > 0.) { + calc_persistent_max(s, max, c); + max_draw = FFMAX(0, calc_max_draw(s, outlink, s->max_persistent[c]) - 1); + draw_max_line(s, max_draw, c); + } } } else { /* horizontal */ for (c = 0; c < inlink->channels; c++) { @@ -371,6 +417,12 @@ 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_duration > 0.) { + calc_persistent_max(s, max, c); + max_draw = FFMAX(0, calc_max_draw(s, outlink, s->max_persistent[c]) - 1); + draw_max_line(s, max_draw, c); + } } } |