static inline gboolean
gst_ts_shifter_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
  gboolean ret = TRUE;
  GstTSShifter *ts = GST_TS_SHIFTER (parent);

  if (G_UNLIKELY (ts == NULL)) {
    gst_event_unref (event);
    return FALSE;
  }

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
    {
      GST_CAT_LOG_OBJECT (ts_flow, ts, "received seek event");
      /* Do the seek ourself now */
      ret = gst_ts_shifter_handle_seek (ts, event);
      break;
    }
    case GST_EVENT_QOS:
    {
      break;
    }
    default:
      GST_CAT_LOG_OBJECT (ts_flow, ts, "dropped event %s",
          GST_EVENT_TYPE_NAME (event));
      ret = FALSE;
      break;
  }

  gst_event_unref (event);

  return ret;
}
예제 #2
0
/**
 * gst_clock_add_observation:
 * @clock: a #GstClock 
 * @slave: a time on the slave
 * @master: a time on the master
 * @r_squared: (out): a pointer to hold the result
 *
 * The time @master of the master clock and the time @slave of the slave
 * clock are added to the list of observations. If enough observations
 * are available, a linear regression algorithm is run on the
 * observations and @clock is recalibrated.
 *
 * If this functions returns %TRUE, @r_squared will contain the 
 * correlation coefficient of the interpolation. A value of 1.0
 * means a perfect regression was performed. This value can
 * be used to control the sampling frequency of the master and slave
 * clocks.
 *
 * Returns: %TRUE if enough observations were added to run the 
 * regression algorithm.
 *
 * MT safe.
 */
gboolean
gst_clock_add_observation (GstClock * clock, GstClockTime slave,
    GstClockTime master, gdouble * r_squared)
{
  GstClockTime m_num, m_denom, b, xbase;
  GstClockPrivate *priv;

  g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
  g_return_val_if_fail (r_squared != NULL, FALSE);

  priv = clock->priv;

  GST_CLOCK_SLAVE_LOCK (clock);

  GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
      "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT,
      GST_TIME_ARGS (slave), GST_TIME_ARGS (master));

  priv->times[(4 * priv->time_index)] = slave;
  priv->times[(4 * priv->time_index) + 2] = master;

  priv->time_index++;
  if (G_UNLIKELY (priv->time_index == priv->window_size)) {
    priv->filling = FALSE;
    priv->time_index = 0;
  }

  if (G_UNLIKELY (priv->filling && priv->time_index < priv->window_threshold))
    goto filling;

  if (!do_linear_regression (clock, &m_num, &m_denom, &b, &xbase, r_squared))
    goto invalid;

  GST_CLOCK_SLAVE_UNLOCK (clock);

  GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
      "adjusting clock to m=%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ", b=%"
      G_GUINT64_FORMAT " (rsquared=%g)", m_num, m_denom, b, *r_squared);

  /* if we have a valid regression, adjust the clock */
  gst_clock_set_calibration (clock, xbase, b, m_num, m_denom);

  return TRUE;

filling:
  {
    GST_CLOCK_SLAVE_UNLOCK (clock);
    return FALSE;
  }
invalid:
  {
    /* no valid regression has been done, ignore the result then */
    GST_CLOCK_SLAVE_UNLOCK (clock);
    return TRUE;
  }
}
/* called repeadedly with @pad as the source pad. This function should push out
 * data to the peer element. */
