memory: further memory tweaking
authorWim Taymans <wim.taymans@collabora.co.uk>
Tue, 29 Mar 2011 17:17:55 +0000 (19:17 +0200)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 29 Mar 2011 17:17:55 +0000 (19:17 +0200)
Allow for automatic merging of memory block in the _map function and automatic
freeing of the temporary memory.
Remove some unneeded functions.
Add possibility to force writable spanned memory.

gst/gstbuffer.c
gst/gstbuffer.h
gst/gstmemory.c
gst/gstmemory.h
win32/common/libgstreamer.def

index 8faadaa..b0facd2 100644 (file)
 GType _gst_buffer_type = 0;
 
 static GstMemory *_gst_buffer_arr_span (GstMemory ** mem[], gsize len[],
-    guint n, gsize offset, gsize size);
+    guint n, gsize offset, gsize size, gboolean writable);
 
 typedef struct _GstMetaItem GstMetaItem;
 
@@ -160,26 +160,36 @@ typedef struct
   GstMetaItem *item;
 } GstBufferImpl;
 
-static void
-_span_memory (GstBuffer * buffer, gsize offset, gsize size)
+static GstMemory *
+_span_memory (GstBuffer * buffer, gsize offset, gsize size, gboolean writable)
 {
   GstMemory *span, **mem[1];
-  gsize len[1], i;
+  gsize len[1];
 
   /* not enough room, span buffers */
   mem[0] = GST_BUFFER_MEM_ARRAY (buffer);
   len[0] = GST_BUFFER_MEM_LEN (buffer);
-  if (len[0] == 1)
-    return;
 
-  span = _gst_buffer_arr_span (mem, len, 1, offset, size);
+  if (size == -1)
+    size = gst_buffer_get_size (buffer);
+
+  span = _gst_buffer_arr_span (mem, len, 1, offset, size, writable);
+
+  return span;
+}
+
+static void
+_replace_memory (GstBuffer * buffer, GstMemory * mem)
+{
+  gsize len, i;
 
   /* unref old buffers */
-  for (i = 0; i < len[0]; i++)
-    gst_memory_unref (mem[0][i]);
+  len = GST_BUFFER_MEM_LEN (buffer);
+  for (i = 0; i < len; i++)
+    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
 
   /* replace with single spanned buffer */
-  GST_BUFFER_MEM_PTR (buffer, 0) = span;
+  GST_BUFFER_MEM_PTR (buffer, 0) = mem;
   GST_BUFFER_MEM_LEN (buffer) = 1;
 }
 
@@ -189,12 +199,12 @@ _memory_add (GstBuffer * buffer, GstMemory * mem)
   guint len = GST_BUFFER_MEM_LEN (buffer);
 
   if (G_UNLIKELY (len >= GST_BUFFER_MEM_MAX)) {
-    gsize size = gst_buffer_get_size (buffer);
     /* to many buffer, span them */
-    _span_memory (buffer, 0, size);
+    _replace_memory (buffer, _span_memory (buffer, 0, -1, FALSE));
     /* we now have 1 single spanned buffer */
     len = 1;
   }
+  /* and append the new buffer */
   GST_BUFFER_MEM_PTR (buffer, len) = mem;
   GST_BUFFER_MEM_LEN (buffer) = len + 1;
 }
@@ -328,7 +338,7 @@ gst_buffer_copy_into (GstBuffer * dest, GstBuffer * src,
       }
     }
     if (flags & GST_BUFFER_COPY_MERGE) {
-      _span_memory (dest, 0, size);
+      _replace_memory (dest, _span_memory (dest, 0, size, FALSE));
     }
   }
 
@@ -598,16 +608,30 @@ gst_buffer_take_memory (GstBuffer * buffer, GstMemory * mem)
  * Returns: a #GstMemory at @idx.
  */
 GstMemory *
-gst_buffer_peek_memory (GstBuffer * buffer, guint idx)
+gst_buffer_peek_memory (GstBuffer * buffer, guint idx, GstMapFlags flags)
 {
   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);
 
