- Removed bufferpool code and move that to gstbuffer.c

Original commit message from CVS:
- Removed bufferpool code and move that to gstbuffer.c
- implemented refcounting on GstData
- implemented new buffer code based on Company's work in the EVENTS2 branch
- added boxed types for GstData/GstEvent/GstBuffer/GstBufferPool
- added refcounting to bufferpools and events
- use lockfree allocation for buffers
- simplified the clock, use lockfree allocation
- use GQueue in GstQueue for faster access to the tail element
- update core plugins to the new event API
This commit is contained in:
Wim Taymans 2002-07-08 19:22:02 +00:00
parent 74b6b732f1
commit fcb10a6c85
26 changed files with 761 additions and 1307 deletions

View file

@ -55,15 +55,16 @@ libgstreamer_la_SOURCES = \
$(GST_AUTOPLUG_SRC) \ $(GST_AUTOPLUG_SRC) \
gstbin.c \ gstbin.c \
gstbuffer.c \ gstbuffer.c \
gstbufferpool.c \
gstcaps.c \ gstcaps.c \
gstclock.c \ gstclock.c \
gstcpu.c \ gstcpu.c \
gstdata.c \
gstelement.c \ gstelement.c \
gstelementfactory.c \ gstelementfactory.c \
gstevent.c \ gstevent.c \
gstextratypes.c \ gstextratypes.c \
gstinfo.c \ gstinfo.c \
gstmemchunk.c \
gstpad.c \ gstpad.c \
gstpipeline.c \ gstpipeline.c \
gstplugin.c \ gstplugin.c \
@ -125,6 +126,7 @@ distclean-local:
libgstreamerincludedir = $(includedir)/gstreamer-@VERSION@/gst libgstreamerincludedir = $(includedir)/gstreamer-@VERSION@/gst
libgstreamerinclude_HEADERS = \ libgstreamerinclude_HEADERS = \
gst.h \ gst.h \
gstatomic.h \
gstconfig.h \ gstconfig.h \
gstmarshal.h \ gstmarshal.h \
gstenumtypes.h \ gstenumtypes.h \
@ -133,7 +135,6 @@ libgstreamerinclude_HEADERS = \
gstautoplug.h \ gstautoplug.h \
gstbin.h \ gstbin.h \
gstbuffer.h \ gstbuffer.h \
gstbufferpool.h \
gstcaps.h \ gstcaps.h \
gstclock.h \ gstclock.h \
gstcpu.h \ gstcpu.h \
@ -144,6 +145,7 @@ libgstreamerinclude_HEADERS = \
gstformat.h \ gstformat.h \
gstinfo.h \ gstinfo.h \
gstlog.h \ gstlog.h \
gstmemchunk.h \
gstpad.h \ gstpad.h \
gstpipeline.h \ gstpipeline.h \
gstplugin.h \ gstplugin.h \

View file

@ -266,8 +266,6 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf)
gst_pad_event_default (pad, event); gst_pad_event_default (pad, event);
break; break;
} }
gst_event_free (event);
return; return;
} }

View file

@ -323,7 +323,6 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
src->buffer_count = GST_EVENT_SEEK_OFFSET (event); src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
gst_event_free (event);
break; break;
} }
/* else we do a flush too */ /* else we do a flush too */
@ -333,6 +332,7 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
default: default:
break; break;
} }
gst_event_unref (event);
return TRUE; return TRUE;
} }
@ -680,8 +680,8 @@ gst_fakesrc_get(GstPad *pad)
if (src->last_message) if (src->last_message)
g_free (src->last_message); g_free (src->last_message);
src->last_message = g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %llu)", src->last_message = g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %llu) %p",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf)); GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (src), "last_message"); g_object_notify (G_OBJECT (src), "last_message");
} }

View file

@ -304,7 +304,7 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event)
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset)) if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
fseek(filesink->file, offset, SEEK_SET); fseek(filesink->file, offset, SEEK_SET);
gst_event_free (event); gst_event_unref (event);
break; break;
} }
case GST_EVENT_NEW_MEDIA: case GST_EVENT_NEW_MEDIA:

View file

@ -337,6 +337,10 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
#endif #endif
/* now unmap the memory */ /* now unmap the memory */
munmap(GST_BUFFER_DATA(buf),GST_BUFFER_MAXSIZE(buf)); munmap(GST_BUFFER_DATA(buf),GST_BUFFER_MAXSIZE(buf));
GST_BUFFER_DATA (buf) = NULL;
_gst_buffer_free (buf);
} }
static GstBuffer * static GstBuffer *
@ -371,7 +375,7 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
GST_BUFFER_OFFSET(buf) = offset; GST_BUFFER_OFFSET(buf) = offset;
GST_BUFFER_TIMESTAMP(buf) = -1LL; GST_BUFFER_TIMESTAMP(buf) = -1LL;
GST_BUFFER_POOL_PRIVATE(buf) = src; GST_BUFFER_POOL_PRIVATE(buf) = src;
GST_BUFFER_FREE_FUNC(buf) = gst_filesrc_free_parent_mmap; GST_BUFFER_FREE_FUNC(buf) = (GstDataFreeFunction) gst_filesrc_free_parent_mmap;
g_mutex_lock(src->map_regions_lock); g_mutex_lock(src->map_regions_lock);
g_tree_insert(src->map_regions,buf,buf); g_tree_insert(src->map_regions,buf,buf);
@ -716,7 +720,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
guint64 offset; guint64 offset;
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
return FALSE; goto error;
} }
offset = GST_EVENT_SEEK_OFFSET (event); offset = GST_EVENT_SEEK_OFFSET (event);
@ -724,24 +728,24 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
switch (GST_EVENT_SEEK_METHOD (event)) { switch (GST_EVENT_SEEK_METHOD (event)) {
case GST_SEEK_METHOD_SET: case GST_SEEK_METHOD_SET:
if (offset > src->filelen) if (offset > src->filelen)
return FALSE; goto error;
src->curoffset = offset; src->curoffset = offset;
GST_DEBUG(0, "seek set pending to %lld", src->curoffset); GST_DEBUG(0, "seek set pending to %lld", src->curoffset);
break; break;
case GST_SEEK_METHOD_CUR: case GST_SEEK_METHOD_CUR:
if (offset + src->curoffset > src->filelen) if (offset + src->curoffset > src->filelen)
return FALSE; goto error;
src->curoffset += offset; src->curoffset += offset;
GST_DEBUG(0, "seek cur pending to %lld", src->curoffset); GST_DEBUG(0, "seek cur pending to %lld", src->curoffset);
break; break;
case GST_SEEK_METHOD_END: case GST_SEEK_METHOD_END:
if (ABS (offset) > src->filelen) if (ABS (offset) > src->filelen)
return FALSE; goto error;
src->curoffset = src->filelen - ABS (offset); src->curoffset = src->filelen - ABS (offset);
GST_DEBUG(0, "seek end pending to %lld", src->curoffset); GST_DEBUG(0, "seek end pending to %lld", src->curoffset);
break; break;
default: default:
return FALSE; goto error;
break; break;
} }
g_object_notify (G_OBJECT (src), "offset"); g_object_notify (G_OBJECT (src), "offset");
@ -751,7 +755,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
} }
case GST_EVENT_SIZE: case GST_EVENT_SIZE:
if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
return FALSE; goto error;
} }
src->block_size = GST_EVENT_SIZE_VALUE (event); src->block_size = GST_EVENT_SIZE_VALUE (event);
g_object_notify (G_OBJECT (src), "blocksize"); g_object_notify (G_OBJECT (src), "blocksize");
@ -760,9 +764,13 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
src->need_flush = TRUE; src->need_flush = TRUE;
break; break;
default: default:
return FALSE; goto error;
break; break;
} }
gst_event_unref (event);
return TRUE; return TRUE;
error:
gst_event_unref (event);
return FALSE;
} }

View file