static void
gst_ts_shifter_loop (GstPad * pad)
{
  GstTSShifter *ts;
  GstFlowReturn ret;

  ts = GST_TS_SHIFTER (GST_PAD_PARENT (pad));

  /* have to lock for thread-safety */
  FLOW_MUTEX_LOCK_CHECK (ts, ts->srcresult, out_flushing);

  if (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos) {
    GST_CAT_LOG_OBJECT (ts_flow, ts, "empty, waiting for new data");
    do {
      /* Wait for data to be available, we could be unlocked because of a flush. */
      FLOW_WAIT_ADD_CHECK (ts, ts->srcresult, out_flushing);
    }
    while (gst_ts_cache_is_empty (ts->cache) && !ts->is_eos);
  }
  ret = gst_ts_shifter_pop (ts);
  ts->srcresult = ret;
  if (ret != GST_FLOW_OK)
    goto out_flushing;

  FLOW_MUTEX_UNLOCK (ts);

  return;

  /* ERRORS */
out_flushing:
  {
    gboolean eos = ts->is_eos;
    GstFlowReturn ret = ts->srcresult;

    gst_pad_pause_task (ts->srcpad);
    FLOW_MUTEX_UNLOCK (ts);
    GST_CAT_LOG_OBJECT (ts_flow, ts,
        "pause task, reason:  %s", gst_flow_get_name (ts->srcresult));
    /* let app know about us giving up if upstream is not expected to do so */
    /* UNEXPECTED is already taken care of elsewhere */
    if (eos && (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS)) {
      GST_ELEMENT_ERROR (ts, STREAM, FAILED,
          ("Internal data flow error."),
          ("streaming task paused, reason %s (%d)",
              gst_flow_get_name (ret), ret));
      GST_CAT_LOG_OBJECT (ts_flow, ts, "pushing EOS");
      gst_pad_push_event (ts->srcpad, gst_event_new_eos ());
    }
    return;
  }
}
예제 #4
0
/* copy data into @dest, skipping @skip bytes from the head buffers */
static void
copy_into_unchecked (GstAdapter * adapter, guint8 * dest, gsize skip,
    gsize size)
{
  GSList *g;
  GstBuffer *buf;
  gsize bsize, csize;

  /* first step, do skipping */
  /* we might well be copying where we were scanning */
  if (adapter->scan_entry && (adapter->scan_offset <= skip)) {
    g = adapter->scan_entry;
    skip -= adapter->scan_offset;
  } else {
    g = adapter->buflist;
  }
  buf = g->data;
  bsize = gst_buffer_get_size (buf);
  while (G_UNLIKELY (skip >= bsize)) {
    skip -= bsize;
    g = g_slist_next (g);
    buf = g->data;
    bsize = gst_buffer_get_size (buf);
  }
  /* copy partial buffer */
  csize = MIN (bsize - skip, size);
  GST_DEBUG ("bsize %" G_GSIZE_FORMAT ", skip %" G_GSIZE_FORMAT ", csize %"
      G_GSIZE_FORMAT, bsize, skip, csize);
  GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter, "extract %" G_GSIZE_FORMAT
      " bytes", csize);
  gst_buffer_extract (buf, skip, dest, csize);
  size -= csize;
  dest += csize;

  /* second step, copy remainder */
  while (size > 0) {
    g = g_slist_next (g);
    buf = g->data;
    bsize = gst_buffer_get_size (buf);
    if (G_LIKELY (bsize > 0)) {
      csize = MIN (bsize, size);
      GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter,
          "extract %" G_GSIZE_FORMAT " bytes", csize);
      gst_buffer_extract (buf, 0, dest, csize);
      size -= csize;
      dest += csize;
    }
  }
}
예제 #5
0
static int
spotify_cb_music_delivery (sp_session *spotify_session, const sp_audioformat *format,const void *frames, int num_frames)
{
  GstBuffer *buffer;
  guint sample_rate = format->sample_rate;
  guint channels = format->channels;
  guint bufsize = num_frames * sizeof (int16_t) * channels;
  guint availible;

  GST_CAT_DEBUG_OBJECT (gst_spot_src_debug_cb, ugly_spot, "Music_delivery callback");

  GST_SPOT_SRC_FORMAT (ugly_spot)->sample_rate = sample_rate;
  GST_SPOT_SRC_FORMAT (ugly_spot)->channels = channels;
  GST_SPOT_SRC_FORMAT (ugly_spot)->sample_type = format->sample_type;

  GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Start %p with %d frames with size=%d", frames, num_frames, bufsize);

  if (num_frames == 0) {
    /* we have a seek */
    return 0;
  }

  buffer = gst_buffer_new_and_alloc (bufsize);

  memcpy (GST_BUFFER_DATA (buffer), (guint8*)frames, bufsize);

  g_mutex_lock (GST_SPOT_SRC_ADAPTER_MUTEX (ugly_spot));
  availible = gst_adapter_available (GST_SPOT_SRC_ADAPTER (ugly_spot));
  GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Availiable before push = %d", availible);
  /* see if we have buffertime of audio */
  if (availible >= (GST_SPOT_SRC_BUFFER_TIME (ugly_spot)/1000000) * sample_rate * 4) {
    GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Return 0, adapter is full = %d", availible);
    gst_buffer_unref (buffer);
    /* data is available broadcast read thread */
    g_cond_broadcast (GST_SPOT_SRC_ADAPTER_COND (ugly_spot));
    g_mutex_unlock (GST_SPOT_SRC_ADAPTER_MUTEX (ugly_spot));
    return 0;
  }

  gst_adapter_push (GST_SPOT_SRC_ADAPTER (ugly_spot), buffer);
  availible = gst_adapter_available (GST_SPOT_SRC_ADAPTER (ugly_spot));
  GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Availiable after push = %d", availible);
  /* data is available broadcast read thread */
  g_cond_broadcast (GST_SPOT_SRC_ADAPTER_COND (ugly_spot));
  g_mutex_unlock (GST_SPOT_SRC_ADAPTER_MUTEX (ugly_spot));
  GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, ugly_spot, "Return num_frames=%d", num_frames);
  return num_frames;
}
예제 #6
0
static gboolean
gst_spot_src_get_size (GstBaseSrc * basesrc, guint64 * size)
{
  GstSpotSrc *spot;
  guint64 duration = 0;

  spot = GST_SPOT_SRC (basesrc);
  /* duration in ms */
  duration = run_spot_cmd (spot, SPOT_CMD_DURATION, 0);
  /* duration in ns */
  duration = 1000000 * duration;

  if (!duration) {
    GST_CAT_ERROR_OBJECT (gst_spot_src_debug_audio, spot, "No duration error");
    goto no_duration;
  }

  *size = (duration/1000000000) * 44100 * 4;
  GST_CAT_LOG_OBJECT (gst_spot_src_debug_audio, spot, "Duration=%" G_GUINT64_FORMAT " => size=%" G_GUINT64_FORMAT, duration, *size);

  return TRUE;

no_duration:
  return FALSE;
}
예제 #7
0
/* Changing a GObject property of a GstObject will result in "deep_notify"
 * signals being emitted by the object itself, as well as in each parent
 * object. This is so that an application can connect a listener to the
 * top-level bin to catch property-change notifications for all contained
 * elements.
 *
 * This function is not MT safe in glib < 2.8 so we need to lock it with a
 * classwide mutex in that case.
 *
 * MT safe.
 */
static void
gst_object_dispatch_properties_changed (GObject * object,
    guint n_pspecs, GParamSpec ** pspecs)
{
  GstObject *gst_object, *parent, *old_parent;
  guint i;
  gchar *name, *debug_name;

  /* do the standard dispatching */
  parent_class->dispatch_properties_changed (object, n_pspecs, pspecs);

  gst_object = GST_OBJECT_CAST (object);
  name = gst_object_get_name (gst_object);
  debug_name = GST_STR_NULL (name);

  /* now let the parent dispatch those, too */
  parent = gst_object_get_parent (gst_object);
  while (parent) {
    for (i = 0; i < n_pspecs; i++) {
      GST_CAT_LOG_OBJECT (GST_CAT_PROPERTIES, parent,
          "deep notification from %s (%s)", debug_name, pspecs[i]->name);

      g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY],
          g_quark_from_string (pspecs[i]->name), gst_object, pspecs[i]);
    }

    old_parent = parent;
    parent = gst_object_get_parent (old_parent);
    gst_object_unref (old_parent);
  }
  g_free (name);
}
예제 #8
0
/* dispose is called when the object has to release all links
 * to other objects */
