/**
 * gst_buffer_pool_acquire_buffer:
 * @pool: a #GstBufferPool
 * @buffer: (out): a location for a #GstBuffer
 * @params: (transfer none) (allow-none) parameters.
 *
 * Acquire a buffer from @pool. @buffer should point to a memory location that
 * can hold a pointer to the new buffer.
 *
 * @params can be NULL or contain optional parameters to influence the allocation.
 *
 * Returns: a #GstFlowReturn such as GST_FLOW_FLUSHING when the pool is
 * inactive.
 */
GstFlowReturn
gst_buffer_pool_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer,
    GstBufferPoolAcquireParams * params)
{
  GstBufferPoolClass *pclass;
  GstFlowReturn result;

  g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), GST_FLOW_ERROR);
  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* assume we'll have one more outstanding buffer we need to do that so
   * that concurrent set_active doesn't clear the buffers */
  g_atomic_int_inc (&pool->priv->outstanding);

  if (G_LIKELY (pclass->acquire_buffer))
    result = pclass->acquire_buffer (pool, buffer, params);
  else
    result = GST_FLOW_NOT_SUPPORTED;

  if (G_LIKELY (result == GST_FLOW_OK)) {
    /* all buffers from the pool point to the pool and have the refcount of the
     * pool incremented */
    (*buffer)->pool = gst_object_ref (pool);
  } else {
    dec_outstanding (pool);
  }

  return result;
}
/* the default implementation for preallocating the buffers
 * in the pool */
static gboolean
default_start (GstBufferPool * pool)
{
  guint i;
  GstBufferPoolPrivate *priv = pool->priv;
  GstBufferPoolClass *pclass;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* we need to prealloc buffers */
  for (i = 0; i < priv->min_buffers; i++) {
    GstBuffer *buffer;

    if (do_alloc_buffer (pool, &buffer, NULL) != GST_FLOW_OK)
      goto alloc_failed;

    /* release to the queue, we call the vmethod directly, we don't need to do
     * the other refcount handling right now. */
    if (G_LIKELY (pclass->release_buffer))
      pclass->release_buffer (pool, buffer);
  }
  return TRUE;

  /* ERRORS */
alloc_failed:
  {
    GST_WARNING_OBJECT (pool, "failed to allocate buffer");
    return FALSE;
  }
}
/**
 * gst_buffer_pool_release_buffer:
 * @pool: a #GstBufferPool
 * @buffer: (transfer full): a #GstBuffer
 *
 * Release @buffer to @pool. @buffer should have previously been allocated from
 * @pool with gst_buffer_pool_acquire_buffer().
 *
 * This function is usually called automatically when the last ref on @buffer
 * disappears.
 */
void
gst_buffer_pool_release_buffer (GstBufferPool * pool, GstBuffer * buffer)
{
  GstBufferPoolClass *pclass;

  g_return_if_fail (GST_IS_BUFFER_POOL (pool));
  g_return_if_fail (buffer != NULL);

  /* check that the buffer is ours, all buffers returned to the pool have the
   * pool member set to NULL and the pool refcount decreased */
  if (!g_atomic_pointer_compare_and_exchange (&buffer->pool, pool, NULL))
    return;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* reset the buffer when needed */
  if (G_LIKELY (pclass->reset_buffer))
    pclass->reset_buffer (pool, buffer);

  if (G_LIKELY (pclass->release_buffer))
    pclass->release_buffer (pool, buffer);

  dec_outstanding (pool);

  /* decrease the refcount that the buffer had to us */
  gst_object_unref (pool);
}
Exemple #4
0
/* must be called with the lock */
static void
do_set_flushing (GstBufferPool * pool, gboolean flushing)
{
  GstBufferPoolPrivate *priv = pool->priv;
  GstBufferPoolClass *pclass;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  if (GST_BUFFER_POOL_IS_FLUSHING (pool) == flushing)
    return;

  if (flushing) {
    g_atomic_int_set (&pool->flushing, 1);
    gst_poll_write_control (priv->poll);

    if (pclass->flush_start)
      pclass->flush_start (pool);
  } else {
    if (pclass->flush_stop)
      pclass->flush_stop (pool);

    gst_poll_read_control (priv->poll);
    g_atomic_int_set (&pool->flushing, 0);
  }
}
/**
 * gst_buffer_pool_set_config:
 * @pool: a #GstBufferPool
 * @config: (transfer full): a #GstStructure
 *
 * Set the configuration of the pool. The pool must be inactive and all buffers
 * allocated form this pool must be returned or else this function will do
 * nothing and return FALSE.
 *
 * @config is a #GstStructure that contains the configuration parameters for
 * the pool. A default and mandatory set of parameters can be configured with
 * gst_buffer_pool_config_set_params(), gst_buffer_pool_config_set_allocator()
 * and gst_buffer_pool_config_add_option().
 *
 * If the parameters in @config can not be set exactly, this function returns
 * FALSE and will try to update as much state as possible. The new state can
 * then be retrieved and refined with gst_buffer_pool_get_config().
 *
 * This function takes ownership of @config.
 *
 * Returns: TRUE when the configuration could be set.
 */
