diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/cutter/gstcutter.c | 169 | ||||
-rw-r--r-- | gst/cutter/gstcutter.h | 9 |
2 files changed, 106 insertions, 72 deletions
diff --git a/gst/cutter/gstcutter.c b/gst/cutter/gstcutter.c index 103f4d06..f256bda7 100644 --- a/gst/cutter/gstcutter.c +++ b/gst/cutter/gstcutter.c @@ -47,7 +47,8 @@ enum { ARG_THRESHOLD, ARG_THRESHOLD_DB, ARG_RUN_LENGTH, - ARG_PRE_LENGTH + ARG_PRE_LENGTH, + ARG_LEAKY }; GST_PAD_TEMPLATE_FACTORY (cutter_src_factory, @@ -72,54 +73,56 @@ GST_PAD_TEMPLATE_FACTORY (cutter_sink_factory, ) ); -static void gst_cutter_class_init (GstCutterClass *klass); -static void gst_cutter_init (GstCutter *filter); +static void gst_cutter_class_init (GstCutterClass *klass); +static void gst_cutter_init (GstCutter *filter); -static void gst_cutter_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec); -static void gst_cutter_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec); +static void gst_cutter_set_property (GObject *object, guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gst_cutter_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); -static void gst_cutter_chain (GstPad *pad, GstBuffer *buf); -static double inline gst_cutter_16bit_ms (gint16* data, guint numsamples); -static double inline gst_cutter_8bit_ms (gint8* data, guint numsamples); +static void gst_cutter_chain (GstPad *pad, GstBuffer *buf); +static double +inline gst_cutter_16bit_ms (gint16* data, guint numsamples); +static double +inline gst_cutter_8bit_ms (gint8* data, guint numsamples); -void gst_cutter_get_caps (GstPad *pad, GstCutter* filter); +void gst_cutter_get_caps (GstPad *pad, GstCutter* filter); static GstElementClass *parent_class = NULL; static guint gst_cutter_signals[LAST_SIGNAL] = { 0 }; GType -gst_cutter_get_type(void) { +gst_cutter_get_type (void) { static GType cutter_type = 0; if (!cutter_type) { static const GTypeInfo cutter_info = { - sizeof(GstCutterClass), NULL, NULL, (GClassInitFunc)gst_cutter_class_init, - NULL, - NULL, - sizeof(GstCutter), - 0, - (GInstanceInitFunc)gst_cutter_init, + sizeof (GstCutterClass), NULL, NULL, + (GClassInitFunc) gst_cutter_class_init, NULL, NULL, + sizeof (GstCutter), 0, + (GInstanceInitFunc) gst_cutter_init, }; - cutter_type = g_type_register_static(GST_TYPE_ELEMENT, "GstCutter", &cutter_info, 0); + cutter_type = g_type_register_static (GST_TYPE_ELEMENT, "GstCutter", + &cutter_info, 0); } return cutter_type; } static GstPadLinkReturn -gst_cutter_connect (GstPad *pad, GstCaps *caps) +gst_cutter_link (GstPad *pad, GstCaps *caps) { GstCutter *filter; GstPad *otherpad; - + filter = GST_CUTTER (gst_pad_get_parent (pad)); g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED); g_return_val_if_fail (GST_IS_CUTTER (filter), GST_PAD_LINK_REFUSED); otherpad = (pad == filter->srcpad ? filter->sinkpad : filter->srcpad); - if (GST_CAPS_IS_FIXED (caps)) + if (GST_CAPS_IS_FIXED (caps)) return gst_pad_try_set_caps (otherpad, caps); return GST_PAD_LINK_DELAYED; } @@ -136,26 +139,35 @@ gst_cutter_class_init (GstCutterClass *klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_THRESHOLD, - g_param_spec_double ("threshold", "threshold", "threshold", - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /* CHECKME */ + g_param_spec_double ("threshold", "Threshold", + "Volume threshold before trigger", + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_THRESHOLD_DB, - g_param_spec_double ("threshold_dB", "threshold_dB", "threshold_dB", - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /* CHECKME */ + g_param_spec_double ("threshold_dB", "Threshold (dB)", + "Volume threshold before trigger (in dB)", + -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RUN_LENGTH, - g_param_spec_double ("runlength", "runlength", "runlength", - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /* CHECKME */ - + g_param_spec_double ("runlength", "Runlength", + "Length of drop below threshold before cut_stop (seconds)", + 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PRE_LENGTH, - g_param_spec_double ("prelength", "prelength", "prelength", - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); /* CHECKME */ - gst_cutter_signals[CUT_START] = - g_signal_new ("cut_start", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GstCutterClass, cut_start), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - gst_cutter_signals[CUT_STOP] = - g_signal_new ("cut_stop", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GstCutterClass, cut_stop), NULL, NULL, - g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + g_param_spec_double ("prelength", "prelength", + "Length of pre-recording buffer (seconds)", + 0.0, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LEAKY, + g_param_spec_boolean ("leaky", "Leaky", + "do we leak buffers when below threshold ?", + FALSE, G_PARAM_READWRITE)); + gst_cutter_signals[CUT_START] = + g_signal_new ("cut_start", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstCutterClass, cut_start), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + gst_cutter_signals[CUT_STOP] = + g_signal_new ("cut_stop", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GstCutterClass, cut_stop), NULL, NULL, + g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gobject_class->set_property = gst_cutter_set_property; @@ -176,13 +188,14 @@ gst_cutter_init (GstCutter *filter) filter->pre_length = 0.2; filter->pre_run_length = 0.0; filter->pre_buffer = NULL; + filter->leaky = FALSE; gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); gst_pad_set_chain_function (filter->sinkpad, gst_cutter_chain); - gst_pad_set_link_function (filter->sinkpad, gst_cutter_connect); + gst_pad_set_link_function (filter->sinkpad, gst_cutter_link); filter->srcpad = gst_pad_new ("src", GST_PAD_SRC); gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); - gst_pad_set_link_function (filter->srcpad, gst_cutter_connect); + gst_pad_set_link_function (filter->srcpad, gst_cutter_link); } static void @@ -194,7 +207,7 @@ gst_cutter_chain (GstPad *pad, GstBuffer *buf) double ms = 0.0; /* mean square value of buffer */ static gboolean silent_prev = FALSE; /* previous value of silent */ GstBuffer *prebuf; /* pointer to a prebuffer element */ - + g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); @@ -204,17 +217,17 @@ gst_cutter_chain (GstPad *pad, GstBuffer *buf) g_return_if_fail (GST_IS_CUTTER (filter)); if (gst_audio_is_buffer_framed (pad, buf) == FALSE) - g_warning ("cutter: audio buffer is not framed !\n"); - + g_warning ("audio buffer is not framed !\n"); + if (!filter->have_caps) gst_cutter_get_caps (pad, filter); in_data = (gint16 *) GST_BUFFER_DATA (buf); - GST_DEBUG (GST_CAT_PLUGIN_INFO, - "cutter: length of prerec buffer: %.3f sec\n", + GST_DEBUG (GST_CAT_PLUGIN_INFO, + "length of prerec buffer: %.3f sec", filter->pre_run_length); /* calculate mean square value on buffer */ - switch (filter->width) + switch (filter->width) { case 16: ms = gst_cutter_16bit_ms (in_data, GST_BUFFER_SIZE (buf) / 2); @@ -232,16 +245,16 @@ gst_cutter_chain (GstPad *pad, GstBuffer *buf) silent_prev = filter->silent; RMS = sqrt (ms) / (double) filter->max_sample; - /* if RMS below threshold, add buffer length to silent run length count + /* if RMS below threshold, add buffer length to silent run length count * if not, reset */ GST_DEBUG (GST_CAT_PLUGIN_INFO, - "DEBUG: cutter: ms %f, RMS %f, audio length %f\n", + "buffer stats: ms %f, RMS %f, audio length %f", ms, RMS, gst_audio_length (filter->srcpad, buf)); if (RMS < filter->threshold_level) filter->silent_run_length += gst_audio_length (filter->srcpad, buf); else - { + { filter->silent_run_length = 0.0; filter->silent = FALSE; } @@ -250,8 +263,8 @@ gst_cutter_chain (GstPad *pad, GstBuffer *buf) /* it has been silent long enough, flag it */ filter->silent = TRUE; - /* has the silent status changed ? if so, send right signal - * and, if from silent -> not silent, flush pre_record buffer + /* has the silent status changed ? if so, send right signal + * and, if from silent -> not silent, flush pre_record buffer */ if (filter->silent != silent_prev) { @@ -262,24 +275,35 @@ gst_cutter_chain (GstPad *pad, GstBuffer *buf) } else { + gint count = 0; /* g_print ("DEBUG: cutter: start from here, turning on out\n"); */ /* first of all, flush current buffer */ g_signal_emit (G_OBJECT (filter), gst_cutter_signals[CUT_START], 0); - GST_DEBUG (GST_CAT_PLUGIN_INFO, "DEBUG: cutter: flushing buffer"); + GST_DEBUG (GST_CAT_PLUGIN_INFO, + "flushing buffer of length %.3f", + filter->pre_run_length); while (filter->pre_buffer) { prebuf = (g_list_first (filter->pre_buffer))->data; filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf); gst_pad_push (filter->srcpad, prebuf); - filter->pre_run_length = 0.0; + ++count; } - } + GST_DEBUG (GST_CAT_PLUGIN_INFO, "flushed %d buffers", count); + filter->pre_run_length = 0.0; + } } - /* now check if we have to add the new buffer to the cache or to the pad */ + /* now check if we have to send the new buffer to the internal buffer cache + * or to the srcpad */ if (filter->silent) { /* we ref it before putting it in the pre_buffer */ + /* FIXME: we shouldn't probably do this, because the buffer + * arrives reffed already; the plugin should just push it + * or unref it to make it disappear */ + /* gst_buffer_ref (buf); + */ filter->pre_buffer = g_list_append (filter->pre_buffer, buf); filter->pre_run_length += gst_audio_length (filter->srcpad, buf); while (filter->pre_run_length > filter->pre_length) @@ -288,7 +312,9 @@ gst_cutter_chain (GstPad *pad, GstBuffer *buf) g_assert (GST_IS_BUFFER (prebuf)); filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf); filter->pre_run_length -= gst_audio_length (filter->srcpad, prebuf); - gst_pad_push (filter->srcpad, prebuf); + /* only pass buffers if we don't leak */ + if (!filter->leaky) + gst_pad_push (filter->srcpad, prebuf); /* we unref it after getting it out of the pre_buffer */ gst_buffer_unref (prebuf); } @@ -306,7 +332,7 @@ gst_cutter_8bit_ms (gint8* data, guint num_samples) #include "filter.func" static void -gst_cutter_set_property (GObject *object, guint prop_id, +gst_cutter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstCutter *filter; @@ -319,28 +345,32 @@ gst_cutter_set_property (GObject *object, guint prop_id, case ARG_THRESHOLD: /* set the level */ filter->threshold_level = g_value_get_double (value); - GST_DEBUG (GST_CAT_PLUGIN_INFO, - "DEBUG: cutter: set threshold level to %f\n", + GST_DEBUG (GST_CAT_PLUGIN_INFO, + "DEBUG: set threshold level to %f", filter->threshold_level); break; case ARG_THRESHOLD_DB: - /* set the level given in dB - * value in dB = 20 * log (value) + /* set the level given in dB + * value in dB = 20 * log (value) * values in dB < 0 result in values between 0 and 1 */ filter->threshold_level = pow (10, g_value_get_double (value) / 20); GST_DEBUG (GST_CAT_PLUGIN_INFO, - "DEBUG: cutter: set threshold level to %f\n", + "DEBUG: set threshold level to %f", filter->threshold_level); break; case ARG_RUN_LENGTH: /* set the minimum length of the silent run required */ filter->threshold_length = g_value_get_double (value); - break; + break; case ARG_PRE_LENGTH: /* set the length of the pre-record block */ filter->pre_length = g_value_get_double (value); break; + case ARG_LEAKY: + /* set if the pre-record buffer is leaky or not */ + filter->leaky = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -348,7 +378,7 @@ gst_cutter_set_property (GObject *object, guint prop_id, } static void -gst_cutter_get_property (GObject *object, guint prop_id, +gst_cutter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstCutter *filter; @@ -370,6 +400,9 @@ gst_cutter_get_property (GObject *object, guint prop_id, case ARG_PRE_LENGTH: g_value_set_double (value, filter->pre_length); break; + case ARG_LEAKY: + g_value_set_boolean (value, filter->leaky); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -384,7 +417,7 @@ plugin_init (GModule *module, GstPlugin *plugin) factory = gst_element_factory_new ("cutter", GST_TYPE_CUTTER, &cutter_details); g_return_val_if_fail(factory != NULL, FALSE); - + gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (cutter_src_factory)); gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (cutter_sink_factory)); @@ -397,7 +430,7 @@ plugin_init (GModule *module, GstPlugin *plugin) return TRUE; } -GstPluginDesc plugin_desc = +GstPluginDesc plugin_desc = { GST_VERSION_MAJOR, GST_VERSION_MINOR, @@ -414,7 +447,7 @@ gst_cutter_get_caps (GstPad *pad, GstCutter* filter) /* FIXME : Please change this to a better warning method ! */ g_assert (caps != NULL); if (caps == NULL) - printf ("WARNING: cutter: get_caps: Could not get caps of pad !\n"); + printf ("WARNING: get_caps: Could not get caps of pad !\n"); gst_caps_get_int (caps, "width", &filter->width); filter->max_sample = gst_audio_highest_sample_value (pad); filter->have_caps = TRUE; diff --git a/gst/cutter/gstcutter.h b/gst/cutter/gstcutter.h index 2c0c0ff9..124cd0f4 100644 --- a/gst/cutter/gstcutter.h +++ b/gst/cutter/gstcutter.h @@ -46,7 +46,7 @@ extern "C" { typedef struct _GstCutter GstCutter; typedef struct _GstCutterClass GstCutterClass; -struct _GstCutter +struct _GstCutter { GstElement element; @@ -61,14 +61,15 @@ struct _GstCutter double pre_length; /* how long can the pre-record buffer be ? */ double pre_run_length; /* how long is it currently ? */ - GList *pre_buffer; - + GList *pre_buffer; /* list of GstBuffers in pre-record buffer */ + gboolean leaky; /* do we leak an overflowing prebuffer ? */ + gboolean have_caps; /* did we get the needed caps yet ? */ gint width; /* bit width of data */ long max_sample; /* maximum sample value */ }; -struct _GstCutterClass +struct _GstCutterClass { GstElementClass parent_class; void (*cut_start) (GstCutter* filter); |