From a8c2d375ca68b7f001564ced14d8ac0757f53a29 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Fri, 23 Mar 2018 19:02:51 +0100 Subject: [PATCH] avfilter/avf_showwaves: add draw mode which controls how single sample is drawn Signed-off-by: Paul B Mahol --- doc/filters.texi | 14 +++++ libavfilter/avf_showwaves.c | 119 ++++++++++++++++++++++++++++++------ 2 files changed, 115 insertions(+), 18 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 870c50441b..421b5f6cd2 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -20033,6 +20033,20 @@ Cubic root. @end table Default is linear. + +@item draw +Set the draw mode. This is mostly useful to set for high @var{n}. + +Available values are: +@table @samp +@item scale +Scale pixel values for each drawn sample. + +@item full +Draw every sample directly. +@end table + +Default vlaue is @code{scale}. @end table @subsection Examples diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index 0866967984..bb7f4ea87e 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -50,6 +50,12 @@ enum ShowWavesScale { SCALE_NB, }; +enum ShowWavesDrawMode { + DRAW_SCALE, + DRAW_FULL, + DRAW_NB, +}; + struct frame_node { AVFrame *frame; struct frame_node *next; @@ -68,6 +74,7 @@ typedef struct ShowWavesContext { int sample_count_mod; int mode; ///< ShowWavesMode int scale; ///< ShowWavesScale + int draw_mode; ///< ShowWavesDrawMode int split_channels; uint8_t *fg; @@ -104,6 +111,9 @@ static const AVOption showwaves_options[] = { { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"}, { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_SQRT}, .flags=FLAGS, .unit="scale"}, { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_CBRT}, .flags=FLAGS, .unit="scale"}, + { "draw", "set draw mode", OFFSET(draw_mode), AV_OPT_TYPE_INT, {.i64 = DRAW_SCALE}, 0, DRAW_NB-1, FLAGS, .unit="draw" }, + { "scale", "scale pixel values for each drawn sample", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_SCALE}, .flags=FLAGS, .unit="draw"}, + { "full", "draw every pixel for sample directly", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_FULL}, .flags=FLAGS, .unit="draw"}, { NULL } }; @@ -202,9 +212,9 @@ static int get_cbrt_h2(int16_t sample, int height) return cbrt(FFABS(sample)) * height / cbrt(INT16_MAX); } -static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_point_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { if (h >= 0 && h < height) { buf[h * linesize + 0] += color[0]; @@ -214,9 +224,21 @@ static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize, } } -static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_point_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + if (h >= 0 && h < height) { + buf[h * linesize + 0] = color[0]; + buf[h * linesize + 1] = color[1]; + buf[h * linesize + 2] = color[2]; + buf[h * linesize + 3] = color[3]; + } +} + +static void draw_sample_line_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { int k; int start = height/2; @@ -231,9 +253,26 @@ static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize, } } -static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_line_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + int k; + int start = height/2; + int end = av_clip(h, 0, height-1); + if (start > end) + FFSWAP(int16_t, start, end); + for (k = start; k < end; k++) { + buf[k * linesize + 0] = color[0]; + buf[k * linesize + 1] = color[1]; + buf[k * linesize + 2] = color[2]; + buf[k * linesize + 3] = color[3]; + } +} + +static void draw_sample_p2p_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { int k; if (h >= 0 && h < height) { @@ -257,9 +296,35 @@ static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize, *prev_y = h; } -static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_p2p_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + int k; + if (h >= 0 && h < height) { + buf[h * linesize + 0] = color[0]; + buf[h * linesize + 1] = color[1]; + buf[h * linesize + 2] = color[2]; + buf[h * linesize + 3] = color[3]; + if (*prev_y && h != *prev_y) { + int start = *prev_y; + int end = av_clip(h, 0, height-1); + if (start > end) + FFSWAP(int16_t, start, end); + for (k = start + 1; k < end; k++) { + buf[k * linesize + 0] = color[0]; + buf[k * linesize + 1] = color[1]; + buf[k * linesize + 2] = color[2]; + buf[k * linesize + 3] = color[3]; + } + } + } + *prev_y = h; +} + +static void draw_sample_cline_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { int k; const int start = (height - h) / 2; @@ -271,6 +336,20 @@ static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize, buf[k * linesize + 3] += color[3]; } } + static void draw_sample_cline_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + int k; + const int start = (height - h) / 2; + const int end = start + h; + for (k = start; k < end; k++) { + buf[k * linesize + 0] = color[0]; + buf[k * linesize + 1] = color[1]; + buf[k * linesize + 2] = color[2]; + buf[k * linesize + 3] = color[3]; + } +} static void draw_sample_point_gray(uint8_t *buf, int height, int linesize, int16_t *prev_y, @@ -368,10 +447,10 @@ static int config_output(AVFilterLink *outlink) break; case AV_PIX_FMT_RGBA: switch (showwaves->mode) { - case MODE_POINT: showwaves->draw_sample = draw_sample_point_rgba; break; - case MODE_LINE: showwaves->draw_sample = draw_sample_line_rgba; break; - case MODE_P2P: showwaves->draw_sample = draw_sample_p2p_rgba; break; - case MODE_CENTERED_LINE: showwaves->draw_sample = draw_sample_cline_rgba; break; + case MODE_POINT: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_point_rgba_scale : draw_sample_point_rgba_full; break; + case MODE_LINE: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_line_rgba_scale : draw_sample_line_rgba_full; break; + case MODE_P2P: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_p2p_rgba_scale : draw_sample_p2p_rgba_full; break; + case MODE_CENTERED_LINE: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_cline_rgba_scale : draw_sample_cline_rgba_full; break; default: return AVERROR_BUG; } @@ -430,8 +509,12 @@ static int config_output(AVFilterLink *outlink) if (!colors) return AVERROR(ENOMEM); - /* multiplication factor, pre-computed to avoid in-loop divisions */ - x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n); + if (showwaves->draw_mode == DRAW_SCALE) { + /* multiplication factor, pre-computed to avoid in-loop divisions */ + x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n); + } else { + x = 255; + } if (outlink->format == AV_PIX_FMT_RGBA) { uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff };