return span;
}
+static GstMemory *
+_get_merged_memory (GstBuffer * buffer)
+{
+ guint len;
+ GstMemory *mem;
+
+ len = GST_BUFFER_MEM_LEN (buffer);
+
+ if (G_UNLIKELY (len == 0)) {
+ /* no memory */
+ mem = NULL;
+ } else if (G_LIKELY (len == 1)) {
+ /* we can take the first one */
+ mem = GST_BUFFER_MEM_PTR (buffer, 0);
+ gst_memory_ref (mem);
+ } else {
+ /* we need to span memory */
+ mem = _span_memory (buffer, 0, -1, FALSE);
+ }
+ return mem;
+}
+
static void
-_replace_memory (GstBuffer * buffer, GstMemory * mem)
+_replace_all_memory (GstBuffer * buffer, GstMemory * mem)
{
gsize len, i;
len = GST_BUFFER_MEM_LEN (buffer);
- /* unref old buffers */
+
+ if (G_LIKELY (len == 1 && GST_BUFFER_MEM_PTR (buffer, 0) == mem)) {
+ gst_memory_unref (mem);
+ return;
+ }
+
+ GST_LOG ("buffer %p replace with memory %p", buffer, mem);
+
+ /* unref old memory */
for (i = 0; i < len; i++)
gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
-
- /* replace with single spanned buffer */
+ /* replace with single memory */
GST_BUFFER_MEM_PTR (buffer, 0) = mem;
GST_BUFFER_MEM_LEN (buffer) = 1;
}
* 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_memory (buffer, _span_memory (buffer, 0, -1, FALSE));
+ _replace_all_memory (buffer, _span_memory (buffer, 0, -1, FALSE));
/* we now have 1 single spanned buffer */
len = 1;
}
}
}
if (flags & GST_BUFFER_COPY_MERGE) {
- _replace_memory (dest, _span_memory (dest, 0, size, FALSE));
+ _replace_all_memory (dest, _span_memory (dest, 0, size, FALSE));
}
}
GstBuffer *newbuf;
newbuf = gst_buffer_new ();
- gst_buffer_take_memory (newbuf, -1,
+ gst_buffer_append_memory (newbuf,
gst_memory_new_wrapped (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
data, free_func, offset + size, offset, size));
}
static GstMemory *
-_get_memory (GstBuffer * buffer, guint idx, gboolean write)
+_get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info,
+ GstMapFlags flags)
{
- GstMemory *mem;
+ GstMemory *mem, *mapped;
mem = GST_BUFFER_MEM_PTR (buffer, idx);
- if (G_UNLIKELY (write && !gst_memory_is_writable (mem))) {
- GstMemory *copy;
- GST_CAT_LOG (GST_CAT_BUFFER,
- "making writable copy of memory %p in buffer %p", mem, buffer);
- /* replace with a writable copy */
- copy = gst_memory_copy (mem, 0, -1);
- GST_BUFFER_MEM_PTR (buffer, idx) = copy;
+ mapped = gst_memory_make_mapped (mem, info, flags);
+ if (!mapped)
+ return NULL;
+
+ if (mapped != mem) {
+ GST_BUFFER_MEM_PTR (buffer, idx) = mapped;
gst_memory_unref (mem);
- mem = copy;
+ mem = mapped;
}
return mem;
}
/**
- * gst_buffer_peek_memory:
+ * gst_buffer_get_memory:
* @buffer: a #GstBuffer.
* @idx: an index
- * @flags: #GstMapFlags
- *
- * Get the memory block in @buffer at @idx for memory access in @flags.
- * This function does not return a refcount to the memory block. The memory
- * block stays valid for as long as the caller has a valid reference to @buffer
- * and as long as no operations that modify the memory blocks are called, such
- * as gst_buffer_remove_memory_range(), gst_buffer_take_memory() and gst_buffer_resize().
*
- * @buffer should be writable when @flags contains #GST_MAP_WRITE. If the memory
- * at @idx is not writable, a new writable copy will be installed in @buffer and
- * returned.
+ * 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.
*
- * Returns: a #GstMemory at @idx.
+ * Returns: (transfer full): a #GstMemory at @idx. Use gst_memory_unref () after usage.
*/
GstMemory *
-gst_buffer_peek_memory (GstBuffer * buffer, guint idx, GstMapFlags flags)
+gst_buffer_get_memory (GstBuffer * buffer, gint idx)
{
GstMemory *mem;
- gboolean write;
-
- write = (flags & GST_MAP_WRITE) != 0;
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
- g_return_val_if_fail (idx < GST_BUFFER_MEM_LEN (buffer), NULL);
+ g_return_val_if_fail (idx == -1 ||
+ (idx >= 0 && idx <= GST_BUFFER_MEM_LEN (buffer)), NULL);
- /* check if we can write when asked for write access */
- if (G_UNLIKELY (write && !gst_buffer_is_writable (buffer)))
- goto not_writable;
+ if (idx == -1) {
+ mem = _get_merged_memory (buffer);
+ } else if ((mem = GST_BUFFER_MEM_PTR (buffer, idx))) {
+ gst_memory_ref (mem);
+ }
+ return mem;
+}
- mem = _get_memory (buffer, idx, write);
+/**
+ * gst_buffer_replace_memory:
+ * @buffer: a #GstBuffer.
+ * @idx: an index
+ * @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.
+ *
+ * @buffer should be writable.
+ */
+void
+gst_buffer_replace_memory (GstBuffer * buffer, gint idx, GstMemory * mem)
+{
+ 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)));
- return mem;
+ if (idx == -1) {
+ _replace_all_memory (buffer, mem);
+ } else {
+ GstMemory *old;
- /* ERRORS */
-not_writable:
- {
- g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);
- return NULL;
+ if ((old = GST_BUFFER_MEM_PTR (buffer, idx)))
+ gst_memory_unref (old);
+ GST_BUFFER_MEM_PTR (buffer, idx) = mem;
}
}
* @length can be -1, in which case all memory starting from @idx is removed.
*/
void
-gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, guint length)
+gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, gint length)
{
guint len, i, end;
g_return_if_fail (gst_buffer_is_writable (buffer));
len = GST_BUFFER_MEM_LEN (buffer);
- if (length == -1) {
- g_return_if_fail (idx < len);
+ g_return_if_fail ((length == -1 && idx < len) || length + idx < len);
+
+ if (length == -1)
length = len - idx;
- }
end = idx + length;
for (i = idx; i < end; i++)
}
/**
- * gst_buffer_get_merged_memory:
- * @buffer: a #GstBuffer.
- *
- * Return a #GstMemory object that contains all the memory in @buffer. If there
- * was only one memory in @buffer, it will be returned directly, otherwise all
- * memory objects will be merged into one object that will be returned.
- *
- * Returns: a #GstMemory with the merged memory in @buffer. This function can
- * return %NULL if there is no memory in @buffer. Use gst_memory_unref() after
- * usage.
- */
-static GstMemory *
-gst_buffer_get_merged_memory (GstBuffer * buffer)
-{
- guint len;
- GstMemory *mem;
-
- g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
-
- len = GST_BUFFER_MEM_LEN (buffer);
-
- if (G_UNLIKELY (len == 0)) {
- /* no memory */
- mem = NULL;
- } else if (G_LIKELY (len == 1)) {
- /* we can take the first one */
- mem = GST_BUFFER_MEM_PTR (buffer, 0);
- gst_memory_ref (mem);
- } else {
- /* we need to span memory */
- mem = _span_memory (buffer, 0, -1, FALSE);
- }
- return mem;
-}
-
-/**
* gst_buffer_get_sizes:
* @buffer: a #GstBuffer.
* @offset: a pointer to the offset
left = MIN (bsize - offset, size);
if (offset != 0 || left != bsize) {
- /* we need to clip something */
- if (gst_memory_is_writable (mem)) {
+ if (gst_memory_is_exclusive (mem)) {
gst_memory_resize (mem, offset, left);
} else {
GstMemory *tmp;
if (G_UNLIKELY (write && !writable))
goto not_writable;
- mem = gst_buffer_get_merged_memory (buffer);
+ mem = _get_merged_memory (buffer);
if (G_UNLIKELY (mem == NULL))
goto no_memory;
goto cannot_map;
/* if the buffer is writable, replace the memory */
- if (writable)
- _replace_memory (buffer, gst_memory_ref (mem));
- else if (GST_BUFFER_MEM_LEN (buffer) > 1) {
- GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
- "temporary mapping for memory %p in buffer %p", mem, buffer);
+ if (writable) {
+ _replace_all_memory (buffer, gst_memory_ref (mem));
+ } else {
+ if (GST_BUFFER_MEM_LEN (buffer) > 1) {
+ GST_CAT_DEBUG (GST_CAT_PERFORMANCE,
+ "temporary mapping for memory %p in buffer %p", mem, buffer);
+ }
}
return TRUE;
gsize tocopy;
GstMemory *mem;
- mem = _get_memory (buffer, i, TRUE);
-
- gst_memory_map (mem, &info, GST_MAP_WRITE);
+ mem = _get_mapped (buffer, i, &info, GST_MAP_WRITE);
if (info.size > offset) {
/* we have enough */
tocopy = MIN (info.size - offset, left);
gsize tocopy;
GstMemory *mem;
- mem = GST_BUFFER_MEM_PTR (buffer, i);
-
- gst_memory_map (mem, &info, GST_MAP_READ);
+ mem = _get_mapped (buffer, i, &info, GST_MAP_READ);
if (info.size > offset) {
/* we have enough */
tocopy = MIN (info.size - offset, left);
gsize tocmp;
GstMemory *mem;
- mem = GST_BUFFER_MEM_PTR (buffer, i);
-
- gst_memory_map (mem, &info, GST_MAP_READ);
+ mem = _get_mapped (buffer, i, &info, GST_MAP_READ);
if (info.size > offset) {
/* we have enough */
tocmp = MIN (info.size - offset, size);
gsize toset;
GstMemory *mem;
- mem = _get_memory (buffer, i, TRUE);
-
- gst_memory_map (mem, &info, GST_MAP_WRITE);
+ mem = _get_mapped (buffer, i, &info, GST_MAP_WRITE);
if (info.size > offset) {
/* we have enough */
toset = MIN (info.size - offset, left);
mem->mem.flags = flags;
mem->mem.refcount = 1;
mem->mem.parent = parent ? gst_memory_ref (parent) : NULL;
- mem->mem.state = (flags & GST_MEMORY_FLAG_READONLY ? 0x5 : 0);
+ mem->mem.state = (flags & GST_MEMORY_FLAG_READONLY ? 0x1 : 0);
mem->mem.maxsize = maxsize;
mem->mem.offset = offset;
mem->mem.size = size;
mem->refcount - 1);
if (g_atomic_int_dec_and_test (&mem->refcount)) {
+ g_return_if_fail (g_atomic_int_get (&mem->state) < 4);
#ifndef GST_DISABLE_TRACE
_gst_alloc_trace_free (_gst_memory_trace, mem);
#endif
}
/**
+ * gst_memory_is_exclusive:
+ * @mem: a #GstMemory
+ *
+ * Check if the current ref to @mem is exclusive, this means that no other
+ * references exist other than @mem.
+ */
+gboolean
+gst_memory_is_exclusive (GstMemory * mem)
+{
+ g_return_val_if_fail (mem != NULL, FALSE);
+
+ return (g_atomic_int_get (&mem->refcount) == 1);
+}
+
+/**
* gst_memory_get_sizes:
* @mem: a #GstMemory
* @offset: pointer to offset
gst_memory_resize (GstMemory * mem, gssize offset, gsize size)
{
g_return_if_fail (mem != NULL);
- g_return_if_fail (gst_memory_is_writable (mem));
g_return_if_fail (offset >= 0 || mem->offset >= -offset);
g_return_if_fail (size + mem->offset + offset <= mem->maxsize);
mem->size = size;
}
-/**
- * gst_memory_is_writable:
- * @mem: a #GstMemory
- *
- * Check if @mem is writable.
- *
- * Returns: %TRUE is @mem is writable.
- */
-gboolean
-gst_memory_is_writable (GstMemory * mem)
-{
- g_return_val_if_fail (mem != NULL, FALSE);
-
- return (mem->refcount == 1) &&
- ((mem->parent == NULL) || (mem->parent->refcount == 1)) &&
- ((mem->flags & GST_MEMORY_FLAG_READONLY) == 0);
-}
-
static gboolean
gst_memory_lock (GstMemory * mem, GstMapFlags flags)
{
* - the memory backed by @mem is not accessible with the given @flags.
* - the memory was already mapped with a different mapping.
*
- * @info and its contents remains valid for as long as @mem is alive and until
- * gst_memory_unmap() is called.
+ * @info and its contents remain valid for as long as @mem is valid and
+ * until gst_memory_unmap() is called.
*
* For each gst_memory_map() call, a corresponding gst_memory_unmap() call
* should be done.
GstMemory *shared;
g_return_val_if_fail (mem != NULL, NULL);
+ g_return_val_if_fail (!GST_MEMORY_FLAG_IS_SET (mem, GST_MEMORY_FLAG_NO_SHARE),
+ NULL);
shared = mem->allocator->info.mem_share (mem, offset, size);
GST_EXPORT gsize gst_memory_alignment;
+#define GST_MEMORY_CAST(mem) ((GstMemory *)(mem))
+
/**
* GstMemoryFlags:
* @GST_MEMORY_FLAG_READONLY: memory is readonly. It is not allowed to map the
} GstMemoryFlags;
/**
+ * GST_MEMORY_FLAGS:
+ * @mem: a #GstMemory.
+ *
+ * A flags word containing #GstMemoryFlags flags set on @mem
+ */
+#define GST_MEMORY_FLAGS(mem) (GST_MEMORY_CAST (mem)->flags)
+/**
+ * GST_MEMORY_FLAG_IS_SET:
+ * @mem: a #GstMemory.
+ * @flag: the #GstMemoryFlags to check.
+ *
+ * Gives the status of a specific flag on a @mem.
+ */
+#define GST_MEMORY_FLAG_IS_SET(mem,flag) !!(GST_MEMORY_FLAGS (mem) & (flag))
+
+/**
+ * GST_MEMORY_IS_READONLY:
+ * @mem: a #GstMemory.
+ *
+ * Check if @mem is readonly.
+ */
+#define GST_MEMORY_IS_READONLY(mem) GST_MEMORY_FLAG_IS_SET(mem,GST_MEMORY_FLAG_READONLY)
+
+/**
* GstMemory:
* @allocator: pointer to the #GstAllocator
* @flags: memory flags
GstMemory * gst_allocator_alloc (GstAllocator * allocator,
gsize maxsize, gsize align);
-GstMemory * gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data, GFreeFunc free_func,
- gsize maxsize, gsize offset, gsize size);
+GstMemory * gst_memory_new_wrapped (GstMemoryFlags flags, gpointer data, GFreeFunc free_func,
+ gsize maxsize, gsize offset, gsize size);
/* refcounting */
-GstMemory * gst_memory_ref (GstMemory *mem);
-void gst_memory_unref (GstMemory *mem);
+GstMemory * gst_memory_ref (GstMemory *mem);
+void gst_memory_unref (GstMemory *mem);
+
+gboolean gst_memory_is_exclusive (GstMemory *mem);
/* getting/setting memory properties */
-gsize gst_memory_get_sizes (GstMemory *mem, gsize *offset, gsize *maxsize);
-void gst_memory_resize (GstMemory *mem, gssize offset, gsize size);
+gsize gst_memory_get_sizes (GstMemory *mem, gsize *offset, gsize *maxsize);
+void gst_memory_resize (GstMemory *mem, gssize offset, gsize size);
/* retrieving data */
-gboolean gst_memory_is_writable (GstMemory *mem);
-
-GstMemory * gst_memory_make_mapped (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
-gboolean gst_memory_map (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
-void gst_memory_unmap (GstMemory *mem, GstMapInfo *info);
+GstMemory * gst_memory_make_mapped (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
+gboolean gst_memory_map (GstMemory *mem, GstMapInfo *info, GstMapFlags flags);
+void gst_memory_unmap (GstMemory *mem, GstMapInfo *info);
/* copy and subregions */
-GstMemory * gst_memory_copy (GstMemory *mem, gssize offset, gssize size);
-GstMemory * gst_memory_share (GstMemory *mem, gssize offset, gssize size);
+GstMemory * gst_memory_copy (GstMemory *mem, gssize offset, gssize size);
+GstMemory * gst_memory_share (GstMemory *mem, gssize offset, gssize size);
/* span memory */
-gboolean gst_memory_is_span (GstMemory *mem1, GstMemory *mem2, gsize *offset);
+gboolean gst_memory_is_span (GstMemory *mem1, GstMemory *mem2, gsize *offset);
G_END_DECLS