bufferpool changes (next commit will update plugins)
[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
253   // round up to the nearest 32 bytes for cache-line and other efficiencies
254   real_buffer_size = (((buffer_size-1) / 32) + 1) * 32;
255   
256   // check for an existing GstBufferPool with the same real_buffer_size
257   // (we won't worry about the pool_size)
258   g_mutex_lock (_default_pool_lock);
259   pool = (GstBufferPool*)g_hash_table_lookup(_default_pools,GINT_TO_POINTER(real_buffer_size));
260   g_mutex_unlock (_default_pool_lock);
261
262   if (pool != NULL){
263     if (oldpool != pool){
264       gst_buffer_pool_ref(pool);
265
266       if (oldpool != NULL){
267         gst_buffer_pool_unref(oldpool);
268       }
269     }
270     return pool;
271   }
272   
273
274   data_chunk = g_mem_chunk_new ("GstBufferPoolDefault", real_buffer_size, 
275     real_buffer_size * pool_size, G_ALLOC_AND_FREE);
276     
277   pool = gst_buffer_pool_new();
278   gst_buffer_pool_set_buffer_create_function (pool, gst_buffer_pool_default_buffer_create, data_chunk);
279   gst_buffer_pool_set_buffer_destroy_function (pool, gst_buffer_pool_default_buffer_destroy, data_chunk);
280   gst_buffer_pool_set_pool_destroy_hook (pool, gst_buffer_pool_default_pool_destroy_hook, data_chunk);
281
282   g_mutex_lock (_default_pool_lock);
283   g_hash_table_insert(_default_pools,GINT_TO_POINTER(real_buffer_size),pool);
284   g_mutex_unlock (_default_pool_lock);
285
286   GST_DEBUG(GST_CAT_BUFFER,"new buffer pool %p bytes:%d size:%d\n", pool, real_buffer_size, pool_size);
287
288   if (oldpool != NULL){
289     gst_buffer_pool_unref(oldpool);
290   }
291   return pool;
292 }
293
294 static GstBuffer* 
295 gst_buffer_pool_default_buffer_create (GstBufferPool *pool, guint64 location /*unused*/,
296                                        gint size /*unused*/, gpointer user_data)
297 {
298   GMemChunk *data_chunk = (GMemChunk*)user_data;
299   GstBuffer *buffer;
300   
301   gst_buffer_pool_ref(pool);
302   buffer = gst_buffer_new();
303   GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p",buffer,pool);
304   GST_BUFFER_FLAG_SET(buffer,GST_BUFFER_DONTFREE);
305   
306   g_mutex_lock (pool->lock);
307   GST_BUFFER_DATA(buffer) = g_mem_chunk_alloc(data_chunk);
308   g_mutex_unlock (pool->lock);
309     
310   return buffer;
311 }
312
313 static void
314 gst_buffer_pool_default_buffer_destroy (GstBufferPool *pool, GstBuffer *buffer, gpointer user_data)
315 {
316   GMemChunk *data_chunk = (GMemChunk*)user_data;
317   gpointer data = GST_BUFFER_DATA(buffer);
318
319   g_mutex_lock (pool->lock);
320   g_mem_chunk_free (data_chunk,data);
321   g_mutex_unlock (pool->lock);
322
323   buffer->pool = NULL;
324   gst_buffer_pool_unref(pool);
325   gst_buffer_destroy (buffer);
326 }
327
328 static void
329 gst_buffer_pool_default_pool_destroy_hook (GstBufferPool *pool, gpointer user_data) 
330 {
331   GMemChunk *data_chunk = (GMemChunk*)user_data;
332   
333   GST_DEBUG(GST_CAT_BUFFER,"destroying default buffer pool %p\n", pool);
334   g_mem_chunk_reset(data_chunk);
335   g_free(data_chunk);
336 }
337