buffer: improve the buffer memory methods

gst_buffer_take_memory -> gst_buffer_insert_memory because insert is what the
method does.
Make all methods deal with ranges so that we can replace, merge, remove and map
a certain subset of the memory in a buffer. With the new methods we can make
some code nicer and reuse more code. Being able to deal with a subset of the
buffer memory allows us to optimize more cases later (most notably RTP headers
and payload that could be in different memory objects).
Make some more convenient macros that call the more generic range methods.
This commit is contained in:
Wim Taymans 2012-03-30 18:04:51 +02:00
parent bcb98f409b
commit 38b96e6c8c
13 changed files with 130 additions and 103 deletions

View file

@ -36,7 +36,7 @@ Managing GstMemory
A GstBuffer contains an array of pointers to GstMemory objects.
When the buffer is writable, gst_buffer_take_memory() can be used to add a
When the buffer is writable, gst_buffer_insert_memory() can be used to add a
new GstMemory object to the buffer. When the array of memory is full, memory
will be merged to make room for the new memory object.

View file

@ -192,15 +192,19 @@ gst_buffer_resize
gst_buffer_set_size
gst_buffer_n_memory
gst_buffer_take_memory
gst_buffer_append_memory
gst_buffer_get_memory
gst_buffer_get_merged_memory
gst_buffer_remove_memory
gst_buffer_insert_memory
gst_buffer_replace_memory_range
gst_buffer_get_memory_range
gst_buffer_remove_memory_range
gst_buffer_remove_all_memory
gst_buffer_replace_all_memory
gst_buffer_prepend_memory
gst_buffer_append_memory
gst_buffer_replace_memory
gst_buffer_replace_all_memory
gst_buffer_get_memory
gst_buffer_get_all_memory
gst_buffer_remove_memory
gst_buffer_remove_all_memory
gst_buffer_map
gst_buffer_unmap

View file

@ -203,7 +203,7 @@ The 0.11 porting guide
A GstBuffer is now a simple boxed type this means that subclassing is not
possible anymore.
To add data to the buffer you would now use gst_buffer_take_memory() with
To add data to the buffer you would now use gst_buffer_insert_memory() with
a GstMemory object containing the data. Multiple memory blocks can added to
a GstBuffer that can then be retrieved with gst_buffer_peek_memory().

View file

