element: Enforce that elements created by gst_element_factory_create/make() are floating
[platform/upstream/gstreamer.git] / gst / gstmemory.c
index 0907f31..a68aa47 100644 (file)
@@ -21,6 +21,7 @@
 
 /**
  * SECTION:gstmemory
+ * @title: GstMemory
  * @short_description: refcounted wrapper for memory blocks
  * @see_also: #GstBuffer
  *
@@ -33,7 +34,7 @@
  * in the allocated region.
  *
  * Memory is usually created by allocators with a gst_allocator_alloc()
- * method call. When NULL is used as the allocator, the default allocator will
+ * method call. When %NULL is used as the allocator, the default allocator will
  * be used.
  *
  * New allocators can be registered with gst_allocator_register().
@@ -59,9 +60,7 @@
  * memory with an existing memory block at a custom offset and with a custom
  * size.
  *
- * Memory can be efficiently merged when gst_memory_is_span() returns TRUE.
- *
- * Last reviewed on 2012-03-28 (0.11.3)
+ * Memory can be efficiently merged when gst_memory_is_span() returns %TRUE.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -71,6 +70,7 @@
 #include "gst_private.h"
 #include "gstmemory.h"
 
+GType _gst_memory_type = 0;
 GST_DEFINE_MINI_OBJECT_TYPE (GstMemory, gst_memory);
 
 static GstMemory *
@@ -95,6 +95,7 @@ _gst_memory_free (GstMemory * mem)
   allocator = mem->allocator;
 
   gst_allocator_free (allocator, mem);
+
   gst_object_unref (allocator);
 }
 
@@ -124,6 +125,7 @@ gst_memory_init (GstMemory * mem, GstMemoryFlags flags,
 
   mem->allocator = gst_object_ref (allocator);
   if (parent) {
+    /* FIXME 2.0: this can fail if the memory is already write locked */
     gst_memory_lock (parent, GST_LOCK_FLAG_EXCLUSIVE);
     gst_memory_ref (parent);
   }
@@ -139,10 +141,31 @@ gst_memory_init (GstMemory * mem, GstMemoryFlags flags,
 }
 
 /**
+ * gst_memory_is_type:
+ * @mem: a #GstMemory
+ * @mem_type: a memory type
+ *
+ * Check if @mem if allocated with an allocator for @mem_type.
+ *
+ * Returns: %TRUE if @mem was allocated from an allocator for @mem_type.
+ *
+ * Since: 1.2
+ */
+gboolean
+gst_memory_is_type (GstMemory * mem, const gchar * mem_type)
+{
+  g_return_val_if_fail (mem != NULL, FALSE);
+  g_return_val_if_fail (mem->allocator != NULL, FALSE);
+  g_return_val_if_fail (mem_type != NULL, FALSE);
+
+  return (g_strcmp0 (mem->allocator->mem_type, mem_type) == 0);
+}
+
+/**
  * gst_memory_get_sizes:
  * @mem: a #GstMemory
- * @offset: pointer to offset
- * @maxsize: pointer to maxsize
+ * @offset: (out) (allow-none): pointer to offset
+ * @maxsize: (out) (allow-none): pointer to maxsize
  *
  * Get the current @size, @offset and @maxsize of @mem.
  *
@@ -177,6 +200,7 @@ void
 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);
 
@@ -205,8 +229,8 @@ gst_memory_resize (GstMemory * mem, gssize offset, gsize size)
  * This function takes ownership of old @mem and returns a reference to a new
  * #GstMemory.
  *
- * Returns: (transfer full): a #GstMemory object mapped with @flags or NULL when
- * a mapping is not possible.
+ * Returns: (transfer full) (nullable): a #GstMemory object mapped
+ * with @flags or %NULL when a mapping is not possible.
  */
 GstMemory *
 gst_memory_make_mapped (GstMemory * mem, GstMapInfo * info, GstMapFlags flags)
@@ -269,18 +293,22 @@ gst_memory_map (GstMemory * mem, GstMapInfo * info, GstMapFlags flags)
   g_return_val_if_fail (mem != NULL, FALSE);
   g_return_val_if_fail (info != NULL, FALSE);
 
-  if (!gst_memory_lock (mem, flags))
+  if (!gst_memory_lock (mem, (GstLockFlags) flags))
     goto lock_failed;
 
-  info->data = mem->allocator->mem_map (mem, mem->maxsize, flags);
+  info->flags = flags;
+  info->memory = mem;
+  info->size = mem->size;
+  info->maxsize = mem->maxsize - mem->offset;
+
+  if (mem->allocator->mem_map_full)
+    info->data = mem->allocator->mem_map_full (mem, info, mem->maxsize);
+  else
+    info->data = mem->allocator->mem_map (mem, mem->maxsize, flags);
 
   if (G_UNLIKELY (info->data == NULL))
     goto error;
 
-  info->memory = mem;
-  info->flags = flags;
-  info->size = mem->size;
-  info->maxsize = mem->maxsize - mem->offset;
   info->data = info->data + mem->offset;
 
   return TRUE;
