bufferlist: Various cleanups

Add new method to iterate a bufferlist without having to allocate an iterator.
Add convenience method for getting an item from the list based on the group and
index.
Remove redundant _do_data callback and method.
Update unit-tests and add some more for the new methods.
This commit is contained in:
Wim Taymans 2009-06-19 15:29:14 +02:00
parent 17f794deeb
commit 6438f6f9b9
5 changed files with 336 additions and 101 deletions

View file

@ -215,14 +215,21 @@ gst_buffer_copy_flags_get_type
GstBufferList
GstBufferListIterator
GstBufferListDoFunction
GstBufferListDoDataFunction
gst_buffer_list_new
gst_buffer_list_ref
gst_buffer_list_unref
gst_buffer_list_copy
gst_buffer_list_is_writable
gst_buffer_list_make_writable
gst_buffer_list_n_groups
GstBufferListItem
GstBufferListFunc
gst_buffer_list_foreach
gst_buffer_list_get
gst_buffer_list_iterate
gst_buffer_list_iterator_free
gst_buffer_list_iterator_n_buffers
@ -234,7 +241,6 @@ gst_buffer_list_iterator_remove
gst_buffer_list_iterator_steal
gst_buffer_list_iterator_take
gst_buffer_list_iterator_do
gst_buffer_list_iterator_do_data
gst_buffer_list_iterator_merge_group
<SUBSECTION Standard>
GstBufferListClass
@ -245,7 +251,9 @@ GST_IS_BUFFER_LIST
GST_IS_BUFFER_LIST_CLASS
GST_TYPE_BUFFER_LIST
GST_BUFFER_LIST_CAST
GST_TYPE_BUFFER_LIST_ITEM
<SUBSECTION Private>
gst_buffer_list_item_get_type
gst_buffer_list_get_type
</SECTION>

View file