static void
gst_object_dispose (GObject * object)
{
  GstObject *parent;

  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");

  GST_OBJECT_LOCK (object);
  if ((parent = GST_OBJECT_PARENT (object)))
    goto have_parent;
  GST_OBJECT_PARENT (object) = NULL;
  GST_OBJECT_UNLOCK (object);

  parent_class->dispose (object);

  return;

  /* ERRORS */
have_parent:
  {
    g_critical ("\nTrying to dispose object \"%s\", but it still has a "
        "parent \"%s\".\nYou need to let the parent manage the "
        "object instead of unreffing the object directly.\n",
        GST_OBJECT_NAME (object), GST_OBJECT_NAME (parent));
    GST_OBJECT_UNLOCK (object);
    /* ref the object again to revive it in this error case */
    object = gst_object_ref (object);
    return;
  }
}
예제 #9
0
static void
spotify_cb_notify_main_thread (sp_session *spotify_session)
{
  GST_CAT_LOG_OBJECT (gst_spot_src_debug_cb, ugly_spot, "Notify_main_thread callback");
  GST_CAT_DEBUG_OBJECT (gst_spot_src_debug_threads, ugly_spot, "Broadcast process_events_cond");
  g_cond_broadcast (ugly_spot->process_events_cond);
}
예제 #10
0
EXPORT_C
#endif

void
gst_object_unparent (GstObject * object)
{
  GstObject *parent;

  g_return_if_fail (GST_IS_OBJECT (object));

  GST_OBJECT_LOCK (object);
  parent = object->parent;

  if (G_LIKELY (parent != NULL)) {
    GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unparent");
    object->parent = NULL;
    GST_OBJECT_UNLOCK (object);

    g_signal_emit (object, gst_object_signals[PARENT_UNSET], 0, parent);

    gst_object_unref (object);
  } else {
    GST_OBJECT_UNLOCK (object);
  }
}
예제 #11
0
/**
 * gst_object_sink:
 * @object: a #GstObject to sink
 *
 * If @object was floating, the #GST_OBJECT_FLOATING flag is removed
 * and @object is unreffed. When @object was not floating,
 * this function does nothing.
 *
 * Any newly created object has a refcount of 1 and is floating.
 * This function should be used when creating a new object to
 * symbolically 'take ownership' of @object. This done by first doing a
 * gst_object_ref() to keep a reference to @object and then gst_object_sink()
 * to remove and unref any floating references to @object.
 * Use gst_object_set_parent() to have this done for you.
 *
 * MT safe. This function grabs and releases @object lock.
 */
void
gst_object_sink (gpointer object)
{
  g_return_if_fail (GST_IS_OBJECT (object));

  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "sink");

  GST_OBJECT_LOCK (object);
  if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
    GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "clear floating flag");
    GST_OBJECT_FLAG_UNSET (object, GST_OBJECT_FLOATING);
    GST_OBJECT_UNLOCK (object);
    gst_object_unref (object);
  } else {
    GST_OBJECT_UNLOCK (object);
  }
}
예제 #12
0
static GstFlowReturn
gst_mpeg2dec_crop_buffer (GstMpeg2dec * dec, GstVideoCodecFrame * in_frame,
    GstVideoFrame * input_vframe)
{
  GstVideoCodecState *state;
  GstVideoInfo *info;
  GstVideoInfo *dinfo;
  GstVideoFrame output_frame;
  GstFlowReturn ret;
  GstBuffer *buffer = NULL;

  state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec));
  info = &state->info;
  dinfo = &dec->decoded_info;

  GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
      "Copying input buffer %ux%u (%" G_GSIZE_FORMAT ") to output buffer "
      "%ux%u (%" G_GSIZE_FORMAT ")", dinfo->width, dinfo->height,
      dinfo->size, info->width, info->height, info->size);

  ret = gst_buffer_pool_acquire_buffer (dec->downstream_pool, &buffer, NULL);
  if (ret != GST_FLOW_OK)
    goto beach;

  if (!gst_video_frame_map (&output_frame, info, buffer, GST_MAP_WRITE))
    goto map_fail;

  if (in_frame->output_buffer)
    gst_buffer_unref (in_frame->output_buffer);
  in_frame->output_buffer = buffer;

  if (!gst_video_frame_copy (&output_frame, input_vframe))
    goto copy_failed;

  gst_video_frame_unmap (&output_frame);

  GST_BUFFER_FLAGS (in_frame->output_buffer) =
      GST_BUFFER_FLAGS (input_vframe->buffer);

beach:
  gst_video_codec_state_unref (state);

  return ret;

map_fail:
  {
    GST_ERROR_OBJECT (dec, "Failed to map output frame");
    gst_video_codec_state_unref (state);
    return GST_FLOW_ERROR;
  }

copy_failed:
  {
    GST_ERROR_OBJECT (dec, "Failed to copy output frame");
    gst_video_codec_state_unref (state);
    return GST_FLOW_ERROR;
  }
}
예제 #13
0
static GstFlowReturn
gst_dshowvideodec_chain (GstPad * pad, GstBuffer * buffer)
{
  GstDshowVideoDec *vdec = (GstDshowVideoDec *) gst_pad_get_parent (pad);
  bool discont = FALSE;
  GstClockTime stop;

  if (!vdec->setup) {
    /* we are not setup */
    GST_WARNING_OBJECT (vdec, "Decoder not set up, failing");
    vdec->last_ret = GST_FLOW_FLUSHING;
    goto beach;
  }

  if (GST_FLOW_IS_FATAL (vdec->last_ret)) {
    GST_DEBUG_OBJECT (vdec, "last decoding iteration generated a fatal error "
        "%s", gst_flow_get_name (vdec->last_ret));
    goto beach;
  }

  /* check if duration is valid and use duration only when it's valid
     /* because dshow is not decoding frames having stop smaller than start */
  if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
    stop = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
  } else {
    stop = GST_BUFFER_TIMESTAMP (buffer);
  }

  GST_CAT_LOG_OBJECT (dshowvideodec_debug, vdec,
      "chain (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT,
      GST_BUFFER_SIZE (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
      GST_TIME_ARGS (stop));

  /* if the incoming buffer has discont flag set => flush decoder data */
  if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
    GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec,
        "this buffer has a DISCONT flag (%" GST_TIME_FORMAT "), flushing",
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
    gst_dshowvideodec_flush (vdec);
    discont = TRUE;
  }

  /* push the buffer to the directshow decoder */
  vdec->fakesrc->GetOutputPin()->PushBuffer(
      GST_BUFFER_DATA (buffer), GST_BUFFER_TIMESTAMP (buffer), stop,
      GST_BUFFER_SIZE (buffer), discont);

