GstMetaItem *walk;
gsize bufsize;
gboolean region = FALSE;
+ gboolean sharing_mem = FALSE;
g_return_val_if_fail (dest != NULL, FALSE);
g_return_val_if_fail (src != NULL, FALSE);
return FALSE;
}
+ /* Indicates if dest references any of src memories. */
+ sharing_mem |= (newmem == mem);
+
_memory_add (dest, -1, newmem);
left -= tocopy;
}
gst_buffer_remove_memory_range (dest, dest_len, -1);
return FALSE;
}
+
+ /* If we were sharing memory and the merge is no-op, we are still sharing. */
+ sharing_mem &= (mem == GST_BUFFER_MEM_PTR (dest, 0));
+
_replace_memory (dest, len, 0, len, mem);
}
}
}
}
+ if (sharing_mem && src->pool != NULL) {
+ /* The new buffer references some of src's memories. We have to ensure that
+ * src buffer does not return to its buffer pool as long as its memories are
+ * used by other buffers. That would cause the buffer to be discarted by the
+ * pool because its memories are not writable. */
+ gst_buffer_add_parent_buffer_meta (dest, src);
+ }
+
return TRUE;
}
GST_END_TEST;
+GST_START_TEST (test_make_writable_parent_meta)
+{
+ GstBufferPool *pool;
+ GstBuffer *buf1, *buf2, *buf3;
+ GstMemory *mem1, *mem2;
+ gint buf1_dcount = 0;
+ gint buf2_dcount = 0;
+
+ pool = create_pool (1, 0, 0);
+ fail_unless (pool);
+ gst_buffer_pool_set_active (pool, TRUE);
+
+ fail_unless (gst_buffer_pool_acquire_buffer (pool, &buf1,
+ NULL) == GST_FLOW_OK);
+ buffer_track_destroy (buf1, &buf1_dcount);
+
+ /* Make buf1 not writable and copy it */
+ gst_buffer_ref (buf1);
+ buf2 = gst_buffer_make_writable (buf1);
+ buffer_track_destroy (buf2, &buf2_dcount);
+ fail_unless (buf1 != buf2);
+ fail_unless (gst_buffer_is_writable (buf2));
+
+ /* buf1 and buf2 should be sharing the same memory */
+ mem1 = gst_buffer_peek_memory (buf1, 0);
+ mem2 = gst_buffer_peek_memory (buf2, 0);
+ fail_unless_equals_pointer (mem1, mem2);
+
+ /* buf1 is still reffed by the meta */
+ gst_buffer_unref (buf1);
+ fail_unless_equals_int (buf1_dcount, 0);
+ fail_unless_equals_int (buf2_dcount, 0);
+
+ /* buf2 gets destroyed and buf1 returns to pool */
+ gst_buffer_unref (buf2);
+ fail_unless_equals_int (buf1_dcount, 0);
+ fail_unless_equals_int (buf2_dcount, 1);
+
+ /* buf1 should be recycled with the same memory */
+ fail_unless (gst_buffer_pool_acquire_buffer (pool, &buf3,
+ NULL) == GST_FLOW_OK);
+ fail_unless_equals_pointer (buf1, buf3);
+ fail_unless_equals_pointer (mem1, gst_buffer_peek_memory (buf3, 0));
+
+ gst_buffer_unref (buf3);
+ fail_unless_equals_int (buf1_dcount, 0);
+ fail_unless_equals_int (buf2_dcount, 1);
+
+ gst_buffer_pool_set_active (pool, FALSE);
+ gst_object_unref (pool);
+ fail_unless_equals_int (buf1_dcount, 1);
+ fail_unless_equals_int (buf2_dcount, 1);
+}
+
+GST_END_TEST;
+
static Suite *
gst_buffer_pool_suite (void)
{
tcase_add_test (tc_chain, test_flushing_pool_returns_flushing);
tcase_add_test (tc_chain, test_no_deadlock_for_buffer_discard);
tcase_add_test (tc_chain, test_parent_meta);
+ tcase_add_test (tc_chain, test_make_writable_parent_meta);
return s;
}