@ -289,6 +289,127 @@ gst_buffer_list_n_groups (GstBufferList * list)
return n;
}
/**
* gst_buffer_list_foreach:
* @list: a #GstBufferList
* @func: a #GstBufferListFunc to call
* @user_data: user data passed to @func
*
* Call @func with @data for each buffer in @list.
*
* @func can modify the passed buffer pointer or its contents. The return value
* of @func define if this function returns or if the remaining buffers in a
* group should be skipped.
*/
void
gst_buffer_list_foreach (GstBufferList * list, GstBufferListFunc func,
gpointer user_data)
{
GList *tmp, *next;
guint group, idx;
GstBufferListItem res;
g_return_if_fail (list != NULL);
g_return_if_fail (func != NULL);
next = list->buffers;
group = idx = 0;
while (next) {
GstBuffer *buffer;
tmp = next;
next = g_list_next (tmp);
buffer = tmp->data;
if (buffer == GROUP_START) {
group++;
idx = 0;
continue;
} else if (buffer == STOLEN)
continue;
else
idx++;
/* need to decrement the indices */
res = func (&buffer, group - 1, idx - 1, user_data);
if (G_UNLIKELY (buffer != tmp->data)) {
/* the function changed the buffer */
if (buffer == NULL) {
/* we were asked to remove the item */
list->buffers = g_list_delete_link (list->buffers, tmp);
idx--;
} else {
/* change the buffer */
tmp->data = buffer;
}
}
switch (res) {
case GST_BUFFER_LIST_CONTINUE:
break;
case GST_BUFFER_LIST_SKIP_GROUP:
while (next && next->data != GROUP_START)
next = g_list_next (next);
break;
case GST_BUFFER_LIST_END:
return;
}
}
}
/**
* gst_buffer_list_get:
* @list: a #GstBufferList
* @group: the group
* @idx: the index in @group
*
* Get the buffer at @idx in @group.
*
* Note that this function is not efficient for iterating over the entire list.
* Use and iterator or gst_buffer_list_foreach() instead.
*
* Returns: the buffer at @idx in @group or NULL when there is no buffer. The
* buffer remaing valid as long as @list is valid.
*/
GstBuffer *
gst_buffer_list_get (GstBufferList * list, guint group, guint idx)
{
GList *tmp;
guint cgroup, cidx;
g_return_val_if_fail (list != NULL, NULL);
tmp = list->buffers;
cgroup = 0;
while (tmp) {
if (tmp->data == GROUP_START) {
if (cgroup == group) {
/* we found the group */
tmp = g_list_next (tmp);
cidx = 0;
while (tmp && tmp->data != GROUP_START) {
if (tmp->data != STOLEN) {
if (cidx == idx)
return GST_BUFFER_CAST (tmp->data);
else
cidx++;
}
tmp = g_list_next (tmp);
}
break;
} else {
cgroup++;
if (cgroup > group)
break;
}
}
tmp = g_list_next (tmp);
}
return NULL;
}
GType
gst_buffer_list_get_type (void)
{
@ -474,9 +595,10 @@ gst_buffer_list_iterator_next (GstBufferListIterator * it)
return buffer;
no_buffer:
it->last_returned = NULL;
return NULL;
{
it->last_returned = NULL;
return NULL;
}
}
/**
@ -590,11 +712,10 @@ gst_buffer_list_iterator_steal (GstBufferListIterator * it)
}
/**
* gst_buffer_list_iterator_do_data:
* gst_buffer_list_iterator_do:
* @it: a #GstBufferListIterator
* @do_func: the function to be called
* @data: the gpointer to optional user data.
* @data_notify: function to be called when @data is no longer used
* @user_data: the gpointer to optional user data.
*
* Calls the given function for the last buffer returned by
* gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
@ -604,15 +725,11 @@ gst_buffer_list_iterator_steal (GstBufferListIterator * it)
*
* See #GstBufferListDoFunction for more details.
*
* The @data_notify function is called after @do_func has returned, before this
* function returns, usually used to free @data.
*
* Returns: the return value from @do_func
*/
GstBuffer *
gst_buffer_list_iterator_do_data (GstBufferListIterator * it,
GstBufferListDoDataFunction do_func, gpointer data,
GDestroyNotify data_notify)
gst_buffer_list_iterator_do (GstBufferListIterator * it,
GstBufferListDoFunction do_func, gpointer user_data)
{
GstBuffer *buffer;
@ -624,56 +741,16 @@ gst_buffer_list_iterator_do_data (GstBufferListIterator * it,
g_assert (it->last_returned->data != GROUP_START);
buffer = gst_buffer_list_iterator_steal (it);
buffer = do_func (buffer, data);
buffer = do_func (buffer, user_data);
if (buffer == NULL) {
gst_buffer_list_iterator_remove (it);
} else {
gst_buffer_list_iterator_take (it, buffer);
}
if (data_notify != NULL) {
data_notify (data);
}
return buffer;
}
static GstBuffer *
do_func_no_data (GstBuffer * buffer, GstBufferListDoFunction do_func)
{
return do_func (buffer);
}
/**
* gst_buffer_list_iterator_do:
* @it: a #GstBufferListIterator
* @do_func: the function to be called
*
* Calls the given function for the last buffer returned by
* gst_buffer_list_iterator_next(). gst_buffer_list_iterator_next() must have
* been called on @it before this function is called.
* gst_buffer_list_iterator_remove() or gst_buffer_list_iterator_steal() must
* not have been called since the last call to gst_buffer_list_iterator_next().
*
* See #GstBufferListDoFunction for more details.
*
* Returns: the return value from @do_func
*/
GstBuffer *
gst_buffer_list_iterator_do (GstBufferListIterator * it,
GstBufferListDoFunction do_func)
{
g_return_val_if_fail (it != NULL, NULL);
g_return_val_if_fail (it->last_returned != NULL, NULL);
g_return_val_if_fail (it->last_returned->data != STOLEN, NULL);
g_return_val_if_fail (do_func != NULL, NULL);
g_return_val_if_fail (gst_buffer_list_is_writable (it->list), NULL);
g_assert (it->last_returned->data != GROUP_START);
return gst_buffer_list_iterator_do_data (it,
(GstBufferListDoDataFunction) do_func_no_data, do_func, NULL);
}
/**
* gst_buffer_list_iterator_merge_group:
* @it: a #GstBufferListIterator

View file

@ -42,6 +42,7 @@ typedef struct _GstBufferListIterator GstBufferListIterator;
/**
* GstBufferListDoFunction:
* @buffer: the #GstBuffer
* @user_data: user data
*
* A function for accessing the last buffer returned by
* gst_buffer_list_iterator_next(). The function can leave @buffer in the list,
@ -58,29 +59,49 @@ typedef struct _GstBufferListIterator GstBufferListIterator;
* Returns: the buffer to replace @buffer in the list, or NULL to remove @buffer
* from the list
*/
typedef GstBuffer* (*GstBufferListDoFunction) (GstBuffer * buffer);
typedef GstBuffer* (*GstBufferListDoFunction) (GstBuffer * buffer, gpointer user_data);
/**
* GstBufferListDoDataFunction:
* @buffer: the #GstBuffer
* @data: the gpointer to optional user data.
* GstBufferListItem:
* @GST_BUFFER_LIST_CONTINUE: Retrieve next buffer
* @GST_BUFFER_LIST_SKIP_GROUP: Skip to next group
* @GST_BUFFER_LIST_REMOVE: Remove the current buffer
* @GST_BUFFER_LIST_END: End iteration
*
* A function for accessing the last buffer returned by
* gst_buffer_list_iterator_next(). The function can leave @buffer in the list,
* replace @buffer in the list or remove @buffer from the list, depending on
* the return value. If the function returns NULL, @buffer will be removed from
* the list, otherwise @buffer will be replaced with the returned buffer.
*
* The last buffer returned by gst_buffer_list_iterator_next() will be replaced
* with the buffer returned from the function. The function takes ownership of
* @buffer and if a different value than @buffer is returned, @buffer must be
* unreffed. If NULL is returned, the buffer will be removed from the list. The
* list must be writable.
*
* Returns: the buffer to replace @buffer in the list, or NULL to remove @buffer
* from the list
* The result of the #GstBufferListFunc.
*/
typedef GstBuffer* (*GstBufferListDoDataFunction) (GstBuffer * buffer, gpointer data);
typedef enum {
GST_BUFFER_LIST_CONTINUE,
GST_BUFFER_LIST_SKIP_GROUP,
GST_BUFFER_LIST_END
} GstBufferListItem;
/**
* GstBufferListFunc:
* @buffer: pointer the buffer
* @group: the group index of @buffer
* @idx: the index in @group of @buffer
* @user_data: user data passed to gst_buffer_list_foreach()
*
* A function that will be called from gst_buffer_list_foreach(). The @buffer
* field will point to a the reference of the buffer at @idx in @group.
*
* When this function returns #GST_BUFFER_LIST_CONTINUE, the next buffer will be
* returned. When #GST_BUFFER_LIST_SKIP_GROUP is returned, all remaining buffers
* in the current group will be skipped and the first buffer of the next group
* is returned (if any). When GST_BUFFER_LIST_END is returned,
* gst_buffer_list_foreach() will return.
*
* When @buffer is set to NULL, the item will be removed from the bufferlist.
* When @buffer has been made writable, the new buffer reference can be assigned
* to @buffer. This function is responsible for unreffing the old buffer when
* removing or modifying.
*
* Returns: a #GstBufferListItem
*/
typedef GstBufferListItem (*GstBufferListFunc) (GstBuffer **buffer, guint group, guint idx,
gpointer user_data);
GType gst_buffer_list_get_type (void);
@ -170,6 +191,11 @@ gst_buffer_list_copy (const GstBufferList * list)
guint gst_buffer_list_n_groups (GstBufferList *list);
void gst_buffer_list_foreach (GstBufferList *list,
GstBufferListFunc func,
gpointer user_data);
GstBuffer * gst_buffer_list_get (GstBufferList *list, guint group, guint idx);
/* iterator */
GstBufferListIterator * gst_buffer_list_iterate (GstBufferList *list);
void gst_buffer_list_iterator_free (GstBufferListIterator *it);
@ -184,9 +210,8 @@ void gst_buffer_list_iterator_remove (GstBufferListIte
GstBuffer * gst_buffer_list_iterator_steal (GstBufferListIterator *it);
void gst_buffer_list_iterator_take (GstBufferListIterator *it, GstBuffer *buffer);
GstBuffer * gst_buffer_list_iterator_do (GstBufferListIterator *it, GstBufferListDoFunction do_func);
GstBuffer * gst_buffer_list_iterator_do_data (GstBufferListIterator *it, GstBufferListDoDataFunction do_func,
gpointer data, GDestroyNotify data_notify);
GstBuffer * gst_buffer_list_iterator_do (GstBufferListIterator *it, GstBufferListDoFunction do_func,
gpointer user_data);
/* conversion */
GstBuffer * gst_buffer_list_iterator_merge_group (const GstBufferListIterator *it);

View file

@ -424,15 +424,6 @@ GST_END_TEST;
static gpointer do_data_func_data;
static gboolean notified;
static void
data_notify (gpointer data)
{
fail_unless (data != NULL);
fail_unless (data == do_data_func_data);
fail_if (notified);
notified = TRUE;
}
static GstBuffer *
do_data_func (GstBuffer * buffer, gpointer data)
{
@ -458,16 +449,12 @@ GST_START_TEST (test_do)
gchar *data;
/* error handling */
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (NULL, NULL)));
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (NULL, NULL, NULL)));
fail_unless (buf == NULL);
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do_data (NULL, NULL, NULL,
NULL)));
fail_unless (buf == NULL);
it = gst_buffer_list_iterate (list);
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (it, NULL)));
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (it, NULL, NULL)));
fail_unless (buf == NULL);
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do_data (it, NULL, NULL,
NULL)));
fail_unless (buf == NULL);
/* add buffers to the list */
@ -481,28 +468,32 @@ GST_START_TEST (test_do)
/* call do-function */
it = gst_buffer_list_iterate (list);
fail_unless (gst_buffer_list_iterator_next_group (it));
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (it, gst_buffer_ref)));
ASSERT_CRITICAL ((buf =
gst_buffer_list_iterator_do (it,
(GstBufferListDoFunction) gst_buffer_ref, NULL)));
fail_unless (buf == NULL);
data = "data";
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do_data (it, do_data_func,
data, data_notify)));
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (it, do_data_func,
data)));
fail_unless (buf == NULL);
fail_unless (do_data_func_data != data);
buf = gst_buffer_list_iterator_next (it);
fail_unless (buf == buf1);
ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 2);
buf = gst_buffer_list_iterator_do (it, gst_buffer_ref);
buf =
gst_buffer_list_iterator_do (it, (GstBufferListDoFunction) gst_buffer_ref,
NULL);
fail_unless (buf == buf1);
ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 3);
gst_buffer_unref (buf);
buf = gst_buffer_list_iterator_do_data (it, do_data_func, data, data_notify);
buf = gst_buffer_list_iterator_do (it, do_data_func, data);
fail_unless (buf == buf1);
fail_unless (do_data_func_data == data);
/* do-function that return a new buffer replaces the buffer in the list */
ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 2);
buf = gst_buffer_list_iterator_do (it,
(GstBufferListDoFunction) gst_mini_object_make_writable);
(GstBufferListDoFunction) gst_mini_object_make_writable, NULL);
fail_unless (buf != buf1);
ASSERT_BUFFER_REFCOUNT (buf, "buf", 1);
ASSERT_BUFFER_REFCOUNT (buf, "buf1", 1);
@ -510,9 +501,12 @@ GST_START_TEST (test_do)
/* do-function that return NULL removes the buffer from the list */
ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 2);
fail_unless (gst_buffer_list_iterator_do (it, do_func_null) == NULL);
fail_unless (gst_buffer_list_iterator_do (it,
(GstBufferListDoFunction) do_func_null, NULL) == NULL);
ASSERT_BUFFER_REFCOUNT (buf1, "buf1", 1);
ASSERT_CRITICAL ((buf = gst_buffer_list_iterator_do (it, gst_buffer_ref)));
ASSERT_CRITICAL ((buf =
gst_buffer_list_iterator_do (it,
(GstBufferListDoFunction) gst_buffer_ref, NULL)));
fail_unless (buf == NULL);
fail_unless (gst_buffer_list_iterator_next (it) == NULL);
gst_buffer_list_iterator_free (it);
@ -645,6 +639,134 @@ GST_START_TEST (test_merge)
GST_END_TEST;
typedef struct
{
GstBuffer *buf[3][3];
guint iter;
} ForeachData;
static GstBufferListItem
foreach_func1 (GstBuffer ** buffer, guint group, guint idx, ForeachData * data)
{
fail_unless (buffer != NULL);
fail_unless (*buffer == data->buf[group][idx]);
data->iter++;
return GST_BUFFER_LIST_CONTINUE;
}
static GstBufferListItem
foreach_func2 (GstBuffer ** buffer, guint group, guint idx, ForeachData * data)
{
fail_unless (idx == 0);
fail_unless (buffer != NULL);
fail_unless (*buffer == data->buf[group][idx]);
data->iter++;
return GST_BUFFER_LIST_SKIP_GROUP;
}
static GstBufferListItem
foreach_func3 (GstBuffer ** buffer, guint group, guint idx, ForeachData * data)
{
fail_unless (group == 0);
fail_unless (idx == 0);
fail_unless (buffer != NULL);
fail_unless (*buffer == data->buf[group][idx]);
data->iter++;
return GST_BUFFER_LIST_END;
}
static GstBufferListItem
foreach_func4 (GstBuffer ** buffer, guint group, guint idx, ForeachData * data)
{
fail_unless (idx == 0);
fail_unless (buffer != NULL);
fail_unless (*buffer == data->buf[group][idx]);
*buffer = NULL;
data->iter++;
return GST_BUFFER_LIST_SKIP_GROUP;
}
static GstBufferListItem
foreach_func5 (GstBuffer ** buffer, guint group, guint idx, ForeachData * data)
{
fail_unless (buffer != NULL);
data->iter++;
return GST_BUFFER_LIST_CONTINUE;
}
GST_START_TEST (test_foreach)
{
GstBufferListIterator *it;
ForeachData data;
/* add buffers to the list */
it = gst_buffer_list_iterate (list);
gst_buffer_list_iterator_add_group (it);
data.buf[0][0] = gst_buffer_new ();
gst_buffer_list_iterator_add (it, data.buf[0][0]);
gst_buffer_list_iterator_add_group (it);
data.buf[1][0] = gst_buffer_new ();
gst_buffer_list_iterator_add (it, data.buf[1][0]);
data.buf[1][1] = gst_buffer_new ();
gst_buffer_list_iterator_add (it, data.buf[1][1]);
gst_buffer_list_iterator_free (it);
gst_buffer_list_iterator_add_group (it);
fail_unless (gst_buffer_list_get (list, 0, 0) == data.buf[0][0]);
fail_unless (gst_buffer_list_get (list, 0, 1) == NULL);
fail_unless (gst_buffer_list_get (list, 1, 0) == data.buf[1][0]);
fail_unless (gst_buffer_list_get (list, 1, 1) == data.buf[1][1]);
fail_unless (gst_buffer_list_get (list, 1, 2) == NULL);
fail_unless (gst_buffer_list_get (list, 2, 0) == NULL);
fail_unless (gst_buffer_list_get (list, 2, 1) == NULL);
fail_unless (gst_buffer_list_get (list, 3, 3) == NULL);
/* iterate everything */
data.iter = 0;
gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func1, &data);
fail_unless (data.iter == 3);
/* iterate only the first buffer of groups */
data.iter = 0;
gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func2, &data);
fail_unless (data.iter == 2);
/* iterate only the first buffer */
data.iter = 0;
gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func3, &data);
fail_unless (data.iter == 1);
/* remove the first buffer of each group */
data.iter = 0;
gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func4, &data);
fail_unless (data.iter == 2);
fail_unless (gst_buffer_list_get (list, 0, 0) == NULL);
fail_unless (gst_buffer_list_get (list, 0, 1) == NULL);
fail_unless (gst_buffer_list_get (list, 1, 0) == data.buf[1][1]);
fail_unless (gst_buffer_list_get (list, 1, 1) == NULL);
fail_unless (gst_buffer_list_get (list, 1, 2) == NULL);
fail_unless (gst_buffer_list_get (list, 2, 0) == NULL);
/* iterate everything, just one more buffer now */
data.iter = 0;
gst_buffer_list_foreach (list, (GstBufferListFunc) foreach_func5, &data);
fail_unless (data.iter == 1);
}
GST_END_TEST;
static Suite *
gst_buffer_list_suite (void)
{
@ -660,6 +782,7 @@ gst_buffer_list_suite (void)
tcase_add_test (tc_chain, test_take);
tcase_add_test (tc_chain, test_do);
tcase_add_test (tc_chain, test_merge);
tcase_add_test (tc_chain, test_foreach);
return s;
}

View file

@ -87,12 +87,14 @@ EXPORTS
gst_buffer_is_metadata_writable
gst_buffer_is_span_fast
gst_buffer_join
gst_buffer_list_foreach
gst_buffer_list_get
gst_buffer_list_get_type
gst_buffer_list_item_get_type
gst_buffer_list_iterate
gst_buffer_list_iterator_add
gst_buffer_list_iterator_add_group
gst_buffer_list_iterator_do
gst_buffer_list_iterator_do_data
gst_buffer_list_iterator_free
gst_buffer_list_iterator_merge_group
gst_buffer_list_iterator_n_buffers