buffer: fix negative offsets some more

Allow for negative offsets when doing memory copy and share.
Add fast path in the _get_sizes() function.
Fix resize for negative offset and expanding the buffer.
Add some unit tests.
This commit is contained in:
Wim Taymans 2011-07-11 18:00:52 +02:00
parent 0849cae4a8
commit 8461249f22
4 changed files with 129 additions and 34 deletions

View file

@ -761,36 +761,46 @@ gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, guint length)
gsize
gst_buffer_get_sizes (GstBuffer * buffer, gsize * offset, gsize * maxsize)
{
guint i, len;
gsize extra, size, offs;
guint len;
gsize size;
GstMemory *mem;
g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
len = GST_BUFFER_MEM_LEN (buffer);
size = offs = extra = 0;
for (i = 0; i < len; i++) {
gsize s, o, ms;
if (G_LIKELY (len == 1)) {
/* common case */
mem = GST_BUFFER_MEM_PTR (buffer, 0);
size = gst_memory_get_sizes (mem, offset, maxsize);
} else {
guint i;
gsize extra, offs;
s = gst_memory_get_sizes (GST_BUFFER_MEM_PTR (buffer, i), &o, &ms);
size = offs = extra = 0;
for (i = 0; i < len; i++) {
gsize s, o, ms;
/* add sizes */
size += s;
mem = GST_BUFFER_MEM_PTR (buffer, i);
s = gst_memory_get_sizes (mem, &o, &ms);
/* keep offset of first memory block */
if (i == 0)
offs = o;
/* this is the amount of extra bytes in this block, we only keep this for
* the last block */
else if (i + 1 == len)
extra = ms - (o + s);
/* add sizes */
size += s;
/* keep offset of first memory block */
if (i == 0)
offs = o;
/* this is the amount of extra bytes in this block, we only keep this for
* the last block */
if (i + 1 == len)
extra = ms - (o + s);
}
if (offset)
*offset = offs;
if (maxsize)
*maxsize = offs + size + extra;
}
if (offset)
*offset = offs;
if (maxsize)
*maxsize = offs + size + extra;
return size;
}
@ -810,7 +820,7 @@ gst_buffer_resize (GstBuffer * buffer, gssize offset, gsize size)
gsize bsize, bufsize, bufoffs, bufmax;
GstMemory *mem;
GST_CAT_LOG (GST_CAT_BUFFER, "trim %p %" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT,
GST_CAT_LOG (GST_CAT_BUFFER, "trim %p %" G_GSSIZE_FORMAT "-%" G_GSIZE_FORMAT,
buffer, offset, size);
g_return_if_fail (gst_buffer_is_writable (buffer));
@ -834,15 +844,20 @@ gst_buffer_resize (GstBuffer * buffer, gssize offset, gsize size)
mem = GST_BUFFER_MEM_PTR (buffer, si);
bsize = gst_memory_get_sizes (mem, NULL, NULL);
if (bsize <= offset) {
if ((gssize) bsize <= offset) {
/* remove buffer */
gst_memory_unref (mem);
offset -= bsize;
} else {
gsize left;
left = MIN (bsize - offset, size);
if (left < bsize) {
/* last buffer always gets resized to the remaining size */
if (si + 1 == len)
left = size;
else
left = MIN (bsize - offset, size);
if (left) {
/* we need to clip something */
if (GST_MEMORY_IS_WRITABLE (mem)) {
gst_memory_resize (mem, offset, left);

View file

@ -228,7 +228,7 @@ _default_mem_free (GstMemoryDefault * mem)
}
static GstMemoryDefault *
_default_mem_copy (GstMemoryDefault * mem, gsize offset, gsize size)
_default_mem_copy (GstMemoryDefault * mem, gssize offset, gsize size)
{
GstMemoryDefault *copy;
@ -242,7 +242,7 @@ _default_mem_copy (GstMemoryDefault * mem, gsize offset, gsize size)
}
static GstMemoryDefault *
_default_mem_share (GstMemoryDefault * mem, gsize offset, gsize size)
_default_mem_share (GstMemoryDefault * mem, gssize offset, gsize size)
{
GstMemoryDefault *sub;
GstMemory *parent;
@ -278,7 +278,7 @@ _default_mem_is_span (GstMemoryDefault * mem1, GstMemoryDefault * mem2,
}
static GstMemory *
_fallback_copy (GstMemory * mem, gsize offset, gsize size)
_fallback_copy (GstMemory * mem, gssize offset, gsize size)
{
GstMemory *copy;
guint8 *data, *dest;
@ -492,7 +492,7 @@ gst_memory_unmap (GstMemory * mem, gpointer data, gsize size)
* Returns: a new #GstMemory.
*/
GstMemory *
gst_memory_copy (GstMemory * mem, gsize offset, gsize size)
gst_memory_copy (GstMemory * mem, gssize offset, gsize size)
{
g_return_val_if_fail (mem != NULL, NULL);
@ -513,7 +513,7 @@ gst_memory_copy (GstMemory * mem, gsize offset, gsize size)
* Returns: a new #GstMemory.
*/
GstMemory *
gst_memory_share (GstMemory * mem, gsize offset, gsize size)
gst_memory_share (GstMemory * mem, gssize offset, gsize size)
{
g_return_val_if_fail (mem != NULL, NULL);

View file

@ -204,7 +204,7 @@ typedef void (*GstMemoryFreeFunction) (GstMemory *mem);
* Returns: a new #GstMemory object wrapping a copy of the requested region in
* @mem.
*/
typedef GstMemory * (*GstMemoryCopyFunction) (GstMemory *mem, gsize offset, gsize size);
typedef GstMemory * (*GstMemoryCopyFunction) (GstMemory *mem, gssize offset, gsize size);
/**
* GstMemoryShareFunction:
@ -218,7 +218,7 @@ typedef GstMemory * (*GstMemoryCopyFunction) (GstMemory *mem, gsize offset,
*
* Returns: a new #GstMemory object sharing the requested region in @mem.
*/
typedef GstMemory * (*GstMemoryShareFunction) (GstMemory *mem, gsize offset, gsize size);
typedef GstMemory * (*GstMemoryShareFunction) (GstMemory *mem, gssize offset, gsize size);
/**
* GstMemoryIsSpanFunction:
@ -293,8 +293,8 @@ gpointer gst_memory_map (GstMemory *mem, gsize *size, gsize *maxsize,
gboolean gst_memory_unmap (GstMemory *mem, gpointer data, gsize size);
/* copy and subregions */
GstMemory * gst_memory_copy (GstMemory *mem, gsize offset, gsize size);
GstMemory * gst_memory_share (GstMemory *mem, gsize offset, gsize size);
GstMemory * gst_memory_copy (GstMemory *mem, gssize offset, gsize size);
GstMemory * gst_memory_share (GstMemory *mem, gssize offset, gsize size);
/* span memory */
gboolean gst_memory_is_span (GstMemory *mem1, GstMemory *mem2, gsize *offset);

View file

@ -441,6 +441,85 @@ GST_START_TEST (test_try_new_and_alloc)
GST_END_TEST;
GST_START_TEST (test_resize)
{
GstBuffer *buf;
gsize maxalloc;
gsize size, maxsize, offset;
/* one memory block */
buf = gst_buffer_new_allocate (NULL, 100, 0);
size = gst_buffer_get_sizes (buf, &offset, &maxalloc);
fail_unless (size == 100);
fail_unless (offset == 0);
fail_unless (maxalloc >= 100);
ASSERT_CRITICAL (gst_buffer_resize (buf, 200, 50));
ASSERT_CRITICAL (gst_buffer_resize (buf, 0, 150));
ASSERT_CRITICAL (gst_buffer_resize (buf, 1, maxalloc));
ASSERT_CRITICAL (gst_buffer_resize (buf, maxalloc, 1));
/* this does nothing */
gst_buffer_resize (buf, 0, 100);
/* nothing should have changed */
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 100);
fail_unless (offset == 0);
fail_unless (maxsize == maxalloc);
gst_buffer_resize (buf, 0, 50);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 50);
fail_unless (offset == 0);
fail_unless (maxsize == maxalloc);
gst_buffer_resize (buf, 0, 100);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 100);
fail_unless (offset == 0);
fail_unless (maxsize == maxalloc);
gst_buffer_resize (buf, 1, 99);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 99);
fail_unless (offset == 1);
fail_unless (maxsize == maxalloc);
ASSERT_CRITICAL (gst_buffer_resize (buf, 1, maxalloc - 1));
gst_buffer_resize (buf, 0, 99);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 99);
fail_unless (offset == 1);
fail_unless (maxsize == maxalloc);
gst_buffer_resize (buf, -1, 100);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 100);
fail_unless (offset == 0);
fail_unless (maxsize == maxalloc);
ASSERT_CRITICAL (gst_buffer_resize (buf, -1, 100));
gst_buffer_resize (buf, 50, 40);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 40);
fail_unless (offset == 50);
fail_unless (maxsize == maxalloc);
gst_buffer_resize (buf, -50, 100);
size = gst_buffer_get_sizes (buf, &offset, &maxsize);
fail_unless (size == 100);
fail_unless (offset == 0);
fail_unless (maxsize == maxalloc);
gst_buffer_unref (buf);
}
GST_END_TEST;
static Suite *
gst_buffer_suite (void)
{
@ -456,6 +535,7 @@ gst_buffer_suite (void)
tcase_add_test (tc_chain, test_metadata_writable);
tcase_add_test (tc_chain, test_copy);
tcase_add_test (tc_chain, test_try_new_and_alloc);
tcase_add_test (tc_chain, test_resize);
return s;
}