beach:
  gst_buffer_unref (buffer);
  gst_object_unref (vdec);

  return vdec->last_ret;
}
예제 #14
0
static GstFlowReturn
gst_v4l2_buffer_pool_copy_buffer (GstV4l2BufferPool * pool, GstBuffer * dest,
    GstBuffer * src)
{
  const GstVideoFormatInfo *finfo = pool->caps_info.finfo;

  GST_LOG_OBJECT (pool, "copying buffer");

  if (finfo && (finfo->format != GST_VIDEO_FORMAT_UNKNOWN &&
          finfo->format != GST_VIDEO_FORMAT_ENCODED)) {
    GstVideoFrame src_frame, dest_frame;

    GST_DEBUG_OBJECT (pool, "copy video frame");

    /* we have raw video, use videoframe copy to get strides right */
    if (!gst_video_frame_map (&src_frame, &pool->caps_info, src, GST_MAP_READ))
      goto invalid_buffer;

    if (!gst_video_frame_map (&dest_frame, &pool->caps_info, dest,
            GST_MAP_WRITE)) {
      gst_video_frame_unmap (&src_frame);
      goto invalid_buffer;
    }

    gst_video_frame_copy (&dest_frame, &src_frame);

    gst_video_frame_unmap (&src_frame);
    gst_video_frame_unmap (&dest_frame);
  } else {
    GstMapInfo map;

    GST_DEBUG_OBJECT (pool, "copy raw bytes");

    if (!gst_buffer_map (src, &map, GST_MAP_READ))
      goto invalid_buffer;

    gst_buffer_fill (dest, 0, map.data, gst_buffer_get_size (src));

    gst_buffer_unmap (src, &map);
    gst_buffer_resize (dest, 0, gst_buffer_get_size (src));
  }

  GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, pool, "slow copy into buffer %p",
      dest);

  return GST_FLOW_OK;

invalid_buffer:
  {
    GST_ERROR_OBJECT (pool, "could not map buffer");
    return GST_FLOW_ERROR;
  }
}
예제 #15
0
/**
 * gst_object_unref:
 * @object: a #GstObject to unreference
 *
 * Decrements the reference count on @object.  If reference count hits
 * zero, destroy @object. This function does not take the lock
 * on @object as it relies on atomic refcounting.
 *
 * The unref method should never be called with the LOCK held since
 * this might deadlock the dispose function.
 */
void
gst_object_unref (gpointer object)
{
  g_return_if_fail (object != NULL);
  g_return_if_fail (((GObject *) object)->ref_count > 0);

#ifdef DEBUG_REFCOUNT
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "%p unref %d->%d",
      object,
      ((GObject *) object)->ref_count, ((GObject *) object)->ref_count - 1);
#endif
  g_object_unref (object);
}
예제 #16
0
/**
 * gst_object_ref:
 * @object: a #GstObject to reference
 *
 * Increments the reference count on @object. This function
 * does not take the lock on @object because it relies on
 * atomic refcounting.
 *
 * This object returns the input parameter to ease writing
 * constructs like :
 *  result = gst_object_ref (object->parent);
 *
 * Returns: A pointer to @object
 */
gpointer
gst_object_ref (gpointer object)
{
  g_return_val_if_fail (object != NULL, NULL);

#ifdef DEBUG_REFCOUNT
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "%p ref %d->%d",
      object,
      ((GObject *) object)->ref_count, ((GObject *) object)->ref_count + 1);
#endif
  g_object_ref (object);

  return object;
}
예제 #17
0
static void
gst_object_init (GstObject * object)
{
  object->lock = g_mutex_new ();
  object->parent = NULL;
  object->name = NULL;
  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "%p new", object);

#ifndef GST_DISABLE_TRACE
  gst_alloc_trace_new (_gst_object_trace, object);
#endif

  object->flags = 0;
  GST_OBJECT_FLAG_SET (object, GST_OBJECT_FLOATING);
}
예제 #18
0
static OMX_ERRORTYPE
FillBufferDone (OMX_HANDLETYPE omx_handle,
                OMX_PTR app_data,
                OMX_BUFFERHEADERTYPE *omx_buffer)
{
    GOmxCore *core;
    GOmxPort *port;

    core = (GOmxCore *) app_data;
    port = get_port (core, omx_buffer->nOutputPortIndex);

    GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer=%p", omx_buffer);
    got_buffer (core, port, omx_buffer);

    return OMX_ErrorNone;
}
예제 #19
0
/* finalize is called when the object has to free its resources */
static void
gst_object_finalize (GObject * object)
{
  GstObject *gstobject = GST_OBJECT (object);

  GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "finalize");

  g_signal_handlers_destroy (object);

  g_free (gstobject->name);
  g_mutex_free (gstobject->lock);

#ifndef GST_DISABLE_TRACE
  gst_alloc_trace_free (_gst_object_trace, object);
#endif

  parent_class->finalize (object);
}
예제 #20
0
/* Changing a GObject property of a GstObject will result in "deep-notify"
 * signals being emitted by the object itself, as well as in each parent
 * object. This is so that an application can connect a listener to the
 * top-level bin to catch property-change notifications for all contained
 * elements.
 *
 * MT safe.
 */
