finished default bufferpool implementation (setting size/maxsize on buffers)
[platform/upstream/gstreamer.git] / gst / gstbufferpool.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstbufferpool.c: Buffer-pool operations
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23
24 #include "gst_private.h"
25
26 #include "gstbuffer.h"
27
28 static GMutex *_default_pool_lock;
29 static GHashTable *_default_pools;
30
31 static GstBuffer* gst_buffer_pool_default_buffer_create (GstBufferPool *pool, guint64 location, gint size, gpointer user_data);
32 static void gst_buffer_pool_default_buffer_destroy (GstBufferPool *pool, GstBuffer *buffer, gpointer user_data);
33 static void gst_buffer_pool_default_pool_destroy_hook (GstBufferPool *pool, gpointer user_data);
34
35 typedef struct _GstBufferPoolDefault GstBufferPoolDefault;
36
37 struct _GstBufferPoolDefault {
38   guint size;
39 };
40
41 void 
42 _gst_buffer_pool_initialize (void) 
43 {
44   _default_pools = g_hash_table_new(NULL,NULL);
45   _default_pool_lock = g_mutex_new ();
46 }
47
48 /**
49  * gst_buffer_pool_new:
50  *
51  * Create a new buffer pool.
52  *
53  * Returns: new buffer pool
54  */
55 GstBufferPool*
56 gst_buffer_pool_new (void)
57 {
58   GstBufferPool *pool;
59
60   pool = g_new0 (GstBufferPool, 1);
61   GST_DEBUG (GST_CAT_BUFFER,"allocating new buffer pool %p\n", pool);
62   
63   /* all hooks and user data set to NULL or 0 by g_new0 */
64   
65   pool->lock = g_mutex_new ();
66 #ifdef HAVE_ATOMIC_H
67   atomic_set (&pool->refcount, 1);
68 #else
69   pool->refcount = 1;
70 #endif
71   
72   return pool;
73 }
74
75 /**
76  * gst_buffer_pool_ref:
77  * @pool: the GstBufferPool to reference
78  *
79  * Increment the refcount of this buffer pool.
80  */
81 void 
82 gst_buffer_pool_ref (GstBufferPool *pool) 
83 {
84   g_return_if_fail (pool != NULL);
85
86   GST_DEBUG(GST_CAT_BUFFER,"referencing buffer pool %p from %d\n", pool, GST_BUFFER_POOL_REFCOUNT(pool));
87   
88 #ifdef HAVE_ATOMIC_H
89   atomic_inc (&(pool->refcount));
90 #else
91   g_return_if_fail (pool->refcount > 0);
92   GST_BUFFER_POOL_LOCK (pool);
93   pool->refcount++;
94   GST_BUFFER_POOL_UNLOCK (pool);
95 #endif
96 }
97
98 /**
99  * gst_buffer_pool_ref_by_count:
100  * @pool: the GstBufferPool to reference
101  * @count: a number
102  *
103  * Increment the refcount of this buffer pool by the given number.
104  */
105 void 
106 gst_buffer_pool_ref_by_count (GstBufferPool *pool, int count) 
107 {
108   g_return_if_fail (pool != NULL);
109   g_return_if_fail (count > 0);
110
111 #ifdef HAVE_ATOMIC_H
112   g_return_if_fail (atomic_read (&(pool->refcount)) > 0);
113   atomic_add (count, &(pool->refcount));
114 #else
115   g_return_if_fail (pool->refcount > 0);
116   GST_BUFFER_POOL_LOCK (pool);
117   pool->refcount += count;
118   GST_BUFFER_POOL_UNLOCK (pool);
119 #endif
120 }
121
122 /**
123  * gst_buffer_pool_unref:
124  * @pool: the GstBufferPool to unref
125  *
126  * Decrement the refcount of this buffer pool. If the refcount is
127  * zero and the pool is a default implementation, 
128  * the buffer pool will be destroyed.
129  */
130 void 
131 gst_buffer_pool_unref (GstBufferPool *pool) 
132 {
133   gint zero;
134
135   g_return_if_fail (pool != NULL);
136
137   GST_DEBUG(GST_CAT_BUFFER, "unreferencing buffer pool %p from %d\n", pool, GST_BUFFER_POOL_REFCOUNT(pool));
138
139 #ifdef HAVE_ATOMIC_H
140   g_return_if_fail (atomic_read (&(pool->refcount)) > 0);
141   zero = atomic_dec_and_test (&(pool->refcount));
142 #else
143   g_return_if_fail (pool->refcount > 0);
144   GST_BUFFER_POOL_LOCK (pool);
145   pool->refcount--;
146   zero = (pool->refcount == 0);
147   GST_BUFFER_POOL_UNLOCK (pool);
148 #endif
149
150   /* if we ended up with the refcount at zero, destroy the buffer pool*/
151   if (zero) {
152     gst_buffer_pool_destroy (pool);
153   }
154 }
155
156 /**
157  * gst_buffer_pool_set_buffer_create_function:
158  * @pool: the pool to set the buffer create function for
159  * @create: the create function
160  * @user_data: any user data to be passed in the create function
161  *
162  * Sets the function that will be called when a buffer is created 
163  * from this pool.
164  */
165 void 
166 gst_buffer_pool_set_buffer_create_function (GstBufferPool *pool, 
167                                             GstBufferPoolBufferCreateFunction create, 
168                                             gpointer user_data) 
169 {
170   g_return_if_fail (pool != NULL);
171
172   pool->new_buffer = create;
173   pool->new_buffer_user_data = user_data;
174 }
175
176 /**
177  * gst_buffer_pool_set_buffer_destroy_function:
178  * @pool: the pool to set the buffer destroy function for
179  * @destroy: the destroy function
180  * @user_data: any user data to be passed to the destroy function
181  *
182  * Sets the function that will be called when a buffer is destroyed 
183  * from this pool.
184  */
185 void 
186 gst_buffer_pool_set_buffer_destroy_function (GstBufferPool *pool, 
187                                              GstBufferPoolBufferDestroyFunction destroy, 
188                                              gpointer user_data) 
189 {
190   g_return_if_fail (pool != NULL);
191
192   pool->destroy_buffer = destroy;
193   pool->destroy_buffer_user_data = user_data;
194 }
195
196 /**
197  * gst_buffer_pool_set_pool_destroy_hook:
198  * @pool: the pool to set the destroy hook for
199  * @destroy: the destroy function
200  * @user_data: any user data to be passed to the destroy hook
201  *
202  * Sets the function that will be called before a bufferpool is destroyed.
203  * You can take care of you private_data here.
204  */
205 void 
206 gst_buffer_pool_set_pool_destroy_hook (GstBufferPool *pool, 
207                                        GstBufferPoolPoolDestroyHook destroy, 
208                                        gpointer user_data) 
209 {
210   g_return_if_fail (pool != NULL);
211
212   pool->destroy_pool_hook = destroy;
213   pool->destroy_pool_user_data = user_data;
214 }
215
216 /**
217  * gst_buffer_pool_destroy:
218  * @pool: the pool to destroy
219  *
220  * Frees the memory for this bufferpool, calls the destroy hook.
221  */
222 void 
223 gst_buffer_pool_destroy (GstBufferPool *pool) 
224 {
225   g_return_if_fail (pool != NULL);
226   
227   if (pool->destroy_pool_hook)
228     pool->destroy_pool_hook (pool, pool->destroy_pool_user_data);
229   
230   g_free(pool);
231 }
232
233 /**
234  * gst_buffer_pool_get_default:
235  * @oldpool: instance of GstBufferPool which is no longer required (or NULL if it doesn't exist)
236  * @buffer_size: the number of bytes this buffer will store
237  * @pool_size: the default number of buffers to be preallocated
238  *
239  * Returns an instance of a buffer pool using the default
240  * implementation.  If a buffer pool instance with the same buffer_size
241  * already exists this will be returned, otherwise a new instance will
242  * be created.
243  * 
244  * Returns: an instance of GstBufferPool
245  */
246 GstBufferPool*
247 gst_buffer_pool_get_default (GstBufferPool *oldpool, guint buffer_size, guint pool_size)
248 {
249   GstBufferPool *pool;
250   GMemChunk *data_chunk;
251   guint real_buffer_size;
252   GstBufferPoolDefault *def;
253   
254   // round up to the nearest 32 bytes for cache-line and other efficiencies
255   real_buffer_size = (((buffer_size-1) / 32) + 1) * 32;
256   
257   // check for an existing GstBufferPool with the same real_buffer_size
258   // (we won't worry about the pool_size)
259   g_mutex_lock (_default_pool_lock);
260   pool = (GstBufferPool*)g_hash_table_lookup(_default_pools,GINT_TO_POINTER(real_buffer_size));
261   g_mutex_unlock (_default_pool_lock);
262
263   if (pool != NULL){
264     if (oldpool != pool){
265       gst_buffer_pool_ref(pool);
266
267       if (oldpool != NULL){
268         gst_buffer_pool_unref(oldpool);
269       }
270     }
271     return pool;
272   }
273   
274
275   data_chunk = g_mem_chunk_new ("GstBufferPoolDefault", real_buffer_size, 
276     real_buffer_size * pool_size, G_ALLOC_AND_FREE);
277     
278   pool = gst_buffer_pool_new();
279   gst_buffer_pool_set_buffer_create_function (pool, gst_buffer_pool_default_buffer_create, data_chunk);
280   gst_buffer_pool_set_buffer_destroy_function (pool, gst_buffer_pool_default_buffer_destroy, data_chunk);
281   gst_buffer_pool_set_pool_destroy_hook (pool, gst_buffer_pool_default_pool_destroy_hook, data_chunk);
282   
283   def = g_new0 (GstBufferPoolDefault, 1);
284   def->size = buffer_size;
285   pool->private_data = def;
286   
287   g_mutex_lock (_default_pool_lock);
288   g_hash_table_insert(_default_pools,GINT_TO_POINTER(real_buffer_size),pool);
289   g_mutex_unlock (_default_pool_lock);
290
291   GST_DEBUG(GST_CAT_BUFFER,"new buffer pool %p bytes:%d size:%d\n", pool, real_buffer_size, pool_size);
292   
293   if (oldpool != NULL){
294     gst_buffer_pool_unref(oldpool);
295   }
296   return pool;
297 }
298
299 static GstBuffer* 
300 gst_buffer_pool_default_buffer_create (GstBufferPool *pool, guint64 location /*unused*/,
301                                        gint size /*unused*/, gpointer user_data)
302 {
303   GMemChunk *data_chunk = (GMemChunk*)user_data;
304   GstBuffer *buffer;
305   GstBufferPoolDefault *def = (GstBufferPoolDefault*) pool->private_data;
306   
307   gst_buffer_pool_ref(pool);
308   buffer = gst_buffer_new();
309   GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p",buffer,pool);
310   
311   g_mutex_lock (pool->lock);
312   GST_BUFFER_DATA(buffer) = g_mem_chunk_alloc(data_chunk);
313   g_mutex_unlock (pool->lock);
314   
315   GST_BUFFER_FLAG_SET(buffer,GST_BUFFER_DONTFREE);
316   GST_BUFFER_SIZE(buffer)    = def->size;
317   GST_BUFFER_MAXSIZE(buffer) = def->size;
318   
319   return buffer;
320 }
321
322 static void
323 gst_buffer_pool_default_buffer_destroy (GstBufferPool *pool, GstBuffer *buffer, gpointer user_data)
324 {
325   GMemChunk *data_chunk = (GMemChunk*)user_data;
326   gpointer data = GST_BUFFER_DATA(buffer);
327
328   g_mutex_lock (pool->lock);
329   g_mem_chunk_free (data_chunk,data);
330   g_mutex_unlock (pool->lock);
331
332   buffer->pool = NULL;
333   gst_buffer_pool_unref(pool);
334   gst_buffer_destroy (buffer);
335 }
336
337 static void
338 gst_buffer_pool_default_pool_destroy_hook (GstBufferPool *pool, gpointer user_data) 
339 {
340   GMemChunk *data_chunk = (GMemChunk*)user_data;
341   
342   GST_DEBUG(GST_CAT_BUFFER,"destroying default buffer pool %p\n", pool);
343   
344   if (pool->private_data)
345       g_free (pool->private_data);
346   
347   g_mem_chunk_reset(data_chunk);
348   g_free(data_chunk);
349 }