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.
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
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
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>
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)
{
return buffer;
no_buffer:
- it->last_returned = NULL;
-
- return NULL;
+ {
+ it->last_returned = NULL;
+ return NULL;
+ }
}
/**
}
/**
- * 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
*
* 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;
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
/**
* 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,
* 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.
- *
- * 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.
+ * 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
*
- * 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);
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);
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);
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)
{
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 */
/* 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);
/* 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);
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)
{
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;
}
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