gstfunnel: avoid access of freed pad
[platform/upstream/gstreamer.git] / gst / gstbuffer.c
index 49d1289..b9783c5 100644 (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>
 #include "gstbufferpool.h"
 #include "gstinfo.h"
 #include "gstutils.h"
-#include "gstminiobject.h"
 #include "gstversion.h"
 
 GType _gst_buffer_type = 0;
@@ -197,27 +196,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;
+    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,11 +231,12 @@ _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,
-            "memcpy for merge %p from memory %p", result, mem[i]);
+            "memcpy %" G_GSIZE_FORMAT " bytes for merge %p from memory %p",
+            tocopy, result, mem[i]);
         memcpy (ptr, (guint8 *) sinfo.data, tocopy);
         left -= tocopy;
         ptr += tocopy;
@@ -248,26 +244,36 @@ _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-%" G_GSIZE_FORMAT " 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));
-  /* replace with single memory */
-  GST_BUFFER_MEM_PTR (buffer, 0) = mem;
-  GST_BUFFER_MEM_LEN (buffer) = 1;
+
+  if (mem != NULL) {
+    /* replace with single memory */
+    GST_BUFFER_MEM_PTR (buffer, idx) = mem;
+    idx++;
+    length--;
+  }
+
+  if (end < len) {
+    g_memmove (&GST_BUFFER_MEM_PTR (buffer, idx),
+        &GST_BUFFER_MEM_PTR (buffer, end), (len - end) * sizeof (gpointer));
+  }
+  GST_BUFFER_MEM_LEN (buffer) = len - length;
 }
 
 static inline void
@@ -276,14 +282,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 +418,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 +738,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 +779,94 @@ _get_mapped (GstBuffer * buffer, guint idx, GstMapInfo * info,
 }
 
 /**
- * gst_buffer_get_memory:
+ * gst_buffer_peek_memory:
  * @buffer: a #GstBuffer.
  * @idx: an index
  *
- * 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 the memory block at @idx in @buffer. The memory block stays valid until
+ * the memory block in @buffer is removed, replaced or merged, typically with
+ * any call that modifies the memory in @buffer.
+ *
+ * Since this call does not influence the refcount of the memory,
+ * gst_memory_is_exclusive() can be used to check if @buffer is the sole owner
+ * of the returned memory.
  *
- * Returns: (transfer full): a #GstMemory at @idx. Use gst_memory_unref () after usage.
+ * Returns: (transfer none): the #GstMemory at @idx.
  */
 GstMemory *
-gst_buffer_get_memory (GstBuffer * buffer, gint idx)
+gst_buffer_peek_memory (GstBuffer * buffer, guint idx)
 {
-  GstMemory *mem;
+  guint len;
 
   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);
-
-  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;
+  len = GST_BUFFER_MEM_LEN (buffer);
+  g_return_val_if_fail (idx < len, NULL);
+
+  return GST_BUFFER_MEM_PTR (buffer, idx);
+}
+
+/**
+ * gst_buffer_get_memory_range:
+ * @buffer: a #GstBuffer.
+ * @idx: an index
+ * @length: a length
+ *
+ * Get @length memory blocks in @buffer starting at @idx. The memory blocks will
+ * be merged into one large #GstMemory.
+ *
+ * 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_range (GstBuffer * buffer, guint idx, gint length)
+{
+  guint len;
+
+  GST_DEBUG ("idx %u, length %d", idx, length);
+
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+  len = GST_BUFFER_MEM_LEN (buffer);
+  g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
+      (length == -1 && idx < len) || (length > 0 && length + idx <= len), NULL);
+
+  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 ((len == 0 && idx == 0 && length == -1) ||
+      (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,72 +875,147 @@ 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.
  */
 void
 gst_buffer_remove_memory_range (GstBuffer * buffer, guint idx, gint length)
 {
-  guint len, i, end;
+  guint len;
 
   g_return_if_fail (GST_IS_BUFFER (buffer));
   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 ((len == 0 && idx == 0 && length == -1) ||
+      (length == -1 && idx < len) || length + idx <= len);
 
   if (length == -1)
     length = len - idx;
 
-  end = idx + length;
-  for (i = idx; i < end; i++)
-    gst_memory_unref (GST_BUFFER_MEM_PTR (buffer, i));
+  _replace_memory (buffer, len, idx, length, NULL);
+}
 
