static void
gst_buffer_pool_init (GstBufferPool * pool)
{
  GstBufferPoolPrivate *priv;

  priv = pool->priv = GST_BUFFER_POOL_GET_PRIVATE (pool);

  g_rec_mutex_init (&priv->rec_lock);

  priv->poll = gst_poll_new_timer ();
  priv->queue = gst_atomic_queue_new (16);
  pool->flushing = 1;
  priv->active = FALSE;
  priv->configured = FALSE;
  priv->started = FALSE;
  priv->config = gst_structure_new_id_empty (GST_QUARK (BUFFER_POOL_CONFIG));
  gst_buffer_pool_config_set_params (priv->config, NULL, 0, 0, 0);
  priv->allocator = NULL;
  gst_allocation_params_init (&priv->params);
  gst_buffer_pool_config_set_allocator (priv->config, priv->allocator,
      &priv->params);
  /* 1 control write for flushing - the flush token */
  gst_poll_write_control (priv->poll);
  /* 1 control write for marking that we are not waiting for poll - the wait token */
  gst_poll_write_control (priv->poll);

  GST_DEBUG_OBJECT (pool, "created");
}
Example #2
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);
  }
}
Example #3
0
static void
default_release_buffer (GstBufferPool * pool, GstBuffer * buffer)
{
  GST_LOG_OBJECT (pool, "released buffer %p %d", buffer,
      GST_MINI_OBJECT_FLAGS (buffer));

  /* memory should be untouched */
  if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY))
    goto discard;

  /* size should have been reset. This is not a catch all, pool with
   * size requirement per memory should do their own check. */
  if (gst_buffer_get_size (buffer) != pool->priv->size)
    goto discard;

  /* all memory should be exclusive to this buffer (and thus be writable) */
  if (!gst_buffer_is_all_memory_writable (buffer))
    goto discard;

  /* keep it around in our queue */
  gst_atomic_queue_push (pool->priv->queue, buffer);
  gst_poll_write_control (pool->priv->poll);

  return;

discard:
  {
    do_free_buffer (pool, buffer);
    return;
  }
}
static void
default_release_buffer (GstBufferPool * pool, GstBuffer * buffer)
{
  /* keep it around in our queue */
  GST_LOG_OBJECT (pool, "released buffer %p", buffer);
  gst_atomic_queue_push (pool->priv->queue, buffer);
  gst_poll_write_control (pool->priv->poll);
}
Example #5
0
static GstFlowReturn
default_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer,
    GstBufferPoolAcquireParams * params)
{
  GstFlowReturn result;
  GstBufferPoolPrivate *priv = pool->priv;

  while (TRUE) {
    if (G_UNLIKELY (GST_BUFFER_POOL_IS_FLUSHING (pool)))
      goto flushing;

    /* try to get a buffer from the queue */
    *buffer = gst_atomic_queue_pop (priv->queue);
    if (G_LIKELY (*buffer)) {
      gst_poll_read_control (priv->poll);
      result = GST_FLOW_OK;
      GST_LOG_OBJECT (pool, "acquired buffer %p", *buffer);
      break;
    }

    /* no buffer, try to allocate some more */
    GST_LOG_OBJECT (pool, "no buffer, trying to allocate");
    result = do_alloc_buffer (pool, buffer, NULL);
    if (G_LIKELY (result == GST_FLOW_OK))
      /* we have a buffer, return it */
      break;

    if (G_UNLIKELY (result != GST_FLOW_EOS))
      /* something went wrong, return error */
      break;

    /* check if we need to wait */
    if (params && (params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT)) {
      GST_LOG_OBJECT (pool, "no more buffers");
      break;
    }

    /* now we release the control socket, we wait for a buffer release or
     * flushing */
    gst_poll_read_control (pool->priv->poll);
    GST_LOG_OBJECT (pool, "waiting for free buffers or flushing");
    gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE);
    gst_poll_write_control (pool->priv->poll);
  }

  return result;

  /* ERRORS */
flushing:
  {
    GST_DEBUG_OBJECT (pool, "we are flushing");
    return GST_FLOW_FLUSHING;
  }
}
static void
default_release_buffer (GstBufferPool * pool, GstBuffer * buffer)
{
  GST_LOG_OBJECT (pool, "released buffer %p %d", buffer,
      GST_MINI_OBJECT_FLAGS (buffer));

  /* memory should be untouched */
  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_TAG_MEMORY)))
    goto memory_tagged;

  /* size should have been reset. This is not a catch all, pool with
   * size requirement per memory should do their own check. */
  if (G_UNLIKELY (gst_buffer_get_size (buffer) != pool->priv->size))
    goto size_changed;

  /* all memory should be exclusive to this buffer (and thus be writable) */
  if (G_UNLIKELY (!gst_buffer_is_all_memory_writable (buffer)))
    goto not_writable;

  /* keep it around in our queue */
  gst_atomic_queue_push (pool->priv->queue, buffer);
  gst_poll_write_control (pool->priv->poll);

  return;

memory_tagged:
  {
    GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, pool,
        "discarding buffer %p: memory tag set", buffer);
    goto discard;
  }