@@ -289,13 +317,16 @@ gst_memory_map (GstMemory * mem, GstMapInfo * info, GstMapFlags flags)
 lock_failed:
   {
     GST_CAT_DEBUG (GST_CAT_MEMORY, "mem %p: lock %d failed", mem, flags);
+    memset (info, 0, sizeof (GstMapInfo));
     return FALSE;
   }
 error:
   {
-    /* something went wrong, restore the orginal state again */
-    GST_CAT_ERROR (GST_CAT_MEMORY, "mem %p: subclass map failed", mem);
-    gst_memory_unlock (mem, flags);
+    /* something went wrong, restore the original state again
+     * it is up to the subclass to log an error if needed. */
+    GST_CAT_INFO (GST_CAT_MEMORY, "mem %p: subclass map failed", mem);
+    gst_memory_unlock (mem, (GstLockFlags) flags);
+    memset (info, 0, sizeof (GstMapInfo));
     return FALSE;
   }
 }
@@ -314,19 +345,22 @@ gst_memory_unmap (GstMemory * mem, GstMapInfo * info)
   g_return_if_fail (info != NULL);
   g_return_if_fail (info->memory == mem);
 
-  mem->allocator->mem_unmap (mem);
-  gst_memory_unlock (mem, info->flags);
+  if (mem->allocator->mem_unmap_full)
+    mem->allocator->mem_unmap_full (mem, info);
+  else
+    mem->allocator->mem_unmap (mem);
+  gst_memory_unlock (mem, (GstLockFlags) info->flags);
 }
 
 /**
  * gst_memory_copy:
  * @mem: a #GstMemory
- * @offset: an offset to copy
- * @size: size to copy or -1 to copy all bytes from offset
+ * @offset: offset to copy from
+ * @size: size to copy, or -1 to copy to the end of the memory region
  *
  * Return a copy of @size bytes from @mem starting from @offset. This copy is
- * guaranteed to be writable. @size can be set to -1 to return a copy all bytes
- * from @offset.
+ * guaranteed to be writable. @size can be set to -1 to return a copy
+ * from @offset to the end of the memory region.
  *
  * Returns: a new #GstMemory.
  */
@@ -345,13 +379,13 @@ gst_memory_copy (GstMemory * mem, gssize offset, gssize size)
 /**
  * gst_memory_share:
  * @mem: a #GstMemory
- * @offset: an offset to share
- * @size: size to share or -1 to share bytes from offset
+ * @offset: offset to share from
+ * @size: size to share, or -1 to share to the end of the memory region
  *
  * Return a shared copy of @size bytes from @mem starting from @offset. No
  * memory copy is performed and the memory region is simply shared. The result
- * is guaranteed to be not-writable. @size can be set to -1 to return a share
- * all bytes from @offset.
+ * is guaranteed to be non-writable. @size can be set to -1 to return a shared
+ * copy from @offset to the end of the memory region.
  *
  * Returns: a new #GstMemory.
  */
@@ -364,8 +398,28 @@ gst_memory_share (GstMemory * mem, gssize offset, gssize size)
   g_return_val_if_fail (!GST_MEMORY_FLAG_IS_SET (mem, GST_MEMORY_FLAG_NO_SHARE),
       NULL);
 
+  /* whether we can lock the memory exclusively */
+  /* in order to maintain backwards compatibility by not requiring subclasses
+   * to lock the memory themselves and propagate the possible failure in their
+   * mem_share implementation */
+  /* FIXME 2.0: remove and fix gst_memory_init() and/or all memory subclasses
+   * to propagate this failure case */
+  if (!gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE))
+    return NULL;
+
+  /* double lock to ensure we are not mapped writable without an
+   * exclusive lock. */
+  if (!gst_memory_lock (mem, GST_LOCK_FLAG_EXCLUSIVE)) {
+    gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE);
+    return NULL;
+  }
+
   shared = mem->allocator->mem_share (mem, offset, size);
 
+  /* unlocking before calling the subclass would be racy */
+  gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE);
+  gst_memory_unlock (mem, GST_LOCK_FLAG_EXCLUSIVE);
+
   return shared;
 }
 
@@ -373,7 +427,7 @@ gst_memory_share (GstMemory * mem, gssize offset, gssize size)
  * gst_memory_is_span:
  * @mem1: a #GstMemory
  * @mem2: a #GstMemory
- * @offset: a pointer to a result offset
+ * @offset: (out): a pointer to a result offset
  *
  * Check if @mem1 and mem2 share the memory with a common parent memory object
  * and that the memory is contiguous.
@@ -404,3 +458,9 @@ gst_memory_is_span (GstMemory * mem1, GstMemory * mem2, gsize * offset)
 
   return TRUE;
 }
+
+void
+_priv_gst_memory_initialize (void)
+{
+  _gst_memory_type = gst_memory_get_type ();
+}