gboolean
gst_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
{
  gboolean result;
  GstBufferPoolClass *pclass;
  GstBufferPoolPrivate *priv;

  g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE);
  g_return_val_if_fail (config != NULL, FALSE);

  priv = pool->priv;

  GST_BUFFER_POOL_LOCK (pool);
  /* can't change the settings when active */
  if (priv->active)
    goto was_active;

  /* we can't change when outstanding buffers */
  if (g_atomic_int_get (&priv->outstanding) != 0)
    goto have_outstanding;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* set the new config */
  if (G_LIKELY (pclass->set_config))
    result = pclass->set_config (pool, config);
  else
    result = FALSE;

  if (result) {
    if (priv->config)
      gst_structure_free (priv->config);
    priv->config = config;

    /* now we are configured */
    priv->configured = TRUE;
  } else {
    gst_structure_free (config);
  }
  GST_BUFFER_POOL_UNLOCK (pool);

  return result;

  /* ERRORS */
was_active:
  {
    gst_structure_free (config);
    GST_WARNING_OBJECT (pool, "can't change config, we are active");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
have_outstanding:
  {
    gst_structure_free (config);
    GST_WARNING_OBJECT (pool, "can't change config, have outstanding buffers");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
}
static GstFlowReturn
do_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer,
    GstBufferPoolAcquireParams * params)
{
  GstBufferPoolPrivate *priv = pool->priv;
  GstFlowReturn result;
  gint cur_buffers, max_buffers;
  GstBufferPoolClass *pclass;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  if (G_UNLIKELY (!pclass->alloc_buffer))
    goto no_function;

  max_buffers = priv->max_buffers;

  /* increment the allocation counter */
  cur_buffers = g_atomic_int_add (&priv->cur_buffers, 1);
  if (max_buffers && cur_buffers >= max_buffers)
    goto max_reached;

  result = pclass->alloc_buffer (pool, buffer, params);
  if (G_UNLIKELY (result != GST_FLOW_OK))
    goto alloc_failed;

  /* lock all metadata and mark as pooled, we want this to remain on
   * the buffer and we want to remove any other metadata that gets added
   * later */
  gst_buffer_foreach_meta (*buffer, mark_meta_pooled, pool);

  /* un-tag memory, this is how we expect the buffer when it is
   * released again */
  GST_BUFFER_FLAG_UNSET (*buffer, GST_BUFFER_FLAG_TAG_MEMORY);

  GST_LOG_OBJECT (pool, "allocated buffer %d/%d, %p", cur_buffers,
      max_buffers, *buffer);

  return result;

  /* ERRORS */
no_function:
  {
    GST_ERROR_OBJECT (pool, "no alloc function");
    return GST_FLOW_NOT_SUPPORTED;
  }
max_reached:
  {
    GST_DEBUG_OBJECT (pool, "max buffers reached");
    g_atomic_int_add (&priv->cur_buffers, -1);
    return GST_FLOW_EOS;
  }
alloc_failed:
  {
    GST_WARNING_OBJECT (pool, "alloc function failed");
    g_atomic_int_add (&priv->cur_buffers, -1);
    return result;
  }
}
static GstFlowReturn
do_alloc_buffer (GstBufferPool * pool, GstBuffer ** buffer,
    GstBufferPoolAcquireParams * params)
{
  GstBufferPoolPrivate *priv = pool->priv;
  GstFlowReturn result;
  gint cur_buffers, max_buffers;
  GstBufferPoolClass *pclass;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  if (G_UNLIKELY (!pclass->alloc_buffer))
    goto no_function;

  max_buffers = priv->max_buffers;

  /* increment the allocation counter */
  cur_buffers = g_atomic_int_add (&priv->cur_buffers, 1);
  if (max_buffers && cur_buffers >= max_buffers)
    goto max_reached;

  result = pclass->alloc_buffer (pool, buffer, params);
  if (G_UNLIKELY (result != GST_FLOW_OK))
    goto alloc_failed;

  gst_buffer_foreach_meta (*buffer, mark_meta_pooled, pool);

  GST_LOG_OBJECT (pool, "allocated buffer %d/%d, %p", cur_buffers,
      max_buffers, buffer);

  return result;

  /* ERRORS */
no_function:
  {
    GST_ERROR_OBJECT (pool, "no alloc function");
    return GST_FLOW_NOT_SUPPORTED;
  }
max_reached:
  {
    GST_DEBUG_OBJECT (pool, "max buffers reached");
    g_atomic_int_add (&priv->cur_buffers, -1);
    return GST_FLOW_EOS;
  }
alloc_failed:
  {
    GST_WARNING_OBJECT (pool, "alloc function failed");
    g_atomic_int_add (&priv->cur_buffers, -1);
    return result;
  }
}
static void
do_free_buffer (GstBufferPool * pool, GstBuffer * buffer)
{
  GstBufferPoolPrivate *priv;
  GstBufferPoolClass *pclass;

  priv = pool->priv;
  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  g_atomic_int_add (&priv->cur_buffers, -1);
  GST_LOG_OBJECT (pool, "freeing buffer %p (%u left)", buffer,
      priv->cur_buffers);

  if (G_LIKELY (pclass->free_buffer))
    pclass->free_buffer (pool, buffer);
}
/* must be called with the lock */
static gboolean
do_stop (GstBufferPool * pool)
{
  GstBufferPoolPrivate *priv = pool->priv;

  if (priv->started) {
    GstBufferPoolClass *pclass;

    pclass = GST_BUFFER_POOL_GET_CLASS (pool);

    GST_LOG_OBJECT (pool, "stopping");
    if (G_LIKELY (pclass->stop)) {
      if (!pclass->stop (pool))
        return FALSE;
    }
    priv->started = FALSE;
  }
  return TRUE;
}
/* must be called with the lock */
static gboolean
default_stop (GstBufferPool * pool)
{
  GstBufferPoolPrivate *priv = pool->priv;
  GstBuffer *buffer;
  GstBufferPoolClass *pclass;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* clear the pool */
  while ((buffer = gst_atomic_queue_pop (priv->queue))) {
    GST_LOG_OBJECT (pool, "freeing %p", buffer);
    gst_poll_read_control (priv->poll);

    if (G_LIKELY (pclass->free_buffer))
      pclass->free_buffer (pool, buffer);
  }
  priv->cur_buffers = 0;

  return TRUE;
}
/* must be called with the lock */
static gboolean
do_start (GstBufferPool * pool)
{
  GstBufferPoolPrivate *priv = pool->priv;

  if (!priv->started) {
    GstBufferPoolClass *pclass;

    pclass = GST_BUFFER_POOL_GET_CLASS (pool);

    GST_LOG_OBJECT (pool, "starting");
    /* start the pool, subclasses should allocate buffers and put them
     * in the queue */
    if (G_LIKELY (pclass->start)) {
      if (!pclass->start (pool))
        return FALSE;
    }
    priv->started = TRUE;
  }
  return TRUE;
}
/* must be called with the lock */
static void
do_set_flushing (GstBufferPool * pool, gboolean flushing)
{
  GstBufferPoolPrivate *priv = pool->priv;
  GstBufferPoolClass *pclass;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  if (GST_BUFFER_POOL_IS_FLUSHING (pool) == flushing)
    return;

  if (flushing) {
    g_atomic_int_set (&pool->flushing, 1);
    /* Write the flush token to wake up any waiters */
    gst_poll_write_control (priv->poll);

    if (pclass->flush_start)
      pclass->flush_start (pool);
  } else {
    if (pclass->flush_stop)
      pclass->flush_stop (pool);

    while (!gst_poll_read_control (priv->poll)) {
      if (errno == EWOULDBLOCK) {
        /* This should not really happen unless flushing and unflushing
         * happens on different threads. Let's wait a bit to get back flush
         * token from the thread that was setting it to flushing */
        g_thread_yield ();
        continue;
      } else {
        /* Critical error but GstPoll already complained */
        break;
      }
    }

    g_atomic_int_set (&pool->flushing, 0);
  }
}
/**
 * gst_buffer_pool_set_config:
 * @pool: a #GstBufferPool
 * @config: (transfer full): a #GstStructure
 *
 * Set the configuration of the pool. If the pool is already configured, and
 * the configuration haven't change, this function will return %TRUE. If the
 * pool is active, this method will return %FALSE and active configuration
 * will remain. Buffers allocated form this pool must be returned or else this
 * function will do nothing and return %FALSE.
 *
 * @config is a #GstStructure that contains the configuration parameters for
 * the pool. A default and mandatory set of parameters can be configured with
 * gst_buffer_pool_config_set_params(), gst_buffer_pool_config_set_allocator()
 * and gst_buffer_pool_config_add_option().
 *
 * If the parameters in @config can not be set exactly, this function returns
 * %FALSE and will try to update as much state as possible. The new state can
 * then be retrieved and refined with gst_buffer_pool_get_config().
 *
 * This function takes ownership of @config.
 *
 * Returns: %TRUE when the configuration could be set.
 */
