/* * gstvaapivideopool.c - Video object pool abstraction * * Copyright (C) 2010-2011 Splitted-Desktop Systems * Copyright (C) 2012 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ /** * SECTION:gstvaapivideopool * @short_description: Video object pool abstraction */ #include "sysdeps.h" #include "gstvaapivideopool.h" #include "gstvaapivideopool_priv.h" #include "gstvaapiobject.h" #define DEBUG 1 #include "gstvaapidebug.h" /* Ensure those symbols are actually defined in the resulting libraries */ #undef gst_vaapi_video_pool_ref #undef gst_vaapi_video_pool_unref #undef gst_vaapi_video_pool_replace #define GST_VAAPI_VIDEO_POOL_GET_CLASS(obj) \ gst_vaapi_video_pool_get_class(GST_VAAPI_VIDEO_POOL(obj)) static inline const GstVaapiVideoPoolClass * gst_vaapi_video_pool_get_class(GstVaapiVideoPool *pool) { return GST_VAAPI_VIDEO_POOL_CLASS(GST_VAAPI_MINI_OBJECT_GET_CLASS(pool)); } static inline gpointer gst_vaapi_video_pool_alloc_object(GstVaapiVideoPool *pool) { return GST_VAAPI_VIDEO_POOL_GET_CLASS(pool)->alloc_object(pool); } void gst_vaapi_video_pool_init(GstVaapiVideoPool *pool, GstVaapiDisplay *display, GstVaapiVideoPoolObjectType object_type) { pool->object_type = object_type; pool->display = gst_vaapi_display_ref(display); pool->used_objects = NULL; pool->used_count = 0; pool->capacity = 0; g_queue_init(&pool->free_objects); g_mutex_init(&pool->mutex); } void gst_vaapi_video_pool_finalize(GstVaapiVideoPool *pool) { g_list_free_full(pool->used_objects, gst_vaapi_object_unref); g_queue_foreach(&pool->free_objects, (GFunc)gst_vaapi_object_unref, NULL); g_queue_clear(&pool->free_objects); gst_vaapi_display_replace(&pool->display, NULL); g_mutex_clear(&pool->mutex); } /** * gst_vaapi_video_pool_ref: * @pool: a #GstVaapiVideoPool * * Atomically increases the reference count of the given @pool by one. * * Returns: The same @pool argument */ GstVaapiVideoPool * gst_vaapi_video_pool_ref(GstVaapiVideoPool *pool) { return gst_vaapi_video_pool_ref_internal(pool); } /** * gst_vaapi_video_pool_unref: * @pool: a #GstVaapiVideoPool * * Atomically decreases the reference count of the @pool by one. If * the reference count reaches zero, the pool will be free'd. */ void gst_vaapi_video_pool_unref(GstVaapiVideoPool *pool) { gst_vaapi_video_pool_unref_internal(pool); } /** * gst_vaapi_video_pool_replace: * @old_pool_ptr: a pointer to a #GstVaapiVideoPool * @new_pool: a #GstVaapiVideoPool * * Atomically replaces the pool pool held in @old_pool_ptr with * @new_pool. This means that @old_pool_ptr shall reference a valid * pool. However, @new_pool can be NULL. */ void gst_vaapi_video_pool_replace(GstVaapiVideoPool **old_pool_ptr, GstVaapiVideoPool *new_pool) { gst_vaapi_video_pool_replace_internal(old_pool_ptr, new_pool); } /** * gst_vaapi_video_pool_get_display: * @pool: a #GstVaapiVideoPool * * Retrieves the #GstVaapiDisplay the @pool is bound to. The @pool * owns the returned object and it shall not be unref'ed. * * Return value: the #GstVaapiDisplay the @pool is bound to */ GstVaapiDisplay * gst_vaapi_video_pool_get_display(GstVaapiVideoPool *pool) { g_return_val_if_fail(pool != NULL, NULL); return pool->display; } /** * gst_vaapi_video_pool_get_object_type: * @pool: a #GstVaapiVideoPool * * Retrieves the type of objects the video @pool supports. * * Return value: the #GstVaapiVideoPoolObjectType of the underlying pool * objects */ GstVaapiVideoPoolObjectType gst_vaapi_video_pool_get_object_type(GstVaapiVideoPool *pool) { g_return_val_if_fail(pool != NULL, (GstVaapiVideoPoolObjectType)0); return pool->object_type; } /** * gst_vaapi_video_pool_get_object: * @pool: a #GstVaapiVideoPool * * Retrieves a new object from the @pool, or allocates a new one if * none was found. The @pool holds a reference on the returned object * and thus shall be released through gst_vaapi_video_pool_put_object() * when it's no longer needed. * * Return value: a possibly newly allocated object, or %NULL on error */ static gpointer gst_vaapi_video_pool_get_object_unlocked(GstVaapiVideoPool *pool) { gpointer object; if (pool->capacity && pool->used_count >= pool->capacity) return NULL; object = g_queue_pop_head(&pool->free_objects); if (!object) { object = gst_vaapi_video_pool_alloc_object(pool); if (!object) return NULL; } ++pool->used_count; pool->used_objects = g_list_prepend(pool->used_objects, object); return gst_vaapi_object_ref(object); } gpointer gst_vaapi_video_pool_get_object(GstVaapiVideoPool *pool) { gpointer object; g_return_val_if_fail(pool != NULL, NULL); g_mutex_lock(&pool->mutex); object = gst_vaapi_video_pool_get_object_unlocked(pool); g_mutex_unlock(&pool->mutex); return object; } /** * gst_vaapi_video_pool_put_object: * @pool: a #GstVaapiVideoPool * @object: the object to add back to the pool * * Pushes the @object back into the pool. The @object shall be * obtained from the @pool through gst_vaapi_video_pool_get_object(). * Calling this function with an arbitrary object yields undefined * behaviour. */ static void gst_vaapi_video_pool_put_object_unlocked(GstVaapiVideoPool *pool, gpointer object) { GList *elem; elem = g_list_find(pool->used_objects, object); if (!elem) return; gst_vaapi_object_unref(object); --pool->used_count; pool->used_objects = g_list_delete_link(pool->used_objects, elem); g_queue_push_tail(&pool->free_objects, object); } void gst_vaapi_video_pool_put_object(GstVaapiVideoPool *pool, gpointer object) { g_return_if_fail(pool != NULL); g_return_if_fail(object != NULL); g_mutex_lock(&pool->mutex); gst_vaapi_video_pool_put_object_unlocked(pool, object); g_mutex_unlock(&pool->mutex); } /** * gst_vaapi_video_pool_add_object: * @pool: a #GstVaapiVideoPool * @object: the object to add to the pool * * Adds the @object to the pool. The pool then holds a reference on * the @object. This operation does not change the capacity of the * pool. * * Return value: %TRUE on success. */ static inline gboolean gst_vaapi_video_pool_add_object_unlocked(GstVaapiVideoPool *pool, gpointer object) { g_queue_push_tail(&pool->free_objects, gst_vaapi_object_ref(object)); return TRUE; } gboolean gst_vaapi_video_pool_add_object(GstVaapiVideoPool *pool, gpointer object) { gboolean success; g_return_val_if_fail(pool != NULL, FALSE); g_return_val_if_fail(object != NULL, FALSE); g_mutex_lock(&pool->mutex); success = gst_vaapi_video_pool_add_object_unlocked(pool, object); g_mutex_unlock(&pool->mutex); return success; } /** * gst_vaapi_video_pool_add_objects: * @pool: a #GstVaapiVideoPool * @objects: a #GPtrArray of objects * * Adds the @objects to the pool. The pool then holds a reference on * the @objects. This operation does not change the capacity of the * pool and is just a wrapper around gst_vaapi_video_pool_add_object(). * * Return value: %TRUE on success. */ static gboolean gst_vaapi_video_pool_add_objects_unlocked(GstVaapiVideoPool *pool, GPtrArray *objects) { guint i; for (i = 0; i < objects->len; i++) { gpointer const object = g_ptr_array_index(objects, i); if (!gst_vaapi_video_pool_add_object_unlocked(pool, object)) return FALSE; } return TRUE; } gboolean gst_vaapi_video_pool_add_objects(GstVaapiVideoPool *pool, GPtrArray *objects) { gboolean success; g_return_val_if_fail(pool != NULL, FALSE); g_mutex_lock(&pool->mutex); success = gst_vaapi_video_pool_add_objects_unlocked(pool, objects); g_mutex_unlock(&pool->mutex); return success; } /** * gst_vaapi_video_pool_get_size: * @pool: a #GstVaapiVideoPool * * Returns the number of free objects available in the pool. * * Return value: number of free objects in the pool */ guint gst_vaapi_video_pool_get_size(GstVaapiVideoPool *pool) { guint size; g_return_val_if_fail(pool != NULL, 0); g_mutex_lock(&pool->mutex); size = g_queue_get_length(&pool->free_objects); g_mutex_unlock(&pool->mutex); return size; } /** * gst_vaapi_video_pool_reserve: * @pool: a #GstVaapiVideoPool * @n: the number of objects to pre-allocate * * Pre-allocates up to @n objects in the pool. If @n is less than or * equal to the number of free and used objects in the pool, this call * has no effect. Otherwise, it is a request for allocation of * additional objects. * * Return value: %TRUE on success */ static gboolean gst_vaapi_video_pool_reserve_unlocked(GstVaapiVideoPool *pool, guint n) { guint i, num_allocated; num_allocated = gst_vaapi_video_pool_get_size(pool) + pool->used_count; if (n < num_allocated) return TRUE; if ((n -= num_allocated) > pool->capacity) n = pool->capacity; for (i = num_allocated; i < n; i++) { gpointer const object = gst_vaapi_video_pool_alloc_object(pool); if (!object) return FALSE; g_queue_push_tail(&pool->free_objects, object); } return TRUE; } gboolean gst_vaapi_video_pool_reserve(GstVaapiVideoPool *pool, guint n) { gboolean success; g_return_val_if_fail(pool != NULL, 0); g_mutex_lock(&pool->mutex); success = gst_vaapi_video_pool_reserve_unlocked(pool, n); g_mutex_unlock(&pool->mutex); return success; } /** * gst_vaapi_video_pool_get_capacity: * @pool: a #GstVaapiVideoPool * * Returns the maximum number of objects in the pool. i.e. the maximum * number of objects that can be returned by gst_vaapi_video_pool_get_object(). * * Return value: the capacity of the pool */ guint gst_vaapi_video_pool_get_capacity(GstVaapiVideoPool *pool) { guint capacity; g_return_val_if_fail(pool != NULL, 0); g_mutex_lock(&pool->mutex); capacity = pool->capacity; g_mutex_unlock(&pool->mutex); return capacity; } /** * gst_vaapi_video_pool_set_capacity: * @pool: a #GstVaapiVideoPool * @capacity: the maximal capacity of the pool * * Sets the maximum number of objects that can be allocated in the pool. */ void gst_vaapi_video_pool_set_capacity(GstVaapiVideoPool *pool, guint capacity) { g_return_if_fail(pool != NULL); g_mutex_lock(&pool->mutex); pool->capacity = capacity; g_mutex_unlock(&pool->mutex); }