static void
gst_object_dispatch_properties_changed (GObject * object,
    guint n_pspecs, GParamSpec ** pspecs)
{
  GstObject *gst_object, *parent, *old_parent;
  guint i;
#ifndef GST_DISABLE_GST_DEBUG
  gchar *name = NULL;
  const gchar *debug_name;
#endif

  /* do the standard dispatching */
  ((GObjectClass *)
      gst_object_parent_class)->dispatch_properties_changed (object, n_pspecs,
      pspecs);

  gst_object = GST_OBJECT_CAST (object);
#ifndef GST_DISABLE_GST_DEBUG
  if (G_UNLIKELY (_gst_debug_min >= GST_LEVEL_LOG)) {
    name = gst_object_get_name (gst_object);
    debug_name = GST_STR_NULL (name);
  } else
    debug_name = "";
#endif

  /* now let the parent dispatch those, too */
  parent = gst_object_get_parent (gst_object);
  while (parent) {
    for (i = 0; i < n_pspecs; i++) {
      GST_CAT_LOG_OBJECT (GST_CAT_PROPERTIES, parent,
          "deep notification from %s (%s)", debug_name, pspecs[i]->name);

      g_signal_emit (parent, gst_object_signals[DEEP_NOTIFY],
          g_quark_from_string (pspecs[i]->name), gst_object, pspecs[i]);
    }

    old_parent = parent;
    parent = gst_object_get_parent (old_parent);
    gst_object_unref (old_parent);
  }
#ifndef GST_DISABLE_GST_DEBUG
  g_free (name);
#endif
}
예제 #21
0
EXPORT_C
#endif

gboolean
gst_object_set_parent (GstObject * object, GstObject * parent)
{
  g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
  g_return_val_if_fail (GST_IS_OBJECT (parent), FALSE);
  g_return_val_if_fail (object != parent, FALSE);

  GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object,
      "set parent (ref and sink)");

  GST_OBJECT_LOCK (object);
  if (G_UNLIKELY (object->parent != NULL))
    goto had_parent;

  /* sink object, we don't call our own function because we don't
   * need to release/acquire the lock needlessly or touch the refcount
   * in the floating case. */
  object->parent = parent;
  if (G_LIKELY (GST_OBJECT_IS_FLOATING (object))) {
    GST_CAT_LOG_OBJECT (GST_CAT_REFCOUNTING, object, "unsetting floating flag");
    GST_OBJECT_FLAG_UNSET (object, GST_OBJECT_FLOATING);
    GST_OBJECT_UNLOCK (object);
  } else {
    GST_OBJECT_UNLOCK (object);
    gst_object_ref (object);
  }

  g_signal_emit (object, gst_object_signals[PARENT_SET], 0, parent);

  return TRUE;

  /* ERROR handling */
had_parent:
  {
    GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object,
        "set parent failed, object already had a parent");
    GST_OBJECT_UNLOCK (object);
    return FALSE;
  }
}
예제 #22
0
/* internal function, nbytes should be flushed after calling this function */
static guint8 *
gst_adapter_take_internal (GstAdapter * adapter, gsize nbytes)
{
  guint8 *data;
  gsize toreuse, tocopy;

  /* see how much data we can reuse from the assembled memory and how much
   * we need to copy */
  toreuse = MIN (nbytes, adapter->assembled_len);
  tocopy = nbytes - toreuse;

  /* find memory to return */
  if (adapter->assembled_size >= nbytes && toreuse > 0) {
    /* we reuse already allocated memory but only when we're going to reuse
     * something from it because else we are worse than the malloc and copy
     * case below */
    GST_LOG_OBJECT (adapter, "reusing %" G_GSIZE_FORMAT " bytes of assembled"
        " data", toreuse);
    /* we have enough free space in the assembled array */
    data = adapter->assembled_data;
    /* flush after this function should set the assembled_size to 0 */
    adapter->assembled_data = g_malloc (adapter->assembled_size);
  } else {
    GST_LOG_OBJECT (adapter, "allocating %" G_GSIZE_FORMAT " bytes", nbytes);
    /* not enough bytes in the assembled array, just allocate new space */
    data = g_malloc (nbytes);
    /* reuse what we can from the already assembled data */
    if (toreuse) {
      GST_LOG_OBJECT (adapter, "reusing %" G_GSIZE_FORMAT " bytes", toreuse);
      GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, adapter,
          "memcpy %" G_GSIZE_FORMAT " bytes", toreuse);
      memcpy (data, adapter->assembled_data, toreuse);
    }
  }
  if (tocopy) {
    /* copy the remaining data */
    copy_into_unchecked (adapter, toreuse + data, toreuse + adapter->skip,
        tocopy);
  }
  return data;
}
예제 #23
0
static GstFlowReturn
gst_ts_shifter_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
{
  GstTSShifter *ts = GST_TS_SHIFTER (parent);
  GstFlowReturn res;
  GstMapInfo map;

  GST_CAT_LOG_OBJECT (ts_flow, ts,
      "received buffer %p of size %d, time %" GST_TIME_FORMAT ", duration %"
      GST_TIME_FORMAT, buffer, gst_buffer_get_size (buffer),
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));

  gst_buffer_map (buffer, &map, GST_MAP_READ);
  res = gst_ts_shifter_push (ts, map.data, map.size);
  gst_buffer_unmap (buffer, &map);

  gst_buffer_unref (buffer);

  return res;
}
예제 #24
0
/******************************************************
 * gst_v4l2src_grab_frame ():
 *   grab a frame for capturing
 * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR
 ******************************************************/
