Tizen 2.0 Release
[framework/multimedia/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapivideopool.c
1 /*
2  *  gstvaapivideopool.c - Video object pool abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public License
8  *  as published by the Free Software Foundation; either version 2.1
9  *  of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free
18  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * SECTION:gstvaapivideopool
24  * @short_description: Video object pool abstraction
25  */
26
27 #include "sysdeps.h"
28 #include "gstvaapivideopool.h"
29
30 #define DEBUG 1
31 #include "gstvaapidebug.h"
32
33 G_DEFINE_TYPE(GstVaapiVideoPool, gst_vaapi_video_pool, G_TYPE_OBJECT);
34
35 #define GST_VAAPI_VIDEO_POOL_GET_PRIVATE(obj)                   \
36     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
37                                  GST_VAAPI_TYPE_VIDEO_POOL,     \
38                                  GstVaapiVideoPoolPrivate))
39
40 #define VAAPI_VIDEO_POOL_LOCK(mutex)    g_static_rec_mutex_lock(mutex)
41 #define VAAPI_VIDEO_POOL_UNLOCK(mutex)  g_static_rec_mutex_unlock(mutex)
42
43
44 struct _GstVaapiVideoPoolPrivate {
45     GstVaapiDisplay    *display;
46     GQueue              free_objects;
47     GList              *used_objects;
48     GstCaps            *caps;
49     guint               used_count;
50     guint               capacity;
51
52     GStaticRecMutex     mutex;
53 };
54
55 enum {
56     PROP_0,
57
58     PROP_DISPLAY,
59     PROP_CAPS,
60     PROP_CAPACITY
61 };
62
63 static void
64 gst_vaapi_video_pool_set_caps(GstVaapiVideoPool *pool, GstCaps *caps);
65
66 static inline gpointer
67 gst_vaapi_video_pool_alloc_object(GstVaapiVideoPool *pool)
68 {
69     GstVaapiVideoPoolClass * const klass = GST_VAAPI_VIDEO_POOL_GET_CLASS(pool);
70
71     return klass->alloc_object(pool, pool->priv->display);
72 }
73
74 static void
75 gst_vaapi_video_pool_clear(GstVaapiVideoPool *pool)
76 {
77     GstVaapiVideoPoolPrivate * const priv = pool->priv;
78     gpointer object;
79     GList *list, *next;
80
81     for (list = priv->used_objects; list; list = next) {
82         next = list->next;
83         g_object_unref(list->data);
84         g_list_free_1(list);
85     }
86     priv->used_objects = NULL;
87
88     while ((object = g_queue_pop_head(&priv->free_objects)))
89         g_object_unref(object);
90 }
91
92 static void
93 gst_vaapi_video_pool_destroy(GstVaapiVideoPool *pool)
94 {
95     GstVaapiVideoPoolPrivate * const priv = pool->priv;
96
97     gst_vaapi_video_pool_clear(pool);
98
99     if (priv->caps) {
100         gst_caps_unref(priv->caps);
101         priv->caps = NULL;
102     }
103
104     g_clear_object(&priv->display);
105 }
106
107 static void
108 gst_vaapi_video_pool_finalize(GObject *object)
109 {
110     gst_vaapi_video_pool_destroy(GST_VAAPI_VIDEO_POOL(object));
111
112     G_OBJECT_CLASS(gst_vaapi_video_pool_parent_class)->finalize(object);
113 }
114
115 static void
116 gst_vaapi_video_pool_set_property(
117     GObject      *object,
118     guint         prop_id,
119     const GValue *value,
120     GParamSpec   *pspec
121 )
122 {
123     GstVaapiVideoPool * const pool = GST_VAAPI_VIDEO_POOL(object);
124
125     switch (prop_id) {
126     case PROP_DISPLAY:
127         pool->priv->display = g_object_ref(g_value_get_object(value));
128         break;
129     case PROP_CAPS:
130         gst_vaapi_video_pool_set_caps(pool, g_value_get_pointer(value));
131         break;
132     case PROP_CAPACITY:
133         gst_vaapi_video_pool_set_capacity(pool, g_value_get_uint(value));
134         break;
135     default:
136         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
137         break;
138     }
139 }
140
141 static void
142 gst_vaapi_video_pool_get_property(
143     GObject    *object,
144     guint       prop_id,
145     GValue     *value,
146     GParamSpec *pspec
147 )
148 {
149     GstVaapiVideoPool * const pool = GST_VAAPI_VIDEO_POOL(object);
150
151     switch (prop_id) {
152     case PROP_DISPLAY:
153         g_value_set_object(value, gst_vaapi_video_pool_get_display(pool));
154         break;
155     case PROP_CAPS:
156         g_value_set_pointer(value, gst_vaapi_video_pool_get_caps(pool));
157         break;
158     case PROP_CAPACITY:
159         g_value_set_uint(value, gst_vaapi_video_pool_get_capacity(pool));
160         break;
161     default:
162         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
163         break;
164     }
165 }
166
167 static void
168 gst_vaapi_video_pool_class_init(GstVaapiVideoPoolClass *klass)
169 {
170     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
171
172     g_type_class_add_private(klass, sizeof(GstVaapiVideoPoolPrivate));
173
174     object_class->finalize      = gst_vaapi_video_pool_finalize;
175     object_class->set_property  = gst_vaapi_video_pool_set_property;
176     object_class->get_property  = gst_vaapi_video_pool_get_property;
177
178     /**
179      * GstVaapiVideoPool:display:
180      *
181      * The #GstVaapiDisplay this pool is bound to.
182      */
183     g_object_class_install_property
184         (object_class,
185          PROP_DISPLAY,
186          g_param_spec_object("display",
187                              "Display",
188                              "The GstVaapiDisplay this pool is bound to",
189                              GST_VAAPI_TYPE_DISPLAY,
190                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
191
192     /**
193      * GstVaapiVidePool:caps:
194      *
195      * The video object capabilities represented as a #GstCaps. This
196      * shall hold at least the "width" and "height" properties.
197      */
198     g_object_class_install_property
199         (object_class,
200          PROP_CAPS,
201          g_param_spec_pointer("caps",
202                               "caps",
203                               "The video object capabilities",
204                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
205
206     /**
207      * GstVaapiVidePool:capacity:
208      *
209      * The maximum number of objects in the pool. Or zero, the pool
210      * will allocate as many objects as possible.
211      */
212     g_object_class_install_property
213         (object_class,
214          PROP_CAPACITY,
215          g_param_spec_uint("capacity",
216                            "capacity",
217                            "The maximum number of objects in the pool",
218                            0, G_MAXUINT32, 0,
219                            G_PARAM_READWRITE));
220 }
221
222 static void
223 gst_vaapi_video_pool_init(GstVaapiVideoPool *pool)
224 {
225     GstVaapiVideoPoolPrivate *priv = GST_VAAPI_VIDEO_POOL_GET_PRIVATE(pool);
226
227     pool->priv          = priv;
228     priv->display       = NULL;
229     priv->used_objects  = NULL;
230     priv->caps          = NULL;
231     priv->used_count    = 0;
232     priv->capacity      = 0;
233
234     g_queue_init(&priv->free_objects);
235     g_static_rec_mutex_init(&priv->mutex);
236 }
237
238 /**
239  * gst_vaapi_video_pool_get_display:
240  * @pool: a #GstVaapiVideoPool
241  *
242  * Retrieves the #GstVaapiDisplay the @pool is bound to. The @pool
243  * owns the returned object and it shall not be unref'ed.
244  *
245  * Return value: the #GstVaapiDisplay the @pool is bound to
246  */
247 GstVaapiDisplay *
248 gst_vaapi_video_pool_get_display(GstVaapiVideoPool *pool)
249 {
250     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL);
251
252     return pool->priv->display;
253 }
254
255 /**
256  * gst_vaapi_video_pool_get_caps:
257  * @pool: a #GstVaapiVideoPool
258  *
259  * Retrieves the #GstCaps the @pool was created with. The @pool owns
260  * the returned object and it shall not be unref'ed.
261  *
262  * Return value: the #GstCaps the @pool was created with
263  */
264 GstCaps *
265 gst_vaapi_video_pool_get_caps(GstVaapiVideoPool *pool)
266 {
267     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL);
268
269     return pool->priv->caps;
270 }
271
272 /*
273  * gst_vaapi_video_pool_set_caps:
274  * @pool: a #GstVaapiVideoPool
275  * @caps: a #GstCaps
276  *
277  * Binds new @caps to the @pool and notify the sub-classes.
278  */
279 void
280 gst_vaapi_video_pool_set_caps(GstVaapiVideoPool *pool, GstCaps *caps)
281 {
282     GstVaapiVideoPoolClass * const klass = GST_VAAPI_VIDEO_POOL_GET_CLASS(pool);
283
284     pool->priv->caps = gst_caps_ref(caps);
285
286     if (klass->set_caps)
287         klass->set_caps(pool, caps);
288 }
289
290 /**
291  * gst_vaapi_video_pool_get_object:
292  * @pool: a #GstVaapiVideoPool
293  *
294  * Retrieves a new object from the @pool, or allocates a new one if
295  * none was found. The @pool holds a reference on the returned object
296  * and thus shall be released through gst_vaapi_video_pool_put_object()
297  * when it's no longer needed.
298  *
299  * Return value: a possibly newly allocated object, or %NULL on error
300  */
301 gpointer
302 gst_vaapi_video_pool_get_object(GstVaapiVideoPool *pool)
303 {
304     GstVaapiVideoPoolPrivate *priv;
305     gpointer object = NULL;
306
307     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), NULL);
308
309     priv = pool->priv;
310
311     VAAPI_VIDEO_POOL_LOCK(&priv->mutex);
312     if (priv->capacity && priv->used_count >= priv->capacity)
313         goto end;
314
315     object = g_queue_pop_head(&priv->free_objects);
316     if (!object) {
317         VAAPI_VIDEO_POOL_UNLOCK(&priv->mutex);
318         object = gst_vaapi_video_pool_alloc_object(pool);
319         VAAPI_VIDEO_POOL_LOCK(&priv->mutex);
320         if (!object)
321             goto end;
322     }
323
324     ++priv->used_count;
325     priv->used_objects = g_list_prepend(priv->used_objects, object);
326     g_object_ref(object);
327
328   end:
329     VAAPI_VIDEO_POOL_UNLOCK(&priv->mutex);
330     return object;
331 }
332
333 /**
334  * gst_vaapi_video_pool_put_object:
335  * @pool: a #GstVaapiVideoPool
336  * @object: the object to add back to the pool
337  *
338  * Pushes the @object back into the pool. The @object shall be
339  * obtained from the @pool through gst_vaapi_video_pool_get_object().
340  * Calling this function with an arbitrary object yields undefined
341  * behaviour.
342  */
343 void
344 gst_vaapi_video_pool_put_object(GstVaapiVideoPool *pool, gpointer object)
345 {
346     GstVaapiVideoPoolPrivate *priv;
347     GList *elem;
348
349     g_return_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool));
350     g_return_if_fail(G_IS_OBJECT(object));
351
352     priv = pool->priv;
353
354     VAAPI_VIDEO_POOL_LOCK(&priv->mutex);
355     elem = g_list_find(priv->used_objects, object);
356     if (!elem)
357         goto end;
358
359     g_object_unref(object);
360     --priv->used_count;
361     priv->used_objects = g_list_delete_link(priv->used_objects, elem);
362     g_queue_push_tail(&priv->free_objects, object);
363
364   end:
365     VAAPI_VIDEO_POOL_UNLOCK(&priv->mutex);
366 }
367
368 /**
369  * gst_vaapi_video_pool_add_object:
370  * @pool: a #GstVaapiVideoPool
371  * @object: the object to add to the pool
372  *
373  * Adds the @object to the pool. The pool then holds a reference on
374  * the @object. This operation does not change the capacity of the
375  * pool.
376  *
377  * Return value: %TRUE on success.
378  */
379 gboolean
380 gst_vaapi_video_pool_add_object(GstVaapiVideoPool *pool, gpointer object)
381 {
382     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), FALSE);
383     g_return_val_if_fail(G_IS_OBJECT(object), FALSE);
384
385     VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex);
386     g_queue_push_tail(&pool->priv->free_objects, g_object_ref(object));
387     VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex);
388
389     return TRUE;
390 }
391
392 /**
393  * gst_vaapi_video_pool_add_objects:
394  * @pool: a #GstVaapiVideoPool
395  * @objects: a #GPtrArray of objects
396  *
397  * Adds the @objects to the pool. The pool then holds a reference on
398  * the @objects. This operation does not change the capacity of the
399  * pool and is just a wrapper around gst_vaapi_video_pool_add_object().
400  *
401  * Return value: %TRUE on success.
402  */
403 gboolean
404 gst_vaapi_video_pool_add_objects(GstVaapiVideoPool *pool, GPtrArray *objects)
405 {
406     guint i;
407
408     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), FALSE);
409
410     for (i = 0; i < objects->len; i++) {
411         gpointer const object = g_ptr_array_index(objects, i);
412         if (!gst_vaapi_video_pool_add_object(pool, object))
413             return FALSE;
414     }
415     return TRUE;
416 }
417
418 /**
419  * gst_vaapi_video_pool_get_size:
420  * @pool: a #GstVaapiVideoPool
421  *
422  * Returns the number of free objects available in the pool.
423  *
424  * Return value: number of free objects in the pool
425  */
426 guint
427 gst_vaapi_video_pool_get_size(GstVaapiVideoPool *pool)
428 {
429     guint size;
430     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), 0);
431
432
433     VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex);
434     size = g_queue_get_length(&pool->priv->free_objects);
435     VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex);
436     return size;
437 }
438
439 /**
440  * gst_vaapi_video_pool_reserve:
441  * @pool: a #GstVaapiVideoPool
442  * @n: the number of objects to pre-allocate
443  *
444  * Pre-allocates up to @n objects in the pool. If @n is less than or
445  * equal to the number of free and used objects in the pool, this call
446  * has no effect. Otherwise, it is a request for allocation of
447  * additional objects.
448  *
449  * Return value: %TRUE on success
450  */
451 gboolean
452 gst_vaapi_video_pool_reserve(GstVaapiVideoPool *pool, guint n)
453 {
454     guint i, num_allocated;
455     gboolean ret = TRUE;
456
457     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), 0);
458
459     VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex);
460
461     num_allocated = gst_vaapi_video_pool_get_size(pool) + pool->priv->used_count;
462     if (n < num_allocated)
463         goto end;
464
465     if ((n -= num_allocated) > pool->priv->capacity)
466         n = pool->priv->capacity;
467
468     for (i = num_allocated; i < n; i++) {
469         gpointer const object = gst_vaapi_video_pool_alloc_object(pool);
470         if (!object) {
471             ret = FALSE;
472             goto end;
473         }
474         g_queue_push_tail(&pool->priv->free_objects, object);
475     }
476     ret = TRUE;
477   end:
478     VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex);
479     return ret;
480 }
481
482 /**
483  * gst_vaapi_video_pool_get_capacity:
484  * @pool: a #GstVaapiVideoPool
485  *
486  * Returns the maximum number of objects in the pool. i.e. the maximum
487  * number of objects that can be returned by gst_vaapi_video_pool_get_object().
488  *
489  * Return value: the capacity of the pool
490  */
491 guint
492 gst_vaapi_video_pool_get_capacity(GstVaapiVideoPool *pool)
493 {
494     guint capacity;
495     g_return_val_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool), 0);
496     VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex);
497     capacity = pool->priv->capacity;
498     VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex);
499     return capacity;
500 }
501
502 /**
503  * gst_vaapi_video_pool_set_capacity:
504  * @pool: a #GstVaapiVideoPool
505  * @capacity: the maximal capacity of the pool
506  *
507  * Sets the maximum number of objects that can be allocated in the pool.
508  */
509 void
510 gst_vaapi_video_pool_set_capacity(GstVaapiVideoPool *pool, guint capacity)
511 {
512     g_return_if_fail(GST_VAAPI_IS_VIDEO_POOL(pool));
513     VAAPI_VIDEO_POOL_LOCK(&pool->priv->mutex);
514     pool->priv->capacity = capacity;
515     VAAPI_VIDEO_POOL_UNLOCK(&pool->priv->mutex);
516 }