+  /* check if we can write when asked for write access */
+  if (G_UNLIKELY (write && !gst_buffer_is_writable (buffer)))
+    goto not_writable;
+
   mem = GST_BUFFER_MEM_PTR (buffer, idx);
 
   return mem;
+
+  /* ERRORS */
+not_writable:
+  {
+    g_return_val_if_fail (gst_buffer_is_writable (buffer), NULL);
+    return NULL;
+  }
 }
 
 /**
@@ -759,38 +783,66 @@ gst_buffer_map (GstBuffer * buffer, gsize * size, gsize * maxsize,
 {
   guint len;
   gpointer data;
+  GstMemory *mem;
+  gboolean write, writable;
 
   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
 
-  len = GST_BUFFER_MEM_LEN (buffer);
+  write = (flags & GST_MAP_WRITE) != 0;
+  writable = gst_buffer_is_writable (buffer);
 
-  if (G_UNLIKELY ((flags & GST_MAP_WRITE) && !gst_buffer_is_writable (buffer)))
+  /* check if we can write when asked for write access */
+  if (G_UNLIKELY (write && !writable))
     goto not_writable;
 
-  if (G_LIKELY (len == 1)) {
-    GstMemory *mem;
-
-    mem = GST_BUFFER_MEM_PTR (buffer, 0);
+  len = GST_BUFFER_MEM_LEN (buffer);
 
-    if (flags & GST_MAP_WRITE) {
-      if (G_UNLIKELY (!GST_MEMORY_IS_WRITABLE (mem))) {
-        GstMemory *copy;
+  if (G_UNLIKELY (len == 0)) {
+    /* no memory, return immediately */
+    if (size)
+      *size = 0;
+    if (maxsize)
+      *maxsize = 0;
+    return NULL;
+  }
 
-        /* replace with a writable copy */
-        copy = gst_memory_copy (mem, 0, gst_memory_get_sizes (mem, NULL));
-        GST_BUFFER_MEM_PTR (buffer, 0) = copy;
-        gst_memory_unref (mem);
-        mem = copy;
-      }
+  if (G_LIKELY (len == 1)) {
+    /* we can take the first one */
+    mem = GST_BUFFER_MEM_PTR (buffer, 0);
+  } else {
+    /* we need to span memory */
+    if (writable) {
+      /* if we can write, we can change the memory with the spanned
+       * memory */
+      mem = _span_memory (buffer, 0, -1, write);
+      _replace_memory (buffer, mem);
+    } else {
+      gsize bsize;
+
+      /* extract all data in new memory, FIXME slow!! */
+      bsize = gst_buffer_get_size (buffer);
+
+      data = g_malloc (bsize);
+      gst_buffer_extract (buffer, 0, data, bsize);
+      if (size)
+        *size = bsize;
+      if (maxsize)
+        *maxsize = bsize;
+      return data;
     }
+  }
 
-    data = gst_memory_map (mem, size, maxsize, flags);
-  } else {
-    /* FIXME, implement me */
-    data = NULL;
-    if (size)
-      *size = 0;
+  if (G_UNLIKELY (write && !GST_MEMORY_IS_WRITABLE (mem))) {
+    GstMemory *copy;
+    /* replace with a writable copy */
+    copy = gst_memory_copy (mem, 0, -1);
+    GST_BUFFER_MEM_PTR (buffer, 0) = copy;
+    gst_memory_unref (mem);
+    mem = copy;
   }
+
+  data = gst_memory_map (mem, size, maxsize, flags);
+
   return data;
 
   /* ERROR */
@@ -827,8 +879,11 @@ gst_buffer_unmap (GstBuffer * buffer, gpointer data, gsize size)
 
     result = gst_memory_unmap (mem, data, size);
   } else {
-    /* FIXME, implement me */
-    result = FALSE;
+    /* this must have been from read-only access. After _map, the buffer either
+     * only contains 1 memory block or it allocated memory to join memory
+     * blocks. It's not allowed to add buffers between _map and _unmap. */
+    g_free (data);
+    result = TRUE;
   }
   return result;
 }
