[FFmpeg-devel] [PATCH] New p2p mode for showwaves filter

mrskman mrskman at gmail.com
Thu Jul 31 14:50:45 CEST 2014


A few months ago I sent this patch and got some comments, which helped me
to understand how this filter works. Thank you for that and I'm sorry it
took me so long to reply. Here is a better version (atleast for me).

Problem with the current mode=point is, you can get almost invisible wave
when you set higher resolution output or when there are high amplitudes
in audio stream.

With this new mode additional points are drawn to make a line between
points and output is readable regardless of the resolution or amplitudes.

Please review and comment.

---
 doc/filters.texi            |    3 +++
 libavfilter/avf_showwaves.c |   38 +++++++++++++++++++++++++++++++++-----
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index a7919a3..145acbf 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -10698,6 +10698,9 @@ Draw a point for each sample.
 
 @item line
 Draw a vertical line for each sample.
+
+ at item p2p
+Draw a point for each sample and a line between them.
 @end table
 
 Default value is @code{point}.
diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c
index 0b45bd0..48e61d1 100644
--- a/libavfilter/avf_showwaves.c
+++ b/libavfilter/avf_showwaves.c
@@ -35,6 +35,7 @@
 enum ShowWavesMode {
     MODE_POINT,
     MODE_LINE,
+    MODE_P2P,
     MODE_NB,
 };
 
@@ -43,6 +44,8 @@ typedef struct {
     int w, h;
     AVRational rate;
     int buf_idx;
+    int *buf_idy;    /* y coordinate of previous sample for each channel */
+    int nb_channels;
     AVFrame *outpicref;
     int req_fullfilled;
     int n;
@@ -59,6 +62,7 @@ static const AVOption showwaves_options[] = {
     { "mode", "select display mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_POINT}, 0, MODE_NB-1, FLAGS, "mode"},
         { "point", "draw a point for each sample", 0, AV_OPT_TYPE_CONST, {.i64=MODE_POINT}, .flags=FLAGS, .unit="mode"},
         { "line",  "draw a line for each sample",  0, AV_OPT_TYPE_CONST, {.i64=MODE_LINE},  .flags=FLAGS, .unit="mode"},
+        { "p2p", "draw a line between samples", 0, AV_OPT_TYPE_CONST, {.i64=MODE_P2P}, .flags=FLAGS, .unit="mode"},
     { "n",    "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
     { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
     { "r",    "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, 0, FLAGS },
@@ -72,6 +76,8 @@ static av_cold void uninit(AVFilterContext *ctx)
     ShowWavesContext *showwaves = ctx->priv;
 
     av_frame_free(&showwaves->outpicref);
+    if (showwaves->buf_idy)
+        av_freep(showwaves->buf_idy);
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -110,6 +116,7 @@ static int query_formats(AVFilterContext *ctx)
 
 static int config_output(AVFilterLink *outlink)
 {
+    int i;
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = ctx->inputs[0];
     ShowWavesContext *showwaves = ctx->priv;
@@ -117,7 +124,14 @@ static int config_output(AVFilterLink *outlink)
     if (!showwaves->n)
         showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5);
 
+    showwaves->nb_channels = inlink->channels;
     showwaves->buf_idx = 0;
+    if (!(showwaves->buf_idy = av_malloc_array(showwaves->nb_channels, 1))) {
+        av_log(NULL, AV_LOG_ERROR, "Could not allocate showwaves buffer\n");
+        return AVERROR(ENOMEM);
+    }
+    for (i = 0; i <= showwaves->nb_channels; i++)
+        showwaves->buf_idy[i] = 0;
     outlink->w = showwaves->w;
     outlink->h = showwaves->h;
     outlink->sample_aspect_ratio = (AVRational){1,1};
@@ -133,12 +147,14 @@ static int config_output(AVFilterLink *outlink)
 inline static int push_frame(AVFilterLink *outlink)
 {
     ShowWavesContext *showwaves = outlink->src->priv;
-    int ret;
+    int ret, i;
 
     if ((ret = ff_filter_frame(outlink, showwaves->outpicref)) >= 0)
         showwaves->req_fullfilled = 1;
     showwaves->outpicref = NULL;
     showwaves->buf_idx = 0;
+    for (i = 0; i <= showwaves->nb_channels; i++)
+        showwaves->buf_idy[i] = 0;
     return ret;
 }
 
@@ -169,10 +185,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
     AVFrame *outpicref = showwaves->outpicref;
     int linesize = outpicref ? outpicref->linesize[0] : 0;
     int16_t *p = (int16_t *)insamples->data[0];
-    int nb_channels = inlink->channels;
     int i, j, k, h, ret = 0;
     const int n = showwaves->n;
-    const int x = 255 / (nb_channels * n); /* multiplication factor, pre-computed to avoid in-loop divisions */
+    const int x = 255 / (showwaves->nb_channels * n); /* multiplication factor, pre-computed to avoid in-loop divisions */
 
     /* draw data in the buffer */
     for (i = 0; i < nb_samples; i++) {
@@ -184,14 +199,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
             outpicref->width  = outlink->w;
             outpicref->height = outlink->h;
             outpicref->pts = insamples->pts +
-                             av_rescale_q((p - (int16_t *)insamples->data[0]) / nb_channels,
+                             av_rescale_q((p - (int16_t *)insamples->data[0]) / showwaves->nb_channels,
                                           (AVRational){ 1, inlink->sample_rate },
                                           outlink->time_base);
             linesize = outpicref->linesize[0];
             for (j = 0; j < outlink->h; j++)
                 memset(outpicref->data[0] + j * linesize, 0, outlink->w);
         }
-        for (j = 0; j < nb_channels; j++) {
+        for (j = 0; j < showwaves->nb_channels; j++) {
             h = showwaves->h/2 - av_rescale(*p++, showwaves->h/2, MAX_INT16);
             switch (showwaves->mode) {
             case MODE_POINT:
@@ -207,7 +222,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
                     *(outpicref->data[0] + showwaves->buf_idx + k * linesize) += x;
                 break;
             }
+            case MODE_P2P:
+                if (h >= 0 && h < outlink->h) {
+                    *(outpicref->data[0] + showwaves->buf_idx + h * linesize) += x;
+                    if (showwaves->buf_idy[j] && h != showwaves->buf_idy[j]) {
+                        int start = showwaves->buf_idy[j], end = av_clip(h, 0, outlink->h-1);
+                        if (start > end) FFSWAP(int16_t, start, end);
+                        for (k = start + 1; k < end; k++)
+                            *(outpicref->data[0] + showwaves->buf_idx + k * linesize) += x;
+                    }
+                }
+                break;
             }
+            /* store current y coordinate for this channel */
+            showwaves->buf_idy[j] = h;
         }
 
         showwaves->sample_count_mod++;
-- 
1.7.1



More information about the ffmpeg-devel mailing list