merge from EVENTS1 on 20011016
[platform/upstream/gstreamer.git] / gst / gstbuffer.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstbuffer.c: Buffer 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 /* this file makes too much noise for most debugging sessions */
24 #define GST_DEBUG_FORCE_DISABLE
25 #include "gst_private.h"
26
27 #include "gstbuffer.h"
28
29
30 GType _gst_buffer_type;
31
32 static GMemChunk *_gst_buffer_chunk;
33 static GMutex *_gst_buffer_chunk_lock;
34
35 void 
36 _gst_buffer_initialize (void) 
37 {
38   int buffersize = sizeof(GstBuffer);
39   static const GTypeInfo buffer_info = {
40     0, // sizeof(class),
41     NULL,
42     NULL,
43     NULL,
44     NULL,
45     NULL,
46     0, // sizeof(object),
47     0,
48     NULL,
49   };
50
51   // round up to the nearest 32 bytes for cache-line and other efficiencies
52   buffersize = (((buffersize-1) / 32) + 1) * 32;
53
54   _gst_buffer_chunk = g_mem_chunk_new ("GstBuffer", buffersize,
55     buffersize * 32, G_ALLOC_AND_FREE);
56
57   _gst_buffer_chunk_lock = g_mutex_new ();
58
59   _gst_buffer_type = g_type_register_static (G_TYPE_INT, "GstBuffer", &buffer_info, 0);
60 }
61
62 /**
63  * gst_buffer_new:
64  *
65  * Create a new buffer.
66  *
67  * Returns: new buffer
68  */
69 GstBuffer*
70 gst_buffer_new (void)
71 {
72   GstBuffer *buffer;
73
74   g_mutex_lock (_gst_buffer_chunk_lock);
75   buffer = g_mem_chunk_alloc (_gst_buffer_chunk);
76   g_mutex_unlock (_gst_buffer_chunk_lock);
77   GST_INFO (GST_CAT_BUFFER,"creating new buffer %p",buffer);
78
79   GST_DATA_TYPE(buffer) = _gst_buffer_type;
80
81   buffer->lock = g_mutex_new ();
82 #ifdef HAVE_ATOMIC_H
83   atomic_set (&buffer->refcount, 1);
84 #else
85   buffer->refcount = 1;
86 #endif
87   buffer->flags = 0;
88   buffer->data = NULL;
89   buffer->size = 0;
90   buffer->maxsize = 0;
91   buffer->offset = -1;
92   buffer->timestamp = 0;
93   buffer->parent = NULL;
94   buffer->pool = NULL;
95   buffer->pool_private = NULL;
96   buffer->free = NULL;
97   buffer->copy = NULL;
98
99   return buffer;
100 }
101
102 /**
103  * gst_buffer_new_from_pool:
104  * @pool: the buffer pool to use
105  *
106  * Create a new buffer using the specified bufferpool.
107  *
108  * Returns: new buffer
109  */
110 GstBuffer*
111 gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size)
112 {
113   GstBuffer *buffer;
114
115   g_return_val_if_fail (pool != NULL, NULL);
116   g_return_val_if_fail (pool->buffer_new != NULL, NULL);
117   
118   buffer = pool->buffer_new (pool, offset, size, pool->user_data);
119   buffer->pool = pool;
120   buffer->free = pool->buffer_free;
121   buffer->copy = pool->buffer_copy;
122   
123   GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p (size %x, offset %x)", 
124                   buffer, pool, size, offset);
125
126   return buffer;
127 }
128
129 /**
130  * gst_buffer_create_sub:
131  * @parent: parent buffer
132  * @offset: offset into parent buffer
133  * @size: size of new subbuffer
134  *
135  * Creates a sub-buffer from the parent at a given offset.
136  *
137  * Returns: new buffer
138  */
139 GstBuffer*
140 gst_buffer_create_sub (GstBuffer *parent,
141                        guint32 offset,
142                        guint32 size) 
143 {
144   GstBuffer *buffer;
145
146   g_return_val_if_fail (parent != NULL, NULL);
147   g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL);
148   g_return_val_if_fail (size > 0, NULL);
149   g_return_val_if_fail ((offset+size) <= parent->size, NULL);
150
151   g_mutex_lock (_gst_buffer_chunk_lock);
152   buffer = g_mem_chunk_alloc (_gst_buffer_chunk);
153   GST_DATA_TYPE(buffer) = _gst_buffer_type;
154   g_mutex_unlock (_gst_buffer_chunk_lock);
155   GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p (size %u, offset %u)", 
156                   buffer, parent, size, offset);
157
158   buffer->lock = g_mutex_new ();
159 #ifdef HAVE_ATOMIC_H
160   atomic_set (&buffer->refcount, 1);
161 #else
162   buffer->refcount = 1;
163 #endif
164
165   // copy flags and type from parent, for lack of better
166   buffer->flags = parent->flags;
167
168   // set the data pointer, size, offset, and maxsize
169   buffer->data = parent->data + offset;
170   buffer->size = size;
171   buffer->maxsize = parent->size - offset;
172
173   // deal with bogus/unknown offsets
174   if (parent->offset != -1)
175     buffer->offset = parent->offset + offset;
176   else
177     buffer->offset = -1;
178
179   // again, for lack of better, copy parent's timestamp
180   buffer->timestamp = parent->timestamp;
181   buffer->maxage = parent->maxage;
182
183   // if the parent buffer is a subbuffer itself, use its parent, a real buffer
184   if (parent->parent != NULL)
185     parent = parent->parent;
186
187   // set parentage and reference the parent
188   buffer->parent = parent;
189   gst_buffer_ref (parent);
190
191   buffer->pool = NULL;
192
193   return buffer;
194 }
195
196
197 // FIXME FIXME: how does this overlap with the newly-added gst_buffer_span() ???
198 /**
199  * gst_buffer_append:
200  * @buffer: a buffer
201  * @append: the buffer to append
202  *
203  * Creates a new buffer by appending the data of append to the
204  * existing data of buffer.
205  *
206  * Returns: new buffer
207  */
208 GstBuffer*
209 gst_buffer_append (GstBuffer *buffer, 
210                    GstBuffer *append) 
211 {
212   guint size;
213   GstBuffer *newbuf;
214
215   g_return_val_if_fail (buffer != NULL, NULL);
216   g_return_val_if_fail (append != NULL, NULL);
217   g_return_val_if_fail (buffer->pool == NULL, NULL);
218   g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
219   g_return_val_if_fail (GST_BUFFER_REFCOUNT(append) > 0, NULL);
220
221   GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",buffer,append);
222
223   GST_BUFFER_LOCK (buffer);
224   // the buffer is not used by anyone else
225   if (GST_BUFFER_REFCOUNT (buffer) == 1 && buffer->parent == NULL 
226           && !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE)) {
227     // save the old size
228     size = buffer->size;
229     buffer->size += append->size;
230     buffer->data = g_realloc (buffer->data, buffer->size);
231     memcpy(buffer->data + size, append->data, append->size);
232     GST_BUFFER_UNLOCK (buffer);
233   }
234   // the buffer is used, create a new one 
235   else {
236     newbuf = gst_buffer_new ();
237     newbuf->size = buffer->size+append->size;
238     newbuf->data = g_malloc (newbuf->size);
239     memcpy (newbuf->data, buffer->data, buffer->size);
240     memcpy (newbuf->data+buffer->size, append->data, append->size);
241     GST_BUFFER_UNLOCK (buffer);
242     gst_buffer_unref (buffer);
243     buffer = newbuf;
244   }
245   return buffer;
246 }
247
248 /**
249  * gst_buffer_destroy:
250  * @buffer: the GstBuffer to destroy
251  *
252  * destroy the buffer
253  */
254 void 
255 gst_buffer_destroy (GstBuffer *buffer) 
256 {
257
258   g_return_if_fail (buffer != NULL);
259   
260   GST_INFO (GST_CAT_BUFFER, "freeing %sbuffer %p",
261             (buffer->parent?"sub":""),
262             buffer);
263   
264   // free the data only if there is some, DONTFREE isn't set, and not sub
265   if (GST_BUFFER_DATA (buffer) &&
266       !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
267       (buffer->parent == NULL)) {
268     // if there's a free function, use it
269     if (buffer->free != NULL) {
270       (buffer->free)(buffer);
271     } else {
272       g_free (GST_BUFFER_DATA (buffer));
273     }
274   }
275
276   // unreference the parent if there is one
277   if (buffer->parent != NULL)
278     gst_buffer_unref (buffer->parent);
279
280   g_mutex_free (buffer->lock);
281   //g_print("freed mutex\n");
282
283 #ifdef GST_DEBUG_ENABLED
284   // make it hard to reuse by mistake
285   memset (buffer, 0, sizeof (GstBuffer));
286 #endif
287
288   // remove it entirely from memory
289   g_mutex_lock (_gst_buffer_chunk_lock);
290   g_mem_chunk_free (_gst_buffer_chunk,buffer);
291   g_mutex_unlock (_gst_buffer_chunk_lock);
292 }
293
294 /**
295  * gst_buffer_ref:
296  * @buffer: the GstBuffer to reference
297  *
298  * Increment the refcount of this buffer.
299  */
300 void 
301 gst_buffer_ref (GstBuffer *buffer) 
302 {
303   g_return_if_fail (buffer != NULL);
304   g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
305
306   GST_INFO (GST_CAT_BUFFER, "ref buffer %p\n", buffer);
307
308 #ifdef HAVE_ATOMIC_H
309   atomic_inc (&(buffer->refcount));
310 #else
311   GST_BUFFER_LOCK (buffer);
312   buffer->refcount++;
313   GST_BUFFER_UNLOCK (buffer);
314 #endif
315 }
316
317 /**
318  * gst_buffer_unref:
319  * @buffer: the GstBuffer to unref
320  *
321  * Decrement the refcount of this buffer. If the refcount is
322  * zero, the buffer will be destroyed.
323  */
324 void 
325 gst_buffer_unref (GstBuffer *buffer) 
326 {
327   gint zero;
328
329   g_return_if_fail (buffer != NULL);
330   g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
331
332   GST_INFO (GST_CAT_BUFFER, "unref buffer %p\n", buffer);
333
334 #ifdef HAVE_ATOMIC_H
335   zero = atomic_dec_and_test (&(buffer->refcount));
336 #else
337   GST_BUFFER_LOCK (buffer);
338   buffer->refcount--;
339   zero = (buffer->refcount == 0);
340   GST_BUFFER_UNLOCK (buffer);
341 #endif
342
343   /* if we ended up with the refcount at zero, destroy the buffer */
344   if (zero) {
345     gst_buffer_destroy (buffer);
346   }
347 }
348
349 /**
350  * gst_buffer_copy:
351  * @buffer: the orignal GstBuffer to make a copy of
352  *
353  * Make a full copy of the give buffer, data and all.
354  *
355  * Returns: new buffer
356  */
357 GstBuffer *
358 gst_buffer_copy (GstBuffer *buffer)
359 {
360   GstBuffer *newbuf;
361
362   g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
363
364   // if a copy function exists, use it, else copy the bytes
365   if (buffer->copy != NULL) {
366     newbuf = (buffer->copy)(buffer);
367   } else {
368     // allocate a new buffer
369     newbuf = gst_buffer_new();
370
371     // copy the absolute size
372     newbuf->size = buffer->size;
373     // allocate space for the copy
374     newbuf->data = (guchar *)g_malloc (buffer->size);
375     // copy the data straight across
376     memcpy(newbuf->data,buffer->data,buffer->size);
377     // the new maxsize is the same as the size, since we just malloc'd it
378     newbuf->maxsize = newbuf->size;
379   }
380   newbuf->offset = buffer->offset;
381   newbuf->timestamp = buffer->timestamp;
382   newbuf->maxage = buffer->maxage;
383
384   // since we just created a new buffer, so we have no ties to old stuff
385   newbuf->parent = NULL;
386   newbuf->pool = NULL;
387
388   return newbuf;
389 }
390
391 /*
392  * gst_buffer_is_span_fast
393  * @buf1: first source buffer
394  * @buf2: second source buffer
395  *
396  * Determines whether a gst_buffer_span is free, or requires a memcpy. 
397  *
398  * Returns: TRUE if the buffers are contiguous, FALSE if a copy would be required.
399  */
400 gboolean
401 gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
402 {
403   g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE);
404   g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE);
405
406   return (buf1->parent && buf2->parent && 
407           (buf1->parent == buf2->parent) &&
408           ((buf1->data + buf1->size) == buf2->data));
409 }
410
411
412 /**
413  * gst_buffer_span:
414  * @buf1: first source buffer to merge
415  * @offset: offset in first buffer to start new buffer
416  * @buf2: second source buffer to merge
417  * @len: length of new buffer
418  *
419  * Create a new buffer that consists of part of buf1 and buf2.
420  * Logically, buf1 and buf2 are concatenated into a single larger
421  * buffer, and a new buffer is created at the given offset inside
422  * this space, with a given length.
423  *
424  * If the two source buffers are children of the same larger buffer,
425  * and are contiguous, the new buffer will be a child of the shared
426  * parent, and thus no copying is necessary.
427  *
428  * Returns: new buffer that spans the two source buffers
429  */
430 // FIXME need to think about CoW and such...
431 GstBuffer *
432 gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
433 {
434   GstBuffer *newbuf;
435
436   g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL);
437   g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL);
438
439   // make sure buf1 has a lower address than buf2
440   if (buf1->data > buf2->data) {
441     GstBuffer *tmp = buf1;
442     g_print ("swapping buffers\n");
443     buf1 = buf2;
444     buf2 = tmp;
445   }
446
447   // if the two buffers have the same parent and are adjacent
448   if (gst_buffer_is_span_fast(buf1,buf2)) {
449     // we simply create a subbuffer of the common parent
450     newbuf = gst_buffer_create_sub (buf1->parent, buf1->data - (buf1->parent->data) + offset, len);
451   }
452   else {
453     g_print ("slow path taken in buffer_span\n");
454     // otherwise we simply have to brute-force copy the buffers
455     newbuf = gst_buffer_new ();
456
457     // put in new size
458     newbuf->size = len;
459     // allocate space for the copy
460     newbuf->data = (guchar *)g_malloc(len);
461     // copy the first buffer's data across
462     memcpy(newbuf->data, buf1->data + offset, buf1->size - offset);
463     // copy the second buffer's data across
464     memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset));
465
466     if (newbuf->offset != -1)
467       newbuf->offset = buf1->offset + offset;
468     newbuf->timestamp = buf1->timestamp;
469     if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
470     else newbuf->maxage = buf1->maxage;
471
472   }
473
474   return newbuf;
475 }
476
477
478 /**
479  * gst_buffer_merge:
480  * @buf1: first source buffer to merge
481  * @buf2: second source buffer to merge
482  *
483  * Create a new buffer that is the concatenation of the two source
484  * buffers.  The original source buffers will not be modified or
485  * unref'd.
486  *
487  * Internally is nothing more than a specialized gst_buffer_span,
488  * so the same optimizations can occur.
489  *
490  * Returns: new buffer that's the concatenation of the source buffers
491  */
492 GstBuffer *
493 gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
494 {
495   // we're just a specific case of the more general gst_buffer_span()
496   return gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
497 }