2000-12-28 22:12:02 +00:00
|
|
|
/* GStreamer
|
|
|
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
|
|
* 2000 Wim Taymans <wtay@chello.be>
|
|
|
|
*
|
|
|
|
* gstbuffer.c: Buffer operations
|
2000-01-30 09:03:00 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 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
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
Changes made to the DEBUG system. New header file gstdebug.h holds the stuff to keep it out of gst.h's hair. DEBUG ...
Original commit message from CVS:
Changes made to the DEBUG system. New header file gstdebug.h holds the
stuff to keep it out of gst.h's hair. DEBUG prints out the process id,
cothread id, source filename and line number. Two new macros DEBUG_ENTER
and DEBUG_LEAVE are used to show the entry and exit of a given function.
This eventually might be used to construct call trace graphs, even taking
cothreads into account. This would be quite useful in visualizing the
scheduling mechanism.
Minor changes to various debug messages.
Also sitting in gstdebug.h is a prototypical DEBUG_ENTER that's capable of
performing DEBUG_LEAVE automatically. It does this by utilizing a
little-known GCC extension that allows one to call a function with the
same parameters as the current function. The macro uses this to basically
call itself. A boolean is used to ensure that when it calls itself it
actually runs the body of the function. In the meantime it prints stuff
out before and after the real function, as well as constructing a
debugging string. This can be used eventually to provide call-wide data
on the DEBUG lines, instead of having to replicate data on each call to
DEBUG. More research is needed into how this would most cleanly be fit
into some other chunk of code, like GStreamer (I think of this DEBUG trick
as a separate project, sorta).
Unfortunately, the aforementioned DEBUG trick interacts quite poorly with
cothreads. Almost any time it's used in a function that has anything
remotely to do with a cothread context (as in, it runs in one), a segfault
results from the __builtin_apply call, which is the heart of the whole
thing. If someone who really knows assembly could analyze the resulting
code to see what's really going on, we might find a way to fix either the
macro or the cothreads (I'm thinking that there's something we missed in
constructing the cothreads themselves) so this works in all cases.
In the meantime, please insert both DEBUG_ENTER and DEBUG_LEAVE in your
functions. Be sure to put DEBUG_ENTER after your variable declarations
and before any functional code, not to put the function name in any DEBUG
strings (it's already there, trust me), and put a DEBUG_LEAVE if you care
enough.
Changes are going to happen in the way DEBUGs and other printouts occur,
so stay tuned.
2000-12-04 09:35:08 +00:00
|
|
|
/* this file makes too much noise for most debugging sessions */
|
|
|
|
#define GST_DEBUG_FORCE_DISABLE
|
2000-12-28 22:12:02 +00:00
|
|
|
#include "gst_private.h"
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-12-15 01:57:34 +00:00
|
|
|
#include "gstbuffer.h"
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-12-28 22:12:02 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
GType _gst_buffer_type;
|
|
|
|
|
2001-03-20 18:29:00 +00:00
|
|
|
static GMemChunk *_gst_buffer_chunk;
|
|
|
|
static GMutex *_gst_buffer_chunk_lock;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
void
|
|
|
|
_gst_buffer_initialize (void)
|
|
|
|
{
|
2001-04-24 21:28:18 +00:00
|
|
|
int buffersize = sizeof(GstBuffer);
|
2001-10-17 10:21:27 +00:00
|
|
|
static const GTypeInfo buffer_info = {
|
|
|
|
0, // sizeof(class),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0, // sizeof(object),
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
};
|
2001-04-24 19:20:15 +00:00
|
|
|
|
|
|
|
// round up to the nearest 32 bytes for cache-line and other efficiencies
|
2001-06-20 14:53:14 +00:00
|
|
|
buffersize = (((buffersize-1) / 32) + 1) * 32;
|
2001-04-24 19:20:15 +00:00
|
|
|
|
|
|
|
_gst_buffer_chunk = g_mem_chunk_new ("GstBuffer", buffersize,
|
|
|
|
buffersize * 32, G_ALLOC_AND_FREE);
|
2001-01-06 18:08:04 +00:00
|
|
|
|
2001-03-20 18:29:00 +00:00
|
|
|
_gst_buffer_chunk_lock = g_mutex_new ();
|
2001-10-17 10:21:27 +00:00
|
|
|
|
|
|
|
_gst_buffer_type = g_type_register_static (G_TYPE_INT, "GstBuffer", &buffer_info, 0);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gst_buffer_new:
|
|
|
|
*
|
|
|
|
* Create a new buffer.
|
|
|
|
*
|
|
|
|
* Returns: new buffer
|
|
|
|
*/
|
2000-11-11 15:13:50 +00:00
|
|
|
GstBuffer*
|
2001-10-17 10:21:27 +00:00
|
|
|
gst_buffer_new (void)
|
2000-11-11 15:13:50 +00:00
|
|
|
{
|
2000-01-30 09:03:00 +00:00
|
|
|
GstBuffer *buffer;
|
|
|
|
|
2001-03-20 18:29:00 +00:00
|
|
|
g_mutex_lock (_gst_buffer_chunk_lock);
|
2000-11-11 15:13:50 +00:00
|
|
|
buffer = g_mem_chunk_alloc (_gst_buffer_chunk);
|
2001-03-20 18:29:00 +00:00
|
|
|
g_mutex_unlock (_gst_buffer_chunk_lock);
|
2001-01-01 03:14:40 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p",buffer);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
GST_DATA_TYPE(buffer) = _gst_buffer_type;
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
buffer->lock = g_mutex_new ();
|
2000-01-30 09:03:00 +00:00
|
|
|
#ifdef HAVE_ATOMIC_H
|
2000-11-11 15:13:50 +00:00
|
|
|
atomic_set (&buffer->refcount, 1);
|
2000-01-30 09:03:00 +00:00
|
|
|
#else
|
|
|
|
buffer->refcount = 1;
|
|
|
|
#endif
|
|
|
|
buffer->flags = 0;
|
|
|
|
buffer->data = NULL;
|
|
|
|
buffer->size = 0;
|
|
|
|
buffer->maxsize = 0;
|
2001-08-11 08:25:05 +00:00
|
|
|
buffer->offset = -1;
|
2000-01-30 09:03:00 +00:00
|
|
|
buffer->timestamp = 0;
|
|
|
|
buffer->parent = NULL;
|
2000-08-14 10:55:35 +00:00
|
|
|
buffer->pool = NULL;
|
2001-09-04 04:34:32 +00:00
|
|
|
buffer->pool_private = NULL;
|
2001-04-24 19:20:15 +00:00
|
|
|
buffer->free = NULL;
|
|
|
|
buffer->copy = NULL;
|
2001-10-17 10:21:27 +00:00
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2000-09-14 20:31:03 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_new_from_pool:
|
|
|
|
* @pool: the buffer pool to use
|
2001-10-21 18:00:31 +00:00
|
|
|
* @offset: the offset of the new buffer
|
|
|
|
* @size: the size of the new buffer
|
2000-09-14 20:31:03 +00:00
|
|
|
*
|
2001-10-21 18:00:31 +00:00
|
|
|
* Create a new buffer using the specified bufferpool, offset and size.
|
2000-09-14 20:31:03 +00:00
|
|
|
*
|
|
|
|
* Returns: new buffer
|
|
|
|
*/
|
2000-11-11 15:13:50 +00:00
|
|
|
GstBuffer*
|
2001-10-17 10:21:27 +00:00
|
|
|
gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size)
|
2000-08-14 10:55:35 +00:00
|
|
|
{
|
2001-08-27 04:19:58 +00:00
|
|
|
GstBuffer *buffer;
|
|
|
|
|
|
|
|
g_return_val_if_fail (pool != NULL, NULL);
|
2001-08-27 06:01:11 +00:00
|
|
|
g_return_val_if_fail (pool->buffer_new != NULL, NULL);
|
2001-08-27 04:19:58 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
buffer = pool->buffer_new (pool, offset, size, pool->user_data);
|
2001-08-27 04:19:58 +00:00
|
|
|
buffer->pool = pool;
|
2001-08-27 06:01:11 +00:00
|
|
|
buffer->free = pool->buffer_free;
|
2001-08-27 06:24:49 +00:00
|
|
|
buffer->copy = pool->buffer_copy;
|
2001-08-27 04:19:58 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p (size %x, offset %x)",
|
|
|
|
buffer, pool, size, offset);
|
|
|
|
|
2001-08-27 04:19:58 +00:00
|
|
|
return buffer;
|
2000-08-14 10:55:35 +00:00
|
|
|
}
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_create_sub:
|
|
|
|
* @parent: parent buffer
|
|
|
|
* @offset: offset into parent buffer
|
|
|
|
* @size: size of new subbuffer
|
|
|
|
*
|
|
|
|
* Creates a sub-buffer from the parent at a given offset.
|
|
|
|
*
|
|
|
|
* Returns: new buffer
|
|
|
|
*/
|
2000-11-11 15:13:50 +00:00
|
|
|
GstBuffer*
|
|
|
|
gst_buffer_create_sub (GstBuffer *parent,
|
|
|
|
guint32 offset,
|
|
|
|
guint32 size)
|
|
|
|
{
|
2000-01-30 09:03:00 +00:00
|
|
|
GstBuffer *buffer;
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
g_return_val_if_fail (parent != NULL, NULL);
|
2001-10-17 10:21:27 +00:00
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL);
|
2000-11-11 15:13:50 +00:00
|
|
|
g_return_val_if_fail (size > 0, NULL);
|
|
|
|
g_return_val_if_fail ((offset+size) <= parent->size, NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-03-20 18:29:00 +00:00
|
|
|
g_mutex_lock (_gst_buffer_chunk_lock);
|
2000-11-11 15:13:50 +00:00
|
|
|
buffer = g_mem_chunk_alloc (_gst_buffer_chunk);
|
2001-10-17 10:21:27 +00:00
|
|
|
GST_DATA_TYPE(buffer) = _gst_buffer_type;
|
2001-03-20 18:29:00 +00:00
|
|
|
g_mutex_unlock (_gst_buffer_chunk_lock);
|
2001-10-17 10:21:27 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p (size %u, offset %u)",
|
|
|
|
buffer, parent, size, offset);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
buffer->lock = g_mutex_new ();
|
2000-01-30 09:03:00 +00:00
|
|
|
#ifdef HAVE_ATOMIC_H
|
2000-11-11 15:13:50 +00:00
|
|
|
atomic_set (&buffer->refcount, 1);
|
2000-01-30 09:03:00 +00:00
|
|
|
#else
|
|
|
|
buffer->refcount = 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// copy flags and type from parent, for lack of better
|
|
|
|
buffer->flags = parent->flags;
|
|
|
|
|
|
|
|
// set the data pointer, size, offset, and maxsize
|
|
|
|
buffer->data = parent->data + offset;
|
|
|
|
buffer->size = size;
|
|
|
|
buffer->maxsize = parent->size - offset;
|
|
|
|
|
2001-08-11 08:25:05 +00:00
|
|
|
// deal with bogus/unknown offsets
|
|
|
|
if (parent->offset != -1)
|
|
|
|
buffer->offset = parent->offset + offset;
|
|
|
|
else
|
|
|
|
buffer->offset = -1;
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
// again, for lack of better, copy parent's timestamp
|
|
|
|
buffer->timestamp = parent->timestamp;
|
2001-04-24 19:20:15 +00:00
|
|
|
buffer->maxage = parent->maxage;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-04-24 19:20:15 +00:00
|
|
|
// if the parent buffer is a subbuffer itself, use its parent, a real buffer
|
|
|
|
if (parent->parent != NULL)
|
|
|
|
parent = parent->parent;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
|
|
|
// set parentage and reference the parent
|
|
|
|
buffer->parent = parent;
|
2000-11-11 15:13:50 +00:00
|
|
|
gst_buffer_ref (parent);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-08-14 10:55:35 +00:00
|
|
|
buffer->pool = NULL;
|
2001-10-17 10:21:27 +00:00
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2001-08-11 08:25:05 +00:00
|
|
|
|
|
|
|
// FIXME FIXME: how does this overlap with the newly-added gst_buffer_span() ???
|
2000-08-14 10:55:35 +00:00
|
|
|
/**
|
2000-09-14 20:31:03 +00:00
|
|
|
* gst_buffer_append:
|
2000-08-14 10:55:35 +00:00
|
|
|
* @buffer: a buffer
|
|
|
|
* @append: the buffer to append
|
|
|
|
*
|
2000-09-14 20:31:03 +00:00
|
|
|
* Creates a new buffer by appending the data of append to the
|
|
|
|
* existing data of buffer.
|
2000-08-14 10:55:35 +00:00
|
|
|
*
|
|
|
|
* Returns: new buffer
|
|
|
|
*/
|
2000-11-11 15:13:50 +00:00
|
|
|
GstBuffer*
|
|
|
|
gst_buffer_append (GstBuffer *buffer,
|
|
|
|
GstBuffer *append)
|
|
|
|
{
|
2000-08-14 10:55:35 +00:00
|
|
|
guint size;
|
|
|
|
GstBuffer *newbuf;
|
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
g_return_val_if_fail (buffer != NULL, NULL);
|
|
|
|
g_return_val_if_fail (append != NULL, NULL);
|
|
|
|
g_return_val_if_fail (buffer->pool == NULL, NULL);
|
2001-10-17 10:21:27 +00:00
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
|
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(append) > 0, NULL);
|
2000-08-14 10:55:35 +00:00
|
|
|
|
2001-01-01 03:14:40 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",buffer,append);
|
2000-12-30 02:41:15 +00:00
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
GST_BUFFER_LOCK (buffer);
|
2000-08-14 10:55:35 +00:00
|
|
|
// the buffer is not used by anyone else
|
2000-12-29 19:45:45 +00:00
|
|
|
if (GST_BUFFER_REFCOUNT (buffer) == 1 && buffer->parent == NULL
|
|
|
|
&& !GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE)) {
|
2000-08-14 10:55:35 +00:00
|
|
|
// save the old size
|
|
|
|
size = buffer->size;
|
|
|
|
buffer->size += append->size;
|
2000-11-11 15:13:50 +00:00
|
|
|
buffer->data = g_realloc (buffer->data, buffer->size);
|
2000-08-14 10:55:35 +00:00
|
|
|
memcpy(buffer->data + size, append->data, append->size);
|
2000-11-11 15:13:50 +00:00
|
|
|
GST_BUFFER_UNLOCK (buffer);
|
2000-08-14 10:55:35 +00:00
|
|
|
}
|
|
|
|
// the buffer is used, create a new one
|
|
|
|
else {
|
2000-11-11 15:13:50 +00:00
|
|
|
newbuf = gst_buffer_new ();
|
2000-08-14 10:55:35 +00:00
|
|
|
newbuf->size = buffer->size+append->size;
|
2000-11-11 15:13:50 +00:00
|
|
|
newbuf->data = g_malloc (newbuf->size);
|
|
|
|
memcpy (newbuf->data, buffer->data, buffer->size);
|
|
|
|
memcpy (newbuf->data+buffer->size, append->data, append->size);
|
|
|
|
GST_BUFFER_UNLOCK (buffer);
|
|
|
|
gst_buffer_unref (buffer);
|
2000-08-14 10:55:35 +00:00
|
|
|
buffer = newbuf;
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2000-03-27 19:53:43 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_destroy:
|
|
|
|
* @buffer: the GstBuffer to destroy
|
|
|
|
*
|
|
|
|
* destroy the buffer
|
|
|
|
*/
|
2001-10-17 10:21:27 +00:00
|
|
|
void
|
|
|
|
gst_buffer_destroy (GstBuffer *buffer)
|
2000-11-11 15:13:50 +00:00
|
|
|
{
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
g_return_if_fail (buffer != NULL);
|
2001-08-27 04:19:58 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER, "freeing %sbuffer %p",
|
|
|
|
(buffer->parent?"sub":""),
|
|
|
|
buffer);
|
2001-08-27 06:01:11 +00:00
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
// free the data only if there is some, DONTFREE isn't set, and not sub
|
2000-11-11 15:13:50 +00:00
|
|
|
if (GST_BUFFER_DATA (buffer) &&
|
|
|
|
!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
|
2000-01-30 09:03:00 +00:00
|
|
|
(buffer->parent == NULL)) {
|
2001-04-24 19:20:15 +00:00
|
|
|
// if there's a free function, use it
|
|
|
|
if (buffer->free != NULL) {
|
|
|
|
(buffer->free)(buffer);
|
|
|
|
} else {
|
|
|
|
g_free (GST_BUFFER_DATA (buffer));
|
|
|
|
}
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// unreference the parent if there is one
|
|
|
|
if (buffer->parent != NULL)
|
2000-11-11 15:13:50 +00:00
|
|
|
gst_buffer_unref (buffer->parent);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
g_mutex_free (buffer->lock);
|
2000-03-20 20:25:03 +00:00
|
|
|
//g_print("freed mutex\n");
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
#ifdef GST_DEBUG_ENABLED
|
|
|
|
// make it hard to reuse by mistake
|
|
|
|
memset (buffer, 0, sizeof (GstBuffer));
|
|
|
|
#endif
|
|
|
|
|
2000-01-30 09:03:00 +00:00
|
|
|
// remove it entirely from memory
|
2001-03-20 18:29:00 +00:00
|
|
|
g_mutex_lock (_gst_buffer_chunk_lock);
|
2000-11-11 15:13:50 +00:00
|
|
|
g_mem_chunk_free (_gst_buffer_chunk,buffer);
|
2001-03-20 18:29:00 +00:00
|
|
|
g_mutex_unlock (_gst_buffer_chunk_lock);
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2000-03-27 19:53:43 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_ref:
|
|
|
|
* @buffer: the GstBuffer to reference
|
|
|
|
*
|
2001-01-06 22:05:15 +00:00
|
|
|
* Increment the refcount of this buffer.
|
2000-03-27 19:53:43 +00:00
|
|
|
*/
|
2000-11-11 15:13:50 +00:00
|
|
|
void
|
|
|
|
gst_buffer_ref (GstBuffer *buffer)
|
|
|
|
{
|
|
|
|
g_return_if_fail (buffer != NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-11-08 22:41:43 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER, "ref buffer %p, current count is %d", buffer,GST_BUFFER_REFCOUNT(buffer));
|
|
|
|
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_ATOMIC_H
|
2000-12-15 01:57:34 +00:00
|
|
|
atomic_inc (&(buffer->refcount));
|
2000-01-30 09:03:00 +00:00
|
|
|
#else
|
2000-11-11 15:13:50 +00:00
|
|
|
GST_BUFFER_LOCK (buffer);
|
2000-01-30 09:03:00 +00:00
|
|
|
buffer->refcount++;
|
2000-11-11 15:13:50 +00:00
|
|
|
GST_BUFFER_UNLOCK (buffer);
|
2000-01-30 09:03:00 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_ref_by_count:
|
|
|
|
* @buffer: the GstBuffer to reference
|
|
|
|
* @count: a number
|
|
|
|
*
|
|
|
|
* Increment the refcount of this buffer by the given number.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gst_buffer_ref_by_count (GstBuffer *buffer, gint count)
|
|
|
|
{
|
|
|
|
g_return_if_fail (buffer != NULL);
|
|
|
|
g_return_if_fail (count > 0);
|
|
|
|
|
|
|
|
#ifdef HAVE_ATOMIC_H
|
|
|
|
g_return_if_fail (atomic_read (&(buffer->refcount)) > 0);
|
|
|
|
atomic_add (count, &(buffer->refcount));
|
|
|
|
#else
|
|
|
|
g_return_if_fail (buffer->refcount > 0);
|
|
|
|
GST_BUFFER_LOCK (buffer);
|
|
|
|
buffer->refcount += count;
|
|
|
|
GST_BUFFER_UNLOCK (buffer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2000-03-27 19:53:43 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_unref:
|
|
|
|
* @buffer: the GstBuffer to unref
|
|
|
|
*
|
2001-01-06 22:05:15 +00:00
|
|
|
* Decrement the refcount of this buffer. If the refcount is
|
2000-03-27 19:53:43 +00:00
|
|
|
* zero, the buffer will be destroyed.
|
|
|
|
*/
|
2000-11-11 15:13:50 +00:00
|
|
|
void
|
|
|
|
gst_buffer_unref (GstBuffer *buffer)
|
|
|
|
{
|
|
|
|
gint zero;
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2000-11-11 15:13:50 +00:00
|
|
|
g_return_if_fail (buffer != NULL);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
2001-11-08 22:41:43 +00:00
|
|
|
GST_INFO (GST_CAT_BUFFER, "unref buffer %p, current count is %d", buffer,GST_BUFFER_REFCOUNT(buffer));
|
|
|
|
g_return_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0);
|
2000-01-30 09:03:00 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_ATOMIC_H
|
2000-12-15 01:57:34 +00:00
|
|
|
zero = atomic_dec_and_test (&(buffer->refcount));
|
2000-01-30 09:03:00 +00:00
|
|
|
#else
|
2000-11-11 15:13:50 +00:00
|
|
|
GST_BUFFER_LOCK (buffer);
|
2000-01-30 09:03:00 +00:00
|
|
|
buffer->refcount--;
|
|
|
|
zero = (buffer->refcount == 0);
|
2000-11-11 15:13:50 +00:00
|
|
|
GST_BUFFER_UNLOCK (buffer);
|
2000-01-30 09:03:00 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* if we ended up with the refcount at zero, destroy the buffer */
|
2000-08-14 10:55:35 +00:00
|
|
|
if (zero) {
|
2001-08-27 04:19:58 +00:00
|
|
|
gst_buffer_destroy (buffer);
|
2000-08-14 10:55:35 +00:00
|
|
|
}
|
2000-01-30 09:03:00 +00:00
|
|
|
}
|
|
|
|
|
2001-04-22 01:41:40 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_copy:
|
|
|
|
* @buffer: the orignal GstBuffer to make a copy of
|
|
|
|
*
|
|
|
|
* Make a full copy of the give buffer, data and all.
|
|
|
|
*
|
|
|
|
* Returns: new buffer
|
|
|
|
*/
|
2001-04-22 01:30:19 +00:00
|
|
|
GstBuffer *
|
2001-04-22 01:41:40 +00:00
|
|
|
gst_buffer_copy (GstBuffer *buffer)
|
2001-04-22 01:30:19 +00:00
|
|
|
{
|
|
|
|
GstBuffer *newbuf;
|
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
|
|
|
|
|
2001-04-24 19:20:15 +00:00
|
|
|
// if a copy function exists, use it, else copy the bytes
|
|
|
|
if (buffer->copy != NULL) {
|
2001-09-14 22:16:47 +00:00
|
|
|
newbuf = (buffer->copy)(buffer);
|
2001-04-24 19:20:15 +00:00
|
|
|
} else {
|
2001-09-15 09:12:39 +00:00
|
|
|
// allocate a new buffer
|
|
|
|
newbuf = gst_buffer_new();
|
|
|
|
|
2001-04-24 19:20:15 +00:00
|
|
|
// copy the absolute size
|
|
|
|
newbuf->size = buffer->size;
|
|
|
|
// allocate space for the copy
|
2001-05-25 21:00:07 +00:00
|
|
|
newbuf->data = (guchar *)g_malloc (buffer->size);
|
2001-04-24 19:20:15 +00:00
|
|
|
// copy the data straight across
|
2001-05-25 21:35:58 +00:00
|
|
|
memcpy(newbuf->data,buffer->data,buffer->size);
|
2001-04-24 19:20:15 +00:00
|
|
|
// the new maxsize is the same as the size, since we just malloc'd it
|
|
|
|
newbuf->maxsize = newbuf->size;
|
|
|
|
}
|
|
|
|
newbuf->offset = buffer->offset;
|
|
|
|
newbuf->timestamp = buffer->timestamp;
|
|
|
|
newbuf->maxage = buffer->maxage;
|
2001-04-22 01:41:40 +00:00
|
|
|
|
|
|
|
// since we just created a new buffer, so we have no ties to old stuff
|
2001-04-24 19:20:15 +00:00
|
|
|
newbuf->parent = NULL;
|
|
|
|
newbuf->pool = NULL;
|
2001-04-22 01:30:19 +00:00
|
|
|
|
|
|
|
return newbuf;
|
|
|
|
}
|
2001-08-11 08:25:05 +00:00
|
|
|
|
2001-10-21 18:00:31 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_is_span_fast:
|
2001-09-10 19:46:01 +00:00
|
|
|
* @buf1: first source buffer
|
|
|
|
* @buf2: second source buffer
|
|
|
|
*
|
|
|
|
* Determines whether a gst_buffer_span is free, or requires a memcpy.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if the buffers are contiguous, FALSE if a copy would be required.
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
|
|
|
|
{
|
2001-10-17 10:21:27 +00:00
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE);
|
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE);
|
|
|
|
|
|
|
|
return (buf1->parent && buf2->parent &&
|
|
|
|
(buf1->parent == buf2->parent) &&
|
2001-09-10 19:46:01 +00:00
|
|
|
((buf1->data + buf1->size) == buf2->data));
|
|
|
|
}
|
|
|
|
|
2001-08-11 08:25:05 +00:00
|
|
|
|
2001-09-04 04:34:32 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_span:
|
|
|
|
* @buf1: first source buffer to merge
|
|
|
|
* @offset: offset in first buffer to start new buffer
|
|
|
|
* @buf2: second source buffer to merge
|
|
|
|
* @len: length of new buffer
|
|
|
|
*
|
|
|
|
* Create a new buffer that consists of part of buf1 and buf2.
|
|
|
|
* Logically, buf1 and buf2 are concatenated into a single larger
|
|
|
|
* buffer, and a new buffer is created at the given offset inside
|
|
|
|
* this space, with a given length.
|
|
|
|
*
|
|
|
|
* If the two source buffers are children of the same larger buffer,
|
|
|
|
* and are contiguous, the new buffer will be a child of the shared
|
|
|
|
* parent, and thus no copying is necessary.
|
|
|
|
*
|
|
|
|
* Returns: new buffer that spans the two source buffers
|
|
|
|
*/
|
|
|
|
// FIXME need to think about CoW and such...
|
2001-08-11 08:25:05 +00:00
|
|
|
GstBuffer *
|
|
|
|
gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
|
|
|
|
{
|
|
|
|
GstBuffer *newbuf;
|
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL);
|
|
|
|
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL);
|
|
|
|
|
2001-08-11 08:25:05 +00:00
|
|
|
// make sure buf1 has a lower address than buf2
|
|
|
|
if (buf1->data > buf2->data) {
|
|
|
|
GstBuffer *tmp = buf1;
|
2001-10-21 18:00:31 +00:00
|
|
|
//g_print ("swapping buffers\n");
|
2001-08-11 08:25:05 +00:00
|
|
|
buf1 = buf2;
|
|
|
|
buf2 = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the two buffers have the same parent and are adjacent
|
2001-09-10 19:46:01 +00:00
|
|
|
if (gst_buffer_is_span_fast(buf1,buf2)) {
|
2001-08-11 08:25:05 +00:00
|
|
|
// we simply create a subbuffer of the common parent
|
2001-10-17 10:21:27 +00:00
|
|
|
newbuf = gst_buffer_create_sub (buf1->parent, buf1->data - (buf1->parent->data) + offset, len);
|
2001-08-11 08:25:05 +00:00
|
|
|
}
|
2001-10-17 10:21:27 +00:00
|
|
|
else {
|
2001-10-21 18:00:31 +00:00
|
|
|
//g_print ("slow path taken in buffer_span\n");
|
2001-10-17 10:21:27 +00:00
|
|
|
// otherwise we simply have to brute-force copy the buffers
|
|
|
|
newbuf = gst_buffer_new ();
|
2001-08-11 08:25:05 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
// put in new size
|
|
|
|
newbuf->size = len;
|
|
|
|
// allocate space for the copy
|
|
|
|
newbuf->data = (guchar *)g_malloc(len);
|
|
|
|
// copy the first buffer's data across
|
|
|
|
memcpy(newbuf->data, buf1->data + offset, buf1->size - offset);
|
|
|
|
// copy the second buffer's data across
|
|
|
|
memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset));
|
|
|
|
|
|
|
|
if (newbuf->offset != -1)
|
|
|
|
newbuf->offset = buf1->offset + offset;
|
|
|
|
newbuf->timestamp = buf1->timestamp;
|
|
|
|
if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
|
|
|
|
else newbuf->maxage = buf1->maxage;
|
2001-08-11 08:25:05 +00:00
|
|
|
|
2001-10-17 10:21:27 +00:00
|
|
|
}
|
2001-08-11 08:25:05 +00:00
|
|
|
|
|
|
|
return newbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-09-04 04:34:32 +00:00
|
|
|
/**
|
|
|
|
* gst_buffer_merge:
|
|
|
|
* @buf1: first source buffer to merge
|
|
|
|
* @buf2: second source buffer to merge
|
|
|
|
*
|
|
|
|
* Create a new buffer that is the concatenation of the two source
|
|
|
|
* buffers. The original source buffers will not be modified or
|
|
|
|
* unref'd.
|
|
|
|
*
|
|
|
|
* Internally is nothing more than a specialized gst_buffer_span,
|
|
|
|
* so the same optimizations can occur.
|
|
|
|
*
|
|
|
|
* Returns: new buffer that's the concatenation of the source buffers
|
|
|
|
*/
|
2001-08-11 08:25:05 +00:00
|
|
|
GstBuffer *
|
|
|
|
gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
|
|
|
|
{
|
|
|
|
// we're just a specific case of the more general gst_buffer_span()
|
2001-10-17 10:21:27 +00:00
|
|
|
return gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
|
2001-08-11 08:25:05 +00:00
|
|
|
}
|