gboolean
gst_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
{
  gboolean result;
  GstBufferPoolClass *pclass;
  GstBufferPoolPrivate *priv;

  g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE);
  g_return_val_if_fail (config != NULL, FALSE);

  priv = pool->priv;

  GST_BUFFER_POOL_LOCK (pool);

  /* nothing to do if config is unchanged */
  if (priv->configured && gst_structure_is_equal (config, priv->config))
    goto config_unchanged;

  /* can't change the settings when active */
  if (priv->active)
    goto was_active;

  /* we can't change when outstanding buffers */
  if (g_atomic_int_get (&priv->outstanding) != 0)
    goto have_outstanding;

  pclass = GST_BUFFER_POOL_GET_CLASS (pool);

  /* set the new config */
  if (G_LIKELY (pclass->set_config))
    result = pclass->set_config (pool, config);
  else
    result = FALSE;

  /* save the config regardless of the result so user can read back the
   * modified config and evaluate if the changes are acceptable */
  if (priv->config)
    gst_structure_free (priv->config);
  priv->config = config;

  if (result) {
    /* now we are configured */
    priv->configured = TRUE;
  }
  GST_BUFFER_POOL_UNLOCK (pool);

  return result;

config_unchanged:
  {
    gst_structure_free (config);
    GST_BUFFER_POOL_UNLOCK (pool);
    return TRUE;
  }
  /* ERRORS */
was_active:
  {
    gst_structure_free (config);
    GST_INFO_OBJECT (pool, "can't change config, we are active");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
have_outstanding:
  {
    gst_structure_free (config);
    GST_WARNING_OBJECT (pool, "can't change config, have outstanding buffers");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
}