GstFlowReturn
gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
{
#define NUM_TRIALS 50
  GstV4l2Object *v4l2object;
  GstV4l2BufferPool *pool;
  gint32 trials = NUM_TRIALS;
  GstBuffer *pool_buffer;
  gboolean need_copy;
  gint ret;

  v4l2object = v4l2src->v4l2object;
  pool = v4l2src->pool;
  if (!pool)
    goto no_buffer_pool;

  GST_DEBUG_OBJECT (v4l2src, "grab frame");

  for (;;) {
    if (v4l2object->can_poll_device) {
      ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
      if (G_UNLIKELY (ret < 0)) {
        if (errno == EBUSY)
          goto stopped;
        if (errno == ENXIO) {
          GST_DEBUG_OBJECT (v4l2src,
              "v4l2 device doesn't support polling. Disabling");
          v4l2object->can_poll_device = FALSE;
        } else {
          if (errno != EAGAIN && errno != EINTR)
            goto select_error;
        }
      }
    }

    pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool));
    if (pool_buffer)
      break;

    GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials);

    /* if the sync() got interrupted, we can retry */
    switch (errno) {
      case EINVAL:
      case ENOMEM:
        /* fatal */
        return GST_FLOW_ERROR;

      case EAGAIN:
      case EIO:
      case EINTR:
      default:
        /* try again, until too many trials */
        break;
    }

    /* check nr. of attempts to capture */
    if (--trials == -1) {
      goto too_many_trials;
    }
  }

  /* if we are handing out the last buffer in the pool, we need to make a
   * copy and bring the buffer back in the pool. */
  need_copy = v4l2src->always_copy
      || !gst_v4l2_buffer_pool_available_buffers (pool);

  if (G_UNLIKELY (need_copy)) {
    if (!v4l2src->always_copy) {
      GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2src,
          "running out of buffers, making a copy to reuse current one");
    }
    *buf = gst_buffer_copy (pool_buffer);
    GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
    /* this will requeue */
    gst_buffer_unref (pool_buffer);
  } else {
    *buf = pool_buffer;
  }
  /* we set the buffer metadata in gst_v4l2src_create() */

  return GST_FLOW_OK;

  /* ERRORS */
no_buffer_pool:
  {
    GST_DEBUG ("no buffer pool");
    return GST_FLOW_WRONG_STATE;
  }
select_error:
  {
    GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL),
        ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
    return GST_FLOW_ERROR;
  }
stopped:
  {
    GST_DEBUG ("stop called");
    return GST_FLOW_WRONG_STATE;
  }
too_many_trials:
  {
    GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
        (_("Failed trying to get video frames from device '%s'."),
            v4l2object->videodev),
        (_("Failed after %d tries. device %s. system error: %s"),
            NUM_TRIALS, v4l2object->videodev, g_strerror (errno)));
    return GST_FLOW_ERROR;
  }
}
예제 #25
0
static GstFlowReturn
gst_mpeg2dec_crop_buffer (GstMpeg2dec * dec, GstVideoCodecFrame * in_frame,
    GstVideoFrame * input_vframe)
{
  GstVideoCodecState *state;
  GstVideoInfo *info;
  GstVideoInfo *dinfo;
  guint c, n_planes;
  GstVideoFrame output_frame;
  GstFlowReturn ret;

  state = gst_video_decoder_get_output_state (GST_VIDEO_DECODER (dec));
  info = &state->info;
  dinfo = &dec->decoded_info;

  GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, dec,
      "Copying input buffer %ux%u (%" G_GSIZE_FORMAT ") to output buffer "
      "%ux%u (%" G_GSIZE_FORMAT ")", dinfo->width, dinfo->height,
      dinfo->size, info->width, info->height, info->size);

  ret =
      gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (dec),
      in_frame);
  if (ret != GST_FLOW_OK)
    goto beach;

  if (!gst_video_frame_map (&output_frame, info, in_frame->output_buffer,
          GST_MAP_WRITE))
    goto map_fail;

  n_planes = GST_VIDEO_FRAME_N_PLANES (&output_frame);
  for (c = 0; c < n_planes; c++) {
    guint w, h, j;
    guint8 *sp, *dp;
    gint ss, ds;

    sp = GST_VIDEO_FRAME_PLANE_DATA (input_vframe, c);
    dp = GST_VIDEO_FRAME_PLANE_DATA (&output_frame, c);

    ss = GST_VIDEO_FRAME_PLANE_STRIDE (input_vframe, c);
    ds = GST_VIDEO_FRAME_PLANE_STRIDE (&output_frame, c);

    w = MIN (ABS (ss), ABS (ds));
    h = GST_VIDEO_FRAME_COMP_HEIGHT (&output_frame, c);

    GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy plane %u, w:%u h:%u ", c, w, h);

    for (j = 0; j < h; j++) {
      memcpy (dp, sp, w);
      dp += ds;
      sp += ss;
    }
  }

  gst_video_frame_unmap (&output_frame);

  GST_BUFFER_FLAGS (in_frame->output_buffer) =
      GST_BUFFER_FLAGS (input_vframe->buffer);

beach:
  gst_video_codec_state_unref (state);

  return ret;

map_fail:
  {
    GST_ERROR_OBJECT (dec, "Failed to map output frame");
    gst_video_codec_state_unref (state);
    return GST_FLOW_ERROR;
  }
}
예제 #26
0
gint
main (gint argc, gchar * argv[])
{

  gst_init (&argc, &argv);

  GST_DEBUG_CATEGORY_INIT (cat_default, "GST_Check_default", 0,
      "default category for this test");
  GST_DEBUG_CATEGORY_INIT (cat2, "GST_Check_2", 0,
      "second category for this test");
#ifndef GST_DISABLE_GST_DEBUG
  g_assert (gst_debug_remove_log_function (gst_debug_log_default) == 1);
#endif
  gst_debug_add_log_function (check_message, NULL);

  count = 0;
  GST_ERROR ("This is an error.");
  ++count;
  GST_WARNING ("This is a warning.");
  ++count;
  GST_INFO ("This is an info message.");
  ++count;
  GST_DEBUG ("This is a debug message.");
  ++count;
  GST_LOG ("This is a log message.");
  ++count;
  GST_CAT_ERROR (cat2, "This is an error with category.");
  ++count;
  GST_CAT_WARNING (cat2, "This is a warning with category.");
  ++count;
  GST_CAT_INFO (cat2, "This is an info message with category.");
  ++count;
  GST_CAT_DEBUG (cat2, "This is a debug message with category.");
  ++count;
  GST_CAT_LOG (cat2, "This is a log message with category.");
  count = -1;
  pipeline = gst_element_factory_make ("pipeline", "testelement");
  count = 10;
  GST_ERROR_OBJECT (pipeline, "This is an error with object.");
  ++count;
  GST_WARNING_OBJECT (pipeline, "This is a warning with object.");
  ++count;
  GST_INFO_OBJECT (pipeline, "This is an info message with object.");
  ++count;
  GST_DEBUG_OBJECT (pipeline, "This is a debug message with object.");
  ++count;
  GST_LOG_OBJECT (pipeline, "This is a log message with object.");
  ++count;
  GST_CAT_ERROR_OBJECT (cat2, pipeline,
      "This is an error with category and object.");
  ++count;
  GST_CAT_WARNING_OBJECT (cat2, pipeline,
      "This is a warning with category and object.");
  ++count;
  GST_CAT_INFO_OBJECT (cat2, pipeline,
      "This is an info message with category and object.");
  ++count;
  GST_CAT_DEBUG_OBJECT (cat2, pipeline,
      "This is a debug message with category and object.");
  ++count;
  GST_CAT_LOG_OBJECT (cat2, pipeline,
      "This is a log message with category and object.");
  count = -1;

#ifndef GST_DISABLE_GST_DEBUG
  g_assert (gst_debug_remove_log_function (check_message) == 1);
#endif

  return 0;
}
예제 #27
0
/**
 * gst_clock_add_observation_unapplied:
 * @clock: a #GstClock
 * @slave: a time on the slave
 * @master: a time on the master
 * @r_squared: (out): a pointer to hold the result
 * @internal: (out) (allow-none): a location to store the internal time
 * @external: (out) (allow-none): a location to store the external time
 * @rate_num: (out) (allow-none): a location to store the rate numerator
 * @rate_denom: (out) (allow-none): a location to store the rate denominator
 *
 * Add a clock observation to the internal slaving algorithm the same as
 * gst_clock_add_observation(), and return the result of the master clock
 * estimation, without updating the internal calibration.
 *
 * The caller can then take the results and call gst_clock_set_calibration()
 * with the values, or some modified version of them.
 *
 * Since: 1.6
 */