@ -377,7 +377,6 @@ init_post (void)
_gst_plugin_initialize (); _gst_plugin_initialize ();
_gst_event_initialize (); _gst_event_initialize ();
_gst_buffer_initialize (); _gst_buffer_initialize ();
_gst_buffer_pool_initialize ();
if (!_gst_registry_fixed) { if (!_gst_registry_fixed) {
/* don't override command-line options */ /* don't override command-line options */

View file

@ -24,44 +24,35 @@
#define GST_DEBUG_FORCE_DISABLE #define GST_DEBUG_FORCE_DISABLE
#include "gst_private.h" #include "gst_private.h"
#include "gstdata_private.h"
#include "gstbuffer.h" #include "gstbuffer.h"
#include "gstmemchunk.h"
/* #define MEMPROF */ #include "gstlog.h"
GType _gst_buffer_type; GType _gst_buffer_type;
GType _gst_buffer_pool_type;
static GMemChunk *_gst_buffer_chunk;
static GMutex *_gst_buffer_chunk_lock;
static gint _gst_buffer_live; static gint _gst_buffer_live;
static gint _gst_buffer_pool_live;
void static GstMemChunk *chunk;
_gst_buffer_initialize (void)
void
_gst_buffer_initialize (void)
{ {
int buffersize = sizeof(GstBuffer); _gst_buffer_type = g_boxed_type_register_static ("GstBuffer",
static const GTypeInfo buffer_info = { (GBoxedCopyFunc) gst_data_ref,
0, /* sizeof(class), */ (GBoxedFreeFunc) gst_data_unref);
NULL,
NULL,
NULL,
NULL,
NULL,
0, /* sizeof(object), */
0,
NULL,
NULL,
};
/* round up to the nearest 32 bytes for cache-line and other efficiencies */ _gst_buffer_pool_type = g_boxed_type_register_static ("GstBufferPool",
buffersize = (((buffersize-1) / 32) + 1) * 32; (GBoxedCopyFunc) gst_data_ref,
(GBoxedFreeFunc) gst_data_unref);
_gst_buffer_chunk = g_mem_chunk_new ("GstBuffer", buffersize,
buffersize * 32, G_ALLOC_AND_FREE);
_gst_buffer_chunk_lock = g_mutex_new ();
_gst_buffer_type = g_type_register_static (G_TYPE_INT, "GstBuffer", &buffer_info, 0);
_gst_buffer_live = 0; _gst_buffer_live = 0;
chunk = gst_mem_chunk_new ("GstBufferChunk", sizeof (GstBuffer), sizeof (GstBuffer) * 200, 0);
GST_INFO (GST_CAT_BUFFER, "Buffers are initialized now");
} }
/** /**
@ -72,53 +63,142 @@ _gst_buffer_initialize (void)
void void
gst_buffer_print_stats (void) gst_buffer_print_stats (void)
{ {
g_log (g_log_domain_gstreamer, G_LOG_LEVEL_INFO, g_log (g_log_domain_gstreamer, G_LOG_LEVEL_INFO,
"%d live buffer(s)", _gst_buffer_live); "%d live buffer(s)", _gst_buffer_live);
g_log (g_log_domain_gstreamer, G_LOG_LEVEL_INFO,
"%d live bufferpool(s)", _gst_buffer_pool_live);
} }
static void
_gst_buffer_free_to_pool (GstBuffer *buffer)
{
GstBufferPool *pool = buffer->pool;
buffer->pool->buffer_free (buffer->pool, buffer, buffer->pool->user_data);
gst_data_unref (GST_DATA (pool));
}
static void
_gst_buffer_sub_free (GstBuffer *buffer)
{
gst_data_unref (GST_DATA (buffer->pool_private));
GST_BUFFER_DATA (buffer) = NULL;
GST_BUFFER_SIZE (buffer) = 0;
_GST_DATA_DISPOSE (GST_DATA (buffer));
gst_mem_chunk_free (chunk, GST_DATA (buffer));
_gst_buffer_live--;
}
/**
* _gst_buffer_free:
* @buffer: a #GstBuffer to free
*
* Free the momory associated with the buffer including the buffer data,
* unless the GST_BUFFER_DONTFREE flags was set or the buffer data is NULL.
* This function is used by bufferpools.
*
* Returns: new #GstBuffer
*/
void
_gst_buffer_free (GstBuffer *buffer)
{
/* free our data */
if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) && GST_BUFFER_DATA (buffer))
g_free (GST_BUFFER_DATA (buffer));
/* set to safe values */
GST_BUFFER_DATA (buffer) = NULL;
GST_BUFFER_SIZE (buffer) = 0;
_GST_DATA_DISPOSE (GST_DATA (buffer));
gst_mem_chunk_free (chunk, GST_DATA (buffer));
_gst_buffer_live--;
}
/**
* _gst_buffer_copy:
* @buffer: a #GstBuffer to make a copy of
*
* Make a full newly allocated copy of the given buffer, data and all.
* This function is used by bufferpools.
*
* Returns: new #GstBuffer
*/
GstBuffer*
_gst_buffer_copy (GstBuffer *buffer)
{
GstBuffer *copy;
/* create a fresh new buffer */
copy = gst_buffer_new ();
/* we simply copy everything from our parent */
GST_BUFFER_DATA (copy) = g_memdup (GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer));
GST_BUFFER_SIZE (copy) = GST_BUFFER_SIZE (buffer);
GST_BUFFER_MAXSIZE (copy) = GST_BUFFER_MAXSIZE (buffer);
GST_BUFFER_TIMESTAMP (copy) = GST_BUFFER_TIMESTAMP (buffer);
GST_BUFFER_OFFSET (copy) = GST_BUFFER_OFFSET (buffer);
return copy;
}
static GstBuffer*
_gst_buffer_copy_to_pool (GstBuffer *buffer)
{
return buffer->pool->buffer_copy (buffer->pool, buffer, buffer->pool->user_data);
}
/** /**
* gst_buffer_new: * gst_buffer_new:
* *
* Creates a newly allocated buffer. * Creates a newly allocated buffer without any data.
* *
* Returns: new #GstBuffer * Returns: new #GstBuffer
*/ */
GstBuffer* GstBuffer*
gst_buffer_new (void) gst_buffer_new (void)
{ {
GstBuffer *buffer; GstBuffer *new;
g_mutex_lock (_gst_buffer_chunk_lock); new = gst_mem_chunk_alloc0 (chunk);
#ifdef MEMPROF
buffer = g_new0 (GstBuffer, 1);
#else
buffer = g_mem_chunk_alloc (_gst_buffer_chunk);
#endif
_gst_buffer_live++; _gst_buffer_live++;
g_mutex_unlock (_gst_buffer_chunk_lock);
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p",buffer);
GST_DATA_TYPE(buffer) = _gst_buffer_type; _GST_DATA_INIT (GST_DATA (new),
_gst_buffer_type,
0,
(GstDataFreeFunction) _gst_buffer_free,
(GstDataCopyFunction) _gst_buffer_copy);
buffer->lock = g_mutex_new (); GST_BUFFER_BUFFERPOOL (new) = NULL;
#ifdef HAVE_ATOMIC_H GST_BUFFER_POOL_PRIVATE (new) = NULL;
atomic_set (&buffer->refcount, 1);
#else
buffer->refcount = 1;
#endif
buffer->flags = 0;
buffer->data = NULL;
buffer->size = 0;
buffer->maxsize = 0;
buffer->offset = -1;
buffer->timestamp = 0;
buffer->parent = NULL;
buffer->pool = NULL;
buffer->pool_private = NULL;
buffer->free = NULL;
buffer->copy = NULL;
return buffer; return new;
}
/**
* gst_buffer_new_and_alloc:
*
* Creates a newly allocated buffer with data of the given size.
*
* Returns: new #GstBuffer
*/
GstBuffer*
gst_buffer_new_and_alloc (guint size)
{
GstBuffer *new;
new = gst_buffer_new ();
GST_BUFFER_DATA (new) = g_malloc (size);
GST_BUFFER_SIZE (new) = size;
return new;
} }
/** /**
@ -132,20 +212,22 @@ gst_buffer_new (void)
* Returns: new #GstBuffer * Returns: new #GstBuffer
*/ */
GstBuffer* GstBuffer*
gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size) gst_buffer_new_from_pool (GstBufferPool *pool, guint64 offset, guint size)
{ {
GstBuffer *buffer; GstBuffer *buffer;
g_return_val_if_fail (pool != NULL, NULL);
g_return_val_if_fail (pool->buffer_new != NULL, NULL);
buffer = pool->buffer_new (pool, offset, size, pool->user_data); buffer = pool->buffer_new (pool, offset, size, pool->user_data);
buffer->pool = pool; if (!buffer)
buffer->free = pool->buffer_free; return NULL;
buffer->copy = pool->buffer_copy;
GST_BUFFER_BUFFERPOOL (buffer) = pool;
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p (size %x, offset %x)", gst_data_ref (GST_DATA (pool));
buffer, pool, size, offset);
/* override the buffer refcount functions with those from the pool (if any) */
if (pool->buffer_free)
GST_DATA (buffer)->free = (GstDataFreeFunction) _gst_buffer_free_to_pool;
if (pool->buffer_copy)
GST_DATA (buffer)->copy = (GstDataCopyFunction) _gst_buffer_copy_to_pool;
return buffer; return buffer;
} }
@ -162,295 +244,77 @@ gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size)
* Returns: a new #GstBuffer * Returns: a new #GstBuffer
*/ */
GstBuffer* GstBuffer*
gst_buffer_create_sub (GstBuffer *parent, gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size)
guint32 offset,
guint32 size)
{ {
GstBuffer *buffer; GstBuffer *buffer;
gpointer buffer_data;
guint64 parent_offset;
g_return_val_if_fail (parent != NULL, NULL); g_return_val_if_fail (parent != NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(parent) > 0, NULL); g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (parent) > 0, NULL);
g_return_val_if_fail (size > 0, NULL); g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail ((offset+size) <= parent->size, NULL); g_return_val_if_fail (parent->size >= offset + size, NULL);
g_mutex_lock (_gst_buffer_chunk_lock); /* remember the data for the new buffer */
#ifdef MEMPROF buffer_data = parent->data + offset;
buffer = g_new0 (GstBuffer, 1); parent_offset = GST_BUFFER_OFFSET (parent);
#else /* make sure we're child not child from a child buffer */
buffer = g_mem_chunk_alloc (_gst_buffer_chunk); while (GST_BUFFER_FLAG_IS_SET (parent, GST_BUFFER_SUBBUFFER)) {
#endif parent = GST_BUFFER (parent->pool_private);
}
/* ref the real parent */
gst_data_ref (GST_DATA (parent));
/* make sure nobody overwrites data in the parent */
if (!GST_DATA_IS_READONLY (parent))
GST_DATA_FLAG_SET(parent, GST_DATA_READONLY);
/* create the new buffer */
buffer = gst_mem_chunk_alloc0 (chunk);
_gst_buffer_live++; _gst_buffer_live++;
g_mutex_unlock (_gst_buffer_chunk_lock);
GST_INFO (GST_CAT_BUFFER,"creating new subbuffer %p from parent %p (size %u, offset %u)",
buffer, parent, size, offset);
GST_DATA_TYPE(buffer) = _gst_buffer_type; /* make sure nobody overwrites data in the new buffer by setting the READONLY flag */
buffer->lock = g_mutex_new (); _GST_DATA_INIT (GST_DATA (buffer),
#ifdef HAVE_ATOMIC_H _gst_buffer_type,
atomic_set (&buffer->refcount, 1); GST_DATA_FLAG_SHIFT (GST_BUFFER_SUBBUFFER) |
#else GST_DATA_FLAG_SHIFT (GST_DATA_READONLY),
buffer->refcount = 1; (GstDataFreeFunction) _gst_buffer_sub_free,
#endif (GstDataCopyFunction) _gst_buffer_copy);
/* copy flags and type from parent, for lack of better */ GST_BUFFER_OFFSET (buffer) = parent_offset + offset;
buffer->flags = parent->flags; GST_BUFFER_TIMESTAMP (buffer) = -1;
GST_BUFFER_BUFFERPOOL (buffer) = NULL;
GST_BUFFER_POOL_PRIVATE (buffer) = parent;
/* set the data pointer, size, offset, and maxsize */ /* set the right values in the child */
buffer->data = parent->data + offset; buffer->data = buffer_data;
buffer->size = size; buffer->size = size;
buffer->maxsize = parent->size - offset;
/* deal with bogus/unknown offsets */
if (parent->offset != (guint32)-1)
buffer->offset = parent->offset + offset;
else
buffer->offset = (guint32)-1;
/* again, for lack of better, copy parent's timestamp */
buffer->timestamp = parent->timestamp;
buffer->maxage = parent->maxage;
/* if the parent buffer is a subbuffer itself, use its parent, a real buffer */
if (parent->parent != NULL)
parent = parent->parent;
/* set parentage and reference the parent */
buffer->parent = parent;
gst_buffer_ref (parent);
buffer->pool = NULL;
return buffer; return buffer;
} }
/* FIXME FIXME: how does this overlap with the newly-added gst_buffer_span() ??? */
/** /**
* gst_buffer_append: * gst_buffer_merge:
* @first: #GstBuffer to append to * @buf1: first source #GstBuffer to merge
* @second: #GstBuffer to append * @buf2: second source #GstBuffer to merge
* *
* Creates a new buffer by appending the data of second to the * Create a new buffer that is the concatenation of the two source
* existing data of first. This will grow first if first is unused elsewhere, * buffers. The original source buffers will not be modified or
* or create a newly allocated buffer if it is in use. * unref'd.
* second will not be changed.
* *
* Returns: a new #GstBuffer * Internally is nothing more than a specialized gst_buffer_span,
* so the same optimizations can occur.
*
* Returns: a new #GstBuffer that's the concatenation of the source buffers
*/ */
GstBuffer* GstBuffer*
gst_buffer_append (GstBuffer *first, gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2)
GstBuffer *second)
{ {
guint size; GstBuffer *result;
GstBuffer *newbuf = NULL; /* we're just a specific case of the more general gst_buffer_span() */
GstBuffer *buffer = NULL; result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
g_return_val_if_fail (first != NULL, NULL); return result;
g_return_val_if_fail (second != NULL, NULL);
g_return_val_if_fail (first->pool == NULL, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT (first) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT (second) > 0, NULL);
GST_INFO (GST_CAT_BUFFER,"appending buffers %p and %p",first, second);
GST_BUFFER_LOCK (first);
/* is the buffer used by anyone else ? */
if (GST_BUFFER_REFCOUNT (first) == 1 && first->parent == NULL
&& !GST_BUFFER_FLAG_IS_SET (first, GST_BUFFER_DONTFREE)) {
/* it's not, so we can realloc and expand the first buffer,
* filling it with the second's data */
size = first->size;
first->size += second->size;
first->data = g_realloc (first->data, first->size);
memcpy(first->data + size, second->data, second->size);
GST_BUFFER_UNLOCK (first);
buffer = first;
}
else {
/* the buffer is used, create a new one */
newbuf = gst_buffer_new ();
newbuf->size = first->size + second->size;
newbuf->data = g_malloc (newbuf->size);
memcpy (newbuf->data, first->data, first->size);
memcpy (newbuf->data + first->size, second->data, second->size);
GST_BUFFER_TIMESTAMP (newbuf) = GST_BUFFER_TIMESTAMP (first);
GST_BUFFER_UNLOCK (first);
gst_buffer_unref (first);
buffer = newbuf;
}
return buffer;
}
/**
* gst_buffer_destroy:
* @buffer: #GstBuffer to destroy
*
* Destroys the buffer. Actual data will be retained if DONTFREE is set.
*/
void
gst_buffer_destroy (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
GST_INFO (GST_CAT_BUFFER, "freeing %sbuffer %p",
(buffer->parent?"sub":""),
buffer);
/* free the data only if there is some, DONTFREE isn't set, and not sub */
if (GST_BUFFER_DATA (buffer) &&
!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_DONTFREE) &&
(buffer->parent == NULL)) {
/* if there's a free function, use it */
if (buffer->free != NULL) {
(buffer->free)(buffer);
} else {
g_free (GST_BUFFER_DATA (buffer));
}
}
/* unreference the parent if there is one */
if (buffer->parent != NULL)
gst_buffer_unref (buffer->parent);
g_mutex_free (buffer->lock);
/* g_print("freed mutex\n"); */
#ifdef GST_DEBUG_ENABLED
/* make it hard to reuse by mistake */
memset (buffer, 0, sizeof (GstBuffer));
#endif
/* remove it entirely from memory */
g_mutex_lock (_gst_buffer_chunk_lock);
#ifdef MEMPROF
g_free (buffer);
#else
g_mem_chunk_free (_gst_buffer_chunk,buffer);
#endif
_gst_buffer_live--;
g_mutex_unlock (_gst_buffer_chunk_lock);
}
/**
* gst_buffer_ref:
* @buffer: a #GstBuffer to reference
*
* Increments the reference count of this buffer.
*/
void
gst_buffer_ref (GstBuffer *buffer)
{
g_return_if_fail (buffer != NULL);
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);
#ifdef HAVE_ATOMIC_H
atomic_inc (&(buffer->refcount));
#else
GST_BUFFER_LOCK (buffer);
buffer->refcount++;
GST_BUFFER_UNLOCK (buffer);
#endif
}
/**
* gst_buffer_ref_by_count:
* @buffer: a #GstBuffer to reference
* @count: the number to increment the reference count by
*
* Increments the reference count 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
}
/**
* gst_buffer_unref:
* @buffer: a #GstBuffer to unreference
*
* Decrements the refcount of this buffer. If the refcount is
* zero, the buffer will be destroyed.
*/
void
gst_buffer_unref (GstBuffer *buffer)
{
gint zero;
g_return_if_fail (buffer != NULL);
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);
#ifdef HAVE_ATOMIC_H
zero = atomic_dec_and_test (&(buffer->refcount));
#else
GST_BUFFER_LOCK (buffer);
buffer->refcount--;
zero = (buffer->refcount == 0);
GST_BUFFER_UNLOCK (buffer);
#endif
/* if we ended up with the refcount at zero, destroy the buffer */
if (zero) {
gst_buffer_destroy (buffer);
}
}
/**
* gst_buffer_copy:
* @buffer: a #GstBuffer to make a copy of
*
* Make a full newly allocated copy of the given buffer, data and all.
*
* Returns: new #GstBuffer
*/
GstBuffer *
gst_buffer_copy (GstBuffer *buffer)
{
GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buffer) > 0, NULL);
/* if a copy function exists, use it, else copy the bytes */
if (buffer->copy != NULL) {
newbuf = (buffer->copy)(buffer);
} else {
/* allocate a new buffer */
newbuf = gst_buffer_new();
/* copy the absolute size */
newbuf->size = buffer->size;
/* allocate space for the copy */
newbuf->data = (guchar *)g_malloc (buffer->size);
/* copy the data straight across */
memcpy(newbuf->data,buffer->data,buffer->size);
/* 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;
/* since we just created a new buffer, so we have no ties to old stuff */
newbuf->parent = NULL;
newbuf->pool = NULL;
return newbuf;
} }
/** /**
@ -466,15 +330,16 @@ gst_buffer_copy (GstBuffer *buffer)
gboolean gboolean
gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2) gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
{ {
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, FALSE); g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf1) > 0, FALSE);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, FALSE); g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf2) > 0, FALSE);
return (buf1->parent && buf2->parent && /* it's only fast if we have subbuffers of the same parent */
(buf1->parent == buf2->parent) && return ((GST_BUFFER_FLAG_IS_SET (buf1, GST_BUFFER_SUBBUFFER)) &&
(GST_BUFFER_FLAG_IS_SET (buf2, GST_BUFFER_SUBBUFFER)) &&
(buf1->pool_private == buf2->pool_private) &&
((buf1->data + buf1->size) == buf2->data)); ((buf1->data + buf1->size) == buf2->data));
} }
/** /**
* gst_buffer_span: * gst_buffer_span:
* @buf1: first source #GstBuffer to merge * @buf1: first source #GstBuffer to merge
@ -493,76 +358,149 @@ gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2)
* *
* Returns: a new #GstBuffer that spans the two source buffers * Returns: a new #GstBuffer that spans the two source buffers
*/ */
/* FIXME need to think about CoW and such... */ GstBuffer*
GstBuffer *
gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len) gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len)
{ {
GstBuffer *newbuf; GstBuffer *newbuf;
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf1) > 0, NULL); g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf1) > 0, NULL);
g_return_val_if_fail (GST_BUFFER_REFCOUNT(buf2) > 0, NULL); g_return_val_if_fail (GST_BUFFER_REFCOUNT_VALUE (buf2) > 0, NULL);
g_return_val_if_fail (len > 0, NULL);
/* make sure buf1 has a lower address than buf2 */
if (buf1->data > buf2->data) {
GstBuffer *tmp = buf1;
/* g_print ("swapping buffers\n"); */
buf1 = buf2;
buf2 = tmp;
}
/* if the two buffers have the same parent and are adjacent */ /* if the two buffers have the same parent and are adjacent */
if (gst_buffer_is_span_fast(buf1,buf2)) { if (gst_buffer_is_span_fast(buf1,buf2)) {
GstBuffer *parent = GST_BUFFER (buf1->pool_private);
/* we simply create a subbuffer of the common parent */ /* we simply create a subbuffer of the common parent */
newbuf = gst_buffer_create_sub (buf1->parent, buf1->data - (buf1->parent->data) + offset, len); newbuf = gst_buffer_create_sub (parent, buf1->data - parent->data + offset, len);
} }
else { else {
/* g_print ("slow path taken in buffer_span\n"); */ GST_DEBUG (GST_CAT_BUFFER,"slow path taken while spanning buffers %p and %p", buffer, append);
/* otherwise we simply have to brute-force copy the buffers */ /* otherwise we simply have to brute-force copy the buffers */
newbuf = gst_buffer_new (); newbuf = gst_buffer_new_and_alloc (len);
/* copy relevant stuff from data struct of buffer1 */
GST_BUFFER_OFFSET (newbuf) = GST_BUFFER_OFFSET (buf1) + offset;
/* 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 */ /* copy the first buffer's data across */
memcpy(newbuf->data, buf1->data + offset, buf1->size - offset); memcpy (newbuf->data, buf1->data + offset, buf1->size - offset);
/* copy the second buffer's data across */ /* copy the second buffer's data across */
memcpy(newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset)); memcpy (newbuf->data + (buf1->size - offset), buf2->data, len - (buf1->size - offset));
if (newbuf->offset != (guint32)-1)
newbuf->offset = buf1->offset + offset;
newbuf->timestamp = buf1->timestamp;
if (buf2->maxage > buf1->maxage) newbuf->maxage = buf2->maxage;
else newbuf->maxage = buf1->maxage;
} }
return newbuf; return newbuf;
} }
static void
_gst_buffer_pool_free (GstBufferPool *pool)
{
_gst_data_free (GST_DATA (pool));
_gst_buffer_pool_live--;
}
/**
* gst_buffer_pool_new:
* @free: The function to free the bufferpool
* @copy: The function to copy the bufferpool
* @buffer_new: the function to create a new buffer from this pool
* @buffer_copy: the function to copy a buffer from this pool
* @buffer_free: the function to free a buffer in this pool
* @user_data: user data passed to buffer_* functions
*
* Create a new bufferpool with the given functions.
*
* Returns: a new GstBufferPool or NULL on error.
*/
GstBufferPool*
gst_buffer_pool_new (GstDataFreeFunction free,
GstDataCopyFunction copy,
GstBufferPoolBufferNewFunction buffer_new,
GstBufferPoolBufferCopyFunction buffer_copy,
GstBufferPoolBufferFreeFunction buffer_free,
gpointer user_data)
{
GstBufferPool *pool;
/* we need at least a buffer_new function */
g_return_val_if_fail (buffer_new != NULL, NULL);
pool = g_new0 (GstBufferPool, 1);
_gst_buffer_pool_live++;
GST_DEBUG (GST_CAT_BUFFER,"allocating new buffer pool %p\n", pool);
/* init data struct */
_GST_DATA_INIT (GST_DATA (pool),
_gst_buffer_pool_type,
0,
(free ? free : (GstDataFreeFunction) _gst_buffer_pool_free),
copy);
/* set functions */
pool->buffer_new = buffer_new;
pool->buffer_copy = buffer_copy;
pool->buffer_free = buffer_free;
pool->user_data = user_data;
return pool;
}
/** /**
* gst_buffer_merge: * gst_buffer_pool_is_active:
* @buf1: first source #GstBuffer to merge * @pool: the pool to query
* @buf2: second source #GstBuffer to merge
* *
* Create a new buffer that is the concatenation of the two source * Query if the geven bufferpool is active.
* buffers. The original source buffers will not be modified or
* unref'd.
* *
* Internally is nothing more than a specialized gst_buffer_span, * Returns: TRUE if the pool is active.
* so the same optimizations can occur.
*
* Returns: a new #GstBuffer that's the concatenation of the source buffers
*/ */
GstBuffer * gboolean
gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2) gst_buffer_pool_is_active (GstBufferPool *pool)
{ {
GstBuffer *result; return pool->active;
/* we're just a specific case of the more general gst_buffer_span() */ }
result = gst_buffer_span (buf1, 0, buf2, buf1->size + buf2->size);
/**
GST_BUFFER_TIMESTAMP (result) = GST_BUFFER_TIMESTAMP (buf1); * gst_buffer_pool_set_active:
* @pool: the pool to activate
return result; * @active: new status of the pool
*
* Set the given pool to the active or inactive state depending on the
* activate parameter
*/
void
gst_buffer_pool_set_active (GstBufferPool *pool, gboolean active)
{
pool->active = active;
}
/**
* gst_buffer_pool_set_user_data:
* @pool: the pool set the user data for
* @user_data: the user_data to set
*
* Set the given user data to the bufferpool
*/
void
gst_buffer_pool_set_user_data (GstBufferPool *pool, gpointer user_data)
{
pool->user_data = user_data;
}
/**
* gst_buffer_pool_get_user_data:
* @pool: the pool get the user data for
*
* Get the user data of the bufferpool
*
* Returns: the user data associated with this bufferpool
*/
gpointer
gst_buffer_pool_get_user_data (GstBufferPool *pool)
{
return pool->user_data;
}
/* FIXME */
GstBufferPool*
gst_buffer_pool_get_default (guint size, guint numbuffers)
{
return NULL;
} }

