/** * gst_clock_set_calibration: * @clock: a #GstClock to calibrate * @internal: a reference internal time * @external: a reference external time * @rate_num: the numerator of the rate of the clock relative to its * internal time * @rate_denom: the denominator of the rate of the clock * * Adjusts the rate and time of @clock. A rate of 1/1 is the normal speed of * the clock. Values bigger than 1/1 make the clock go faster. * * @internal and @external are calibration parameters that arrange that * gst_clock_get_time() should have been @external at internal time @internal. * This internal time should not be in the future; that is, it should be less * than the value of gst_clock_get_internal_time() when this function is called. * * Subsequent calls to gst_clock_get_time() will return clock times computed as * follows: * * <programlisting> * time = (internal_time - internal) * rate_num / rate_denom + external * </programlisting> * * This formula is implemented in gst_clock_adjust_unlocked(). Of course, it * tries to do the integer arithmetic as precisely as possible. * * Note that gst_clock_get_time() always returns increasing values so when you * move the clock backwards, gst_clock_get_time() will report the previous value * until the clock catches up. * * MT safe. */ void gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime external, GstClockTime rate_num, GstClockTime rate_denom) { GstClockPrivate *priv; g_return_if_fail (GST_IS_CLOCK (clock)); g_return_if_fail (rate_num != GST_CLOCK_TIME_NONE); g_return_if_fail (rate_denom > 0 && rate_denom != GST_CLOCK_TIME_NONE); priv = clock->priv; write_seqlock (clock); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal), GST_TIME_ARGS (external), rate_num, rate_denom, gst_guint64_to_gdouble (rate_num) / gst_guint64_to_gdouble (rate_denom)); priv->internal_calibration = internal; priv->external_calibration = external; priv->rate_numerator = rate_num; priv->rate_denominator = rate_denom; write_sequnlock (clock); }
static inline gdouble _interpolate_cubic (GstTimedValueControlSource * self, GstControlPoint * cp1, gdouble value1, GstControlPoint * cp2, gdouble value2, GstClockTime timestamp) { if (!self->valid_cache) { _interpolate_cubic_update_cache (self); self->valid_cache = TRUE; } if (cp2) { gdouble diff1, diff2; gdouble out; diff1 = gst_guint64_to_gdouble (timestamp - cp1->timestamp); diff2 = gst_guint64_to_gdouble (cp2->timestamp - timestamp); out = (cp2->cache.cubic.z * diff1 * diff1 * diff1 + cp1->cache.cubic.z * diff2 * diff2 * diff2) / cp1->cache.cubic.h; out += (value2 / cp1->cache.cubic.h - cp1->cache.cubic.h * cp2->cache.cubic.z) * diff1; out += (value1 / cp1->cache.cubic.h - cp1->cache.cubic.h * cp1->cache.cubic.z) * diff2; return out; } else { return value1; } }
/* smoothes in between values */ static inline gdouble _interpolate_linear (GstClockTime timestamp1, gdouble value1, GstClockTime timestamp2, gdouble value2, GstClockTime timestamp) { if (GST_CLOCK_TIME_IS_VALID (timestamp2)) { gdouble slope; slope = (value2 - value1) / gst_guint64_to_gdouble (timestamp2 - timestamp1); return value1 + (gst_guint64_to_gdouble (timestamp - timestamp1) * slope); } else { return value1; } }
static void seek_to (AppInfo * info, gdouble percent) { GstSeekFlags seek_flags; gint64 seek_pos, dur = -1; if (!gst_element_query_duration (info->pipe, GST_FORMAT_TIME, &dur) || dur <= 0) { g_printerr ("Could not query duration\n"); return; } seek_pos = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (dur) * percent); g_print ("Seeking to %" GST_TIME_FORMAT ", accurate: %d\n", GST_TIME_ARGS (seek_pos), info->accurate); seek_flags = GST_SEEK_FLAG_FLUSH; if (info->accurate) seek_flags |= GST_SEEK_FLAG_ACCURATE; else seek_flags |= GST_SEEK_FLAG_KEY_UNIT; if (!gst_element_seek_simple (info->pipe, GST_FORMAT_TIME, seek_flags, seek_pos)) { g_printerr ("Seek failed.\n"); return; } }
EXPORT_C #endif void gst_clock_set_calibration (GstClock * clock, GstClockTime internal, GstClockTime external, GstClockTime rate_num, GstClockTime rate_denom) { g_return_if_fail (GST_IS_CLOCK (clock)); g_return_if_fail (rate_num >= 0); g_return_if_fail (rate_denom > 0); g_return_if_fail (internal <= gst_clock_get_internal_time (clock)); GST_OBJECT_LOCK (clock); GST_CAT_DEBUG_OBJECT (GST_CAT_CLOCK, clock, "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f", GST_TIME_ARGS (internal), GST_TIME_ARGS (external), rate_num, rate_denom, gst_guint64_to_gdouble (rate_num / rate_denom)); clock->internal_calibration = internal; clock->external_calibration = external; clock->rate_numerator = rate_num; clock->rate_denominator = rate_denom; GST_OBJECT_UNLOCK (clock); }
static void gst_level_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstLevel *filter = GST_LEVEL (object); switch (prop_id) { case PROP_POST_MESSAGES: /* fall-through */ case PROP_MESSAGE: filter->post_messages = g_value_get_boolean (value); break; case PROP_INTERVAL: filter->interval = g_value_get_uint64 (value); /* Not exactly thread-safe, but property does not advertise that it * can be changed at runtime anyway */ if (GST_AUDIO_INFO_RATE (&filter->info)) { gst_level_recalc_interval_frames (filter); } break; case PROP_PEAK_TTL: filter->decay_peak_ttl = gst_guint64_to_gdouble (g_value_get_uint64 (value)); break; case PROP_PEAK_FALLOFF: filter->decay_peak_falloff = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_level_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstLevel *filter = GST_LEVEL (object); switch (prop_id) { case PROP_POST_MESSAGES: /* fall-through */ case PROP_MESSAGE: filter->post_messages = g_value_get_boolean (value); break; case PROP_INTERVAL: filter->interval = g_value_get_uint64 (value); if (GST_AUDIO_INFO_RATE (&filter->info)) { filter->interval_frames = GST_CLOCK_TIME_TO_FRAMES (filter->interval, GST_AUDIO_INFO_RATE (&filter->info)); } break; case PROP_PEAK_TTL: filter->decay_peak_ttl = gst_guint64_to_gdouble (g_value_get_uint64 (value)); break; case PROP_PEAK_FALLOFF: filter->decay_peak_falloff = g_value_get_double (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
void test_math_scale_random() { guint64 val, num, denom, res; GRand *rand; gint i; xmlfile = "gstutils_test_math_scale_random"; std_log(LOG_FILENAME_LINE, "Test Started gstutils_test_math_scale_random"); rand = g_rand_new (); i = 100000; while (i--) { guint64 check, diff; val = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); num = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); denom = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand); res = gst_util_uint64_scale (val, num, denom); check = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (val) * gst_guint64_to_gdouble (num) / gst_guint64_to_gdouble (denom)); if (res < G_MAXUINT64 && check < G_MAXUINT64) { if (res > check) diff = res - check; else diff = check - res; /* some arbitrary value, really.. someone do the proper math to get * the upper bound */ if (diff > 20000) fail_if (diff > 20000); } } g_rand_free (rand); std_log(LOG_FILENAME_LINE, "Test Successful"); create_xml(0); }
static void gst_cutter_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstCutter *filter; g_return_if_fail (GST_IS_CUTTER (object)); filter = GST_CUTTER (object); switch (prop_id) { case PROP_THRESHOLD: filter->threshold_level = g_value_get_double (value); GST_DEBUG ("DEBUG: set threshold level to %f", filter->threshold_level); break; case PROP_THRESHOLD_DB: /* 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_OBJECT (filter, "set threshold level to %f", filter->threshold_level); break; case PROP_RUN_LENGTH: /* set the minimum length of the silent run required */ filter->threshold_length = gst_guint64_to_gdouble (g_value_get_uint64 (value)); break; case PROP_PRE_LENGTH: /* set the length of the pre-record block */ filter->pre_length = gst_guint64_to_gdouble (g_value_get_uint64 (value)); break; case PROP_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; } }
static inline gdouble _interpolate_cubic_monotonic (GstTimedValueControlSource * self, GstControlPoint * cp1, gdouble value1, GstControlPoint * cp2, gdouble value2, GstClockTime timestamp) { if (!self->valid_cache) { _interpolate_cubic_monotonic_update_cache (self); self->valid_cache = TRUE; } if (cp2) { gdouble diff = gst_guint64_to_gdouble (timestamp - cp1->timestamp); gdouble diff2 = diff * diff; gdouble out; out = value1 + cp1->cache.cubic_monotonic.c1s * diff; out += cp1->cache.cubic_monotonic.c2s * diff2; out += cp1->cache.cubic_monotonic.c3s * diff * diff2; return out; } else { return value1; } }
static GstFlowReturn gst_aiff_parse_stream_data (GstAiffParse * aiff) { GstBuffer *buf = NULL; GstFlowReturn res = GST_FLOW_OK; guint64 desired, obtained; GstClockTime timestamp, next_timestamp, duration; guint64 pos, nextpos; iterate_adapter: GST_LOG_OBJECT (aiff, "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %" G_GINT64_FORMAT, aiff->offset, aiff->end_offset, aiff->dataleft); /* Get the next n bytes and output them */ if (aiff->dataleft == 0 || aiff->dataleft < aiff->bytes_per_sample) goto found_eos; /* scale the amount of data by the segment rate so we get equal * amounts of data regardless of the playback rate */ desired = MIN (gst_guint64_to_gdouble (aiff->dataleft), MAX_BUFFER_SIZE * aiff->segment.abs_rate); if (desired >= aiff->bytes_per_sample && aiff->bytes_per_sample > 0) desired -= (desired % aiff->bytes_per_sample); GST_LOG_OBJECT (aiff, "Fetching %" G_GINT64_FORMAT " bytes of data " "from the sinkpad", desired); if (aiff->streaming) { guint avail = gst_adapter_available (aiff->adapter); if (avail < desired) { GST_LOG_OBJECT (aiff, "Got only %d bytes of data from the sinkpad", avail); return GST_FLOW_OK; } buf = gst_adapter_take_buffer (aiff->adapter, desired); } else { if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset, desired, &buf)) != GST_FLOW_OK) goto pull_error; } /* If we have a pending close/start segment, send it now. */ if (G_UNLIKELY (aiff->close_segment != NULL)) { gst_pad_push_event (aiff->srcpad, aiff->close_segment); aiff->close_segment = NULL; } if (G_UNLIKELY (aiff->start_segment != NULL)) { gst_pad_push_event (aiff->srcpad, aiff->start_segment); aiff->start_segment = NULL; } obtained = GST_BUFFER_SIZE (buf); /* our positions in bytes */ pos = aiff->offset - aiff->datastart; nextpos = pos + obtained; /* update offsets, does not overflow. */ GST_BUFFER_OFFSET (buf) = pos / aiff->bytes_per_sample; GST_BUFFER_OFFSET_END (buf) = nextpos / aiff->bytes_per_sample; if (aiff->bps > 0) { /* and timestamps if we have a bitrate, be careful for overflows */ timestamp = uint64_ceiling_scale (pos, GST_SECOND, (guint64) aiff->bps); next_timestamp = uint64_ceiling_scale (nextpos, GST_SECOND, (guint64) aiff->bps); duration = next_timestamp - timestamp; /* update current running segment position */ gst_segment_set_last_stop (&aiff->segment, GST_FORMAT_TIME, next_timestamp); } else { /* no bitrate, all we know is that the first sample has timestamp 0, all * other positions and durations have unknown timestamp. */ if (pos == 0) timestamp = 0; else timestamp = GST_CLOCK_TIME_NONE; duration = GST_CLOCK_TIME_NONE; /* update current running segment position with byte offset */ gst_segment_set_last_stop (&aiff->segment, GST_FORMAT_BYTES, nextpos); } if (aiff->discont) { GST_DEBUG_OBJECT (aiff, "marking DISCONT"); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); aiff->discont = FALSE; } GST_BUFFER_TIMESTAMP (buf) = timestamp; GST_BUFFER_DURATION (buf) = duration; gst_buffer_set_caps (buf, aiff->caps); GST_LOG_OBJECT (aiff, "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT ", size:%u", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration), GST_BUFFER_SIZE (buf)); if ((res = gst_pad_push (aiff->srcpad, buf)) != GST_FLOW_OK) goto push_error; if (obtained < aiff->dataleft) { aiff->offset += obtained; aiff->dataleft -= obtained; } else { aiff->offset += aiff->dataleft; aiff->dataleft = 0; } /* Iterate until need more data, so adapter size won't grow */ if (aiff->streaming) { GST_LOG_OBJECT (aiff, "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, aiff->offset, aiff->end_offset); goto iterate_adapter; } return res; /* ERROR */ found_eos: { GST_DEBUG_OBJECT (aiff, "found EOS"); return GST_FLOW_UNEXPECTED; } pull_error: { /* check if we got EOS */ if (res == GST_FLOW_UNEXPECTED) goto found_eos; GST_WARNING_OBJECT (aiff, "Error getting %" G_GINT64_FORMAT " bytes from the " "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, aiff->dataleft); return res; } push_error: { GST_INFO_OBJECT (aiff, "Error pushing on srcpad %s:%s, reason %s, is linked? = %d", GST_DEBUG_PAD_NAME (aiff->srcpad), gst_flow_get_name (res), gst_pad_is_linked (aiff->srcpad)); return res; } }
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 void _interpolate_cubic_monotonic_update_cache (GstTimedValueControlSource * self) { gint i, n = self->nvalues; gdouble *dxs = g_new0 (gdouble, n); gdouble *dys = g_new0 (gdouble, n); gdouble *ms = g_new0 (gdouble, n); gdouble *c1s = g_new0 (gdouble, n); GSequenceIter *iter; GstControlPoint *cp; GstClockTime x, x_next, dx; gdouble y, y_next, dy; /* Get consecutive differences and slopes */ iter = g_sequence_get_begin_iter (self->values); cp = g_sequence_get (iter); x_next = cp->timestamp; y_next = cp->value; for (i = 0; i < n - 1; i++) { x = x_next; y = y_next; iter = g_sequence_iter_next (iter); cp = g_sequence_get (iter); x_next = cp->timestamp; y_next = cp->value; dx = gst_guint64_to_gdouble (x_next - x); dy = y_next - y; dxs[i] = dx; dys[i] = dy; ms[i] = dy / dx; } /* Get degree-1 coefficients */ c1s[0] = ms[0]; for (i = 1; i < n; i++) { gdouble m = ms[i - 1]; gdouble m_next = ms[i]; if (m * m_next <= 0) { c1s[i] = 0.0; } else { gdouble dx_next, dx_sum; dx = dxs[i], dx_next = dxs[i + 1], dx_sum = dx + dx_next; c1s[i] = 3.0 * dx_sum / ((dx_sum + dx_next) / m + (dx_sum + dx) / m_next); } } c1s[n - 1] = ms[n - 1]; /* Get degree-2 and degree-3 coefficients */ iter = g_sequence_get_begin_iter (self->values); for (i = 0; i < n - 1; i++) { gdouble c1, m, inv_dx, common; cp = g_sequence_get (iter); c1 = c1s[i]; m = ms[i]; inv_dx = 1.0 / dxs[i]; common = c1 + c1s[i + 1] - m - m; cp->cache.cubic_monotonic.c1s = c1; cp->cache.cubic_monotonic.c2s = (m - c1 - common) * inv_dx; cp->cache.cubic_monotonic.c3s = common * inv_dx * inv_dx; iter = g_sequence_iter_next (iter); } /* Free our temporary arrays */ g_free (dxs); g_free (dys); g_free (ms); g_free (c1s); }
static void _interpolate_cubic_update_cache (GstTimedValueControlSource * self) { gint i, n = self->nvalues; gdouble *o = g_new0 (gdouble, n); gdouble *p = g_new0 (gdouble, n); gdouble *q = g_new0 (gdouble, n); gdouble *h = g_new0 (gdouble, n); gdouble *b = g_new0 (gdouble, n); gdouble *z = g_new0 (gdouble, n); GSequenceIter *iter; GstControlPoint *cp; GstClockTime x, x_next; gdouble y_prev, y, y_next; /* Fill linear system of equations */ iter = g_sequence_get_begin_iter (self->values); cp = g_sequence_get (iter); x = cp->timestamp; y = cp->value; p[0] = 1.0; iter = g_sequence_iter_next (iter); cp = g_sequence_get (iter); x_next = cp->timestamp; y_next = cp->value; h[0] = gst_guint64_to_gdouble (x_next - x); for (i = 1; i < n - 1; i++) { /* Shuffle x and y values */ y_prev = y; x = x_next; y = y_next; iter = g_sequence_iter_next (iter); cp = g_sequence_get (iter); x_next = cp->timestamp; y_next = cp->value; h[i] = gst_guint64_to_gdouble (x_next - x); o[i] = h[i - 1]; p[i] = 2.0 * (h[i - 1] + h[i]); q[i] = h[i]; b[i] = (y_next - y) / h[i] - (y - y_prev) / h[i - 1]; } p[n - 1] = 1.0; /* Use Gauss elimination to set everything below the diagonal to zero */ for (i = 1; i < n - 1; i++) { gdouble a = o[i] / p[i - 1]; p[i] -= a * q[i - 1]; b[i] -= a * b[i - 1]; } /* Solve everything else from bottom to top */ for (i = n - 2; i > 0; i--) z[i] = (b[i] - q[i] * z[i + 1]) / p[i]; /* Save cache next in the GstControlPoint */ iter = g_sequence_get_begin_iter (self->values); for (i = 0; i < n; i++) { cp = g_sequence_get (iter); cp->cache.cubic.h = h[i]; cp->cache.cubic.z = z[i]; iter = g_sequence_iter_next (iter); } /* Free our temporary arrays */ g_free (o); g_free (p); g_free (q); g_free (h); g_free (b); g_free (z); }
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; }