@ -43,7 +43,7 @@
* size = width * height * bpp;
* buffer = gst_buffer_new ();
* memory = gst_allocator_alloc (NULL, size, NULL);
* gst_buffer_take_memory (buffer, -1, memory);
* gst_buffer_insert_memory (buffer, -1, memory);
* ...
* </programlisting>
* </example>
@ -197,27 +197,23 @@ _is_span (GstMemory ** mem, gsize len, gsize * poffset, GstMemory ** parent)
}
static GstMemory *
_get_merged_memory (GstBuffer * buffer, gboolean * merged)
_get_merged_memory (GstBuffer * buffer, guint idx, guint length)
{
GstMemory **mem, *result;
gsize len;
mem = GST_BUFFER_MEM_ARRAY (buffer);
len = GST_BUFFER_MEM_LEN (buffer);
if (G_UNLIKELY (len == 0)) {
if (G_UNLIKELY (length == 0)) {
result = NULL;
*merged = FALSE;
} else if (G_LIKELY (len == 1)) {
result = gst_memory_ref (mem[0]);
*merged = FALSE;
} else if (G_LIKELY (length == 1)) {
result = gst_memory_ref (mem[idx]);
} else {
GstMemory *parent = NULL;
gsize size, poffset = 0;
size = gst_buffer_get_size (buffer);
if (G_UNLIKELY (_is_span (mem, len, &poffset, &parent))) {
if (G_UNLIKELY (_is_span (mem + idx, length, &poffset, &parent))) {
if (parent->flags & GST_MEMORY_FLAG_NO_SHARE) {
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "copy for merge %p", parent);
@ -236,7 +232,7 @@ _get_merged_memory (GstBuffer * buffer, gboolean * merged)
ptr = dinfo.data;
left = size;
for (i = 0; i < len && left > 0; i++) {
for (i = idx; i < length && left > 0; i++) {
gst_memory_map (mem[i], &sinfo, GST_MAP_READ);
tocopy = MIN (sinfo.size, left);
GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
@ -248,26 +244,30 @@ _get_merged_memory (GstBuffer * buffer, gboolean * merged)
}
gst_memory_unmap (result, &dinfo);
}
*merged = TRUE;
}
return result;
}
static void
_replace_all_memory (GstBuffer * buffer, GstMemory * mem)
_replace_memory (GstBuffer * buffer, guint len, guint idx, guint length,
GstMemory * mem)
{
gsize len, i;
gsize end, i;
GST_LOG ("buffer %p replace with memory %p", buffer, mem);
len = GST_BUFFER_MEM_LEN (buffer);
end = idx + length;
GST_LOG ("buffer %p replace %u-%u with memory %p", buffer, idx, end, mem);
/* unref old memory */
for (i = 0; i < len; i++)
for (i = idx; i < end; i++)
gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
if (end != len) {
g_memmove (&GST_BUFFER_MEM_PTR (buffer, idx + 1),
&GST_BUFFER_MEM_PTR (buffer, end), (len - end) * sizeof (gpointer));
}
/* replace with single memory */
GST_BUFFER_MEM_PTR (buffer, 0) = mem;
GST_BUFFER_MEM_LEN (buffer) = 1;
GST_BUFFER_MEM_PTR (buffer, idx) = mem;
GST_BUFFER_MEM_LEN (buffer) = len - length + 1;
}
static inline void
@ -276,14 +276,13 @@ _memory_add (GstBuffer * buffer, guint idx, GstMemory * mem)
guint i, len = GST_BUFFER_MEM_LEN (buffer);
if (G_UNLIKELY (len >= GST_BUFFER_MEM_MAX)) {
gboolean merged;
/* too many buffer, span them. */
/* FIXME, there is room for improvement here: We could only try to merge
* 2 buffers to make some room. If we can't efficiently merge 2 buffers we
* could try to only merge the two smallest buffers to avoid memcpy, etc. */
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "memory array overflow in buffer %p",
buffer);
_replace_all_memory (buffer, _get_merged_memory (buffer, &merged));
_replace_memory (buffer, len, 0, len, _get_merged_memory (buffer, 0, len));
/* we now have 1 single spanned buffer */
len = 1;
}
@ -413,8 +412,8 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
}
}
if (flags & GST_BUFFER_COPY_MERGE) {
gboolean merged;
_replace_all_memory (dest, _get_merged_memory (dest, &merged));
len = GST_BUFFER_MEM_LEN (dest);
_replace_memory (dest, len, 0, len, _get_merged_memory (dest, 0, len));
}
}
@ -733,16 +732,16 @@ gst_buffer_n_memory (GstBuffer * buffer)
}
/**
* gst_buffer_take_memory:
* gst_buffer_insert_memory:
* @buffer: a #GstBuffer.
* @idx: the index to add the memory at, or -1 to append it to the end
* @mem: (transfer full): a #GstMemory.
*
* Add the memory block @mem to @buffer at @idx. This function takes ownership
* Insert the memory block @mem to @buffer at @idx. This function takes ownership
* of @mem and thus doesn't increase its refcount.
*/
void
gst_buffer_take_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
gst_buffer_insert_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
{
g_return_if_fail (GST_IS_BUFFER (buffer));
g_return_if_fail (gst_buffer_is_writable (buffer));
@ -774,61 +773,67 @@ _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info,
}
/**
* gst_buffer_get_memory:
* gst_buffer_get_memory_range:
* @buffer: a #GstBuffer.
* @idx: an index
* @length: a length
*
* Get the memory block in @buffer at @idx. If @idx is -1, all memory is merged
* into one large #GstMemory object that is then returned.
* Get @length memory blocks in @buffer starting at @idx. The memory blocks will
* be merged into one large #GstMemory.
*
* Returns: (transfer full): a #GstMemory at @idx. Use gst_memory_unref () after usage.
* If @length is -1, all memory starting from @idx is merged.
*
* Returns: (transfer full): a #GstMemory that contains the merged data of @length
* blocks starting at @idx. Use gst_memory_unref () after usage.
*/
GstMemory *
gst_buffer_get_memory (GstBuffer * buffer, gint idx)
gst_buffer_get_memory_range (GstBuffer * buffer, guint idx, gint length)
{
GstMemory *mem;
guint len;
GST_DEBUG ("idx %u, length %d", idx, length);
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
g_return_val_if_fail (idx == -1 ||
(idx >= 0 && idx <= GST_BUFFER_MEM_LEN (buffer)), NULL);
len = GST_BUFFER_MEM_LEN (buffer);
g_return_val_if_fail ((length == -1 && idx < len) ||
(length > 0 && length + idx <= len), NULL);
if (idx == -1) {
gboolean merged;
mem = _get_merged_memory (buffer, &merged);
} else if ((mem = GST_BUFFER_MEM_PTR (buffer, idx))) {
gst_memory_ref (mem);
}
return mem;
if (length == -1)
length = len - idx;
return _get_merged_memory (buffer, idx, length);
}
/**
* gst_buffer_replace_memory:
* gst_buffer_replace_memory_range:
* @buffer: a #GstBuffer.
* @idx: an index
* @length: a length should not be 0
* @mem: (transfer full): a #GstMemory
*
* Replaces the memory block in @buffer at @idx with @mem. If @idx is -1, all
* memory will be removed and replaced with @mem.
* Replaces @length memory blocks in @buffer starting at @idx with @mem.
*
* If @length is -1, all memory starting from @idx will be removed and
* replaced with @mem.
*
* @buffer should be writable.
*/
void
gst_buffer_replace_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
gst_buffer_replace_memory_range (GstBuffer * buffer, guint idx, gint length,
GstMemory * mem)
{
guint len;
g_return_if_fail (GST_IS_BUFFER (buffer));
g_return_if_fail (gst_buffer_is_writable (buffer));
g_return_if_fail (idx == -1 ||
(idx >= 0 && idx < GST_BUFFER_MEM_LEN (buffer)));
len = GST_BUFFER_MEM_LEN (buffer);
g_return_if_fail ((length == -1 && idx < len) || (length > 0
&& length + idx <= len));
if (idx == -1) {
_replace_all_memory (buffer, mem);
} else {
GstMemory *old;
if (length == -1)
length = len - idx;
if ((old = GST_BUFFER_MEM_PTR (buffer, idx)))
gst_memory_unref (old);
GST_BUFFER_MEM_PTR (buffer, idx) = mem;
}
_replace_memory (buffer, len, idx, length, mem);
}
/**
@ -837,7 +842,7 @@ gst_buffer_replace_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
* @idx: an index
* @length: a length
*
* Remove @len memory blocks in @buffer starting from @idx.
* Remove @length memory blocks in @buffer starting from @idx.
*
* @length can be -1, in which case all memory starting from @idx is removed.
*/
@ -850,7 +855,7 @@ gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, gint length)
g_return_if_fail (gst_buffer_is_writable (buffer));
len = GST_BUFFER_MEM_LEN (buffer);
g_return_if_fail ((length == -1 && idx < len) || length + idx < len);
g_return_if_fail ((length == -1 && idx < len) || length + idx <= len);
if (length == -1)
length = len - idx;
@ -1014,12 +1019,16 @@ gst_buffer_resize (GstBuffer * buffer, gssize offset, gssize size)
}
/**
* gst_buffer_map:
* gst_buffer_map_range:
* @buffer: a #GstBuffer.
* @idx: an index
* @length: a length
* @info: (out): info about the mapping
* @flags: flags for the mapping
*
* This function fills @info with a pointer to the merged memory in @buffer.
* This function fills @info with the #GstMapInfo of @length merged memory blocks
* starting at @idx in @buffer. When @length is -1, all memory blocks starting
* from @idx are merged and mapped.
* @flags describe the desired access of the memory. When @flags is
* #GST_MAP_WRITE, @buffer should be writable (as returned from
* gst_buffer_is_writable()).
@ -1028,22 +1037,26 @@ gst_buffer_resize (GstBuffer * buffer, gssize offset, gssize size)
* automatically be created and returned. The readonly copy of the buffer memory
* will then also be replaced with this writable copy.
*
* When the buffer contains multiple memory blocks, the returned pointer will be
* a concatenation of the memory blocks.
*
* The memory in @info should be unmapped with gst_buffer_unmap() after usage.
*
* Returns: (transfer full): %TRUE if the map succeeded and @info contains valid
* data.
*/
gboolean
gst_buffer_map (GstBuffer * buffer, GstMapInfo * info, GstMapFlags flags)
gst_buffer_map_range (GstBuffer * buffer, guint idx, gint length,
GstMapInfo * info, GstMapFlags flags)
{
GstMemory *mem, *nmem;
gboolean write, writable, merged;
gboolean write, writable;
gsize len;
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
len = GST_BUFFER_MEM_LEN (buffer);
if (len == 0)
goto no_memory;
g_return_val_if_fail ((length == -1 && idx < len) || (length > 0
&& length + idx <= len), FALSE);
write = (flags & GST_MAP_WRITE) != 0;
writable = gst_buffer_is_writable (buffer);
@ -1052,7 +1065,10 @@ gst_buffer_map (GstBuffer * buffer, GstMapInfo * info, GstMapFlags flags)
if (G_UNLIKELY (write && !writable))
goto not_writable;
mem = _get_merged_memory (buffer, &merged);
if (length == -1)
length = len - idx;
mem = _get_merged_memory (buffer, idx, length);
if (G_UNLIKELY (mem == NULL))
goto no_memory;
@ -1063,12 +1079,12 @@ gst_buffer_map (GstBuffer * buffer, GstMapInfo * info, GstMapFlags flags)
/* if we merged or when the map returned a different memory, we try to replace
* the memory in the buffer */
if (G_UNLIKELY (merged || nmem != mem)) {
if (G_UNLIKELY (length > 1 || nmem != mem)) {
/* if the buffer is writable, replace the memory */
if (writable) {
_replace_all_memory (buffer, gst_memory_ref (nmem));
_replace_memory (buffer, len, idx, length, gst_memory_ref (nmem));
} else {
if (GST_BUFFER_MEM_LEN (buffer) > 1) {
if (len > 1) {
GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
"temporary mapping for memory %p in buffer %p", nmem, buffer);
}

View file

@ -266,15 +266,18 @@ GstBuffer * gst_buffer_new_wrapped_full (GstMemoryFlags flags, gpointer data,
GstBuffer * gst_buffer_new_wrapped (gpointer data, gsize size);
/* memory blocks */
guint gst_buffer_n_memory (GstBuffer *buffer);
void gst_buffer_take_memory (GstBuffer *buffer, gint idx, GstMemory *mem);
void gst_buffer_replace_memory (GstBuffer *buffer, gint idx, GstMemory *mem);
GstMemory * gst_buffer_get_memory (GstBuffer *buffer, gint idx);
void gst_buffer_remove_memory_range (GstBuffer *buffer, guint idx, gint length);
guint gst_buffer_n_memory (GstBuffer *buffer);
void gst_buffer_insert_memory (GstBuffer *buffer, gint idx, GstMemory *mem);
void gst_buffer_replace_memory_range (GstBuffer *buffer, guint idx, gint length, GstMemory *mem);
GstMemory * gst_buffer_get_memory_range (GstBuffer *buffer, guint idx, gint length);
void gst_buffer_remove_memory_range (GstBuffer *buffer, guint idx, gint length);
#define gst_buffer_append_memory(b,m) gst_buffer_take_memory ((b), -1, (m))
#define gst_buffer_replace_all_memory(b,m) gst_buffer_replace_memory ((b), -1, (m))
#define gst_buffer_get_merged_memory(b) gst_buffer_get_memory ((b), -1)
#define gst_buffer_prepend_memory(b,m) gst_buffer_insert_memory ((b), 0, (m))
#define gst_buffer_append_memory(b,m) gst_buffer_insert_memory ((b), -1, (m))
#define gst_buffer_replace_memory(b,i,m) gst_buffer_replace_memory_range ((b), (i), 1, (m))
#define gst_buffer_replace_all_memory(b,m) gst_buffer_replace_memory ((b), 0, -1, (m))
#define gst_buffer_get_memory(b,i) gst_buffer_get_memory_range ((b), (i), 1)
#define gst_buffer_get_all_memory(b) gst_buffer_get_memory_range ((b), 0, -1)
/**
* gst_buffer_remove_memory:
* @b: a #GstBuffer.
@ -314,9 +317,13 @@ void gst_buffer_resize (GstBuffer *buffer, gssize offset, gs
*/
#define gst_buffer_set_size(b,s) gst_buffer_resize ((b), 0, (s))
gboolean gst_buffer_map (GstBuffer *buffer, GstMapInfo *info, GstMapFlags flags);
gboolean gst_buffer_map_range (GstBuffer *buffer, guint idx, gint length,
GstMapInfo *info, GstMapFlags flags);
#define gst_buffer_map(b,i,f) gst_buffer_map_range ((b), 0, -1, (i), (f))
void gst_buffer_unmap (GstBuffer *buffer, GstMapInfo *info);
/* refcounting */
/**
* gst_buffer_ref:

View file

@ -769,7 +769,7 @@ gst_adapter_take_buffer (GstAdapter * adapter, gsize nbytes)
data = gst_adapter_take_internal (adapter, nbytes);
buffer = gst_buffer_new ();
gst_buffer_take_memory (buffer, -1,
gst_buffer_append_memory (buffer,
gst_memory_new_wrapped (0, data, nbytes, 0, nbytes, data, g_free));
done:

View file

@ -260,7 +260,7 @@ gst_byte_writer_reset_and_get_buffer (GstByteWriter * writer)
buffer = gst_buffer_new ();
if (data != NULL) {
gst_buffer_take_memory (buffer, -1,
gst_buffer_append_memory (buffer,
gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
}

View file

@ -659,7 +659,7 @@ gst_fake_src_alloc_buffer (GstFakeSrc * src, guint size)
if (do_prepare)
gst_fake_src_prepare_buffer (src, data, size);
gst_buffer_take_memory (buf, -1,
gst_buffer_append_memory (buf,
gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
}

View file

@ -191,7 +191,7 @@ create_read_only_buffer (void)
buf = gst_buffer_new ();
/* assign some read-only data to the new buffer */
gst_buffer_take_memory (buf, -1,
gst_buffer_insert_memory (buf, -1,
gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
(gpointer) ro_memory, sizeof (ro_memory),
0, sizeof (ro_memory), NULL, NULL));
@ -420,7 +420,7 @@ GST_START_TEST (test_size)
fail_unless (maxsize == maxalloc2);
/* append */
gst_buffer_take_memory (buf, -1, mem);
gst_buffer_insert_memory (buf, -1, mem);
size = gst_buffer_get_sizes (buf, &offset, &maxalloc);
fail_unless (size == 130);
@ -433,7 +433,7 @@ GST_START_TEST (test_size)
mem = gst_allocator_alloc (NULL, 100, NULL);
size = gst_memory_get_sizes (mem, &offset, &maxalloc3);
gst_memory_resize (mem, 0, 0);
gst_buffer_take_memory (buf, -1, mem);
gst_buffer_insert_memory (buf, -1, mem);
size = gst_buffer_get_sizes (buf, &offset, &maxalloc);
fail_unless (size == 130);
@ -446,7 +446,7 @@ GST_START_TEST (test_size)
mem = gst_allocator_alloc (NULL, 100, NULL);
size = gst_memory_get_sizes (mem, &offset, &maxalloc4);
gst_memory_resize (mem, 0, 0);
gst_buffer_take_memory (buf, 0, mem);
gst_buffer_insert_memory (buf, 0, mem);
size = gst_buffer_get_sizes (buf, &offset, &maxalloc);
fail_unless (size == 130);
@ -566,8 +566,8 @@ GST_START_TEST (test_map)
gsize size, offset;
buf = gst_buffer_new ();
gst_buffer_take_memory (buf, -1, gst_allocator_alloc (NULL, 50, NULL));
gst_buffer_take_memory (buf, -1, gst_allocator_alloc (NULL, 50, NULL));
gst_buffer_insert_memory (buf, -1, gst_allocator_alloc (NULL, 50, NULL));
gst_buffer_insert_memory (buf, -1, gst_allocator_alloc (NULL, 50, NULL));
size = gst_buffer_get_sizes (buf, &offset, &maxalloc);
fail_unless (size == 100);

View file

@ -48,7 +48,7 @@ GST_START_TEST (test_initialization)
guint8 x = 0;
GstMapInfo info;
gst_buffer_take_memory (buffer, -1,
gst_buffer_insert_memory (buffer, -1,
gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, data, 4, 0, 4, NULL,
NULL));

View file

@ -48,7 +48,7 @@ GST_START_TEST (test_initialization)
guint8 x = 0;
GstMapInfo info;
gst_buffer_take_memory (buffer, -1,
gst_buffer_insert_memory (buffer, -1,
gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, data, 4, 0, 4, NULL,
NULL));

View file

@ -53,7 +53,7 @@ GST_START_TEST (test_buffer_range)
buf = gst_buffer_new ();
fail_unless (buf != NULL);
gst_buffer_take_memory (buf, -1,
gst_buffer_insert_memory (buf, -1,
gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
(gpointer) vorbisid, 30, 0, 30, NULL, NULL));

View file

@ -98,10 +98,11 @@ EXPORTS
gst_buffer_fill
gst_buffer_flags_get_type
gst_buffer_foreach_meta
gst_buffer_get_memory
gst_buffer_get_memory_range
gst_buffer_get_meta
gst_buffer_get_sizes
gst_buffer_get_type
gst_buffer_insert_memory
gst_buffer_iterate_meta
gst_buffer_list_foreach
gst_buffer_list_get
@ -111,7 +112,7 @@ EXPORTS
gst_buffer_list_new
gst_buffer_list_new_sized
gst_buffer_list_remove
gst_buffer_map
gst_buffer_map_range
gst_buffer_memcmp
gst_buffer_memset
gst_buffer_n_memory
@ -140,9 +141,8 @@ EXPORTS
gst_buffer_pool_set_config
gst_buffer_remove_memory_range
gst_buffer_remove_meta
gst_buffer_replace_memory
gst_buffer_replace_memory_range
gst_buffer_resize
gst_buffer_take_memory
gst_buffer_unmap
gst_buffering_mode_get_type
gst_bus_add_signal_watch