View file

@ -24,153 +24,150 @@
#ifndef __GST_BUFFER_H__ #ifndef __GST_BUFFER_H__
#define __GST_BUFFER_H__ #define __GST_BUFFER_H__
/*
* Define this to add file:line info to each GstBuffer showing
* the location in the source code where the buffer was created.
*
* #define GST_BUFFER_WHERE
*
* Then in gdb, you can `call gst_buffer_print_live()' to get a list
* of allocated GstBuffers and also the file:line where they were
* allocated.
*/
#include <gst/gstdata.h> #include <gst/gstdata.h>
#ifdef HAVE_CONFIG_H G_BEGIN_DECLS
#include "config.h"
#endif
#ifdef HAVE_ATOMIC_H typedef struct _GstBuffer GstBuffer;
#include <asm/atomic.h> typedef struct _GstBufferPool GstBufferPool;
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern GType _gst_buffer_type; extern GType _gst_buffer_type;
extern GType _gst_buffer_pool_type;
#define GST_TYPE_BUFFER (_gst_buffer_type) #define GST_TYPE_BUFFER (_gst_buffer_type)
#define GST_BUFFER(buf) ((GstBuffer *)(buf)) #define GST_TYPE_BUFFER_POOL (_gst_buffer_pool_type)
#define GST_IS_BUFFER(buf) (GST_DATA_TYPE(buf) == GST_TYPE_BUFFER)
#define GST_BUFFER_FLAGS(buf) (GST_BUFFER(buf)->flags) #define GST_BUFFER(buf) ((GstBuffer *)(buf))
#define GST_BUFFER_FLAG_IS_SET(buf,flag) (GST_BUFFER_FLAGS(buf) & (1<<(flag))) #define GST_BUFFER_POOL(pool) ((GstBufferPool *)(pool))
#define GST_BUFFER_FLAG_SET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) |= (1<<(flag))); }G_STMT_END #define GST_IS_BUFFER(buf) (GST_DATA_TYPE(buf) == GST_TYPE_BUFFER)
#define GST_BUFFER_FLAG_UNSET(buf,flag) G_STMT_START{ (GST_BUFFER_FLAGS(buf) &= ~(1<<(flag))); }G_STMT_END #define GST_IS_BUFFER_POOL(buf) (GST_DATA_TYPE(buf) == GST_TYPE_BUFFER_POOL)
#define GST_BUFFER_REFCOUNT(buf) GST_DATA_REFCOUNT(buf)
#define GST_BUFFER_REFCOUNT_VALUE(buf) GST_DATA_REFCOUNT_VALUE(buf)
#define GST_BUFFER_COPY_FUNC(buf) GST_DATA_COPY_FUNC(buf)
#define GST_BUFFER_FREE_FUNC(buf) GST_DATA_FREE_FUNC(buf)
#define GST_BUFFER_DATA(buf) (GST_BUFFER(buf)->data) #define GST_BUFFER_FLAGS(buf) GST_DATA_FLAGS(buf)
#define GST_BUFFER_SIZE(buf) (GST_BUFFER(buf)->size) #define GST_BUFFER_FLAG_IS_SET(buf,flag) GST_DATA_FLAG_IS_SET (buf, flag)
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset) #define GST_BUFFER_FLAG_SET(buf,flag) GST_DATA_FLAG_SET (buf, flag)
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize) #define GST_BUFFER_FLAG_UNSET(buf,flag) GST_DATA_FLAG_UNSET (buf, flag)
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
#define GST_BUFFER_MAXAGE(buf) (GST_BUFFER(buf)->maxage)
#define GST_BUFFER_BUFFERPOOL(buf) (GST_BUFFER(buf)->pool)
#define GST_BUFFER_PARENT(buf) (GST_BUFFER(buf)->parent)
#define GST_BUFFER_POOL_PRIVATE(buf) (GST_BUFFER(buf)->pool_private)
#define GST_BUFFER_COPY_FUNC(buf) (GST_BUFFER(buf)->copy)
#define GST_BUFFER_FREE_FUNC(buf) (GST_BUFFER(buf)->free)
#define GST_BUFFER_DATA(buf) (GST_BUFFER(buf)->data)
#define GST_BUFFER_SIZE(buf) (GST_BUFFER(buf)->size)
#define GST_BUFFER_MAXSIZE(buf) (GST_BUFFER(buf)->maxsize)
#define GST_BUFFER_TIMESTAMP(buf) (GST_BUFFER(buf)->timestamp)
#define GST_BUFFER_OFFSET(buf) (GST_BUFFER(buf)->offset)
#define GST_BUFFER_BUFFERPOOL(buf) (GST_BUFFER(buf)->pool)
#define GST_BUFFER_POOL_PRIVATE(buf) (GST_BUFFER(buf)->pool_private)
#define GST_BUFFER_LOCK(buf) (g_mutex_lock(GST_BUFFER(buf)->lock)) enum {
#define GST_BUFFER_TRYLOCK(buf) (g_mutex_trylock(GST_BUFFER(buf)->lock)) GST_BUFFER_READONLY = GST_DATA_FLAG_LAST,
#define GST_BUFFER_UNLOCK(buf) (g_mutex_unlock(GST_BUFFER(buf)->lock)) GST_BUFFER_SUBBUFFER,
typedef enum {
GST_BUFFER_READONLY,
GST_BUFFER_ORIGINAL, GST_BUFFER_ORIGINAL,
GST_BUFFER_DONTFREE, GST_BUFFER_DONTFREE,
GST_BUFFER_DISCONTINOUS, GST_BUFFER_DISCONTINOUS,
GST_BUFFER_KEY_UNIT, GST_BUFFER_KEY_UNIT,
GST_BUFFER_PREROLL, GST_BUFFER_PREROLL,
} GstBufferFlag;
GST_BUFFER_FLAG_LAST = GST_DATA_FLAG_LAST + 8,
typedef struct _GstBuffer GstBuffer;
typedef void (*GstBufferFreeFunc) (GstBuffer *buf);
typedef GstBuffer *(*GstBufferCopyFunc) (GstBuffer *srcbuf);
#include <gst/gstbufferpool.h>
struct _GstBuffer {
GstData data_type;
/* locking */
GMutex *lock;
/* refcounting */
#ifdef HAVE_ATOMIC_H
atomic_t refcount;
#define GST_BUFFER_REFCOUNT(buf) (atomic_read(&(GST_BUFFER((buf))->refcount)))
#else
int refcount;
#define GST_BUFFER_REFCOUNT(buf) (GST_BUFFER(buf)->refcount)
#endif
/* flags */
guint16 flags; /* boolean properties of buffer */
/* pointer to data, its size, and offset in original source if known */
guchar *data;
guint32 size;
guint32 maxsize;
guint32 offset;
/* timestamp */
gint64 timestamp; /* nanoseconds since zero */
gint64 maxage; /* FIXME: not used yet */
/* subbuffer support, who's my parent? */
GstBuffer *parent;
/* this is a pointer to the buffer pool (if any) */
GstBufferPool *pool;
gpointer pool_private;
/* utility function pointers, can override default */
GstBufferFreeFunc free; /* free the data associated with the buffer */
GstBufferCopyFunc copy; /* copy the data from one buffer to another */
}; };
/* initialisation */ struct _GstBuffer {
void _gst_buffer_initialize (void); GstData data_type;
/* creating a new buffer from scratch */
GstBuffer* gst_buffer_new (void);
GstBuffer* gst_buffer_new_from_pool (GstBufferPool *pool, guint32 offset, guint32 size);
/* creating a subbuffer */ /* pointer to data and its size */
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint32 offset, guint32 size); guint8 *data; /* pointer to buffer data */
guint size; /* size of buffer data */
guint64 maxsize; /* max size of this buffer */
/* refcounting */ guint64 timestamp;
void gst_buffer_ref (GstBuffer *buffer); guint64 offset;
void gst_buffer_ref_by_count (GstBuffer *buffer, gint count);
void gst_buffer_unref (GstBuffer *buffer);
/* destroying the buffer */ /* this is a pointer to the buffer pool (if any) */
void gst_buffer_destroy (GstBuffer *buffer); GstBufferPool *pool;
/* pointer to pool private data of parent buffer in case of a subbuffer */
gpointer pool_private;
};
/* copy buffer */ /* bufferpools */
GstBuffer* gst_buffer_copy (GstBuffer *buffer);
/* merge, span, or append two buffers, intelligently */ typedef GstBuffer* (*GstBufferPoolBufferNewFunction) (GstBufferPool *pool, guint64 offset, guint size, gpointer user_data);
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2); typedef GstBuffer* (*GstBufferPoolBufferCopyFunction) (GstBufferPool *pool, const GstBuffer *buffer, gpointer user_data);
GstBuffer* gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len); typedef void (*GstBufferPoolBufferFreeFunction) (GstBufferPool *pool, GstBuffer *buffer, gpointer user_data);
GstBuffer* gst_buffer_append (GstBuffer *buffer, GstBuffer *append);
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2); struct _GstBufferPool {
GstData data;
gboolean active;
GstBufferPoolBufferNewFunction buffer_new;
GstBufferPoolBufferCopyFunction buffer_copy;
GstBufferPoolBufferFreeFunction buffer_free;
gpointer user_data;
};
/*< private >*/
void _gst_buffer_initialize (void);
void _gst_buffer_free (GstBuffer *buf);
GstBuffer* _gst_buffer_copy (GstBuffer *buf);
void gst_buffer_print_stats (void); void gst_buffer_print_stats (void);
#ifdef __cplusplus /* refcounting */
} #define gst_buffer_ref(buf) GST_BUFFER (gst_data_ref (GST_DATA (buf)))
#endif /* __cplusplus */ #define gst_buffer_ref_by_count(buf,c) GST_BUFFER (gst_data_ref_by_count (GST_DATA (buf), c))
#define gst_buffer_unref(buf) gst_data_unref (GST_DATA (buf))
/* copy buffer */
#define gst_buffer_copy(buffer) GST_BUFFER (gst_data_copy (GST_DATA (buffer)))
#define gst_buffer_copy_on_write(buffer) GST_BUFFER (gst_data_copy_on_write (GST_DATA (buffer)))
#define gst_buffer_free(buffer) gst_data_free (GST_DATA (buffer))
/* allocation */
GstBuffer* gst_buffer_new (void);
GstBuffer* gst_buffer_new_and_alloc (guint size);
/* creating a new buffer from a pool */
GstBuffer* gst_buffer_new_from_pool (GstBufferPool *pool, guint64 offset, guint size);
/* creating a subbuffer */
GstBuffer* gst_buffer_create_sub (GstBuffer *parent, guint offset, guint size);
/* merge, span, or append two buffers, intelligently */
GstBuffer* gst_buffer_merge (GstBuffer *buf1, GstBuffer *buf2);
gboolean gst_buffer_is_span_fast (GstBuffer *buf1, GstBuffer *buf2);
GstBuffer* gst_buffer_span (GstBuffer *buf1, guint32 offset, GstBuffer *buf2, guint32 len);
/* creating a new buffer pools */
GstBufferPool* gst_buffer_pool_new (GstDataFreeFunction free,
GstDataCopyFunction copy,
GstBufferPoolBufferNewFunction buffer_create,
GstBufferPoolBufferCopyFunction buffer_copy,
GstBufferPoolBufferFreeFunction buffer_free,
gpointer user_data);
gboolean gst_buffer_pool_is_active (GstBufferPool *pool);
void gst_buffer_pool_set_active (GstBufferPool *pool, gboolean active);
GstBufferPool* gst_buffer_pool_get_default (guint size, guint numbuffers);
#define gst_buffer_pool_ref(buf) GST_BUFFER_POOL (gst_data_ref (GST_DATA (buf)))
#define gst_buffer_pool_ref_by_count(buf,c) GST_BUFFER_POOL (gst_data_ref_by_count (GST_DATA (buf), c))
#define gst_buffer_pool_unref(buf) gst_data_unref (GST_DATA (buf))
/* bufferpool operations */
#define gst_buffer_pool_copy(pool) GST_BUFFER_POOL (gst_data_copy (GST_DATA (pool)))
#define gst_buffer_pool_copy_on_write(pool) GST_BUFFER_POOL (gst_data_copy_on_write (GST_DATA (pool)))
#define gst_buffer_pool_free(pool) gst_data_free (GST_DATA (pool))
void gst_buffer_pool_set_user_data (GstBufferPool *pool, gpointer user_data);
gpointer gst_buffer_pool_get_user_data (GstBufferPool *pool);
G_END_DECLS
#endif /* __GST_BUFFER_H__ */ #endif /* __GST_BUFFER_H__ */