gboolean
gst_clock_add_observation_unapplied (GstClock * clock, GstClockTime slave,
    GstClockTime master, gdouble * r_squared,
    GstClockTime * internal, GstClockTime * external,
    GstClockTime * rate_num, GstClockTime * rate_denom)
{
  GstClockTime m_num, m_denom, b, xbase;
  GstClockPrivate *priv;
  guint n;

  g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
  g_return_val_if_fail (r_squared != NULL, FALSE);

  priv = clock->priv;

  GST_CLOCK_SLAVE_LOCK (clock);

  GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
      "adding observation slave %" GST_TIME_FORMAT ", master %" GST_TIME_FORMAT,
      GST_TIME_ARGS (slave), GST_TIME_ARGS (master));

  priv->times[(4 * priv->time_index)] = slave;
  priv->times[(4 * priv->time_index) + 2] = master;

  priv->time_index++;
  if (G_UNLIKELY (priv->time_index == priv->window_size)) {
    priv->filling = FALSE;
    priv->time_index = 0;
  }

  if (G_UNLIKELY (priv->filling && priv->time_index < priv->window_threshold))
    goto filling;

  n = priv->filling ? priv->time_index : priv->window_size;
  if (!_priv_gst_do_linear_regression (priv->times, n, &m_num, &m_denom, &b,
          &xbase, r_squared))
    goto invalid;

  GST_CLOCK_SLAVE_UNLOCK (clock);

  GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, clock,
      "adjusting clock to m=%" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT ", b=%"
      G_GUINT64_FORMAT " (rsquared=%g)", m_num, m_denom, b, *r_squared);

  if (internal)
    *internal = xbase;
  if (external)
    *external = b;
  if (rate_num)
    *rate_num = m_num;
  if (rate_denom)
    *rate_denom = m_denom;

  return TRUE;

filling:
  {
    GST_CLOCK_SLAVE_UNLOCK (clock);
    return FALSE;
  }
