{
guint i, len;
gboolean ret = TRUE;
- gboolean list_was_writable;
+ gboolean list_was_writable, first_warning = TRUE;
g_return_val_if_fail (GST_IS_BUFFER_LIST (list), FALSE);
g_return_val_if_fail (func != NULL, FALSE);
/* Check if the function changed the buffer */
if (buf != buf_ret) {
- if (buf_ret == NULL) {
+ /* If the list was not writable but the callback was actually changing
+ * our buffer, then it wouldn't have been allowed to do so.
+ *
+ * Fortunately we still have a reference to the old buffer in that case
+ * and just not modify the list, unref the new buffer (if any) and warn
+ * about this */
+ if (!list_was_writable) {
+ if (first_warning) {
+ g_critical
+ ("gst_buffer_list_foreach: non-writable list %p was changed from callback",
+ list);
+ first_warning = FALSE;
+ }
+ if (buf_ret)
+ gst_buffer_unref (buf_ret);
+ } else if (buf_ret == NULL) {
gst_buffer_list_remove_range_internal (list, i, 1, !was_writable);
--len;
} else {
GST_END_TEST;
+static gboolean
+foreach_replace_buffer (GstBuffer ** buffer, guint idx, gpointer user_data)
+{
+ gst_buffer_unref (*buffer);
+ *buffer = gst_buffer_new ();
+
+ return TRUE;
+}
+
+GST_START_TEST (test_foreach_modify_non_writeable_list)
+{
+ GstBufferList *b = gst_buffer_list_new_sized (1);
+ GstBuffer *buf;
+
+ buf = gst_buffer_new ();
+ gst_buffer_list_add (b, gst_buffer_ref (buf));
+ gst_buffer_list_ref (b);
+
+ fail_if (gst_buffer_list_is_writable (b));
+
+ ASSERT_CRITICAL (gst_buffer_list_foreach (b, foreach_replace_buffer, NULL));
+
+ fail_unless (gst_buffer_list_get (b, 0) == buf);
+
+ gst_buffer_list_unref (b);
+ gst_buffer_list_unref (b);
+ gst_buffer_unref (buf);
+}
+
+GST_END_TEST;
+
static Suite *
gst_buffer_list_suite (void)
{
tcase_add_test (tc_chain, test_calc_size);
tcase_add_test (tc_chain, test_new_sized_0);
tcase_add_test (tc_chain, test_multiple_mutable_buffer_references);
+ tcase_add_test (tc_chain, test_foreach_modify_non_writeable_list);
return s;
}