View file

@ -1,390 +0,0 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbufferpool.c: Buffer-pool operations
*
* 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.
*/
#include "gst_private.h"
#include "gstbuffer.h"
static GMutex *_default_pool_lock;
static GHashTable *_default_pools;
static GstBuffer* gst_buffer_pool_default_buffer_new (GstBufferPool *pool, gint64 location, gint size, gpointer user_data);
static void gst_buffer_pool_default_buffer_free (GstBuffer *buffer);
static void gst_buffer_pool_default_destroy_hook (GstBufferPool *pool, gpointer user_data);
typedef struct _GstBufferPoolDefault GstBufferPoolDefault;
struct _GstBufferPoolDefault {
GMemChunk *mem_chunk;
guint size;
};
void
_gst_buffer_pool_initialize (void)
{
_default_pools = g_hash_table_new(NULL,NULL);
_default_pool_lock = g_mutex_new ();
}
/**
* gst_buffer_pool_new:
*
* Create a new buffer pool.
*
* Returns: new buffer pool
*/
GstBufferPool*
gst_buffer_pool_new (void)
{
GstBufferPool *pool;
pool = g_new0 (GstBufferPool, 1);
GST_DEBUG (GST_CAT_BUFFER,"allocating new buffer pool %p", pool);
/* all hooks and user data set to NULL or 0 by g_new0 */
pool->lock = g_mutex_new ();
#ifdef HAVE_ATOMIC_H
atomic_set (&pool->refcount, 1);
#else
pool->refcount = 1;
#endif
return pool;
}
/**
* gst_buffer_pool_ref:
* @pool: the GstBufferPool to reference
*
* Increment the refcount of this buffer pool.
*/
void
gst_buffer_pool_ref (GstBufferPool *pool)
{
g_return_if_fail (pool != NULL);
GST_DEBUG(GST_CAT_BUFFER,"referencing buffer pool %p from %d", pool, GST_BUFFER_POOL_REFCOUNT(pool));
#ifdef HAVE_ATOMIC_H
atomic_inc (&(pool->refcount));
#else
g_return_if_fail (pool->refcount > 0);
GST_BUFFER_POOL_LOCK (pool);
pool->refcount++;
GST_BUFFER_POOL_UNLOCK (pool);
#endif
}
/**
* gst_buffer_pool_ref_by_count:
* @pool: the GstBufferPool to reference
* @count: a number
*
* Increment the refcount of this buffer pool by the given number.
*/
void
gst_buffer_pool_ref_by_count (GstBufferPool *pool, int count)
{
g_return_if_fail (pool != NULL);
g_return_if_fail (count >= 0);
#ifdef HAVE_ATOMIC_H
g_return_if_fail (atomic_read (&(pool->refcount)) > 0);
atomic_add (count, &(pool->refcount));
#else
g_return_if_fail (pool->refcount > 0);
GST_BUFFER_POOL_LOCK (pool);
pool->refcount += count;
GST_BUFFER_POOL_UNLOCK (pool);
#endif
}
/**
* gst_buffer_pool_unref:
* @pool: the GstBufferPool to unref
*
* Decrement the refcount of this buffer pool. If the refcount is
* zero and the pool is a default implementation,
* the buffer pool will be destroyed.
*/
void
gst_buffer_pool_unref (GstBufferPool *pool)
{
gint zero;
g_return_if_fail (pool != NULL);
GST_DEBUG(GST_CAT_BUFFER, "unreferencing buffer pool %p from %d", pool, GST_BUFFER_POOL_REFCOUNT(pool));
#ifdef HAVE_ATOMIC_H
g_return_if_fail (atomic_read (&(pool->refcount)) > 0);
zero = atomic_dec_and_test (&(pool->refcount));
#else
g_return_if_fail (pool->refcount > 0);
GST_BUFFER_POOL_LOCK (pool);
pool->refcount--;
zero = (pool->refcount == 0);
GST_BUFFER_POOL_UNLOCK (pool);
#endif
/* if we ended up with the refcount at zero, destroy the buffer pool*/
if (zero) {
gst_buffer_pool_destroy (pool);
}
}
/**
* gst_buffer_pool_set_buffer_new_function:
* @pool: the pool to set the buffer create function for
* @create: the create function
*
* Sets the function that will be called when a buffer is created
* from this pool.
*/
void
gst_buffer_pool_set_buffer_new_function (GstBufferPool *pool,
GstBufferPoolBufferNewFunction create)
{
g_return_if_fail (pool != NULL);
pool->buffer_new = create;
}
/**
* gst_buffer_pool_set_buffer_free_function:
* @pool: the pool to set the buffer free function for
* @destroy: the free function
*
* Sets the function that will be called when a buffer is freed
* from this pool.
*/
void
gst_buffer_pool_set_buffer_free_function (GstBufferPool *pool,
GstBufferFreeFunc destroy)
{
g_return_if_fail (pool != NULL);
pool->buffer_free = destroy;
}
/**
* gst_buffer_pool_set_buffer_copy_function:
* @pool: the pool to set the buffer copy function for
* @copy: the copy function
*
* Sets the function that will be called when a buffer is copied.
*
* You may use the default GstBuffer implementation (gst_buffer_copy).
*/
void
gst_buffer_pool_set_buffer_copy_function (GstBufferPool *pool,
GstBufferCopyFunc copy)
{
g_return_if_fail (pool != NULL);
pool->buffer_copy = copy;
}
/**
* gst_buffer_pool_set_destroy_hook:
* @pool: the pool to set the destroy hook for
* @destroy: the destroy function
*
* Sets the function that will be called before a bufferpool is destroyed.
* You can take care of you private_data here.
*/
void
gst_buffer_pool_set_destroy_hook (GstBufferPool *pool,
GstBufferPoolDestroyHook destroy)
{
g_return_if_fail (pool != NULL);
pool->destroy_hook = destroy;
}
/**
* gst_buffer_pool_set_user_data:
* @pool: the pool to set the user data for
* @user_data: any user data to be passed to the create/destroy buffer functions
* and the destroy hook
*
* You can put your private data here.
*/
void
gst_buffer_pool_set_user_data (GstBufferPool *pool,
gpointer user_data)
{
g_return_if_fail (pool != NULL);
pool->user_data = user_data;
}
/**
* gst_buffer_pool_get_user_data:
* @pool: the pool to get the user data from
*
* gets user data
*
* Returns: The user data of this bufferpool
*/
gpointer
gst_buffer_pool_get_user_data (GstBufferPool *pool)
{
g_return_val_if_fail (pool != NULL, NULL);
return pool->user_data;
}
/**
* gst_buffer_pool_destroy:
* @pool: the pool to destroy
*
* Frees the memory for this bufferpool, calls the destroy hook.
*/
void
gst_buffer_pool_destroy (GstBufferPool *pool)
{
g_return_if_fail (pool != NULL);
if (pool->destroy_hook)
pool->destroy_hook (pool, pool->user_data);
g_free(pool);
}
/*
* This is so we don't get messed up by GST_BUFFER_WHERE.
*/
static GstBuffer *
_pool_gst_buffer_copy (GstBuffer *buffer)
{ return gst_buffer_copy (buffer); }
/**
* gst_buffer_pool_get_default:
* @buffer_size: the number of bytes this buffer will store
* @pool_size: the default number of buffers to be preallocated
*
* Returns an instance of a buffer pool using the default
* implementation. If a buffer pool instance with the same buffer_size
* already exists this will be returned, otherwise a new instance will
* be created.
*
* Returns: an instance of GstBufferPool
*/
GstBufferPool*
gst_buffer_pool_get_default (guint buffer_size, guint pool_size)
{
GstBufferPool *pool;
GMemChunk *data_chunk;
guint real_buffer_size;
GstBufferPoolDefault *def;
/* round up to the nearest 32 bytes for cache-line and other efficiencies */
real_buffer_size = (((buffer_size-1) / 32) + 1) * 32;
/* check for an existing GstBufferPool with the same real_buffer_size */
/* (we won't worry about the pool_size) */
g_mutex_lock (_default_pool_lock);
pool = (GstBufferPool*)g_hash_table_lookup(_default_pools,GINT_TO_POINTER(real_buffer_size));
g_mutex_unlock (_default_pool_lock);
if (pool != NULL){
gst_buffer_pool_ref(pool);
return pool;
}
data_chunk = g_mem_chunk_new ("GstBufferPoolDefault", real_buffer_size,
real_buffer_size * pool_size, G_ALLOC_AND_FREE);
pool = gst_buffer_pool_new();
gst_buffer_pool_set_buffer_new_function (pool, gst_buffer_pool_default_buffer_new);
gst_buffer_pool_set_buffer_free_function (pool, gst_buffer_pool_default_buffer_free);
gst_buffer_pool_set_buffer_copy_function (pool, _pool_gst_buffer_copy);
gst_buffer_pool_set_destroy_hook (pool, gst_buffer_pool_default_destroy_hook);
def = g_new0 (GstBufferPoolDefault, 1);
def->size = buffer_size;
def->mem_chunk = data_chunk;
pool->user_data = def;
g_mutex_lock (_default_pool_lock);
g_hash_table_insert(_default_pools,GINT_TO_POINTER(real_buffer_size),pool);
g_mutex_unlock (_default_pool_lock);
GST_DEBUG(GST_CAT_BUFFER,"new buffer pool %p bytes:%d size:%d", pool, real_buffer_size, pool_size);
return pool;
}
static GstBuffer*
gst_buffer_pool_default_buffer_new (GstBufferPool *pool, gint64 location /*unused*/,
gint size /*unused*/, gpointer user_data)
{
GstBuffer *buffer;
GstBufferPoolDefault *def = (GstBufferPoolDefault*) user_data;
GMemChunk *data_chunk = def->mem_chunk;
gst_buffer_pool_ref(pool);
buffer = gst_buffer_new();
GST_INFO (GST_CAT_BUFFER,"creating new buffer %p from pool %p",buffer,pool);
g_mutex_lock (pool->lock);
GST_BUFFER_DATA(buffer) = g_mem_chunk_alloc(data_chunk);
g_mutex_unlock (pool->lock);
GST_BUFFER_SIZE(buffer) = def->size;
GST_BUFFER_MAXSIZE(buffer) = def->size;
return buffer;
}
static void
gst_buffer_pool_default_buffer_free (GstBuffer *buffer)
{
GstBufferPool *pool = buffer->pool;
GstBufferPoolDefault *def = (GstBufferPoolDefault*) pool->user_data;
GMemChunk *data_chunk = def->mem_chunk;
gpointer data = GST_BUFFER_DATA(buffer);
g_mutex_lock (pool->lock);
g_mem_chunk_free (data_chunk,data);
g_mutex_unlock (pool->lock);
buffer->pool = NULL;
gst_buffer_pool_unref(pool);
}
static void
gst_buffer_pool_default_destroy_hook (GstBufferPool *pool, gpointer user_data)
{
GstBufferPoolDefault *def = (GstBufferPoolDefault*) user_data;
GMemChunk *data_chunk = def->mem_chunk;
GST_DEBUG(GST_CAT_BUFFER,"destroying default buffer pool %p", pool);
g_mutex_free (pool->lock);
g_mem_chunk_reset(data_chunk);
g_free(data_chunk);
g_free(def);
}

