/** * 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); }
/* 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; } }