invalid:
  {
    /* no valid regression has been done, ignore the result then */
    GST_CLOCK_SLAVE_UNLOCK (clock);
    return TRUE;
  }
}
예제 #28
0
static GstCaps *
gst_waveform_sink_getcaps (GstBaseSink * bsink)
{
  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink);
  MMRESULT mmresult;
  WAVEOUTCAPS wocaps;
  GstCaps *caps, *caps_temp;

  /* return the cached caps if already defined */
  if (wfsink->cached_caps) {
    return gst_caps_ref (wfsink->cached_caps);
  }

  /* get the default device caps */
  mmresult = waveOutGetDevCaps (WAVE_MAPPER, &wocaps, sizeof (wocaps));
  if (mmresult != MMSYSERR_NOERROR) {
    waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
    GST_ELEMENT_ERROR (wfsink, RESOURCE, SETTINGS,
        ("gst_waveform_sink_getcaps: waveOutGetDevCaps failed error=>%s",
            wfsink->error_string), (NULL));
    return NULL;
  }

  caps = gst_caps_new_empty ();

  /* create a caps for all wave formats supported by the device 
     starting by the best quality format */
  if (wocaps.dwFormats & WAVE_FORMAT_96S16) {
    caps_temp = gst_waveform_sink_create_caps (96000, 2, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_96S08) {
    caps_temp = gst_waveform_sink_create_caps (96000, 2, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_96M16) {
    caps_temp = gst_waveform_sink_create_caps (96000, 1, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_96M08) {
    caps_temp = gst_waveform_sink_create_caps (96000, 1, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_4S16) {
    caps_temp = gst_waveform_sink_create_caps (44100, 2, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_4S08) {
    caps_temp = gst_waveform_sink_create_caps (44100, 2, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_4M16) {
    caps_temp = gst_waveform_sink_create_caps (44100, 1, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_4M08) {
    caps_temp = gst_waveform_sink_create_caps (44100, 1, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_2S16) {
    caps_temp = gst_waveform_sink_create_caps (22050, 2, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_2S08) {
    caps_temp = gst_waveform_sink_create_caps (22050, 2, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_2M16) {
    caps_temp = gst_waveform_sink_create_caps (22050, 1, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_2M08) {
    caps_temp = gst_waveform_sink_create_caps (22050, 1, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_1S16) {
    caps_temp = gst_waveform_sink_create_caps (11025, 2, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_1S08) {
    caps_temp = gst_waveform_sink_create_caps (11025, 2, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_1M16) {
    caps_temp = gst_waveform_sink_create_caps (11025, 1, 16);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }
  if (wocaps.dwFormats & WAVE_FORMAT_1M08) {
    caps_temp = gst_waveform_sink_create_caps (11025, 1, 8);
    if (caps_temp) {
      gst_caps_append (caps, caps_temp);
    }
  }

  if (gst_caps_is_empty (caps)) {
    gst_caps_unref (caps);
    caps = NULL;
  } else {
    wfsink->cached_caps = gst_caps_ref (caps);
  }

  GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink, "Returning caps %s",
      gst_caps_to_string (caps));

  return caps;
}
예제 #29
0
static gboolean
gst_dshowvideodec_push_buffer (byte * buffer, long size, byte * src_object,
    UINT64 start, UINT64 stop)
{
  GstDshowVideoDec *vdec = (GstDshowVideoDec *) src_object;
  GstDshowVideoDecClass *klass =
      (GstDshowVideoDecClass *) G_OBJECT_GET_CLASS (vdec);
  GstBuffer *buf = NULL;
  gboolean in_seg = FALSE;
  gint64 clip_start = 0, clip_stop = 0;

  /* check if this buffer is in our current segment */
  in_seg = gst_segment_clip (vdec->segment, GST_FORMAT_TIME,
      start, stop, &clip_start, &clip_stop);

  /* if the buffer is out of segment do not push it downstream */
  if (!in_seg) {
    GST_CAT_DEBUG_OBJECT (dshowvideodec_debug, vdec,
        "buffer is out of segment, start %" GST_TIME_FORMAT " stop %"
        GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
    return FALSE;
  }

  /* buffer is in our segment allocate a new out buffer and clip its
   * timestamps */
  vdec->last_ret = gst_pad_alloc_buffer (vdec->srcpad, GST_BUFFER_OFFSET_NONE,
      size, GST_PAD_CAPS (vdec->srcpad), &buf);
  if (!buf) {
    GST_CAT_WARNING_OBJECT (dshowvideodec_debug, vdec,
        "can't not allocate a new GstBuffer");
    return FALSE;
  }

  /* set buffer properties */
  GST_BUFFER_TIMESTAMP (buf) = clip_start;
  GST_BUFFER_DURATION (buf) = clip_stop - clip_start;

  if (strstr (klass->entry->srccaps, "rgb")) {
    /* FOR RGB directshow decoder will return bottom-up BITMAP 
     * There is probably a way to get top-bottom video frames from
     * the decoder...
     */
    gint line = 0;
    guint stride = vdec->width * 4;

    for (; line < vdec->height; line++) {
      memcpy (GST_BUFFER_DATA (buf) + (line * stride),
          buffer + (size - ((line + 1) * (stride))), stride);
    }
  } else {
    memcpy (GST_BUFFER_DATA (buf), buffer, MIN (size, GST_BUFFER_SIZE (buf)));
  }

  GST_CAT_LOG_OBJECT (dshowvideodec_debug, vdec,
      "push_buffer (size %d)=> pts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
      " duration %" GST_TIME_FORMAT, size,
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));

  /* push the buffer downstream */
  vdec->last_ret = gst_pad_push (vdec->srcpad, buf);

  return TRUE;
}
예제 #30
0
static guint
gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length)
{
  GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
  WAVEHDR *waveheader;
  MMRESULT mmresult;
  guint bytes_to_write = length;
  guint remaining_length = length;

  wfsink->bytes_in_queue += length;

  while (remaining_length > 0) {
    if (wfsink->free_buffers_count == 0) {
      /* no free buffer available, wait for one */
      Sleep (10);
      continue;
    }

    /* get the current write buffer header */
    waveheader = &wfsink->wave_buffers[wfsink->write_buffer];

    /* unprepare the header if needed */
    if (waveheader->dwFlags & WHDR_PREPARED) {
      mmresult =
          waveOutUnprepareHeader (wfsink->hwaveout, waveheader,
          sizeof (WAVEHDR));
      if (mmresult != MMSYSERR_NOERROR) {
        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
            "Error unpreparing buffer => %s", wfsink->error_string);
      }
    }

    if (wfsink->buffer_size - waveheader->dwUser >= remaining_length)
      bytes_to_write = remaining_length;
    else
      bytes_to_write = wfsink->buffer_size - waveheader->dwUser;

    memcpy (waveheader->lpData + waveheader->dwUser, data, bytes_to_write);
    waveheader->dwUser += bytes_to_write;
    remaining_length -= bytes_to_write;
    data = (byte *) data + bytes_to_write;

    if (waveheader->dwUser == wfsink->buffer_size) {
      /* we have filled a buffer, let's prepare it and next write it to the device */
      mmresult =
          waveOutPrepareHeader (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
      if (mmresult != MMSYSERR_NOERROR) {
        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
            "gst_waveform_sink_write: Error preparing header => %s",
            wfsink->error_string);
      }
      mmresult = waveOutWrite (wfsink->hwaveout, waveheader, sizeof (WAVEHDR));
      if (mmresult != MMSYSERR_NOERROR) {
        waveOutGetErrorText (mmresult, wfsink->error_string, ERROR_LENGTH - 1);
        GST_CAT_WARNING_OBJECT (waveformsink_debug, wfsink,
            "gst_waveform_sink_write: Error writting buffer to the device => %s",
            wfsink->error_string);
      }

      EnterCriticalSection (&wfsink->critic_wave);
      wfsink->free_buffers_count--;
      LeaveCriticalSection (&wfsink->critic_wave);

      wfsink->write_buffer++;
      wfsink->write_buffer %= wfsink->buffer_count;
      waveheader->dwUser = 0;
      wfsink->bytes_in_queue = 0;
      GST_CAT_LOG_OBJECT (waveformsink_debug, wfsink,
          "gst_waveform_sink_write: Writting a buffer to the device (free buffers remaining=%d, write buffer=%d)",
          wfsink->free_buffers_count, wfsink->write_buffer);
    }
  }

  return length;
}