View file

@ -1,99 +0,0 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstbufferpool.h: Header for buffer-pool management
*
* 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.
*/
#ifndef __GST_BUFFER_POOL_H__
#define __GST_BUFFER_POOL_H__
#include <gst/gstbuffer.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GST_BUFFER_POOL(pool) \
((GstBufferPool *)(pool))
#define GST_BUFFER_POOL_LOCK(pool) (g_mutex_lock(GST_BUFFER_POOL(pool)->lock))
#define GST_BUFFER_POOL_UNLOCK(pool) (g_mutex_unlock(GST_BUFFER_POOL(pool)->lock))
typedef struct _GstBufferPool GstBufferPool;
typedef GstBuffer* (*GstBufferPoolBufferNewFunction) (GstBufferPool *pool, gint64 location, gint size, gpointer user_data);
typedef void (*GstBufferPoolDestroyHook) (GstBufferPool *pool, gpointer user_data);
struct _GstBufferPool {
/* locking */
GMutex *lock;
/* refcounting */
#ifdef HAVE_ATOMIC_H
atomic_t refcount;
#define GST_BUFFER_POOL_REFCOUNT(pool) (atomic_read(&(GST_BUFFER_POOL((pool))->refcount)))
#else
int refcount;
#define GST_BUFFER_POOL_REFCOUNT(pool) (GST_BUFFER_POOL(pool)->refcount)
#endif
GstBufferPoolBufferNewFunction buffer_new;
GstBufferFreeFunc buffer_free;
GstBufferCopyFunc buffer_copy;
GstBufferPoolDestroyHook destroy_hook;
gpointer user_data;
};
void _gst_buffer_pool_initialize (void);
/* creating a new buffer pool from scratch */
GstBufferPool* gst_buffer_pool_new (void);
/* refcounting */
void gst_buffer_pool_ref (GstBufferPool *pool);
void gst_buffer_pool_ref_by_count (GstBufferPool *pool, int count);
void gst_buffer_pool_unref (GstBufferPool *pool);
/* setting create and destroy functions */
void gst_buffer_pool_set_buffer_new_function (GstBufferPool *pool,
GstBufferPoolBufferNewFunction create);
void gst_buffer_pool_set_buffer_free_function (GstBufferPool *pool,
GstBufferFreeFunc destroy);
void gst_buffer_pool_set_buffer_copy_function (GstBufferPool *pool,
GstBufferCopyFunc copy);
void gst_buffer_pool_set_destroy_hook (GstBufferPool *pool,
GstBufferPoolDestroyHook destroy);
void gst_buffer_pool_set_user_data (GstBufferPool *pool,
gpointer user_data);
gpointer gst_buffer_pool_get_user_data (GstBufferPool *pool);
/* destroying the buffer pool */
void gst_buffer_pool_destroy (GstBufferPool *pool);
/* a default buffer pool implementation */
GstBufferPool* gst_buffer_pool_get_default (guint buffer_size, guint pool_size);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_BUFFER_POOL_H__ */

View file

@ -26,12 +26,12 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstclock.h" #include "gstclock.h"
#include "gstlog.h"
#include "gstmemchunk.h"
#define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock)) #define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock))
static GMemChunk *_gst_clock_entries_chunk; static GstMemChunk *_gst_clock_entries_chunk;
static GMutex *_gst_clock_entries_chunk_lock;
static GList *_gst_clock_entries_pool;
static void gst_clock_class_init (GstClockClass *klass); static void gst_clock_class_init (GstClockClass *klass);
static void gst_clock_init (GstClock *clock); static void gst_clock_init (GstClock *clock);
@ -54,17 +54,10 @@ struct _GstClockEntry {
GstEntryStatus status; GstEntryStatus status;
GstClockCallback func; GstClockCallback func;
gpointer user_data; gpointer user_data;
GMutex *lock;
GCond *cond;
}; };
#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry)) #define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry))
#define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time) #define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time)
#define GST_CLOCK_ENTRY_LOCK(entry) (g_mutex_lock ((entry)->lock))
#define GST_CLOCK_ENTRY_UNLOCK(entry) (g_mutex_unlock ((entry)->lock))
#define GST_CLOCK_ENTRY_SIGNAL(entry) (g_cond_signal ((entry)->cond))
#define GST_CLOCK_ENTRY_WAIT(entry) (g_cond_wait (entry->cond, entry->lock))
#define GST_CLOCK_ENTRY_TIMED_WAIT(entry, time) (g_cond_timed_wait (entry->cond, entry->lock, (time)))
static GstClockEntry* static GstClockEntry*
gst_clock_entry_new (GstClockTime time, gst_clock_entry_new (GstClockTime time,
@ -72,20 +65,8 @@ gst_clock_entry_new (GstClockTime time,
{ {
GstClockEntry *entry; GstClockEntry *entry;
g_mutex_lock (_gst_clock_entries_chunk_lock); entry = gst_mem_chunk_alloc (_gst_clock_entries_chunk);
if (_gst_clock_entries_pool) {
entry = GST_CLOCK_ENTRY (_gst_clock_entries_pool->data);
_gst_clock_entries_pool = g_list_remove (_gst_clock_entries_pool, entry);
g_mutex_unlock (_gst_clock_entries_chunk_lock);
}
else {
entry = g_mem_chunk_alloc (_gst_clock_entries_chunk);
g_mutex_unlock (_gst_clock_entries_chunk_lock);
entry->lock = g_mutex_new ();
entry->cond = g_cond_new ();
}
entry->time = time; entry->time = time;
entry->func = func; entry->func = func;
entry->user_data = user_data; entry->user_data = user_data;
@ -93,6 +74,7 @@ gst_clock_entry_new (GstClockTime time,
return entry; return entry;
} }
/*
static gint static gint
clock_compare_func (gconstpointer a, clock_compare_func (gconstpointer a,
gconstpointer b) gconstpointer b)
@ -102,6 +84,7 @@ clock_compare_func (gconstpointer a,
return (entry1->time - entry2->time); return (entry1->time - entry2->time);
} }
*/
GType GType
gst_clock_get_type (void) gst_clock_get_type (void)
@ -141,11 +124,9 @@ gst_clock_class_init (GstClockClass *klass)
if (!g_thread_supported ()) if (!g_thread_supported ())
g_thread_init (NULL); g_thread_init (NULL);
_gst_clock_entries_chunk = g_mem_chunk_new ("GstClockEntries", _gst_clock_entries_chunk = gst_mem_chunk_new ("GstClockEntries",
sizeof (GstClockEntry), sizeof (GstClockEntry) * 32, sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
G_ALLOC_AND_FREE); G_ALLOC_AND_FREE);
_gst_clock_entries_chunk_lock = g_mutex_new ();
_gst_clock_entries_pool = NULL;
} }
static void static void
@ -384,10 +365,6 @@ gst_clock_wait_async_func (GstClock *clock, GstClockTime time,
entry = gst_clock_entry_new (time, func, user_data); entry = gst_clock_entry_new (time, func, user_data);
GST_LOCK (clock);
clock->entries = g_list_insert_sorted (clock->entries, entry, clock_compare_func);
GST_UNLOCK (clock);
return entry; return entry;
} }
@ -493,11 +470,6 @@ gst_clock_remove_notify_async (GstClock *clock, GstClockID id)
static void static void
gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data) gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data)
{ {
GstClockEntry *entry = (GstClockEntry *) id;
GST_CLOCK_ENTRY_LOCK (entry);
GST_CLOCK_ENTRY_SIGNAL (entry);
GST_CLOCK_ENTRY_UNLOCK (entry);
} }
/** /**
@ -516,8 +488,7 @@ gst_clock_wait_id (GstClock *clock, GstClockID id, GstClockTimeDiff *jitter)
{ {
GstClockReturn res = GST_CLOCK_TIMEOUT; GstClockReturn res = GST_CLOCK_TIMEOUT;
GstClockEntry *entry = (GstClockEntry *) id; GstClockEntry *entry = (GstClockEntry *) id;
GstClockTime current_real, current, target; GstClockTime current, target;
GTimeVal timeval;
GstClockTimeDiff this_jitter; GstClockTimeDiff this_jitter;
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR); g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR);
@ -525,27 +496,25 @@ gst_clock_wait_id (GstClock *clock, GstClockID id, GstClockTimeDiff *jitter)
current = gst_clock_get_time (clock); current = gst_clock_get_time (clock);
g_get_current_time (&timeval);
current_real = GST_TIMEVAL_TO_TIME (timeval);
GST_CLOCK_ENTRY_LOCK (entry);
entry->func = gst_clock_unlock_func; entry->func = gst_clock_unlock_func;
target = GST_CLOCK_ENTRY_TIME (entry) - current + current_real; target = GST_CLOCK_ENTRY_TIME (entry) - current;
GST_DEBUG (GST_CAT_CLOCK, "real_target %llu, current_real %llu, target %llu, now %llu", GST_DEBUG (GST_CAT_CLOCK, "real_target %llu, target %llu, now %llu",
target, current_real, GST_CLOCK_ENTRY_TIME (entry), current); target, GST_CLOCK_ENTRY_TIME (entry), current);
if (target > current_real) { if (((gint64)target) > 0) {
GST_TIME_TO_TIMEVAL (target, timeval); struct timeval tv;
GST_CLOCK_ENTRY_TIMED_WAIT (entry, &timeval);
GST_TIME_TO_TIMEVAL (target, tv);
select (0, NULL, NULL, NULL, &tv);
current = gst_clock_get_time (clock); current = gst_clock_get_time (clock);
this_jitter = current - GST_CLOCK_ENTRY_TIME (entry); this_jitter = current - GST_CLOCK_ENTRY_TIME (entry);
} }
else { else {
res = GST_CLOCK_EARLY; res = GST_CLOCK_EARLY;
this_jitter = target - current_real; this_jitter = target;
} }
GST_CLOCK_ENTRY_UNLOCK (entry);
if (jitter) if (jitter)
*jitter = this_jitter; *jitter = this_jitter;
@ -593,13 +562,7 @@ gst_clock_id_get_time (GstClockID id)
static void static void
gst_clock_free_entry (GstClock *clock, GstClockEntry *entry) gst_clock_free_entry (GstClock *clock, GstClockEntry *entry)
{ {
GST_LOCK (clock); gst_mem_chunk_free (_gst_clock_entries_chunk, entry);
clock->entries = g_list_remove (clock->entries, entry);
GST_UNLOCK (clock);
g_mutex_lock (_gst_clock_entries_chunk_lock);
_gst_clock_entries_pool = g_list_prepend (_gst_clock_entries_pool, entry);
g_mutex_unlock (_gst_clock_entries_chunk_lock);
} }
/** /**

View file

@ -24,23 +24,77 @@
#ifndef __GST_DATA_H__ #ifndef __GST_DATA_H__
#define __GST_DATA_H__ #define __GST_DATA_H__
#include <gst/gstobject.h> #include <glib-object.h>
#include <gst/gstatomic.h>
#ifdef __cplusplus G_BEGIN_DECLS
extern "C" {
#endif /* __cplusplus */
#define GST_DATA(data) (GstData*)(data) /* type */
#define GST_DATA_TYPE(data) (((GstData*)(data))->type) #define GST_DATA(data) ((GstData*)(data))
#define GST_DATA_TYPE(data) (GST_DATA(data)->type)
/* flags */
#define GST_DATA_FLAGS(data) (GST_DATA(data)->flags)
#define GST_DATA_FLAG_SHIFT(flag) (1<<(flag))
#define GST_DATA_FLAG_IS_SET(data,flag) (GST_DATA_FLAGS(data) & (1<<(flag)))
#define GST_DATA_FLAG_SET(data,flag) G_STMT_START{ (GST_DATA_FLAGS(data) |= (1<<(flag))); }G_STMT_END
#define GST_DATA_FLAG_UNSET(data,flag) G_STMT_START{ (GST_DATA_FLAGS(data) &= ~(1<<(flag))); }G_STMT_END
typedef struct _GstData GstData; typedef struct _GstData GstData;
typedef void (*GstDataFreeFunction) (GstData *data);
typedef GstData* (*GstDataCopyFunction) (const GstData *data);
typedef enum
{
GST_DATA_READONLY = 1,
/* insert more */
GST_DATA_FLAG_LAST = 8,
} GstDataFlags;
#define GST_DATA_IS_READONLY(data) (GST_DATA_FLAG_IS_SET((data), GST_DATA_READONLY))
/* refcount */
#define GST_DATA_REFCOUNT(data) ((GST_DATA(data))->refcount)
#define GST_DATA_REFCOUNT_VALUE(data) (GST_ATOMIC_INT_VALUE((&GST_DATA_REFCOUNT (data))))
#define GST_DATA_REFCOUNT_READ(data,value) (GST_ATOMIC_INT_READ(&(GST_DATA_REFCOUNT (data)),value)
/* copy/free functions */
#define GST_DATA_COPY_FUNC(data) (GST_DATA(data)->copy)
#define GST_DATA_FREE_FUNC(data) (GST_DATA(data)->free)
struct _GstData { struct _GstData {
GType type; GType type;
/* refcounting */
GstAtomicInt refcount;
guint16 flags;
/* utility function pointers, can override default */
GstDataFreeFunction free; /* free the data */
GstDataCopyFunction copy; /* free the data */
}; };
#ifdef __cplusplus /* function used by subclasses only */
} void _gst_data_init (GstData *data, GType type, guint16 flags,
#endif /* __cplusplus */ GstDataFreeFunction free,
GstDataCopyFunction copy);
void _gst_data_free (GstData *data);
GstData* _gst_data_copy (const GstData *data);
/* basic operations on data */
GstData* gst_data_copy (const GstData *data);
GstData* gst_data_copy_on_write (const GstData *data);
void gst_data_free (GstData *data);
/* reference counting */
GstData* gst_data_ref (GstData* data);
GstData* gst_data_ref_by_count (GstData* data, gint count);
void gst_data_unref (GstData* data);
G_END_DECLS
#endif /* __GST_DATA_H__ */ #endif /* __GST_DATA_H__ */

View file

@ -32,6 +32,7 @@
#include "gstscheduler.h" #include "gstscheduler.h"
#include "gstevent.h" #include "gstevent.h"
#include "gstutils.h" #include "gstutils.h"
#include "gstlog.h"
/* Element signals and args */ /* Element signals and args */
enum { enum {

View file

@ -20,44 +20,72 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include "gst/gstinfo.h"
#include "gst/gstevent.h"
#include <string.h> /* memcpy */ #include <string.h> /* memcpy */
#include "gstinfo.h"
#include "gstdata_private.h"
#include "gstevent.h"
#include "gstlog.h"
/* #define MEMPROF */ /* #define MEMPROF */
GType _gst_event_type; GType _gst_event_type;
static GMemChunk *_gst_event_chunk; static gint _gst_event_live;
static GMutex *_gst_event_chunk_lock;
void void
_gst_event_initialize (void) _gst_event_initialize (void)
{ {
gint eventsize = sizeof(GstEvent);
static const GTypeInfo event_info = {
0,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
0,
NULL,
NULL,
};
/* round up to the nearest 32 bytes for cache-line and other efficiencies */
eventsize = (((eventsize-1) / 32) + 1) * 32;
_gst_event_chunk = g_mem_chunk_new ("GstEvent", eventsize,
eventsize * 32, G_ALLOC_AND_FREE);
_gst_event_chunk_lock = g_mutex_new ();
/* register the type */ /* register the type */
_gst_event_type = g_type_register_static (G_TYPE_INT, "GstEvent", &event_info, 0); _gst_event_type = g_boxed_type_register_static ("GstEvent",
(GBoxedCopyFunc) gst_data_ref,
(GBoxedFreeFunc) gst_data_unref);
_gst_event_live = 0;
}
/**
* gst_buffer_print_stats:
*
* Logs statistics about live buffers (using g_log).
*/
void
gst_event_print_stats (void)
{
g_log (g_log_domain_gstreamer, G_LOG_LEVEL_INFO,
"%d live event(s)", _gst_event_live);
}
static GstEvent*
_gst_event_copy (GstEvent *event)
{
GstEvent *copy;
copy = g_new0(GstEvent, 1);
_gst_event_live++;
memcpy (copy, event, sizeof (GstEvent));
/* FIXME copy/ref additional fields */
return copy;
}
static void
_gst_event_free (GstEvent* event)
{
GST_INFO (GST_CAT_EVENT, "freeing event %p", event);
if (GST_EVENT_SRC (event)) {
gst_object_unref (GST_EVENT_SRC (event));
}
switch (GST_EVENT_TYPE (event)) {
default:
break;
}
_GST_DATA_DISPOSE (GST_DATA (event));
_gst_event_live--;
g_free (event);
} }
/** /**
@ -73,16 +101,16 @@ gst_event_new (GstEventType type)
{ {
GstEvent *event; GstEvent *event;
#ifndef MEMPROF
g_mutex_lock (_gst_event_chunk_lock);
event = g_mem_chunk_alloc (_gst_event_chunk);
g_mutex_unlock (_gst_event_chunk_lock);
#else
event = g_new0(GstEvent, 1); event = g_new0(GstEvent, 1);
#endif _gst_event_live++;
GST_INFO (GST_CAT_EVENT, "creating new event %p", event); GST_INFO (GST_CAT_EVENT, "creating new event %p", event);
GST_DATA_TYPE (event) = _gst_event_type; _GST_DATA_INIT (GST_DATA (event),
_gst_event_type,
0,
(GstDataFreeFunction) _gst_event_free,
(GstDataCopyFunction) _gst_event_copy);
GST_EVENT_TYPE (event) = type; GST_EVENT_TYPE (event) = type;
GST_EVENT_TIMESTAMP (event) = 0LL; GST_EVENT_TIMESTAMP (event) = 0LL;
GST_EVENT_SRC (event) = NULL; GST_EVENT_SRC (event) = NULL;
@ -90,61 +118,6 @@ gst_event_new (GstEventType type)
return event; return event;
} }
/**
* gst_event_copy:
* @event: The event to copy
*
* Copy the event
*
* Returns: A copy of the event.
*/
GstEvent*
gst_event_copy (GstEvent *event)
{
GstEvent *copy;
#ifndef MEMPROF
g_mutex_lock (_gst_event_chunk_lock);
copy = g_mem_chunk_alloc (_gst_event_chunk);
g_mutex_unlock (_gst_event_chunk_lock);
#else
copy = g_new0(GstEvent, 1);
#endif
memcpy (copy, event, sizeof (GstEvent));
/* FIXME copy/ref additional fields */
return copy;
}
/**
* gst_event_free:
* @event: The event to free
*
* Free the given element.
*/
void
gst_event_free (GstEvent* event)
{
GST_INFO (GST_CAT_EVENT, "freeing event %p", event);
g_mutex_lock (_gst_event_chunk_lock);
if (GST_EVENT_SRC (event)) {
gst_object_unref (GST_EVENT_SRC (event));
}
switch (GST_EVENT_TYPE (event)) {
default:
break;
}
#ifndef MEMPROF
g_mem_chunk_free (_gst_event_chunk, event);
#else
g_free (event);
#endif
g_mutex_unlock (_gst_event_chunk_lock);
}
/** /**
* gst_event_new_seek: * gst_event_new_seek:
* @type: The type of the seek event * @type: The type of the seek event
@ -160,6 +133,7 @@ gst_event_new_seek (GstSeekType type, gint64 offset)
GstEvent *event; GstEvent *event;
event = gst_event_new (GST_EVENT_SEEK); event = gst_event_new (GST_EVENT_SEEK);
GST_EVENT_SEEK_TYPE (event) = type; GST_EVENT_SEEK_TYPE (event) = type;
GST_EVENT_SEEK_OFFSET (event) = offset; GST_EVENT_SEEK_OFFSET (event) = offset;
@ -235,12 +209,22 @@ gst_event_discont_get_value (GstEvent *event, GstFormat format, gint64 *value)
} }
/**
* gst_event_new_size:
* @format: The format of the size value
* @value: The value of the size event
*
* Create a new size event with the given values.
*
* Returns: The new size event.
*/
GstEvent* GstEvent*
gst_event_new_size (GstFormat format, gint64 value) gst_event_new_size (GstFormat format, gint64 value)
{ {
GstEvent *event; GstEvent *event;
event = gst_event_new (GST_EVENT_SIZE); event = gst_event_new (GST_EVENT_SIZE);
GST_EVENT_SIZE_FORMAT (event) = format; GST_EVENT_SIZE_FORMAT (event) = format;
GST_EVENT_SIZE_VALUE (event) = value; GST_EVENT_SIZE_VALUE (event) = value;

View file

@ -26,8 +26,8 @@
#include <gst/gsttypes.h> #include <gst/gsttypes.h>
#include <gst/gstdata.h> #include <gst/gstdata.h>
#include <gst/gstcaps.h>
#include <gst/gstformat.h> #include <gst/gstformat.h>
#include <gst/gstobject.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -123,10 +123,17 @@ struct _GstEvent {
}; };
void _gst_event_initialize (void); void _gst_event_initialize (void);
void gst_event_print_stats (void);
GstEvent* gst_event_new (GstEventType type); GstEvent* gst_event_new (GstEventType type);
GstEvent* gst_event_copy (GstEvent *event);
void gst_event_free (GstEvent *event); /* refcounting */
#define gst_event_ref(ev) gst_data_ref (GST_DATA (ev))
#define gst_event_ref_by_count(ev,c) gst_data_ref_by_count (GST_DATA (ev), c)
#define gst_event_unref(ev) gst_data_unref (GST_DATA (ev))
/* copy buffer */
#define gst_event_copy(ev) GST_EVENT (gst_data_copy (GST_DATA (ev)))
/* seek event */ /* seek event */
GstEvent* gst_event_new_seek (GstSeekType type, gint64 offset); GstEvent* gst_event_new_seek (GstSeekType type, gint64 offset);

View file

@ -30,6 +30,7 @@
#include "gstbin.h" #include "gstbin.h"
#include "gstscheduler.h" #include "gstscheduler.h"
#include "gstevent.h" #include "gstevent.h"
#include "gstlog.h"
enum { enum {
TEMPL_PAD_CREATED, TEMPL_PAD_CREATED,
@ -1045,7 +1046,6 @@ gst_pad_try_set_caps_func (GstRealPad *pad, GstCaps *caps, gboolean notify)
GstPadTemplate *template; GstPadTemplate *template;
GstElement *parent = GST_PAD_PARENT (pad); GstElement *parent = GST_PAD_PARENT (pad);
/* thomas: FIXME: is this the right result to return ? */
g_return_val_if_fail (pad != NULL, GST_PAD_CONNECT_REFUSED); g_return_val_if_fail (pad != NULL, GST_PAD_CONNECT_REFUSED);
g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_CONNECT_REFUSED); g_return_val_if_fail (GST_IS_PAD (pad), GST_PAD_CONNECT_REFUSED);
@ -1856,10 +1856,7 @@ gst_pad_push (GstPad *pad, GstBuffer *buf)
} }
/* clean up the mess here */ /* clean up the mess here */
if (buf != NULL) { if (buf != NULL) {
if (GST_IS_BUFFER (buf)) gst_data_unref (GST_DATA (buf));
gst_buffer_unref (buf);
else
gst_event_free (GST_EVENT (buf));
} }
} }
#endif #endif
@ -2341,7 +2338,9 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *even
/* for all pads in the opposite direction that are connected */ /* for all pads in the opposite direction that are connected */
if (GST_PAD_DIRECTION (eventpad) != GST_PAD_DIRECTION (pad) && GST_PAD_IS_CONNECTED (eventpad)) { if (GST_PAD_DIRECTION (eventpad) != GST_PAD_DIRECTION (pad) && GST_PAD_IS_CONNECTED (eventpad)) {
if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) { if (GST_PAD_DIRECTION (eventpad) == GST_PAD_SRC) {
gst_pad_push (eventpad, GST_BUFFER (gst_event_copy (event))); /* increase the refcount */
gst_event_ref (event);
gst_pad_push (eventpad, GST_BUFFER (event));
} }
else { else {
GstPad *peerpad = GST_PAD_CAST (GST_RPAD_PEER (eventpad)); GstPad *peerpad = GST_PAD_CAST (GST_RPAD_PEER (eventpad));
@ -2352,6 +2351,7 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *even
} }
} }
} }
gst_event_unref (event);
return TRUE; return TRUE;
} }
@ -2398,17 +2398,17 @@ gst_pad_event_default (GstPad *pad, GstEvent *event)
/** /**
* gst_pad_dispatcher: * gst_pad_dispatcher:
* @pad: the pad to dispatch * @pad: the pad to dispatch
* @dispatch: the GstDispatcherFunc to call * @dispatch: the GstDispatcherFunction to call
* @data: data passed to the dispatcher function. * @data: data passed to the dispatcher function.
* *
* Invoke the given dispatcher function on all internally connected * Invoke the given dispatcher function on all internally connected
* pads of the given pad. The GstPadDispatcherFunc should return * pads of the given pad. The GstPadDispatcherFunction should return
* TRUE when no further pads need to be preocessed. * TRUE when no further pads need to be preocessed.
* *
* Returns: TRUE if one of the dispatcher functions returned TRUE. * Returns: TRUE if one of the dispatcher functions returned TRUE.
*/ */
gboolean gboolean
gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunc dispatch, gpointer data) gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch, gpointer data)
{ {
gboolean res = FALSE; gboolean res = FALSE;
GList *int_pads, *orig; GList *int_pads, *orig;
@ -2464,6 +2464,7 @@ gst_pad_send_event (GstPad *pad, GstEvent *event)
success = GST_RPAD_EVENTFUNC (pad) (pad, event); success = GST_RPAD_EVENTFUNC (pad) (pad, event);
else { else {
GST_DEBUG(GST_CAT_EVENT, "there's no event function for pad %s:%s", GST_DEBUG_PAD_NAME (pad)); GST_DEBUG(GST_CAT_EVENT, "there's no event function for pad %s:%s", GST_DEBUG_PAD_NAME (pad));
gst_event_unref (event);
} }
return success; return success;
@ -2514,7 +2515,7 @@ gst_pad_convert_default (GstPad *pad,
data.dest_format = dest_format; data.dest_format = dest_format;
data.dest_value = dest_value; data.dest_value = dest_value;
return gst_pad_dispatcher (pad, (GstPadDispatcherFunc) gst_pad_convert_dispatcher, &data); return gst_pad_dispatcher (pad, (GstPadDispatcherFunction) gst_pad_convert_dispatcher, &data);
} }
/** /**
@ -2594,7 +2595,7 @@ gst_pad_query_default (GstPad *pad, GstPadQueryType type,
data.format = format; data.format = format;
data.value = value; data.value = value;
return gst_pad_dispatcher (pad, (GstPadDispatcherFunc) gst_pad_query_dispatcher, &data); return gst_pad_dispatcher (pad, (GstPadDispatcherFunction) gst_pad_query_dispatcher, &data);
} }
/** /**

View file

@ -32,9 +32,7 @@
#include <gst/gstevent.h> #include <gst/gstevent.h>
#ifdef __cplusplus G_BEGIN_DECLS
extern "C" {
#endif /* __cplusplus */
extern GType _gst_pad_type; extern GType _gst_pad_type;
extern GType _gst_real_pad_type; extern GType _gst_real_pad_type;
@ -142,7 +140,7 @@ typedef GstPadConnectReturn (*GstPadConnectFunction) (GstPad *pad, GstCaps *cap
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad, GstCaps *caps); typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad, GstCaps *caps);
typedef GstBufferPool* (*GstPadBufferPoolFunction) (GstPad *pad); typedef GstBufferPool* (*GstPadBufferPoolFunction) (GstPad *pad);
typedef gboolean (*GstPadDispatcherFunc) (GstPad *pad, gpointer data); typedef gboolean (*GstPadDispatcherFunction) (GstPad *pad, gpointer data);
typedef enum { typedef enum {
GST_PAD_UNKNOWN, GST_PAD_UNKNOWN,
@ -436,7 +434,7 @@ gboolean gst_pad_query_default (GstPad *pad, GstPadQueryType type,
GList* gst_pad_get_internal_connections (GstPad *pad); GList* gst_pad_get_internal_connections (GstPad *pad);
GList* gst_pad_get_internal_connections_default (GstPad *pad); GList* gst_pad_get_internal_connections_default (GstPad *pad);
gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunc dispatch, gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunction dispatch,
gpointer data); gpointer data);
@ -467,9 +465,7 @@ xmlNodePtr gst_pad_ghost_save_thyself (GstPad *pad,
GstElement *bin, GstElement *bin,
xmlNodePtr parent); xmlNodePtr parent);
#ifdef __cplusplus G_END_DECLS
}
#endif /* __cplusplus */
#endif /* __GST_PAD_H__ */ #endif /* __GST_PAD_H__ */

View file

@ -22,6 +22,7 @@
/* #define DEBUG_ENABLED */ /* #define DEBUG_ENABLED */
/* #define STATUS_ENABLED */ /* #define STATUS_ENABLED */
#ifdef STATUS_ENABLED #ifdef STATUS_ENABLED
#define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue)) #define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
#else #else
@ -36,6 +37,7 @@
#include "gstqueue.h" #include "gstqueue.h"
#include "gstscheduler.h" #include "gstscheduler.h"
#include "gstevent.h" #include "gstevent.h"
#include "gstlog.h"
GstElementDetails gst_queue_details = { GstElementDetails gst_queue_details = {
"Queue", "Queue",
@ -239,6 +241,7 @@ gst_queue_init (GstQueue *queue)
queue->not_empty = g_cond_new (); queue->not_empty = g_cond_new ();
queue->not_full = g_cond_new (); queue->not_full = g_cond_new ();
queue->events = g_async_queue_new(); queue->events = g_async_queue_new();
queue->queue = g_queue_new ();
GST_DEBUG_ELEMENT (GST_CAT_THREAD, queue, "initialized queue's not_empty & not_full conditions"); GST_DEBUG_ELEMENT (GST_CAT_THREAD, queue, "initialized queue's not_empty & not_full conditions");
} }
@ -250,6 +253,8 @@ gst_queue_dispose (GObject *object)
g_mutex_free (queue->qlock); g_mutex_free (queue->qlock);
g_cond_free (queue->not_empty); g_cond_free (queue->not_empty);
g_cond_free (queue->not_full); g_cond_free (queue->not_full);
gst_queue_locked_flush (queue);
g_queue_free (queue->queue);
g_async_queue_unref(queue->events); g_async_queue_unref(queue->events);
@ -267,28 +272,25 @@ gst_queue_get_bufferpool (GstPad *pad)
} }
static void static void
gst_queue_cleanup_buffers (gpointer data, const gpointer user_data) gst_queue_cleanup_data (gpointer data, const gpointer user_data)
{ {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, user_data, "cleaning buffer %p", data); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, user_data, "cleaning buffer %p", data);
if (GST_IS_BUFFER (data)) { gst_data_unref (GST_DATA (data));
gst_buffer_unref (GST_BUFFER (data));
}
else {
gst_event_free (GST_EVENT (data));
}
} }
static void static void
gst_queue_locked_flush (GstQueue *queue) gst_queue_locked_flush (GstQueue *queue)
{ {
g_list_foreach (queue->queue, gst_queue_cleanup_buffers, gpointer data;
(gpointer) queue);
g_list_free (queue->queue); while ((data = g_queue_pop_head (queue->queue))) {
gst_queue_cleanup_data (data, (gpointer) queue);
queue->queue = NULL; }
queue->level_buffers = 0;
queue->timeval = NULL; queue->timeval = NULL;
queue->level_buffers = 0;
queue->level_bytes = 0;
queue->level_time = 0LL;
/* make sure any pending buffers to be added are flushed too */ /* make sure any pending buffers to be added are flushed too */
queue->flush = TRUE; queue->flush = TRUE;
} }
@ -364,25 +366,28 @@ restart:
} }
/* otherwise we have to push a buffer off the other end */ /* otherwise we have to push a buffer off the other end */
else { else {
GList *front; gpointer front;
GstBuffer *leakbuf; GstBuffer *leakbuf;
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end"); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end");
front = queue->queue;
leakbuf = (GstBuffer *)(front->data); front = g_queue_pop_head (queue->queue);
if (GST_IS_EVENT (leakbuf)) leakbuf = (GstBuffer *)(front);
if (GST_IS_EVENT (leakbuf)) {
fprintf(stderr, "Error: queue [%s] leaked an event, type:%d\n", fprintf(stderr, "Error: queue [%s] leaked an event, type:%d\n",
GST_ELEMENT_NAME(GST_ELEMENT(queue)), GST_ELEMENT_NAME(GST_ELEMENT(queue)),
GST_EVENT_TYPE(GST_EVENT(leakbuf))); GST_EVENT_TYPE(GST_EVENT(leakbuf)));
}
queue->level_buffers--; queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf); queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
gst_buffer_unref(leakbuf); gst_data_unref (GST_DATA (leakbuf));
queue->queue = g_list_remove_link (queue->queue, front);
g_list_free (front);
} }
} }
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "pre full wait, level:%d/%d", GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "pre full wait, level:%d/%d",
queue->level_buffers, queue->size_buffers); queue->level_buffers, queue->size_buffers);
while (queue->level_buffers == queue->size_buffers) { while (queue->level_buffers == queue->size_buffers) {
/* if there's a pending state change for this queue or its manager, switch */ /* if there's a pending state change for this queue or its manager, switch */
/* back to iterator so bottom half of state change executes */ /* back to iterator so bottom half of state change executes */
@ -404,8 +409,7 @@ restart:
/* this means the other end is shut down */ /* this means the other end is shut down */
/* try to signal to resolve the error */ /* try to signal to resolve the error */
if (!queue->may_deadlock) { if (!queue->may_deadlock) {
if (GST_IS_BUFFER (buf)) gst_buffer_unref (buf); gst_data_unref (GST_DATA (buf));
else gst_event_free (GST_EVENT (buf));
g_mutex_unlock (queue->qlock); g_mutex_unlock (queue->qlock);
gst_element_error (GST_ELEMENT (queue), "deadlock found, source pad elements are shut down"); gst_element_error (GST_ELEMENT (queue), "deadlock found, source pad elements are shut down");
return; return;
@ -429,17 +433,18 @@ restart:
} }
/* put the buffer on the tail of the list */ /* put the buffer on the tail of the list */
queue->queue = g_list_append (queue->queue, buf); g_queue_push_tail (queue->queue, buf);
queue->level_buffers++; queue->level_buffers++;
queue->level_bytes += GST_BUFFER_SIZE(buf); queue->level_bytes += GST_BUFFER_SIZE(buf);
/* this assertion _has_ to hold */
g_assert (queue->queue->length == queue->level_buffers);
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "(%s:%s)+ level:%d/%d", GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "(%s:%s)+ level:%d/%d",
GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(pad),
queue->level_buffers, queue->size_buffers); queue->level_buffers, queue->size_buffers);
/* this assertion _has_ to hold */
/* g_assert (g_list_length (queue->queue) == queue->level_buffers); */
/* reader waiting on an empty queue */ /* reader waiting on an empty queue */
reader = queue->reader; reader = queue->reader;
@ -457,7 +462,7 @@ gst_queue_get (GstPad *pad)
{ {
GstQueue *queue; GstQueue *queue;
GstBuffer *buf = NULL; GstBuffer *buf = NULL;
GList *front; gpointer front;
gboolean writer; gboolean writer;
g_assert(pad != NULL); g_assert(pad != NULL);
@ -467,8 +472,6 @@ gst_queue_get (GstPad *pad)
queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
restart: restart:
/* have to lock for thread-safety */ /* have to lock for thread-safety */
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld", pthread_self ()); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld", pthread_self ());
@ -505,12 +508,14 @@ restart:
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "WARNING: multiple readers on queue!"); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "WARNING: multiple readers on queue!");
queue->reader = TRUE; queue->reader = TRUE;
if (queue->block_timeout > -1){ //if (queue->block_timeout > -1){
if (FALSE) {
GTimeVal timeout; GTimeVal timeout;
g_get_current_time(&timeout); g_get_current_time(&timeout);
g_time_val_add(&timeout, queue->block_timeout); g_time_val_add(&timeout, queue->block_timeout);
if (!g_cond_timed_wait (queue->not_empty, queue->qlock, &timeout)){ if (!g_cond_timed_wait (queue->not_empty, queue->qlock, &timeout)){
g_mutex_unlock (queue->qlock); g_mutex_unlock (queue->qlock);
g_warning ("filler");
return GST_BUFFER(gst_event_new_filler()); return GST_BUFFER(gst_event_new_filler());
} }
} }
@ -522,11 +527,9 @@ restart:
} }
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "post empty wait, level:%d/%d", queue->level_buffers, queue->size_buffers); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "post empty wait, level:%d/%d", queue->level_buffers, queue->size_buffers);
front = queue->queue; front = g_queue_pop_head (queue->queue);
buf = (GstBuffer *)(front->data); buf = (GstBuffer *)(front);
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "retrieved buffer %p from queue", buf); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "retrieved buffer %p from queue", buf);
queue->queue = g_list_remove_link (queue->queue, front);
g_list_free (front);
queue->level_buffers--; queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(buf); queue->level_bytes -= GST_BUFFER_SIZE(buf);
@ -536,7 +539,7 @@ restart:
queue->level_buffers, queue->size_buffers); queue->level_buffers, queue->size_buffers);
/* this assertion _has_ to hold */ /* this assertion _has_ to hold */
/* g_assert (g_list_length (queue->queue) == queue->level_buffers); */ g_assert (queue->queue->length == queue->level_buffers);
/* writer waiting on a full queue */ /* writer waiting on a full queue */
writer = queue->writer; writer = queue->writer;
@ -640,11 +643,7 @@ gst_queue_change_state (GstElement *element)
new_state = GST_STATE_PENDING (element); new_state = GST_STATE_PENDING (element);
if (new_state == GST_STATE_PAUSED) { if (new_state == GST_STATE_READY) {
/*g_cond_signal (queue->not_full); */
/*g_cond_signal (queue->not_empty); */
}
else if (new_state == GST_STATE_READY) {
gst_queue_locked_flush (queue); gst_queue_locked_flush (queue);
} }
else if (new_state == GST_STATE_PLAYING) { else if (new_state == GST_STATE_PLAYING) {

View file

@ -28,10 +28,7 @@
#include <gst/gstelement.h> #include <gst/gstelement.h>
#ifdef __cplusplus G_BEGIN_DECLS
extern "C" {
#endif /* __cplusplus */
extern GstElementDetails gst_queue_details; extern GstElementDetails gst_queue_details;
@ -63,7 +60,7 @@ struct _GstQueue {
GstPad *srcpad; GstPad *srcpad;
/* the queue of buffers we're keeping our grubby hands on */ /* the queue of buffers we're keeping our grubby hands on */
GList *queue; GQueue *queue;
guint level_buffers; /* number of buffers queued here */ guint level_buffers; /* number of buffers queued here */
guint level_bytes; /* number of bytes queued here */ guint level_bytes; /* number of bytes queued here */
@ -101,9 +98,7 @@ struct _GstQueueClass {
GType gst_queue_get_type (void); GType gst_queue_get_type (void);
#ifdef __cplusplus G_END_DECLS
}
#endif /* __cplusplus */
#endif /* __GST_QUEUE_H__ */ #endif /* __GST_QUEUE_H__ */

View file

@ -26,6 +26,7 @@
#include "gst_private.h" #include "gst_private.h"
#include "gstutils.h" #include "gstutils.h"
#include "gstlog.h"
#include "gstextratypes.h" #include "gstextratypes.h"
@ -218,14 +219,14 @@ gst_util_dump_mem (guchar * mem, guint size)
guint k; guint k;
for (k = i - 16; k < i; k++) { for (k = i - 16; k < i; k++) {
if (isprint (mem[k])) if (mem[k]>'a' && mem[k] < 'Z')
g_print ("%c", mem[k]); g_print ("%c", mem[k]);
else else
g_print ("."); g_print (".");
} }
g_print ("\n"); g_print ("\n");
} }
g_print ("%08x : ", i); g_print ("%08x (%p): ", i, mem+i);
j = 15; j = 15;
} }
else { else {

View file

@ -266,8 +266,6 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf)
gst_pad_event_default (pad, event); gst_pad_event_default (pad, event);
break; break;
} }
gst_event_free (event);
return; return;
} }

View file

@ -323,7 +323,6 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
src->buffer_count = GST_EVENT_SEEK_OFFSET (event); src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
gst_event_free (event);
break; break;
} }
/* else we do a flush too */ /* else we do a flush too */
@ -333,6 +332,7 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event)
default: default:
break; break;
} }
gst_event_unref (event);
return TRUE; return TRUE;
} }
@ -680,8 +680,8 @@ gst_fakesrc_get(GstPad *pad)
if (src->last_message) if (src->last_message)
g_free (src->last_message); g_free (src->last_message);
src->last_message = g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %llu)", src->last_message = g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %llu) %p",
GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf)); GST_DEBUG_PAD_NAME (pad), GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (src), "last_message"); g_object_notify (G_OBJECT (src), "last_message");
} }

View file

@ -304,7 +304,7 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event)
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset)) if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset))
fseek(filesink->file, offset, SEEK_SET); fseek(filesink->file, offset, SEEK_SET);
gst_event_free (event); gst_event_unref (event);
break; break;
} }
case GST_EVENT_NEW_MEDIA: case GST_EVENT_NEW_MEDIA:

View file

@ -337,6 +337,10 @@ gst_filesrc_free_parent_mmap (GstBuffer *buf)
#endif #endif
/* now unmap the memory */ /* now unmap the memory */
munmap(GST_BUFFER_DATA(buf),GST_BUFFER_MAXSIZE(buf)); munmap(GST_BUFFER_DATA(buf),GST_BUFFER_MAXSIZE(buf));
GST_BUFFER_DATA (buf) = NULL;
_gst_buffer_free (buf);
} }
static GstBuffer * static GstBuffer *
@ -371,7 +375,7 @@ gst_filesrc_map_region (GstFileSrc *src, off_t offset, size_t size)
GST_BUFFER_OFFSET(buf) = offset; GST_BUFFER_OFFSET(buf) = offset;
GST_BUFFER_TIMESTAMP(buf) = -1LL; GST_BUFFER_TIMESTAMP(buf) = -1LL;
GST_BUFFER_POOL_PRIVATE(buf) = src; GST_BUFFER_POOL_PRIVATE(buf) = src;
GST_BUFFER_FREE_FUNC(buf) = gst_filesrc_free_parent_mmap; GST_BUFFER_FREE_FUNC(buf) = (GstDataFreeFunction) gst_filesrc_free_parent_mmap;
g_mutex_lock(src->map_regions_lock); g_mutex_lock(src->map_regions_lock);
g_tree_insert(src->map_regions,buf,buf); g_tree_insert(src->map_regions,buf,buf);
@ -716,7 +720,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
guint64 offset; guint64 offset;
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
return FALSE; goto error;
} }
offset = GST_EVENT_SEEK_OFFSET (event); offset = GST_EVENT_SEEK_OFFSET (event);
@ -724,24 +728,24 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
switch (GST_EVENT_SEEK_METHOD (event)) { switch (GST_EVENT_SEEK_METHOD (event)) {
case GST_SEEK_METHOD_SET: case GST_SEEK_METHOD_SET:
if (offset > src->filelen) if (offset > src->filelen)
return FALSE; goto error;
src->curoffset = offset; src->curoffset = offset;
GST_DEBUG(0, "seek set pending to %lld", src->curoffset); GST_DEBUG(0, "seek set pending to %lld", src->curoffset);
break; break;
case GST_SEEK_METHOD_CUR: case GST_SEEK_METHOD_CUR:
if (offset + src->curoffset > src->filelen) if (offset + src->curoffset > src->filelen)
return FALSE; goto error;
src->curoffset += offset; src->curoffset += offset;
GST_DEBUG(0, "seek cur pending to %lld", src->curoffset); GST_DEBUG(0, "seek cur pending to %lld", src->curoffset);
break; break;
case GST_SEEK_METHOD_END: case GST_SEEK_METHOD_END:
if (ABS (offset) > src->filelen) if (ABS (offset) > src->filelen)
return FALSE; goto error;
src->curoffset = src->filelen - ABS (offset); src->curoffset = src->filelen - ABS (offset);
GST_DEBUG(0, "seek end pending to %lld", src->curoffset); GST_DEBUG(0, "seek end pending to %lld", src->curoffset);
break; break;
default: default:
return FALSE; goto error;
break; break;
} }
g_object_notify (G_OBJECT (src), "offset"); g_object_notify (G_OBJECT (src), "offset");
@ -751,7 +755,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
} }
case GST_EVENT_SIZE: case GST_EVENT_SIZE:
if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
return FALSE; goto error;
} }
src->block_size = GST_EVENT_SIZE_VALUE (event); src->block_size = GST_EVENT_SIZE_VALUE (event);
g_object_notify (G_OBJECT (src), "blocksize"); g_object_notify (G_OBJECT (src), "blocksize");
@ -760,9 +764,13 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event)
src->need_flush = TRUE; src->need_flush = TRUE;
break; break;
default: default:
return FALSE; goto error;
break; break;
} }
gst_event_unref (event);
return TRUE; return TRUE;
error:
gst_event_unref (event);
return FALSE;
} }

View file

@ -22,6 +22,7 @@
/* #define DEBUG_ENABLED */ /* #define DEBUG_ENABLED */
/* #define STATUS_ENABLED */ /* #define STATUS_ENABLED */
#ifdef STATUS_ENABLED #ifdef STATUS_ENABLED
#define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue)) #define STATUS(A) GST_DEBUG(GST_CAT_DATAFLOW, A, GST_ELEMENT_NAME(queue))
#else #else
@ -36,6 +37,7 @@
#include "gstqueue.h" #include "gstqueue.h"
#include "gstscheduler.h" #include "gstscheduler.h"
#include "gstevent.h" #include "gstevent.h"
#include "gstlog.h"
GstElementDetails gst_queue_details = { GstElementDetails gst_queue_details = {
"Queue", "Queue",
@ -239,6 +241,7 @@ gst_queue_init (GstQueue *queue)
queue->not_empty = g_cond_new (); queue->not_empty = g_cond_new ();
queue->not_full = g_cond_new (); queue->not_full = g_cond_new ();
queue->events = g_async_queue_new(); queue->events = g_async_queue_new();
queue->queue = g_queue_new ();
GST_DEBUG_ELEMENT (GST_CAT_THREAD, queue, "initialized queue's not_empty & not_full conditions"); GST_DEBUG_ELEMENT (GST_CAT_THREAD, queue, "initialized queue's not_empty & not_full conditions");
} }
@ -250,6 +253,8 @@ gst_queue_dispose (GObject *object)
g_mutex_free (queue->qlock); g_mutex_free (queue->qlock);
g_cond_free (queue->not_empty); g_cond_free (queue->not_empty);
g_cond_free (queue->not_full); g_cond_free (queue->not_full);
gst_queue_locked_flush (queue);
g_queue_free (queue->queue);
g_async_queue_unref(queue->events); g_async_queue_unref(queue->events);
@ -267,28 +272,25 @@ gst_queue_get_bufferpool (GstPad *pad)
} }
static void static void
gst_queue_cleanup_buffers (gpointer data, const gpointer user_data) gst_queue_cleanup_data (gpointer data, const gpointer user_data)
{ {
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, user_data, "cleaning buffer %p", data); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, user_data, "cleaning buffer %p", data);
if (GST_IS_BUFFER (data)) { gst_data_unref (GST_DATA (data));
gst_buffer_unref (GST_BUFFER (data));
}
else {
gst_event_free (GST_EVENT (data));
}
} }
static void static void
gst_queue_locked_flush (GstQueue *queue) gst_queue_locked_flush (GstQueue *queue)
{ {
g_list_foreach (queue->queue, gst_queue_cleanup_buffers, gpointer data;
(gpointer) queue);
g_list_free (queue->queue); while ((data = g_queue_pop_head (queue->queue))) {
gst_queue_cleanup_data (data, (gpointer) queue);
queue->queue = NULL; }
queue->level_buffers = 0;
queue->timeval = NULL; queue->timeval = NULL;
queue->level_buffers = 0;
queue->level_bytes = 0;
queue->level_time = 0LL;
/* make sure any pending buffers to be added are flushed too */ /* make sure any pending buffers to be added are flushed too */
queue->flush = TRUE; queue->flush = TRUE;
} }
@ -364,25 +366,28 @@ restart:
} }
/* otherwise we have to push a buffer off the other end */ /* otherwise we have to push a buffer off the other end */
else { else {
GList *front; gpointer front;
GstBuffer *leakbuf; GstBuffer *leakbuf;
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end"); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "queue is full, leaking buffer on downstream end");
front = queue->queue;
leakbuf = (GstBuffer *)(front->data); front = g_queue_pop_head (queue->queue);
if (GST_IS_EVENT (leakbuf)) leakbuf = (GstBuffer *)(front);
if (GST_IS_EVENT (leakbuf)) {
fprintf(stderr, "Error: queue [%s] leaked an event, type:%d\n", fprintf(stderr, "Error: queue [%s] leaked an event, type:%d\n",
GST_ELEMENT_NAME(GST_ELEMENT(queue)), GST_ELEMENT_NAME(GST_ELEMENT(queue)),
GST_EVENT_TYPE(GST_EVENT(leakbuf))); GST_EVENT_TYPE(GST_EVENT(leakbuf)));
}
queue->level_buffers--; queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(leakbuf); queue->level_bytes -= GST_BUFFER_SIZE(leakbuf);
gst_buffer_unref(leakbuf); gst_data_unref (GST_DATA (leakbuf));
queue->queue = g_list_remove_link (queue->queue, front);
g_list_free (front);
} }
} }
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "pre full wait, level:%d/%d", GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "pre full wait, level:%d/%d",
queue->level_buffers, queue->size_buffers); queue->level_buffers, queue->size_buffers);
while (queue->level_buffers == queue->size_buffers) { while (queue->level_buffers == queue->size_buffers) {
/* if there's a pending state change for this queue or its manager, switch */ /* if there's a pending state change for this queue or its manager, switch */
/* back to iterator so bottom half of state change executes */ /* back to iterator so bottom half of state change executes */
@ -404,8 +409,7 @@ restart:
/* this means the other end is shut down */ /* this means the other end is shut down */
/* try to signal to resolve the error */ /* try to signal to resolve the error */
if (!queue->may_deadlock) { if (!queue->may_deadlock) {
if (GST_IS_BUFFER (buf)) gst_buffer_unref (buf); gst_data_unref (GST_DATA (buf));
else gst_event_free (GST_EVENT (buf));
g_mutex_unlock (queue->qlock); g_mutex_unlock (queue->qlock);
gst_element_error (GST_ELEMENT (queue), "deadlock found, source pad elements are shut down"); gst_element_error (GST_ELEMENT (queue), "deadlock found, source pad elements are shut down");
return; return;
@ -429,17 +433,18 @@ restart:
} }
/* put the buffer on the tail of the list */ /* put the buffer on the tail of the list */
queue->queue = g_list_append (queue->queue, buf); g_queue_push_tail (queue->queue, buf);
queue->level_buffers++; queue->level_buffers++;
queue->level_bytes += GST_BUFFER_SIZE(buf); queue->level_bytes += GST_BUFFER_SIZE(buf);
/* this assertion _has_ to hold */
g_assert (queue->queue->length == queue->level_buffers);
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "(%s:%s)+ level:%d/%d", GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "(%s:%s)+ level:%d/%d",
GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(pad),
queue->level_buffers, queue->size_buffers); queue->level_buffers, queue->size_buffers);
/* this assertion _has_ to hold */
/* g_assert (g_list_length (queue->queue) == queue->level_buffers); */
/* reader waiting on an empty queue */ /* reader waiting on an empty queue */
reader = queue->reader; reader = queue->reader;
@ -457,7 +462,7 @@ gst_queue_get (GstPad *pad)
{ {
GstQueue *queue; GstQueue *queue;
GstBuffer *buf = NULL; GstBuffer *buf = NULL;
GList *front; gpointer front;
gboolean writer; gboolean writer;
g_assert(pad != NULL); g_assert(pad != NULL);
@ -467,8 +472,6 @@ gst_queue_get (GstPad *pad)
queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); queue = GST_QUEUE (GST_OBJECT_PARENT (pad));
restart: restart:
/* have to lock for thread-safety */ /* have to lock for thread-safety */
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld", pthread_self ()); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "locking t:%ld", pthread_self ());
@ -505,12 +508,14 @@ restart:
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "WARNING: multiple readers on queue!"); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "WARNING: multiple readers on queue!");
queue->reader = TRUE; queue->reader = TRUE;
if (queue->block_timeout > -1){ //if (queue->block_timeout > -1){
if (FALSE) {
GTimeVal timeout; GTimeVal timeout;
g_get_current_time(&timeout); g_get_current_time(&timeout);
g_time_val_add(&timeout, queue->block_timeout); g_time_val_add(&timeout, queue->block_timeout);
if (!g_cond_timed_wait (queue->not_empty, queue->qlock, &timeout)){ if (!g_cond_timed_wait (queue->not_empty, queue->qlock, &timeout)){
g_mutex_unlock (queue->qlock); g_mutex_unlock (queue->qlock);
g_warning ("filler");
return GST_BUFFER(gst_event_new_filler()); return GST_BUFFER(gst_event_new_filler());
} }
} }
@ -522,11 +527,9 @@ restart:
} }
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "post empty wait, level:%d/%d", queue->level_buffers, queue->size_buffers); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "post empty wait, level:%d/%d", queue->level_buffers, queue->size_buffers);
front = queue->queue; front = g_queue_pop_head (queue->queue);
buf = (GstBuffer *)(front->data); buf = (GstBuffer *)(front);
GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "retrieved buffer %p from queue", buf); GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "retrieved buffer %p from queue", buf);
queue->queue = g_list_remove_link (queue->queue, front);
g_list_free (front);
queue->level_buffers--; queue->level_buffers--;
queue->level_bytes -= GST_BUFFER_SIZE(buf); queue->level_bytes -= GST_BUFFER_SIZE(buf);
@ -536,7 +539,7 @@ restart:
queue->level_buffers, queue->size_buffers); queue->level_buffers, queue->size_buffers);
/* this assertion _has_ to hold */ /* this assertion _has_ to hold */
/* g_assert (g_list_length (queue->queue) == queue->level_buffers); */ g_assert (queue->queue->length == queue->level_buffers);
/* writer waiting on a full queue */ /* writer waiting on a full queue */
writer = queue->writer; writer = queue->writer;
@ -640,11 +643,7 @@ gst_queue_change_state (GstElement *element)
new_state = GST_STATE_PENDING (element); new_state = GST_STATE_PENDING (element);
if (new_state == GST_STATE_PAUSED) { if (new_state == GST_STATE_READY) {
/*g_cond_signal (queue->not_full); */
/*g_cond_signal (queue->not_empty); */
}
else if (new_state == GST_STATE_READY) {
gst_queue_locked_flush (queue); gst_queue_locked_flush (queue);
} }
else if (new_state == GST_STATE_PLAYING) { else if (new_state == GST_STATE_PLAYING) {

View file

@ -28,10 +28,7 @@
#include <gst/gstelement.h> #include <gst/gstelement.h>
#ifdef __cplusplus G_BEGIN_DECLS
extern "C" {
#endif /* __cplusplus */
extern GstElementDetails gst_queue_details; extern GstElementDetails gst_queue_details;
@ -63,7 +60,7 @@ struct _GstQueue {
GstPad *srcpad; GstPad *srcpad;
/* the queue of buffers we're keeping our grubby hands on */ /* the queue of buffers we're keeping our grubby hands on */
GList *queue; GQueue *queue;
guint level_buffers; /* number of buffers queued here */ guint level_buffers; /* number of buffers queued here */
guint level_bytes; /* number of bytes queued here */ guint level_bytes; /* number of bytes queued here */
@ -101,9 +98,7 @@ struct _GstQueueClass {
GType gst_queue_get_type (void); GType gst_queue_get_type (void);
#ifdef __cplusplus G_END_DECLS
}
#endif /* __cplusplus */
#endif /* __GST_QUEUE_H__ */ #endif /* __GST_QUEUE_H__ */