Commit 382346a6 authored by Tiago César Katcipis's avatar Tiago César Katcipis Committed by David Schleef

removesilence: new plugin

Fixes: #597822.
Signed-off-by: David Schleef's avatarDavid Schleef <ds@schleef.org>
parent 6c272aaf
......@@ -345,6 +345,7 @@ AG_GST_CHECK_PLUGIN(pcapparse)
AG_GST_CHECK_PLUGIN(pnm)
AG_GST_CHECK_PLUGIN(rawparse)
AG_GST_CHECK_PLUGIN(real)
AG_GST_CHECK_PLUGIN(removesilence)
AG_GST_CHECK_PLUGIN(rtpmux)
AG_GST_CHECK_PLUGIN(rtpvp8)
AG_GST_CHECK_PLUGIN(scaletempo)
......@@ -1912,6 +1913,7 @@ gst/pcapparse/Makefile
gst/pnm/Makefile
gst/rawparse/Makefile
gst/real/Makefile
gst/removesilence/Makefile
gst/rtpmux/Makefile
gst/rtpvp8/Makefile
gst/scaletempo/Makefile
......
plugin_LTLIBRARIES = libgstremovesilence.la
libgstremovesilence_la_SOURCES = gstremovesilence.c vad_private.c
libgstremovesilence_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstremovesilence_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)
libgstremovesilence_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstremovesilence_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = \
gstremovesilence.h \
vad_private.h
/* GStreamer
* Copyright (C) 2011 Tiago Katcipis <tiagokatcipis@gmail.com>
* Copyright (C) 2011 Paulo Pizarro <paulo.pizarro@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:element-removesilence
*
* Removes all silence periods from an audio stream, dropping silence buffers.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch -v -m filesrc location="audiofile" ! decodebin2 ! removesilence remove=true ! wavenc ! filesink location=without_audio.wav
* ]|
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/controller/gstcontroller.h>
#include "gstremovesilence.h"
GST_DEBUG_CATEGORY_STATIC (gst_remove_silence_debug);
#define GST_CAT_DEFAULT gst_remove_silence_debug
#define DEFAULT_VAD_HYSTERESIS 480 /* 60 mseg */
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_REMOVE,
PROP_HYSTERESIS
};
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
("audio/x-raw-int, "
"rate=[1, MAX], channels=1, endianness=BYTE_ORDER, "
"width=16, depth=16, signed=true"));
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS
("audio/x-raw-int, "
"rate=[1, MAX], channels=1, endianness=BYTE_ORDER, "
"width=16, depth=16, signed=true"));
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (gst_remove_silence_debug, "removesilence", 0, "removesilence element")
GST_BOILERPLATE_FULL (GstRemoveSilence, gst_remove_silence, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
static void gst_remove_silence_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_remove_silence_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstFlowReturn gst_remove_silence_transform_ip (GstBaseTransform * base,
GstBuffer * buf);
static void gst_remove_silence_finalize (GObject * obj);
static void gst_remove_silence_reset (GstRemoveSilence * filter);
/* GObject vmethod implementations */
static void
gst_remove_silence_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_set_details_simple (element_class,
"RemoveSilence",
"Filter/Effect/Audio",
"Removes all the silence periods from the audio stream.",
"Tiago Katcipis <tiagokatcipis@gmail.com>\n \
Paulo Pizarro <paulo.pizarro@gmail.com>");
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
}
/* initialize the removesilence's class */
static void
gst_remove_silence_class_init (GstRemoveSilenceClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gst_remove_silence_finalize;
gobject_class->set_property = gst_remove_silence_set_property;
gobject_class->get_property = gst_remove_silence_get_property;
g_object_class_install_property (gobject_class, PROP_REMOVE,
g_param_spec_boolean ("remove", "Remove",
"Set to true to remove silence from the stream, false otherwhise",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (gobject_class, PROP_HYSTERESIS,
g_param_spec_uint64 ("hysteresis",
"Hysteresis",
"Set the hysteresis (on samples) used on the internal VAD",
1, G_MAXUINT64, DEFAULT_VAD_HYSTERESIS, G_PARAM_READWRITE));
GST_BASE_TRANSFORM_CLASS (klass)->transform_ip =
GST_DEBUG_FUNCPTR (gst_remove_silence_transform_ip);
}
/* initialize the new element
* instantiate pads and add them to element
* set pad calback functions
* initialize instance structure
*/
static void
gst_remove_silence_init (GstRemoveSilence * filter,
GstRemoveSilenceClass * gclass)
{
filter->vad = vad_new (DEFAULT_VAD_HYSTERESIS);
filter->remove = FALSE;
if (!filter->vad) {
GST_DEBUG ("Error initializing VAD !!");
return;
}
gst_remove_silence_reset (filter);
}
static void
gst_remove_silence_reset (GstRemoveSilence * filter)
{
GST_DEBUG ("Reseting VAD");
if (filter->vad) {
vad_reset (filter->vad);
}
GST_DEBUG ("VAD Reseted");
}
static void
gst_remove_silence_finalize (GObject * obj)
{
GstRemoveSilence *filter = GST_REMOVE_SILENCE (obj);
GST_DEBUG ("Destroying VAD");
vad_destroy (filter->vad);
filter->vad = NULL;
GST_DEBUG ("VAD Destroyed");
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
gst_remove_silence_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstRemoveSilence *filter = GST_REMOVE_SILENCE (object);
switch (prop_id) {
case PROP_REMOVE:
filter->remove = g_value_get_boolean (value);
break;
case PROP_HYSTERESIS:
vad_set_hysteresis (filter->vad, g_value_get_uint64 (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_remove_silence_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstRemoveSilence *filter = GST_REMOVE_SILENCE (object);
switch (prop_id) {
case PROP_REMOVE:
g_value_set_boolean (value, filter->remove);
break;
case PROP_HYSTERESIS:
g_value_set_uint64 (value, vad_get_hysteresis (filter->vad));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstFlowReturn
gst_remove_silence_transform_ip (GstBaseTransform * trans, GstBuffer * inbuf)
{
GstRemoveSilence *filter = NULL;
int frame_type;
filter = GST_REMOVE_SILENCE (trans);
frame_type =
vad_update (filter->vad, (gint16 *) GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf) / sizeof (gint16));
if (frame_type == VAD_SILENCE) {
GST_DEBUG ("Silence detected");
if (filter->remove) {
GST_DEBUG ("Removing silence");
return GST_BASE_TRANSFORM_FLOW_DROPPED;
}
}
return GST_FLOW_OK;
}
/*Plugin init functions*/
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "removesilence", GST_RANK_NONE,
gst_remove_silence_get_type ());
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"removesilence",
"Removes silence from an audio stream",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
/* GStreamer
* Copyright (C) 2011 Tiago Katcipis <tiagokatcipis@gmail.com>
* Copyright (C) 2011 Paulo Pizarro <paulo.pizarro@gmail.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_REMOVE_SILENCE_H__
#define __GST_REMOVE_SILENCE_H__
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include "vad_private.h"
G_BEGIN_DECLS
#define GST_TYPE_REMOVE_SILENCE \
(gst_remove_silence_get_type())
#define GST_REMOVE_SILENCE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_REMOVE_SILENCE,GstRemoveSilence))
#define GST_REMOVE_SILENCE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_REMOVE_SILENCE,GstRemoveSilenceClass))
#define GST_IS_REMOVESILENCE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_REMOVE_SILENCE))
#define GST_IS_REMOVESILENCE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_REMOVE_SILENCE))
typedef struct _GstRemoveSilence {
GstBaseTransform parent;
VADFilter* vad;
gboolean remove;
} GstRemoveSilence;
typedef struct _GstRemoveSilenceClass {
GstBaseTransformClass parent_class;
} GstRemoveSilenceClass;
GType gst_remove_silence_get_type (void);
G_END_DECLS
#endif /* __GST_REMOVE_SILENCE_H__ */
/* GStreamer
* Copyright (C) 2009 Tiago Katcipis <tiagokatcipis@gmail.com>
* Copyright (C) 2009 Paulo Pizarro <paulo.pizarro@gmail.com>
* Copyright (C) 2009 Rogério Santos <rogerio.santos@digitro.com.br>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include "vad_private.h"
#define VAD_POWER_ALPHA 0x0800 /* Q16 */
#define VAD_POWER_THRESHOLD 0x000010C7 /* -60 dB (square wave) */
#define VAD_ZCR_THRESHOLD 0
#define VAD_BUFFER_SIZE 256
union pgen
{
guint64 a;
gpointer v;
guint64 *l;
guchar *b;
guint16 *w;
gint16 *s;
};
struct _cqueue_s
{
union pgen base;
union pgen tail;
union pgen head;
gint size;
};
typedef struct _cqueue_s cqueue_t;
struct _vad_s
{
gint16 vad_buffer[VAD_BUFFER_SIZE];
cqueue_t cqueue;
gint vad_state;
guint64 hysteresis;
guint64 vad_samples;
guint64 vad_power;
long vad_zcr;
};
VADFilter *
vad_new (guint64 hysteresis)
{
VADFilter *vad = malloc (sizeof (VADFilter));
vad_reset (vad);
vad->hysteresis = hysteresis;
return vad;
}
void
vad_reset (VADFilter * vad)
{
memset (vad, 0, sizeof (vad));
vad->cqueue.base.s = vad->vad_buffer;
vad->cqueue.tail.a = vad->cqueue.head.a = 0;
vad->cqueue.size = VAD_BUFFER_SIZE;
vad->vad_state = VAD_SILENCE;
}
void
vad_destroy (VADFilter * p)
{
free (p);
}
void
vad_set_hysteresis (struct _vad_s *p, guint64 hysteresis)
{
p->hysteresis = hysteresis;
}
guint64
vad_get_hysteresis (struct _vad_s *p)
{
return p->hysteresis;
}
gint
vad_update (struct _vad_s * p, gint16 * data, gint len)
{
guint64 tail;
gint frame_type;
gint16 sample;
gint i;
for (i = 0; i < len; i++) {
p->vad_power = VAD_POWER_ALPHA * ((data[i] * data[i] >> 14) & 0xFFFF) +
(0xFFFF - VAD_POWER_ALPHA) * (p->vad_power >> 16) +
((0xFFFF - VAD_POWER_ALPHA) * (p->vad_power & 0xFFFF) >> 16);
/* Update VAD buffer */
p->cqueue.base.s[p->cqueue.head.a] = data[i];
p->cqueue.head.a = (p->cqueue.head.a + 1) & (p->cqueue.size - 1);
if (p->cqueue.head.a == p->cqueue.tail.a)
p->cqueue.tail.a = (p->cqueue.tail.a + 1) & (p->cqueue.size - 1);
}
tail = p->cqueue.tail.a;
p->vad_zcr = 0;
for (;;) {
sample = p->cqueue.base.s[tail];
tail = (tail + 1) & (p->cqueue.size - 1);
if (tail == p->cqueue.head.a)
break;
p->vad_zcr +=
((sample & 0x8000) != (p->cqueue.base.s[tail] & 0x8000)) ? 1 : -1;
}
frame_type = (p->vad_power > VAD_POWER_THRESHOLD
&& p->vad_zcr < VAD_ZCR_THRESHOLD) ? VAD_VOICE : VAD_SILENCE;
if (p->vad_state != frame_type) {
/* Voice to silence transition */
if (p->vad_state == VAD_VOICE) {
p->vad_samples += len;
if (p->vad_samples >= p->hysteresis) {
p->vad_state = frame_type;
p->vad_samples = 0;
}
} else {
p->vad_state = frame_type;
p->vad_samples = 0;
}
} else {
p->vad_samples = 0;
}
return p->vad_state;
}
/* GStreamer
* Copyright (C) 2009 Tiago Katcipis <tiagokatcipis@gmail.com>
* Copyright (C) 2009 Paulo Pizarro <paulo.pizarro@gmail.com>
* Copyright (C) 2009 Rogério Santos <rogerio.santos@digitro.com.br>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __VAD_FILTER_H__
#define __VAD_FILTER_H__
#define VAD_SILENCE 0
#define VAD_VOICE 1
typedef struct _vad_s VADFilter;
gint vad_update(VADFilter *p, gint16 *data, gint len);
void vad_set_hysteresis(VADFilter *p, guint64 hysteresis);
guint64 vad_get_hysteresis(VADFilter *p);
VADFilter* vad_new(guint64 hysteresis);
void vad_reset(VADFilter *p);
void vad_destroy(VADFilter *p);
#endif /* __VAD_FILTER__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment