cutter: bring cutter somewhat into this millennium
authorWim Taymans <wim.taymans@collabora.co.uk>
Sat, 20 Aug 2011 08:46:18 +0000 (10:46 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Sat, 20 Aug 2011 08:46:18 +0000 (10:46 +0200)
gst/cutter/gstcutter.c
gst/cutter/gstcutter.h

index 32816da..2168a28 100644 (file)
@@ -100,10 +100,9 @@ static void gst_cutter_set_property (GObject * object, guint prop_id,
 static void gst_cutter_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
+static gboolean gst_cutter_event (GstPad * pad, GstEvent * event);
 static GstFlowReturn gst_cutter_chain (GstPad * pad, GstBuffer * buffer);
 
-static gboolean gst_cutter_get_caps (GstPad * pad, GstCutter * filter);
-
 static void
 gst_cutter_class_init (GstCutterClass * klass)
 {
@@ -156,8 +155,15 @@ gst_cutter_init (GstCutter * filter)
 {
   filter->sinkpad =
       gst_pad_new_from_static_template (&cutter_sink_factory, "sink");
+  gst_pad_set_chain_function (filter->sinkpad, gst_cutter_chain);
+  gst_pad_set_event_function (filter->sinkpad, gst_cutter_event);
+  gst_pad_use_fixed_caps (filter->sinkpad);
+  gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+
   filter->srcpad =
       gst_pad_new_from_static_template (&cutter_src_factory, "src");
+  gst_pad_use_fixed_caps (filter->srcpad);
+  gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
 
   filter->threshold_level = CUTTER_DEFAULT_THRESHOLD_LEVEL;
   filter->threshold_length = CUTTER_DEFAULT_THRESHOLD_LENGTH;
@@ -169,13 +175,6 @@ gst_cutter_init (GstCutter * filter)
   filter->pre_run_length = 0 * GST_SECOND;
   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_use_fixed_caps (filter->sinkpad);
-
-  gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
-  gst_pad_use_fixed_caps (filter->srcpad);
 }
 
 static GstMessage *
@@ -223,51 +222,86 @@ gst_cutter_calculate_##TYPE (TYPE * in, guint num,                            \
 DEFINE_CUTTER_CALCULATOR (gint16, 15);
 DEFINE_CUTTER_CALCULATOR (gint8, 7);
 
+static gboolean
+gst_cutter_setcaps (GstCutter * filter, GstCaps * caps)
+{
+  GstAudioInfo info;
+
+  if (!gst_audio_info_from_caps (&info, caps))
+    return FALSE;
+
+  filter->info = info;
+
+  return gst_pad_set_caps (filter->srcpad, caps);
+}
+
+static gboolean
+gst_cutter_event (GstPad * pad, GstEvent * event)
+{
+  gboolean ret;
+  GstCutter *filter;
+
+  filter = GST_CUTTER (GST_OBJECT_PARENT (pad));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CAPS:
+    {
+      GstCaps *caps;
+
+      gst_event_parse_caps (event, &caps);
+      ret = gst_cutter_setcaps (filter, caps);
+      break;
+    }
+    default:
+      ret = gst_pad_event_default (pad, event);
+      break;
+  }
+  return ret;
+}
 
 static GstFlowReturn
 gst_cutter_chain (GstPad * pad, GstBuffer * buf)
 {
+  GstFlowReturn ret = GST_FLOW_OK;
   GstCutter *filter;
   gint16 *in_data;
+  gint bpf, rate;
   gsize in_size;
   guint num_samples;
   gdouble NCS = 0.0;            /* Normalized Cumulative Square of buffer */
   gdouble RMS = 0.0;            /* RMS of signal in buffer */
   gdouble NMS = 0.0;            /* Normalized Mean Square of buffer */
   GstBuffer *prebuf;            /* pointer to a prebuffer element */
-
-  g_return_val_if_fail (pad != NULL, GST_FLOW_ERROR);
-  g_return_val_if_fail (GST_IS_PAD (pad), GST_FLOW_ERROR);
-  g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
+  GstClockTime duration;
 
   filter = GST_CUTTER (GST_OBJECT_PARENT (pad));
-  g_return_val_if_fail (filter != NULL, GST_FLOW_ERROR);
-  g_return_val_if_fail (GST_IS_CUTTER (filter), GST_FLOW_ERROR);
 
-  if (!filter->have_caps) {
-    if (!(gst_cutter_get_caps (pad, filter)))
-      return GST_FLOW_NOT_NEGOTIATED;
-  }
+  if (GST_AUDIO_INFO_FORMAT (&filter->info) == GST_AUDIO_FORMAT_UNKNOWN)
+    goto not_negotiated;
+
+  bpf = GST_AUDIO_INFO_BPF (&filter->info);
+  rate = GST_AUDIO_INFO_RATE (&filter->info);
+
+  in_data = gst_buffer_map (buf, &in_size, NULL, GST_MAP_READ);
 
-  in_data = (gint16 *) gst_buffer_map (buf, &in_size, NULL, GST_MAP_READ);
   GST_LOG_OBJECT (filter, "length of prerec buffer: %" GST_TIME_FORMAT,
       GST_TIME_ARGS (filter->pre_run_length));
 
   /* calculate mean square value on buffer */
-  switch (filter->width) {
-    case 16:
+  switch (GST_AUDIO_INFO_FORMAT (&filter->info)) {
+    case GST_AUDIO_FORMAT_S16:
       num_samples = in_size / 2;
       gst_cutter_calculate_gint16 (in_data, num_samples, &NCS);
       NMS = NCS / num_samples;
       break;
-    case 8:
+    case GST_AUDIO_FORMAT_S8:
       num_samples = in_size;
       gst_cutter_calculate_gint8 ((gint8 *) in_data, num_samples, &NCS);
       NMS = NCS / num_samples;
       break;
     default:
       /* this shouldn't happen */
-      g_warning ("no mean square function for width %d\n", filter->width);
+      g_warning ("no mean square function for format");
       break;
   }
 
@@ -275,18 +309,17 @@ gst_cutter_chain (GstPad * pad, GstBuffer * buf)
 
   filter->silent_prev = filter->silent;
 
+  duration = gst_util_uint64_scale (in_size / bpf, GST_SECOND, rate);
+
   RMS = sqrt (NMS);
   /* if RMS below threshold, add buffer length to silent run length count
    * if not, reset
    */
   GST_LOG_OBJECT (filter, "buffer stats: NMS %f, RMS %f, audio length %f", NMS,
-      RMS,
-      gst_guint64_to_gdouble (gst_audio_duration_from_pad_buffer
-          (filter->sinkpad, buf)));
+      RMS, gst_guint64_to_gdouble (duration));
+
   if (RMS < filter->threshold_level)
-    filter->silent_run_length +=
-        gst_guint64_to_gdouble (gst_audio_duration_from_pad_buffer
-        (filter->sinkpad, buf));
+    filter->silent_run_length += gst_guint64_to_gdouble (duration);
   else {
     filter->silent_run_length = 0 * GST_SECOND;
     filter->silent = FALSE;
@@ -315,6 +348,7 @@ gst_cutter_chain (GstPad * pad, GstBuffer * buf)
       /* first of all, flush current buffer */
       GST_DEBUG_OBJECT (filter, "flushing buffer of length %" GST_TIME_FORMAT,
           GST_TIME_ARGS (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);
@@ -329,55 +363,39 @@ gst_cutter_chain (GstPad * pad, GstBuffer * buf)
    * or to the srcpad */
   if (filter->silent) {
     filter->pre_buffer = g_list_append (filter->pre_buffer, buf);
-    filter->pre_run_length +=
-        gst_guint64_to_gdouble (gst_audio_duration_from_pad_buffer
-        (filter->sinkpad, buf));
+    filter->pre_run_length += gst_guint64_to_gdouble (duration);
+
     while (filter->pre_run_length > filter->pre_length) {
+      GstClockTime pduration;
+      gsize psize;
+
       prebuf = (g_list_first (filter->pre_buffer))->data;
       g_assert (GST_IS_BUFFER (prebuf));
+
+      psize = gst_buffer_get_size (prebuf);
+      pduration = gst_util_uint64_scale (psize / bpf, GST_SECOND, rate);
+
       filter->pre_buffer = g_list_remove (filter->pre_buffer, prebuf);
-      filter->pre_run_length -=
-          gst_guint64_to_gdouble (gst_audio_duration_from_pad_buffer
-          (filter->sinkpad, prebuf));
+      filter->pre_run_length -= gst_guint64_to_gdouble (pduration);
+
       /* only pass buffers if we don't leak */
       if (!filter->leaky)
-        gst_pad_push (filter->srcpad, prebuf);
+        ret = gst_pad_push (filter->srcpad, prebuf);
       else
         gst_buffer_unref (prebuf);
     }
   } else
-    gst_pad_push (filter->srcpad, buf);
-
-  return GST_FLOW_OK;
-}
-
+    ret = gst_pad_push (filter->srcpad, buf);
 
-static gboolean
-gst_cutter_get_caps (GstPad * pad, GstCutter * filter)
-{
-  GstCaps *caps;
-  GstStructure *structure;
-  const gchar *format;
+  return ret;
 
-  caps = gst_pad_get_current_caps (pad);
-  if (!caps) {
-    GST_INFO ("no caps on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
-    return FALSE;
+  /* ERRORS */
+not_negotiated:
+  {
+    return GST_FLOW_NOT_NEGOTIATED;
   }
-  structure = gst_caps_get_structure (caps, 0);
-
-  format = gst_structure_get_string (structure, "format");
-  if (g_str_has_prefix (format, "S16"))
-    filter->width = 16;
-  else
-    filter->width = 8;
-  filter->have_caps = TRUE;
-
-  gst_caps_unref (caps);
-  return TRUE;
 }
 
-
 static void
 gst_cutter_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
index d64c301..47c1750 100644 (file)
@@ -54,7 +54,6 @@ struct _GstCutter
   double threshold_level;       /* level below which to cut */
   double threshold_length;      /* how long signal has to remain
                                  * below this level before cutting */
-
   double silent_run_length;     /* how long has it been below threshold ? */
   gboolean silent;
   gboolean silent_prev;
@@ -64,9 +63,7 @@ struct _GstCutter
   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 */
+  GstAudioInfo info;
 };
 
 struct _GstCutterClass