size_changed:
  {
    GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, pool,
        "discarding buffer %p: size %" G_GSIZE_FORMAT " != %u",
        buffer, gst_buffer_get_size (buffer), pool->priv->size);
    goto discard;
  }
not_writable:
  {
    GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, pool,
        "discarding buffer %p: memory not writable", buffer);
    goto discard;
  }
discard:
  {
    do_free_buffer (pool, buffer);
    return;
  }
}
/* 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_active:
 * @pool: a #GstBufferPool
 * @active: the new active state
 *
 * Control the active state of @pool. When the pool is active, new calls to
 * gst_buffer_pool_acquire_buffer() will return with GST_FLOW_FLUSHING.
 *
 * Activating the bufferpool will preallocate all resources in the pool based on
 * the configuration of the pool.
 *
 * Deactivating will free the resources again when there are no outstanding
 * buffers. When there are outstanding buffers, they will be freed as soon as
 * they are all returned to the pool.
 *
 * Returns: %FALSE when the pool was not configured or when preallocation of the
 * buffers failed.
 */
gboolean
gst_buffer_pool_set_active (GstBufferPool * pool, gboolean active)
{
  gboolean res = TRUE;
  GstBufferPoolPrivate *priv;

  g_return_val_if_fail (GST_IS_BUFFER_POOL (pool), FALSE);

  GST_LOG_OBJECT (pool, "active %d", active);

  priv = pool->priv;

  GST_BUFFER_POOL_LOCK (pool);
  /* just return if we are already in the right state */
  if (priv->active == active)
    goto was_ok;

  /* we need to be configured */
  if (!priv->configured)
    goto not_configured;

  if (active) {
    if (!do_start (pool))
      goto start_failed;

    /* unset the flushing state now */
    gst_poll_read_control (priv->poll);
    g_atomic_int_set (&pool->flushing, 0);
  } else {
    gint outstanding;

    /* set to flushing first */
    g_atomic_int_set (&pool->flushing, 1);
    gst_poll_write_control (priv->poll);

    /* when all buffers are in the pool, free them. Else they will be
     * freed when they are released */
    outstanding = g_atomic_int_get (&priv->outstanding);
    GST_LOG_OBJECT (pool, "outstanding buffers %d", outstanding);
    if (outstanding == 0) {
      if (!do_stop (pool))
        goto stop_failed;
    }
  }
  priv->active = active;
  GST_BUFFER_POOL_UNLOCK (pool);

  return res;

was_ok:
  {
    GST_DEBUG_OBJECT (pool, "pool was in the right state");
    GST_BUFFER_POOL_UNLOCK (pool);
    return TRUE;
  }
not_configured:
  {
    GST_ERROR_OBJECT (pool, "pool was not configured");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
start_failed:
  {
    GST_ERROR_OBJECT (pool, "start failed");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
stop_failed:
  {
    GST_WARNING_OBJECT (pool, "stop failed");
    GST_BUFFER_POOL_UNLOCK (pool);
    return FALSE;
  }
}
Example #9
0
/**
 * gst_bus_post:
 * @bus: a #GstBus to post on
 * @message: (transfer full): the #GstMessage to post
 *
 * Post a message on the given bus. Ownership of the message
 * is taken by the bus.
 *
 * Returns: %TRUE if the message could be posted, %FALSE if the bus is flushing.
 *
 * MT safe.
 */
gboolean
gst_bus_post (GstBus * bus, GstMessage * message)
{
  GstBusSyncReply reply = GST_BUS_PASS;
  GstBusSyncHandler handler;
  gboolean emit_sync_message;
  gpointer handler_data;

  g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
  g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);

  GST_DEBUG_OBJECT (bus, "[msg %p] posting on bus %" GST_PTR_FORMAT, message,
      message);

  /* check we didn't accidentally add a public flag that maps to same value */
  g_assert (!GST_MINI_OBJECT_FLAG_IS_SET (message,
          GST_MESSAGE_FLAG_ASYNC_DELIVERY));

  GST_OBJECT_LOCK (bus);
  /* check if the bus is flushing */
  if (GST_OBJECT_FLAG_IS_SET (bus, GST_BUS_FLUSHING))
    goto is_flushing;

  handler = bus->priv->sync_handler;
  handler_data = bus->priv->sync_handler_data;
  emit_sync_message = bus->priv->num_sync_message_emitters > 0;
  GST_OBJECT_UNLOCK (bus);

  /* first call the sync handler if it is installed */
  if (handler)
    reply = handler (bus, message, handler_data);

  /* emit sync-message if requested to do so via
     gst_bus_enable_sync_message_emission. terrible but effective */
  if (emit_sync_message && reply != GST_BUS_DROP
      && handler != gst_bus_sync_signal_handler)
    gst_bus_sync_signal_handler (bus, message, NULL);

  /* If this is a bus without async message delivery
   * always drop the message */
  if (!bus->priv->poll)
    reply = GST_BUS_DROP;

  /* now see what we should do with the message */
  switch (reply) {
    case GST_BUS_DROP:
      /* drop the message */
      GST_DEBUG_OBJECT (bus, "[msg %p] dropped", message);
      break;
    case GST_BUS_PASS:
      /* pass the message to the async queue, refcount passed in the queue */
      GST_DEBUG_OBJECT (bus, "[msg %p] pushing on async queue", message);
      gst_atomic_queue_push (bus->priv->queue, message);
      gst_poll_write_control (bus->priv->poll);
      GST_DEBUG_OBJECT (bus, "[msg %p] pushed on async queue", message);

      break;
    case GST_BUS_ASYNC:
    {
      /* async delivery, we need a mutex and a cond to block
       * on */
      GCond *cond = GST_MESSAGE_GET_COND (message);
      GMutex *lock = GST_MESSAGE_GET_LOCK (message);

      g_cond_init (cond);
      g_mutex_init (lock);

      GST_MINI_OBJECT_FLAG_SET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY);

      GST_DEBUG_OBJECT (bus, "[msg %p] waiting for async delivery", message);

      /* now we lock the message mutex, send the message to the async
       * queue. When the message is handled by the app and destroyed,
       * the cond will be signalled and we can continue */
      g_mutex_lock (lock);

      gst_atomic_queue_push (bus->priv->queue, message);
      gst_poll_write_control (bus->priv->poll);

      /* now block till the message is freed */
      g_cond_wait (cond, lock);

      /* we acquired a new ref from gst_message_dispose() so we can clean up */
      g_mutex_unlock (lock);

      GST_DEBUG_OBJECT (bus, "[msg %p] delivered asynchronously", message);

      GST_MINI_OBJECT_FLAG_UNSET (message, GST_MESSAGE_FLAG_ASYNC_DELIVERY);

      g_mutex_clear (lock);
      g_cond_clear (cond);

      gst_message_unref (message);
      break;
    }
    default:
      g_warning ("invalid return from bus sync handler");
      break;
  }
  return TRUE;

  /* ERRORS */
is_flushing:
  {
    GST_DEBUG_OBJECT (bus, "bus is flushing");
    GST_OBJECT_UNLOCK (bus);
    gst_message_unref (message);

    return FALSE;
  }
}
static GstFlowReturn
default_acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer,
    GstBufferPoolAcquireParams * params)
{
  GstFlowReturn result;
  GstBufferPoolPrivate *priv = pool->priv;

  while (TRUE) {
    if (G_UNLIKELY (GST_BUFFER_POOL_IS_FLUSHING (pool)))
      goto flushing;

    /* try to get a buffer from the queue */
    *buffer = gst_atomic_queue_pop (priv->queue);
    if (G_LIKELY (*buffer)) {
      while (!gst_poll_read_control (priv->poll)) {
        if (errno == EWOULDBLOCK) {
          /* We put the buffer into the queue but did not finish writing control
           * yet, let's wait a bit and retry */
          g_thread_yield ();
          continue;
        } else {
          /* Critical error but GstPoll already complained */
          break;
        }
      }
      result = GST_FLOW_OK;
      GST_LOG_OBJECT (pool, "acquired buffer %p", *buffer);
      break;
    }

    /* no buffer, try to allocate some more */
    GST_LOG_OBJECT (pool, "no buffer, trying to allocate");
    result = do_alloc_buffer (pool, buffer, params);
    if (G_LIKELY (result == GST_FLOW_OK))
      /* we have a buffer, return it */
      break;

    if (G_UNLIKELY (result != GST_FLOW_EOS))
      /* something went wrong, return error */
      break;

    /* check if we need to wait */
    if (params && (params->flags & GST_BUFFER_POOL_ACQUIRE_FLAG_DONTWAIT)) {
      GST_LOG_OBJECT (pool, "no more buffers");
      break;
    }

    /* now we release the control socket, we wait for a buffer release or
     * flushing */
    if (!gst_poll_read_control (pool->priv->poll)) {
      if (errno == EWOULDBLOCK) {
        /* This means that we have two threads trying to allocate buffers
         * already, and the other one already got the wait token. This
         * means that we only have to wait for the poll now and not write the
         * token afterwards: we will be woken up once the other thread is
         * woken up and that one will write the wait token it removed */
        GST_LOG_OBJECT (pool, "waiting for free buffers or flushing");
        gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE);
      } else {
        /* This is a critical error, GstPoll already gave a warning */
        result = GST_FLOW_ERROR;
        break;
      }
    } else {
      /* We're the first thread waiting, we got the wait token and have to
       * write it again later 
       * OR
       * We're a second thread and just consumed the flush token and block all
       * other threads, in which case we must not wait and give it back
       * immediately */
      if (!GST_BUFFER_POOL_IS_FLUSHING (pool)) {
        GST_LOG_OBJECT (pool, "waiting for free buffers or flushing");
        gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE);
      }
      gst_poll_write_control (pool->priv->poll);
    }
  }

  return result;

  /* ERRORS */
flushing:
  {
    GST_DEBUG_OBJECT (pool, "we are flushing");
    return GST_FLOW_FLUSHING;
  }
}