static GstFlowReturn gst_cutter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstCutter *filter; GstMapInfo map; 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 */ GstClockTime duration; filter = GST_CUTTER (parent); 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); gst_buffer_map (buf, &map, GST_MAP_READ); in_data = (gint16 *) map.data; in_size = map.size; 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 (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 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 format"); break; } gst_buffer_unmap (buf, &map); 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 (duration)); if (RMS < filter->threshold_level) filter->silent_run_length += gst_guint64_to_gdouble (duration); else { filter->silent_run_length = 0 * GST_SECOND; filter->silent = FALSE; } if (filter->silent_run_length > filter->threshold_length) /* 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 */ if (filter->silent != filter->silent_prev) { if (filter->silent) { GstMessage *m = gst_cutter_message_new (filter, FALSE, GST_BUFFER_TIMESTAMP (buf)); GST_DEBUG_OBJECT (filter, "signaling CUT_STOP"); gst_element_post_message (GST_ELEMENT (filter), m); } else { gint count = 0; GstMessage *m = gst_cutter_message_new (filter, TRUE, GST_BUFFER_TIMESTAMP (buf)); GST_DEBUG_OBJECT (filter, "signaling CUT_START"); gst_element_post_message (GST_ELEMENT (filter), m); /* 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); gst_pad_push (filter->srcpad, prebuf); ++count; } GST_DEBUG_OBJECT (filter, "flushed %d buffers", count); filter->pre_run_length = 0 * GST_SECOND; } } /* now check if we have to send the new buffer to the internal buffer cache * 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 (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 (pduration); /* only pass buffers if we don't leak */ if (!filter->leaky) ret = gst_pad_push (filter->srcpad, prebuf); else gst_buffer_unref (prebuf); } } else ret = gst_pad_push (filter->srcpad, buf); return ret; /* ERRORS */ not_negotiated: { return GST_FLOW_NOT_NEGOTIATED; } }
static GstFlowReturn gst_cutter_chain (GstPad * pad, GstBuffer * buf) { GstCutter *filter; gint16 *in_data; 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); 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; } in_data = (gint16 *) GST_BUFFER_DATA (buf); 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: num_samples = GST_BUFFER_SIZE (buf) / 2; gst_cutter_calculate_gint16 (in_data, num_samples, &NCS); NMS = NCS / num_samples; break; case 8: num_samples = GST_BUFFER_SIZE (buf); 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); break; } filter->silent_prev = filter->silent; 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))); if (RMS < filter->threshold_level) filter->silent_run_length += gst_guint64_to_gdouble (gst_audio_duration_from_pad_buffer (filter->sinkpad, buf)); else { filter->silent_run_length = 0 * GST_SECOND; filter->silent = FALSE; } if (filter->silent_run_length > filter->threshold_length) /* 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 */ if (filter->silent != filter->silent_prev) { if (filter->silent) { GstMessage *m = gst_cutter_message_new (filter, FALSE, GST_BUFFER_TIMESTAMP (buf)); GST_DEBUG_OBJECT (filter, "signaling CUT_STOP"); gst_element_post_message (GST_ELEMENT (filter), m); } else { gint count = 0; GstMessage *m = gst_cutter_message_new (filter, TRUE, GST_BUFFER_TIMESTAMP (buf)); GST_DEBUG_OBJECT (filter, "signaling CUT_START"); gst_element_post_message (GST_ELEMENT (filter), m); /* 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); gst_pad_push (filter->srcpad, prebuf); ++count; } GST_DEBUG_OBJECT (filter, "flushed %d buffers", count); filter->pre_run_length = 0 * GST_SECOND; } } /* now check if we have to send the new buffer to the internal buffer cache * 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)); while (filter->pre_run_length > filter->pre_length) { prebuf = (g_list_first (filter->pre_buffer))->data; g_assert (GST_IS_BUFFER (prebuf)); 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)); /* only pass buffers if we don't leak */ if (!filter->leaky) gst_pad_push (filter->srcpad, prebuf); else gst_buffer_unref (prebuf); } } else gst_pad_push (filter->srcpad, buf); return GST_FLOW_OK; }