@@ -1064,12 +1119,13 @@ _gst_buffer_arr_is_span_fast (GstMemory ** mem[], gsize len[], guint n,
 
 static GstMemory *
 _gst_buffer_arr_span (GstMemory ** mem[], gsize len[], guint n, gsize offset,
-    gsize size)
+    gsize size, gboolean writable)
 {
   GstMemory *span, *parent;
   gsize poffset;
 
-  if (_gst_buffer_arr_is_span_fast (mem, len, n, &poffset, &parent)) {
+  if (!writable
+      && _gst_buffer_arr_is_span_fast (mem, len, n, &poffset, &parent)) {
     span = gst_memory_sub (parent, offset + poffset, size);
   } else {
     gsize count, left;
@@ -1188,7 +1244,7 @@ gst_buffer_span (GstBuffer * buf1, gsize offset, GstBuffer * buf2, gsize size)
   mem[1] = GST_BUFFER_MEM_ARRAY (buf2);
   len[1] = GST_BUFFER_MEM_LEN (buf2);
 
-  span = _gst_buffer_arr_span (mem, len, 2, offset, size);
+  span = _gst_buffer_arr_span (mem, len, 2, offset, size, FALSE);
 
   newbuf = gst_buffer_new ();
   _memory_add (newbuf, span);
index 591ab49..b4cc88e 100644 (file)
@@ -284,7 +284,7 @@ GstBuffer * gst_buffer_new_and_alloc       (guint size);
 /* memory blocks */
 guint       gst_buffer_n_memory            (GstBuffer *buffer);
 void        gst_buffer_take_memory         (GstBuffer *buffer, GstMemory *mem);
-GstMemory * gst_buffer_peek_memory         (GstBuffer *buffer, guint idx);
+GstMemory * gst_buffer_peek_memory         (GstBuffer *buffer, guint idx, GstMapFlags flags);
 void        gst_buffer_remove_memory_range (GstBuffer *buffer, guint idx, guint length);
 
 /**
index 38df7ed..75b94ab 100644 (file)
@@ -188,21 +188,14 @@ _default_mem_copy (GstMemoryDefault * mem, gsize offset, gsize size)
 {
   GstMemoryDefault *copy;
 
+  if (size == -1)
+    size = mem->size > offset ? mem->size - offset : 0;
   copy = _default_mem_new_block (mem->maxsize, 0, mem->offset + offset, size);
   memcpy (copy->data, mem->data, mem->maxsize);
 
   return copy;
 }
 
-static void
-_default_mem_extract (GstMemoryDefault * mem, gsize offset, gpointer dest,
-    gsize size)
-{
-  g_return_if_fail (size + mem->offset + offset <= mem->maxsize);
-
-  memcpy (dest, mem->data + mem->offset + offset, size);
-}
-
 static GstMemoryDefault *
 _default_mem_sub (GstMemoryDefault * mem, gsize offset, gsize size)
 {
@@ -233,17 +226,6 @@ _default_mem_is_span (GstMemoryDefault * mem1, GstMemoryDefault * mem2,
   return mem1->data + mem1->offset + mem1->size == mem2->data + mem2->offset;
 }
 
-static void
-_fallback_extract (GstMemory * mem, gsize offset, gpointer dest, gsize size)
-{
-  guint8 *data;
-  gsize msize;
-
-  data = gst_memory_map (mem, &msize, NULL, GST_MAP_READ);
-  memcpy (dest, data + offset, size);
-  gst_memory_unmap (mem, data, msize);
-}
-
 static GstMemory *
 _fallback_copy (GstMemory * mem, gsize offset, gsize size)
 {
@@ -252,6 +234,8 @@ _fallback_copy (GstMemory * mem, gsize offset, gsize size)
   gsize msize;
 
   data = gst_memory_map (mem, &msize, NULL, GST_MAP_READ);
+  if (size == -1)
+    size = msize > offset ? msize - offset : 0;
   copy = _default_mem_new_block (size, 0, 0, size);
   memcpy (copy->data, data + offset, size);
   gst_memory_unmap (mem, data, msize);
@@ -289,7 +273,6 @@ _gst_memory_init (void)
     (GstMemoryUnmapFunction) _default_mem_unmap,
     (GstMemoryFreeFunction) _default_mem_free,
     (GstMemoryCopyFunction) _default_mem_copy,
-    (GstMemoryExtractFunction) _default_mem_extract,
     (GstMemorySubFunction) _default_mem_sub,
     (GstMemoryIsSpanFunction) _default_mem_is_span
   };
@@ -301,7 +284,6 @@ _gst_memory_init (void)
     (GstMemoryFreeFunction) _default_mem_free,
     NULL,
     NULL,
-    NULL,
     NULL
   };
 
@@ -336,7 +318,6 @@ gst_memory_register (const gchar * name, const GstMemoryInfo * info)
   impl->name = g_quark_from_string (name);
   impl->info = *info;
   INSTALL_FALLBACK (copy);
-  INSTALL_FALLBACK (extract);
   INSTALL_FALLBACK (sub);
   INSTALL_FALLBACK (is_span);
 
@@ -456,15 +437,6 @@ gst_memory_copy (GstMemory * mem, gsize offset, gsize size)
 }
 
 void
-gst_memory_extract (GstMemory * mem, gsize offset, gpointer dest, gsize size)
-{
-  g_return_if_fail (mem != NULL);
-  g_return_if_fail (dest != NULL);
-
-  return mem->impl->info.extract (mem, offset, dest, size);
-}
-
-void
 gst_memory_trim (GstMemory * mem, gsize offset, gsize size)
 {
   g_return_if_fail (mem != NULL);
index 517c591..80d537d 100644 (file)
@@ -81,8 +81,6 @@ typedef gboolean (*GstMemoryUnmapFunction)  (GstMemory *mem, gpointer data, gsiz
 
 typedef void        (*GstMemoryFreeFunction)      (GstMemory *mem);
 typedef GstMemory * (*GstMemoryCopyFunction)      (GstMemory *mem, gsize offset, gsize size);
-typedef void        (*GstMemoryExtractFunction)   (GstMemory *mem, gsize offset,
-                                                   gpointer dest, gsize size);
 typedef void        (*GstMemoryTrimFunction)  (GstMemory *mem, gsize offset, gsize size);
 typedef GstMemory * (*GstMemorySubFunction)   (GstMemory *mem, gsize offset, gsize size);
 typedef gboolean    (*GstMemoryIsSpanFunction) (GstMemory *mem1, GstMemory *mem2,
@@ -102,7 +100,6 @@ struct _GstMemoryInfo {
   GstMemoryFreeFunction     free;
 
   GstMemoryCopyFunction     copy;
-  GstMemoryExtractFunction  extract;
   GstMemorySubFunction      sub;
   GstMemoryIsSpanFunction   is_span;
 };
@@ -128,13 +125,12 @@ void        gst_memory_trim       (GstMemory *mem, gsize offset, gsize size);
 gpointer    gst_memory_map        (GstMemory *mem, gsize *size, gsize *maxsize,
                                    GstMapFlags flags);
 gboolean    gst_memory_unmap      (GstMemory *mem, gpointer data, gsize size);
-void        gst_memory_extract    (GstMemory *mem, gsize offset, gpointer dest,
-                                   gsize size);
+
 /* copy and subregions */
 GstMemory * gst_memory_copy       (GstMemory *mem, gsize offset, gsize size);
 GstMemory * gst_memory_sub        (GstMemory *mem, gsize offset, gsize size);
 
-/* memory arrays */
+/* span memory */
 gboolean    gst_memory_is_span    (GstMemory *mem1, GstMemory *mem2, gsize *offset);
 GstMemory * gst_memory_span       (GstMemory **mem1, gsize len1, gsize offset,
                                    GstMemory **mem2, gsize len2, gsize size);
index 207ca55..4ab8c7f 100644 (file)
@@ -531,7 +531,6 @@ EXPORTS
        gst_marshal_VOID__POINTER_OBJECT
        gst_marshal_VOID__UINT_BOXED
        gst_memory_copy
-       gst_memory_extract
        gst_memory_flags_get_type
        gst_memory_get_sizes
        gst_memory_is_span