예제 #1
0
/**
 * 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;
  }
}
예제 #5
0
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);
}
예제 #6
0
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;
  }
}
예제 #7
0
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;
  }
}
예제 #8
0
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);

}
예제 #9
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;
  }
}
예제 #11
0
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;
  }
}
예제 #12
0
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);
}
예제 #15
0
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;
}