-  if (end != len) {
-    g_memmove (&GST_BUFFER_MEM_PTR (buffer, idx),
-        &GST_BUFFER_MEM_PTR (buffer, end), (len - end) * sizeof (gpointer));
+/**
+ * gst_buffer_find_memory:
+ * @buffer: a #GstBuffer.
+ * @offset: an offset
+ * @size: a size
+ * @idx: (out): pointer to index
+ * @length: (out): pointer to length
+ * @skip: (out): pointer to skip
+ *
+ * Find the memory blocks that span @size bytes starting from @offset
+ * in @buffer.
+ *
+ * When this function returns %TRUE, @idx will contain the index of the first
+ * memory bock where the byte for @offset can be found and @length contains the
+ * number of memory blocks containing the @size remaining bytes. @skip contains
+ * the number of bytes to skip in the memory bock at @idx to get to the byte
+ * for @offset.
+ *
+ * @size can be -1 to get all the memory blocks after @idx.
+ *
+ * Returns: %TRUE when @size bytes starting from @offset could be found in
+ * @buffer and @idx, @length and @skip will be filled.
+ */
+gboolean
+gst_buffer_find_memory (GstBuffer * buffer, gsize offset, gsize size,
+    guint * idx, guint * length, gsize * skip)
+{
+  guint i, len, found;
+
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+  g_return_val_if_fail (idx != NULL, FALSE);
+  g_return_val_if_fail (length != NULL, FALSE);
+  g_return_val_if_fail (skip != NULL, FALSE);
+
+  len = GST_BUFFER_MEM_LEN (buffer);
+
+  found = 0;
+  for (i = 0; i < len; i++) {
+    GstMemory *mem;
+    gsize s;
+
+    mem = GST_BUFFER_MEM_PTR (buffer, i);
+    s = gst_memory_get_sizes (mem, NULL, NULL);
+
+    if (s <= offset) {
+      /* block before offset, or empty block, skip */
+      offset -= s;
+    } else {
+      /* block after offset */
+      if (found == 0) {
+        /* first block, remember index and offset */
+        *idx = i;
+        *skip = offset;
+        if (size == -1) {
+          /* return remaining blocks */
+          *length = len - i;
+          return TRUE;
+        }
+        s -= offset;
+        offset = 0;
+      }
+      /* count the amount of found bytes */
+      found += s;
+      if (found >= size) {
+        /* we have enough bytes */
+        *length = i - *idx + 1;
+        return TRUE;
+      }
+    }
   }
-  GST_BUFFER_MEM_LEN (buffer) = len - length;
+  return FALSE;
 }
 
 /**
- * gst_buffer_get_sizes:
+ * gst_buffer_get_sizes_range:
  * @buffer: a #GstBuffer.
+ * @idx: an index
+ * @length: a length
  * @offset: a pointer to the offset
  * @maxsize: a pointer to the maxsize
  *
- * Get the total size of all memory blocks in @buffer.
+ * Get the total size of @length memory blocks stating from @idx in @buffer.
  *
- * When not %NULL, @offset will contain the offset of the data in the first
- * memory block in @buffer and @maxsize will contain the sum of the size
- * and @offset and the amount of extra padding on the last memory block.
- * @offset and @maxsize can be used to resize the buffer with
- * gst_buffer_resize().
+ * When not %NULL, @offset will contain the offset of the data in the
+ * memory block in @buffer at @idx and @maxsize will contain the sum of the size
+ * and @offset and the amount of extra padding on the memory block at @idx +
+ * @length -1.
+ * @offset and @maxsize can be used to resize the buffer memory blocks with
+ * gst_buffer_resize_range().
  *
- * Returns: the total size of the memory in @buffer.
+ * Returns: total size @length memory blocks starting at @idx in @buffer.
  */
 gsize
-gst_buffer_get_sizes (GstBuffer * buffer, gsize * offset, gsize * maxsize)
+gst_buffer_get_sizes_range (GstBuffer * buffer, guint idx, gint length,
+    gsize * offset, gsize * maxsize)
 {
   guint len;
   gsize size;
   GstMemory *mem;
 
   g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
-
   len = GST_BUFFER_MEM_LEN (buffer);
+  g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
+      (length == -1 && idx < len) || (length + idx <= len), 0);
+
+  if (length == -1)
+    length = len - idx;
 
-  if (G_LIKELY (len == 1)) {
+  if (G_LIKELY (length == 1)) {
     /* common case */
-    mem = GST_BUFFER_MEM_PTR (buffer, 0);
+    mem = GST_BUFFER_MEM_PTR (buffer, idx);
     size = gst_memory_get_sizes (mem, offset, maxsize);
   } else {
-    guint i;
+    guint i, end;
     gsize extra, offs;
 
+    end = idx + length;
     size = offs = extra = 0;
-    for (i = 0; i < len; i++) {
+    for (i = idx; i < end; i++) {
       gsize s, o, ms;
 
       mem = GST_BUFFER_MEM_PTR (buffer, i);
@@ -930,25 +1043,34 @@ gst_buffer_get_sizes (GstBuffer * buffer, gsize * offset, gsize * maxsize)
 }
 
 /**
- * gst_buffer_resize:
+ * gst_buffer_resize_range:
  * @buffer: a #GstBuffer.
+ * @idx: an index
+ * @length: a length
  * @offset: the offset adjustement
  * @size: the new size or -1 to just adjust the offset
  *
- * Set the total size of the buffer
+ * Set the total size of the @length memory blocks starting at @idx in
+ * @buffer
  */
 void
-gst_buffer_resize (GstBuffer * buffer, gssize offset, gssize size)
+gst_buffer_resize_range (GstBuffer * buffer, guint idx, gint length,
+    gssize offset, gssize size)
 {
-  guint len;
-  guint i;
+  guint i, len, end;
   gsize bsize, bufsize, bufoffs, bufmax;
   GstMemory *mem;
 
   g_return_if_fail (gst_buffer_is_writable (buffer));
   g_return_if_fail (size >= -1);
+  len = GST_BUFFER_MEM_LEN (buffer);
+  g_return_if_fail ((len == 0 && idx == 0 && length == -1) ||
+      (length == -1 && idx < len) || (length + idx <= len));
 
-  bufsize = gst_buffer_get_sizes (buffer, &bufoffs, &bufmax);
+  if (length == -1)
+    length = len - idx;
+
+  bufsize = gst_buffer_get_sizes_range (buffer, idx, length, &bufoffs, &bufmax);
 
   GST_CAT_LOG (GST_CAT_BUFFER, "trim %p %" G_GSSIZE_FORMAT "-%" G_GSSIZE_FORMAT
       " size:%" G_GSIZE_FORMAT " offs:%" G_GSIZE_FORMAT " max:%"
@@ -968,10 +1090,9 @@ gst_buffer_resize (GstBuffer * buffer, gssize offset, gssize size)
   if (offset == 0 && size == bufsize)
     return;
 
-  len = GST_BUFFER_MEM_LEN (buffer);
-
+  end = idx + length;
   /* copy and trim */
-  for (i = 0; i < len; i++) {
+  for (i = idx; i < end; i++) {
     gsize left, noffs;
 
     mem = GST_BUFFER_MEM_PTR (buffer, i);
@@ -979,7 +1100,7 @@ gst_buffer_resize (GstBuffer * buffer, gssize offset, gssize size)
 
     noffs = 0;
     /* last buffer always gets resized to the remaining size */
-    if (i + 1 == len)
+    if (i + 1 == end)
       left = size;
     /* shrink buffers before the offset */
     else if ((gssize) bsize <= offset) {
@@ -1014,12 +1135,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 +1153,25 @@ 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);
+  g_return_val_if_fail ((len == 0 && idx == 0 && length == -1) ||
+      (length == -1 && idx < len) || (length > 0
+          && length + idx <= len), FALSE);
 
   write = (flags & GST_MAP_WRITE) != 0;
   writable = gst_buffer_is_writable (buffer);
@@ -1052,7 +1180,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 +1194,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);
       }
@@ -1494,6 +1625,8 @@ gst_buffer_remove_meta (GstBuffer * buffer, GstMeta * meta)
   g_return_val_if_fail (buffer != NULL, FALSE);
   g_return_val_if_fail (meta != NULL, FALSE);
   g_return_val_if_fail (gst_buffer_is_writable (buffer), FALSE);
+  g_return_val_if_fail (!GST_META_FLAG_IS_SET (meta, GST_META_FLAG_LOCKED),
+      FALSE);
 
   /* find the metadata and delete */
   prev = GST_BUFFER_META (buffer);
@@ -1593,6 +1726,7 @@ gst_buffer_foreach_meta (GstBuffer * buffer, GstBufferForeachMetaFunc func,
           g_type_name (info->type));
 
       g_return_if_fail (gst_buffer_is_writable (buffer));
+      g_return_if_fail (!GST_META_FLAG_IS_SET (m, GST_META_FLAG_LOCKED));
 
       /* remove from list */
       if (GST_BUFFER_META (buffer) == walk)