Hi everyone,
I'm an FFmpeg user for quite a while now and though I might as well
switch to dev at some point...
Please find attached to this mail a simple audio filter which makes it
possible to extract and print volume information from audio streams. It
works more or less like the showinfo filters only that it returns the
pcm value information for each audio sample.
This output can then be used to easily plot a waveform image like this:
http://larskiesow.de/waveform.png
Example:
./ffmpeg -nostats -i ... -filter:a aresample=100,showvolume -f null -
[...]
[Parsed_showvolume_1 @ 0x1bcc300] n: 0, channel: 0, volume: -239
[Parsed_showvolume_1 @ 0x1bcc300] n: 1, channel: 0, volume: 126
[Parsed_showvolume_1 @ 0x1bcc300] n: 2, channel: 0, volume: -74
[Parsed_showvolume_1 @ 0x1bcc300] n: 3, channel: 0, volume: 29
[...]
Example (Generate waveform using gnuplot):
./ffmpeg -nostats -i ... -ac 1 -filter:a aresample=100,showvolume \
-f null - 2>&1 | grep '^\[Parsed_showvolume_1' | \
gnuplot -p -e 'plot "-" using 9 with lines'
The code can be found at
https://github.com/lkiesow/FFmpeg/tree/libavfilter-audio-showvolume
and is also attached to this mail split into three separate patches.
The first patch contains the filter itself, the necessary changes to
allfilters.c and the build files. The second patch contains the
documentation. Finally, the third patch contains a small script added
to the tools section utilizing the showvolume filter for generating
waveform images with gnuplot.
Please let me know if you think it makes sense to add this code to
ffmpeg and/or if anything is still missing.
Regards,
Lars
>From c7bd248165f1e331b3e205bff681e567d826c317 Mon Sep 17 00:00:00 2001
From: Lars Kiesow <lkie...@uos.de>
Date: Mon, 22 Dec 2014 00:01:46 +0100
Subject: [PATCH 1/3] Added showvolume audio filter
This commit adds the showvolume audio filter which can be used to show a
line containing volume information for each input audio sample like
this:
[Parsed_showvolume_1 @ 0x34a5220] n: 47784, channel: 0, volume: 364
This output can for example easily be used to generate waveform plots
using gnuplot or any other kind of plotting engine.
Signed-off-by: Lars Kiesow <lkie...@uos.de>
---
MAINTAINERS | 1 +
libavfilter/Makefile | 1 +
libavfilter/af_showvolume.c | 99 +++++++++++++++++++++++++++++++++++++++++++++
libavfilter/allfilters.c | 1 +
4 files changed, 102 insertions(+)
create mode 100644 libavfilter/af_showvolume.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 6e46280..ce966a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -345,6 +345,7 @@ Filters:
af_compand.c Paul B Mahol
af_ladspa.c Paul B Mahol
af_pan.c Nicolas George
+ af_showvolume.c Lars Kiesow
af_silenceremove.c Paul B Mahol
avf_avectorscope.c Paul B Mahol
avf_showcqt.c Muhammad Faiz
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 67a7e4b..c360181 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -81,6 +81,7 @@ OBJS-$(CONFIG_SILENCEREMOVE_FILTER) += af_silenceremove.o
OBJS-$(CONFIG_TREBLE_FILTER) += af_biquads.o
OBJS-$(CONFIG_VOLUME_FILTER) += af_volume.o
OBJS-$(CONFIG_VOLUMEDETECT_FILTER) += af_volumedetect.o
+OBJS-$(CONFIG_SHOWVOLUME_FILTER) += af_showvolume.o
OBJS-$(CONFIG_AEVALSRC_FILTER) += aeval.o
OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o
diff --git a/libavfilter/af_showvolume.c b/libavfilter/af_showvolume.c
new file mode 100644
index 0000000..ef93aa5
--- /dev/null
+++ b/libavfilter/af_showvolume.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014 Lars Kiesow <lkie...@uos.de>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavutil/channel_layout.h"
+#include "avfilter.h"
+#include "internal.h"
+
+static int query_formats(AVFilterContext *ctx)
+{
+ static const enum AVSampleFormat sample_fmts[] = {
+ AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_S16P,
+ AV_SAMPLE_FMT_NONE
+ };
+ AVFilterFormats *formats;
+
+ if (!(formats = ff_make_format_list(sample_fmts)))
+ return AVERROR(ENOMEM);
+ ff_set_common_formats(ctx, formats);
+
+ return 0;
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *samples)
+{
+ AVFilterContext *ctx = inlink->dst;
+ uint64_t *n = ctx->priv;
+ int64_t layout = samples->channel_layout;
+ int nb_samples = samples->nb_samples;
+ int nb_channels = av_get_channel_layout_nb_channels(layout);
+ int nb_planes = nb_channels;
+ int is_planar = av_sample_fmt_is_planar(samples->format);
+ int plane, i;
+ int16_t *pcm;
+
+ /* Interleaved audio data means there is only one large array */
+ if (!is_planar) {
+ nb_samples *= nb_channels;
+ nb_planes = 1;
+ }
+ for (plane = 0; plane < nb_planes; plane++) {
+ pcm = (int16_t *)samples->extended_data[plane];
+ for (i = 0; i < nb_samples; i++) {
+ av_log(ctx, AV_LOG_INFO, "n: %lu, channel: %i, volume: %i\n", (*n)++,
+ is_planar ? plane : i % nb_channels, pcm[i]);
+ }
+ }
+
+ return ff_filter_frame(inlink->dst->outputs[0], samples);
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ /* print_stats(ctx); */
+}
+
+static const AVFilterPad showvolume_inputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .filter_frame = filter_frame,
+ },
+ { NULL }
+};
+
+static const AVFilterPad showvolume_outputs[] = {
+ {
+ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ },
+ { NULL }
+};
+
+AVFilter ff_af_showvolume = {
+ .name = "showvolume",
+ .description = NULL_IF_CONFIG_SMALL("Show audio volume information."),
+ .priv_size = sizeof(uint64_t),
+ .query_formats = query_formats,
+ .uninit = uninit,
+ .inputs = showvolume_inputs,
+ .outputs = showvolume_outputs,
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 066d9af..ed8487f 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -92,6 +92,7 @@ void avfilter_register_all(void)
REGISTER_FILTER(PAN, pan, af);
REGISTER_FILTER(REPLAYGAIN, replaygain, af);
REGISTER_FILTER(RESAMPLE, resample, af);
+ REGISTER_FILTER(SHOWVOLUME, showvolume, af);
REGISTER_FILTER(SILENCEDETECT, silencedetect, af);
REGISTER_FILTER(SILENCEREMOVE, silenceremove, af);
REGISTER_FILTER(TREBLE, treble, af);
--
2.1.0
>From 3320c04ee6bebe2fba577d35eeb7f2e404c436f6 Mon Sep 17 00:00:00 2001
From: Lars Kiesow <lkie...@uos.de>
Date: Mon, 22 Dec 2014 00:08:53 +0100
Subject: [PATCH 2/3] Add documentation for showvolume filter
Signed-off-by: Lars Kiesow <lkie...@uos.de>
---
doc/filters.texi | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/doc/filters.texi b/doc/filters.texi
index 7fac8fb..4c880c2 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1806,6 +1806,27 @@ At end of filtering it displays @code{track_gain} and @code{track_peak}.
Convert the audio sample format, sample rate and channel layout. It is
not meant to be used directly.
+@section showvolume
+
+Show a line containing volume information for each input audio sample.
+The input audio is not modified.
+
+The shown line contains a sequence of key/value pairs of the form
+@var{key}: @var{value} separated by comma.
+
+The following values are shown in the output:
+
+@table @option
+@item n
+The (sequential) number of the input sample, starting from 0.
+
+@item channel
+The audio channel this sample is part of.
+
+@item volume
+The pcm value representing the volume of that sample.
+@end table
+
@section silencedetect
Detect silence in an audio stream.
--
2.1.0
>From bd0aa864fcc5d82d44b79c081a27a03c9ad21dff Mon Sep 17 00:00:00 2001
From: Lars Kiesow <lkie...@uos.de>
Date: Mon, 22 Dec 2014 00:10:32 +0100
Subject: [PATCH 3/3] Added script for waveform generation to tools
The commit adds a simple script which utilizes gnuplot as well as ffmpeg
and its showvolume filter for generating waveform plots as PNG files.
Signed-off-by: Lars Kiesow <lkie...@uos.de>
---
tools/generate-waveform | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
create mode 100755 tools/generate-waveform
diff --git a/tools/generate-waveform b/tools/generate-waveform
new file mode 100755
index 0000000..e8a1513
--- /dev/null
+++ b/tools/generate-waveform
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+# Copyright (c) 2014 Lars Kiesow
+#
+# This file is part of FFmpeg.
+#
+# FFmpeg is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# FFmpeg is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+[ $# -ne 2 ] && echo Usage: $0 INFILE OUTFILE && exit
+
+# Define plotting options:
+# - Define output format and size
+# - Define output file
+# - Remove axis and borders
+# - Plot from stdin
+PLOTCMD="
+ set terminal png size 5000,500;
+ set output '$2';
+
+ unset key;
+ unset tics;
+ unset border;
+ set lmargin 0;
+ set rmargin 0;
+ set tmargin 0;
+ set bmargin 0;
+
+ plot '-' using 9 with lines"
+
+# To make the y-axis centered and cut off peaks add the following line (adjust
+# the values):
+# set yrange [-600:600];
+
+# For plotting stereo (or even more channels, use a gnuplot multiplot command
+# instead of the plot command:
+#
+# set multiplot layout 2,1
+# plot '-' using 9 every 2::0 with lines
+# plot '-' using 9 every 2::1 with lines
+# unset multiplot
+#
+# ...also make sure to change the audio channel option in the ffmpeg command to
+# stereo (-ac 2)
+
+ffmpeg -hide_banner -nostats -i "$1" -ac 1 -filter:a aresample=100,showvolume -f null - 2>&1 | \
+ grep '^\[Parsed_showvolume_1' | \
+ gnuplot -e "${PLOTCMD}"
--
2.1.0
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel