--- a/gstreamer_core/libs/gst/base/gstadapter.c Tue Aug 31 15:30:33 2010 +0300
+++ b/gstreamer_core/libs/gst/base/gstadapter.c Wed Sep 01 12:16:41 2010 +0100
@@ -36,10 +36,6 @@
* in chunks of the desired size using gst_adapter_peek(). After the data is
* processed, it is freed using gst_adapter_flush().
*
- * Other methods such as gst_adapter_take() and gst_adapter_take_buffer()
- * combine gst_adapter_peek() and gst_adapter_flush() in one method and are
- * potentially more convenient for some use cases.
- *
* For example, a sink pad's chain function that needs to pass data to a library
* in 512-byte chunks could be implemented like this:
* <programlisting>
@@ -78,22 +74,11 @@
* Also check the GST_BUFFER_FLAG_DISCONT flag on the buffer. Some elements might
* need to clear the adapter after a discontinuity.
*
- * Since 0.10.24, the adapter will keep track of the timestamps of the buffers
- * that were pushed. The last seen timestamp before the current position
- * can be queried with gst_adapter_prev_timestamp(). This function can
- * optionally return the amount of bytes between the start of the buffer that
- * carried the timestamp and the current adapter position. The distance is
- * useful when dealing with, for example, raw audio samples because it allows
- * you to calculate the timestamp of the current adapter position by using the
- * last seen timestamp and the amount of bytes since.
- *
* A last thing to note is that while GstAdapter is pretty optimized,
- * merging buffers still might be an operation that requires a malloc() and
- * memcpy() operation, and these operations are not the fastest. Because of
- * this, some functions like gst_adapter_available_fast() are provided to help
- * speed up such cases should you want to. To avoid repeated memory allocations,
- * gst_adapter_copy() can be used to copy data into a (statically allocated)
- * user provided buffer.
+ * merging buffers still might be an operation that requires a memcpy()
+ * operation, and this operation is not the fastest. Because of this, some
+ * functions like gst_adapter_available_fast() are provided to help speed up
+ * such cases should you want to.
*
* GstAdapter is not MT safe. All operations on an adapter must be serialized by
* the caller. This is not normally a problem, however, as the normal use case
@@ -105,31 +90,22 @@
* access the buffer later. The adapter will never modify the data in the
* buffer pushed in it.
*
- * Last reviewed on 2009-05-13 (0.10.24).
+ * Last reviewed on 2006-04-04 (0.10.6).
*/
-#include <gst/gst_private.h>
#ifdef __SYMBIAN32__
#include <gst_global.h>
#endif
+
#include "gstadapter.h"
#include <string.h>
/* default size for the assembled data buffer */
-#define DEFAULT_SIZE 4096
+#define DEFAULT_SIZE 16
GST_DEBUG_CATEGORY_STATIC (gst_adapter_debug);
#define GST_CAT_DEFAULT gst_adapter_debug
-#define GST_ADAPTER_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_ADAPTER, GstAdapterPrivate))
-
-struct _GstAdapterPrivate
-{
- GstClockTime timestamp;
- guint64 distance;
-};
-
#define _do_init(thing) \
GST_DEBUG_CATEGORY_INIT (gst_adapter_debug, "adapter", 0, "object to splice and merge buffers to desired size")
GST_BOILERPLATE_FULL (GstAdapter, gst_adapter, GObject, G_TYPE_OBJECT,
@@ -149,8 +125,6 @@
{
GObjectClass *object = G_OBJECT_CLASS (klass);
- g_type_class_add_private (klass, sizeof (GstAdapterPrivate));
-
object->dispose = gst_adapter_dispose;
object->finalize = gst_adapter_finalize;
}
@@ -158,11 +132,8 @@
static void
gst_adapter_init (GstAdapter * adapter, GstAdapterClass * g_class)
{
- adapter->priv = GST_ADAPTER_GET_PRIVATE (adapter);
adapter->assembled_data = g_malloc (DEFAULT_SIZE);
adapter->assembled_size = DEFAULT_SIZE;
- adapter->priv->timestamp = GST_CLOCK_TIME_NONE;
- adapter->priv->distance = 0;
}
static void
@@ -224,58 +195,6 @@
adapter->size = 0;
adapter->skip = 0;
adapter->assembled_len = 0;
- adapter->priv->timestamp = GST_CLOCK_TIME_NONE;
- adapter->priv->distance = 0;
-}
-
-static inline void
-update_timestamp (GstAdapter * adapter, GstBuffer * buf)
-{
- GstClockTime timestamp;
-
- timestamp = GST_BUFFER_TIMESTAMP (buf);
- if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
- GST_LOG_OBJECT (adapter, "new timestamp %" GST_TIME_FORMAT,
- GST_TIME_ARGS (timestamp));
- adapter->priv->timestamp = timestamp;
- adapter->priv->distance = 0;
- }
-}
-
-/* copy data into @dest, skipping @skip bytes from the head buffers */
-static void
-copy_into_unchecked (GstAdapter * adapter, guint8 * dest, guint skip,
- guint size)
-{
- GSList *g;
- GstBuffer *buf;
- guint bsize, csize;
-
- /* first step, do skipping */
- g = adapter->buflist;
- buf = g->data;
- bsize = GST_BUFFER_SIZE (buf);
- while (G_UNLIKELY (skip >= bsize)) {
- skip -= bsize;
- g = g_slist_next (g);
- buf = g->data;
- bsize = GST_BUFFER_SIZE (buf);
- }
- /* copy partial buffer */
- csize = MIN (bsize - skip, size);
- memcpy (dest, GST_BUFFER_DATA (buf) + skip, csize);
- size -= csize;
- dest += csize;
-
- /* second step, copy remainder */
- while (size > 0) {
- g = g_slist_next (g);
- buf = g->data;
- csize = MIN (GST_BUFFER_SIZE (buf), size);
- memcpy (dest, GST_BUFFER_DATA (buf), csize);
- size -= csize;
- dest += csize;
- }
}
/**
@@ -285,8 +204,6 @@
*
* Adds the data from @buf to the data stored inside @adapter and takes
* ownership of the buffer.
- * Empty buffers will be automatically dereferenced and not stored in the
- * @adapter.
*/
#ifdef __SYMBIAN32__
EXPORT_C
@@ -295,33 +212,46 @@
void
gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
{
- guint size;
-
g_return_if_fail (GST_IS_ADAPTER (adapter));
g_return_if_fail (GST_IS_BUFFER (buf));
- size = GST_BUFFER_SIZE (buf);
+ adapter->size += GST_BUFFER_SIZE (buf);
- if (G_UNLIKELY (size == 0)) {
- /* we can't have empty buffers, several parts in this file rely on it, this
- * has some problems for the timestamp tracking. */
- GST_LOG_OBJECT (adapter, "discarding empty buffer");
- gst_buffer_unref (buf);
+ /* Note: merging buffers at this point is premature. */
+ if (G_UNLIKELY (adapter->buflist == NULL)) {
+ adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
} else {
- adapter->size += size;
+ /* Otherwise append to the end, and advance our end pointer */
+ adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
+ adapter->buflist_end = g_slist_next (adapter->buflist_end);
+ }
+}
- /* Note: merging buffers at this point is premature. */
- if (G_UNLIKELY (adapter->buflist == NULL)) {
- GST_LOG_OBJECT (adapter, "pushing first %u bytes", size);
- adapter->buflist = adapter->buflist_end = g_slist_append (NULL, buf);
- update_timestamp (adapter, buf);
- } else {
- /* Otherwise append to the end, and advance our end pointer */
- GST_LOG_OBJECT (adapter, "pushing %u bytes at end, size now %u", size,
- adapter->size);
- adapter->buflist_end = g_slist_append (adapter->buflist_end, buf);
- adapter->buflist_end = g_slist_next (adapter->buflist_end);
- }
+/* Internal function that copies data into the given buffer, size must be
+ * bigger than the first buffer */
+static void
+gst_adapter_peek_into (GstAdapter * adapter, guint8 * data, guint size)
+{
+ GstBuffer *cur;
+ GSList *cur_list;
+ guint copied, to_copy;
+
+ /* The first buffer might be partly consumed, so need to handle
+ * 'skipped' bytes. */
+ cur = adapter->buflist->data;
+ copied = to_copy = MIN (GST_BUFFER_SIZE (cur) - adapter->skip, size);
+ memcpy (data, GST_BUFFER_DATA (cur) + adapter->skip, copied);
+ data += copied;
+
+ cur_list = g_slist_next (adapter->buflist);
+ while (copied < size) {
+ g_assert (cur_list);
+ cur = cur_list->data;
+ cur_list = g_slist_next (cur_list);
+ to_copy = MIN (GST_BUFFER_SIZE (cur), size - copied);
+ memcpy (data, GST_BUFFER_DATA (cur), to_copy);
+ data += to_copy;
+ copied += to_copy;
}
}
@@ -398,7 +328,6 @@
gst_adapter_peek (GstAdapter * adapter, guint size)
{
GstBuffer *cur;
- guint skip;
g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
g_return_val_if_fail (size > 0, NULL);
@@ -415,33 +344,29 @@
/* our head buffer has enough data left, return it */
cur = adapter->buflist->data;
- skip = adapter->skip;
- if (GST_BUFFER_SIZE (cur) >= size + skip)
- return GST_BUFFER_DATA (cur) + skip;
+ if (GST_BUFFER_SIZE (cur) >= size + adapter->skip)
+ return GST_BUFFER_DATA (cur) + adapter->skip;
/* We may be able to efficiently merge buffers in our pool to
* gather a big enough chunk to return it from the head buffer directly */
if (gst_adapter_try_to_merge_up (adapter, size)) {
/* Merged something! Check if there's enough avail now */
cur = adapter->buflist->data;
- if (GST_BUFFER_SIZE (cur) >= size + skip)
- return GST_BUFFER_DATA (cur) + skip;
+ if (GST_BUFFER_SIZE (cur) >= size + adapter->skip)
+ return GST_BUFFER_DATA (cur) + adapter->skip;
}
/* Gonna need to copy stuff out */
- if (G_UNLIKELY (adapter->assembled_size < size)) {
+ if (adapter->assembled_size < size) {
adapter->assembled_size = (size / DEFAULT_SIZE + 1) * DEFAULT_SIZE;
- GST_DEBUG_OBJECT (adapter, "resizing internal buffer to %u",
+ GST_DEBUG_OBJECT (adapter, "setting size of internal buffer to %u",
adapter->assembled_size);
- /* no g_realloc to avoid a memcpy that is not desired here since we are
- * going to copy new data into the area below */
g_free (adapter->assembled_data);
adapter->assembled_data = g_malloc (adapter->assembled_size);
}
adapter->assembled_len = size;
- GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy data from adapter");
- copy_into_unchecked (adapter, adapter->assembled_data, skip, size);
+ gst_adapter_peek_into (adapter, adapter->assembled_data, size);
return adapter->assembled_data;
}
@@ -469,11 +394,37 @@
void
gst_adapter_copy (GstAdapter * adapter, guint8 * dest, guint offset, guint size)
{
+ GSList *g;
+ int skip;
+
g_return_if_fail (GST_IS_ADAPTER (adapter));
g_return_if_fail (size > 0);
- g_return_if_fail (offset + size <= adapter->size);
+
+ /* we don't have enough data, return. This is unlikely
+ * as one usually does an _available() first instead of copying a
+ * random size. */
+ if (G_UNLIKELY (offset + size > adapter->size))
+ return;
+
+ skip = adapter->skip;
+ for (g = adapter->buflist; g && size > 0; g = g_slist_next (g)) {
+ GstBuffer *buf;
- copy_into_unchecked (adapter, dest, offset + adapter->skip, size);
+ buf = g->data;
+ if (offset < GST_BUFFER_SIZE (buf) - skip) {
+ int n;
+
+ n = MIN (GST_BUFFER_SIZE (buf) - skip - offset, size);
+ memcpy (dest, GST_BUFFER_DATA (buf) + skip + offset, n);
+
+ dest += n;
+ offset = 0;
+ size -= n;
+ } else {
+ offset -= GST_BUFFER_SIZE (buf) - skip;
+ }
+ skip = 0;
+ }
}
/**
@@ -494,56 +445,29 @@
gst_adapter_flush (GstAdapter * adapter, guint flush)
{
GstBuffer *cur;
- guint size;
- GstAdapterPrivate *priv;
- GSList *g;
g_return_if_fail (GST_IS_ADAPTER (adapter));
g_return_if_fail (flush <= adapter->size);
GST_LOG_OBJECT (adapter, "flushing %u bytes", flush);
-
- /* flushing out 0 bytes will do nothing */
- if (G_UNLIKELY (flush == 0))
- return;
-
- priv = adapter->priv;
-
- /* clear state */
adapter->size -= flush;
adapter->assembled_len = 0;
-
- /* take skip into account */
- flush += adapter->skip;
- /* distance is always at least the amount of skipped bytes */
- priv->distance -= adapter->skip;
-
- g = adapter->buflist;
- cur = g->data;
- size = GST_BUFFER_SIZE (cur);
- while (flush >= size) {
- /* can skip whole buffer */
- GST_LOG_OBJECT (adapter, "flushing out head buffer");
- priv->distance += size;
- flush -= size;
-
- gst_buffer_unref (cur);
- g = g_slist_delete_link (g, g);
-
- if (G_UNLIKELY (g == NULL)) {
- GST_LOG_OBJECT (adapter, "adapter empty now");
- adapter->buflist_end = NULL;
+ while (flush > 0) {
+ cur = adapter->buflist->data;
+ if (GST_BUFFER_SIZE (cur) <= flush + adapter->skip) {
+ /* can skip whole buffer */
+ flush -= GST_BUFFER_SIZE (cur) - adapter->skip;
+ adapter->skip = 0;
+ adapter->buflist =
+ g_slist_delete_link (adapter->buflist, adapter->buflist);
+ if (G_UNLIKELY (adapter->buflist == NULL))
+ adapter->buflist_end = NULL;
+ gst_buffer_unref (cur);
+ } else {
+ adapter->skip += flush;
break;
}
- /* there is a new head buffer, update the timestamp */
- cur = g->data;
- update_timestamp (adapter, cur);
- size = GST_BUFFER_SIZE (cur);
}
- adapter->buflist = g;
- /* account for the remaining bytes */
- adapter->skip = flush;
- adapter->priv->distance += flush;
}
/**
@@ -576,18 +500,15 @@
if (G_UNLIKELY (nbytes > adapter->size))
return NULL;
- /* we have enough assembled data, take from there */
+ data = g_malloc (nbytes);
+
+ /* we have enough assembled data, copy from there */
if (adapter->assembled_len >= nbytes) {
GST_LOG_OBJECT (adapter, "taking %u bytes already assembled", nbytes);
- data = adapter->assembled_data;
- /* allocate new data, assembled_len will be set to 0 in the flush below */
- adapter->assembled_data = g_malloc (adapter->assembled_size);
+ memcpy (data, adapter->assembled_data, nbytes);
} else {
- /* we need to allocate and copy. We could potentially copy bytes from the
- * assembled data before doing the copy_into */
GST_LOG_OBJECT (adapter, "taking %u bytes by collection", nbytes);
- data = g_malloc (nbytes);
- copy_into_unchecked (adapter, data, adapter->skip, nbytes);
+ gst_adapter_peek_into (adapter, data, nbytes);
}
gst_adapter_flush (adapter, nbytes);
@@ -622,7 +543,6 @@
{
GstBuffer *buffer;
GstBuffer *cur;
- guint hsize, skip;
g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
g_return_val_if_fail (nbytes > 0, NULL);
@@ -635,52 +555,43 @@
if (G_UNLIKELY (nbytes > adapter->size))
return NULL;
+ /* our head buffer has enough data left, return it */
cur = adapter->buflist->data;
- skip = adapter->skip;
- hsize = GST_BUFFER_SIZE (cur);
-
- /* our head buffer has enough data left, return it */
- if (skip == 0 && hsize == nbytes) {
- GST_LOG_OBJECT (adapter, "providing buffer of %d bytes as head buffer",
- nbytes);
- buffer = gst_buffer_ref (cur);
- goto done;
- } else if (hsize >= nbytes + skip) {
+ if (GST_BUFFER_SIZE (cur) >= nbytes + adapter->skip) {
GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
nbytes);
- buffer = gst_buffer_create_sub (cur, skip, nbytes);
- goto done;
+ buffer = gst_buffer_create_sub (cur, adapter->skip, nbytes);
+
+ gst_adapter_flush (adapter, nbytes);
+
+ return buffer;
}
if (gst_adapter_try_to_merge_up (adapter, nbytes)) {
/* Merged something, let's try again for sub-buffering */
cur = adapter->buflist->data;
- if (GST_BUFFER_SIZE (cur) >= nbytes + skip) {
+ if (GST_BUFFER_SIZE (cur) >= nbytes + adapter->skip) {
GST_LOG_OBJECT (adapter, "providing buffer of %d bytes via sub-buffer",
nbytes);
- buffer = gst_buffer_create_sub (cur, skip, nbytes);
- goto done;
+ buffer = gst_buffer_create_sub (cur, adapter->skip, nbytes);
+
+ gst_adapter_flush (adapter, nbytes);
+
+ return buffer;
}
}
+ buffer = gst_buffer_new_and_alloc (nbytes);
+
/* we have enough assembled data, copy from there */
if (adapter->assembled_len >= nbytes) {
GST_LOG_OBJECT (adapter, "taking %u bytes already assembled", nbytes);
- buffer = gst_buffer_new ();
- GST_BUFFER_SIZE (buffer) = nbytes;
- GST_BUFFER_DATA (buffer) = adapter->assembled_data;
- GST_BUFFER_MALLOCDATA (buffer) = adapter->assembled_data;
- /* flush will set the assembled_len to 0 */
- adapter->assembled_data = g_malloc (adapter->assembled_size);
+ memcpy (GST_BUFFER_DATA (buffer), adapter->assembled_data, nbytes);
} else {
- /* we need to allocate and copy. We could potentially copy bytes from the
- * assembled data before doing the copy_into */
- buffer = gst_buffer_new_and_alloc (nbytes);
GST_LOG_OBJECT (adapter, "taking %u bytes by collection", nbytes);
- copy_into_unchecked (adapter, GST_BUFFER_DATA (buffer), skip, nbytes);
+ gst_adapter_peek_into (adapter, GST_BUFFER_DATA (buffer), nbytes);
}
-done:
gst_adapter_flush (adapter, nbytes);
return buffer;
@@ -726,9 +637,6 @@
guint
gst_adapter_available_fast (GstAdapter * adapter)
{
- GstBuffer *first;
- guint size;
-
g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);
/* no buffers, we have no data */
@@ -739,153 +647,9 @@
if (adapter->assembled_len)
return adapter->assembled_len;
- /* take the first buffer and its size */
- first = GST_BUFFER_CAST (adapter->buflist->data);
- size = GST_BUFFER_SIZE (first);
-
- /* we can quickly get the (remaining) data of the first buffer */
- return size - adapter->skip;
-}
-
-/**
- * gst_adapter_prev_timestamp:
- * @adapter: a #GstAdapter
- * @distance: pointer to location for distance or NULL
- *
- * Get the timestamp that was before the current byte in the adapter. When
- * @distance is given, the amount of bytes between the timestamp and the current
- * position is returned.
- *
- * The timestamp is reset to GST_CLOCK_TIME_NONE when the adapter is first
- * created or when it is cleared.
- *
- * Returns: The previously seen timestamp.
- *
- * Since: 0.10.24
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-GstClockTime
-gst_adapter_prev_timestamp (GstAdapter * adapter, guint64 * distance)
-{
- g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_CLOCK_TIME_NONE);
-
- if (distance)
- *distance = adapter->priv->distance;
-
- return adapter->priv->timestamp;
-}
+ /* we cannot have skipped more than the first buffer */
+ g_assert (GST_BUFFER_SIZE (adapter->buflist->data) > adapter->skip);
-/**
- * gst_adapter_masked_scan_uint32:
- * @adapter: a #GstAdapter
- * @mask: mask to apply to data before matching against @pattern
- * @pattern: pattern to match (after mask is applied)
- * @offset: offset into the adapter data from which to start scanning, returns
- * the last scanned position.
- * @size: number of bytes to scan from offset
- *
- * Scan for pattern @pattern with applied mask @mask in the adapter data,
- * starting from offset @offset.
- *
- * The bytes in @pattern and @mask are interpreted left-to-right, regardless
- * of endianness. All four bytes of the pattern must be present in the
- * adapter for it to match, even if the first or last bytes are masked out.
- *
- * It is an error to call this function without making sure that there is
- * enough data (offset+size bytes) in the adapter.
- *
- * Returns: offset of the first match, or -1 if no match was found.
- *
- * Example:
- * <programlisting>
- * // Assume the adapter contains 0x00 0x01 0x02 ... 0xfe 0xff
- *
- * gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x00010203, 0, 256);
- * // -> returns 0
- * gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x00010203, 1, 255);
- * // -> returns -1
- * gst_adapter_masked_scan_uint32 (adapter, 0xffffffff, 0x01020304, 1, 255);
- * // -> returns 1
- * gst_adapter_masked_scan_uint32 (adapter, 0xffff, 0x0001, 0, 256);
- * // -> returns -1
- * gst_adapter_masked_scan_uint32 (adapter, 0xffff, 0x0203, 0, 256);
- * // -> returns 0
- * gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0x02030000, 0, 256);
- * // -> returns 2
- * gst_adapter_masked_scan_uint32 (adapter, 0xffff0000, 0x02030000, 0, 4);
- * // -> returns -1
- * </programlisting>
- *
- * Since: 0.10.24
- */
-#ifdef __SYMBIAN32__
-EXPORT_C
-#endif
-
-guint
-gst_adapter_masked_scan_uint32 (GstAdapter * adapter, guint32 mask,
- guint32 pattern, guint offset, guint size)
-{
- GSList *g;
- guint skip, bsize, i;
- guint32 state;
- guint8 *bdata;
- GstBuffer *buf;
-
- g_return_val_if_fail (size > 0, -1);
- g_return_val_if_fail (offset + size <= adapter->size, -1);
-
- /* we can't find the pattern with less than 4 bytes */
- if (G_UNLIKELY (size < 4))
- return -1;
-
- skip = offset + adapter->skip;
-
- /* first step, do skipping and position on the first buffer */
- g = adapter->buflist;
- buf = g->data;
- bsize = GST_BUFFER_SIZE (buf);
- while (G_UNLIKELY (skip >= bsize)) {
- skip -= bsize;
- g = g_slist_next (g);
- buf = g->data;
- bsize = GST_BUFFER_SIZE (buf);
- }
- /* get the data now */
- bsize -= skip;
- bdata = GST_BUFFER_DATA (buf) + skip;
- skip = 0;
-
- /* set the state to something that does not match */
- state = ~pattern;
-
- /* now find data */
- do {
- bsize = MIN (bsize, size);
- for (i = 0; i < bsize; i++) {
- state = ((state << 8) | bdata[i]);
- if (G_UNLIKELY ((state & mask) == pattern)) {
- /* we have a match but we need to have skipped at
- * least 4 bytes to fill the state. */
- if (G_LIKELY (skip + i >= 3))
- return offset + skip + i - 3;
- }
- }
- size -= bsize;
- if (size == 0)
- break;
-
- /* nothing found yet, go to next buffer */
- skip += bsize;
- g = g_slist_next (g);
- buf = g->data;
- bsize = GST_BUFFER_SIZE (buf);
- bdata = GST_BUFFER_DATA (buf);
- } while (TRUE);
-
- /* nothing found */
- return -1;
+ /* we can quickly get the data of the first buffer */
+ return GST_BUFFER_SIZE (adapter->buflist->data) - adapter->skip;
}