Index: gst/gstbuffer.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstbuffer.c,v
retrieving revision 1.120
diff -u -r1.120 gstbuffer.c
--- gst/gstbuffer.c	12 Jan 2006 16:07:50 -0000	1.120
+++ gst/gstbuffer.c	16 Jan 2006 09:54:29 -0000
@@ -83,10 +83,15 @@
  * To efficiently create a smaller buffer out of an existing one, you can
  * use gst_buffer_create_sub().
  *
- * If the plug-in wants to modify the buffer in-place, it should first obtain
+ * If a plug-in wants to modify the buffer data in-place, it should first obtain
  * a buffer that is safe to modify by using gst_buffer_make_writable().  This
  * function is optimized so that a copy will only be made when it is necessary.
  *
+ * A plugin that only wishes to modify the metadata of a buffer, such as the offset,
+ * timestamp or caps, should use gst_buffer_make_metadata_writable(), which will
+ * create a subbuffer of the original buffer to ensure the caller has sole ownership,
+ * and not copy the buffer data.
+ *
  * Several flags of the buffer can be set and unset with the
  * GST_BUFFER_FLAG_SET() and GST_BUFFER_FLAG_UNSET() macros. Use
  * GST_BUFFER_FLAG_IS_SET() to test if a certain #GstBufferFlag is set.
@@ -333,6 +338,42 @@
   gst_caps_replace (&GST_BUFFER_CAPS (buffer), caps);
 }
 
+/**
+ * gst_buffer_is_metadata_writable:
+ * @buf: a #GstBuffer
+ *
+ * Similar to gst_buffer_is_writable, but this only ensures that the
+ * refcount of the buffer is 1, indicating that the caller is the sole
+ * owner and can change the buffer metadata, such as caps and timestamps.
+ */
+gboolean gst_buffer_is_metadata_writable (GstBuffer *buf)
+{
+  return (GST_MINI_OBJECT_REFCOUNT_VALUE (GST_MINI_OBJECT (buf)) == 1);
+}
+
+/**
+ * gst_buffer_make_metadata_writable:
+ * @buf: a #GstBuffer
+ *
+ * Similar to gst_buffer_make_writable, but does not ensure that the buffer
+ * data array is writable. Instead, this just ensures that the returned buffer
+ * is solely owned by the caller, by creating a subbuffer of the original
+ * buffer if necessary.
+ */
+GstBuffer*      gst_buffer_make_metadata_writable (GstBuffer *buf)
+{
+  GstBuffer *ret;
+
+  if (gst_buffer_is_metadata_writable (buf)) {
+    ret = buf;
+  } else {
+    ret = gst_buffer_create_sub (buf, 0, GST_BUFFER_SIZE (buf));
+    gst_buffer_unref (buf);
+  }
+
+  return ret;
+}
+
 typedef struct _GstSubBuffer GstSubBuffer;
 typedef struct _GstSubBufferClass GstSubBufferClass;
 
Index: gst/gstbuffer.h
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstbuffer.h,v
retrieving revision 1.102
diff -u -r1.102 gstbuffer.h
--- gst/gstbuffer.h	20 Nov 2005 14:50:43 -0000	1.102
+++ gst/gstbuffer.h	16 Jan 2006 09:54:30 -0000
@@ -310,7 +310,10 @@
  * gst_buffer_is_writable:
  * @buf: a #GstBuffer
  *
- * Tests if you can safely write data into a buffer's data array.
+ * Tests if you can safely write data into a buffer's data array or validly
+ * modify the caps and timestamp metadata. Metadata in a GstBuffer is always
+ * writable, but it is only safe to change it when there is only one owner
+ * of the buffer - ie, the buffer is 1. 
  */
 #define		gst_buffer_is_writable(buf)	gst_mini_object_is_writable (GST_MINI_OBJECT (buf))
 /**
@@ -323,6 +326,11 @@
  */
 #define		gst_buffer_make_writable(buf)   GST_BUFFER_CAST (gst_mini_object_make_writable (GST_MINI_OBJECT (buf)))
 
+/* Ensure that the metadata of the buffer is writable, even if the buffer data
+ * isn't */
+gboolean        gst_buffer_is_metadata_writable (GstBuffer *buf);
+GstBuffer*      gst_buffer_make_metadata_writable (GstBuffer *buf);
+
 /**
  * gst_buffer_replace:
  * @obuf: pointer to a pointer to a #GstBuffer to be replaced.
Index: gst/gstminiobject.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/gst/gstminiobject.c,v
retrieving revision 1.22
diff -u -r1.22 gstminiobject.c
--- gst/gstminiobject.c	15 Dec 2005 12:22:37 -0000	1.22
+++ gst/gstminiobject.c	16 Jan 2006 09:54:30 -0000
@@ -209,7 +209,7 @@
  *
  * MT safe
  *
- * Returns: a mini-object (possibly a duplicate) that it writable.
+ * Returns: a mini-object (possibly a duplicate) that is writable.
  */
 GstMiniObject *
 gst_mini_object_make_writable (GstMiniObject * mini_object)
Index: libs/gst/base/gstbasetransform.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/libs/gst/base/gstbasetransform.c,v
retrieving revision 1.64
diff -u -r1.64 gstbasetransform.c
--- libs/gst/base/gstbasetransform.c	6 Dec 2005 23:32:01 -0000	1.64
+++ libs/gst/base/gstbasetransform.c	16 Jan 2006 09:54:30 -0000
@@ -866,7 +866,7 @@
 
   /* If the output buffer metadata is modifiable, copy timestamps and
    * buffer flags */
-  if (*out_buf != in_buf && GST_MINI_OBJECT_REFCOUNT_VALUE (*out_buf) == 1) {
+  if (*out_buf != in_buf && gst_buffer_is_metadata_writable (*out_buf) == 1) {
 
     if (copy_inbuf && gst_buffer_is_writable (*out_buf))
       memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
Index: plugins/elements/gstcapsfilter.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/plugins/elements/gstcapsfilter.c,v
retrieving revision 1.17
diff -u -r1.17 gstcapsfilter.c
--- plugins/elements/gstcapsfilter.c	29 Nov 2005 18:00:15 -0000	1.17
+++ plugins/elements/gstcapsfilter.c	16 Jan 2006 09:54:30 -0000
@@ -260,7 +260,7 @@
     if (gst_caps_is_fixed (out_caps) && !gst_caps_is_empty (out_caps)) {
       GST_DEBUG_OBJECT (trans, "Have fixed output caps %"
           GST_PTR_FORMAT " to apply to buffer with no caps", out_caps);
-      if (gst_buffer_is_writable (input)) {
+      if (gst_buffer_is_metadata_writable (input)) {
         gst_buffer_ref (input);
         *buf = input;
       } else {
Index: tests/check/gst/gstbuffer.c
===================================================================
RCS file: /cvs/gstreamer/gstreamer/tests/check/gst/gstbuffer.c,v
retrieving revision 1.8
diff -u -r1.8 gstbuffer.c
--- tests/check/gst/gstbuffer.c	27 Sep 2005 13:25:18 -0000	1.8
+++ tests/check/gst/gstbuffer.c	16 Jan 2006 09:54:30 -0000
@@ -268,6 +268,39 @@
 
 GST_END_TEST;
 
+GST_START_TEST (test_metadata_writable)
+{
+  GstBuffer *buffer, *sub1;
+
+  buffer = gst_buffer_new_and_alloc (4);
+  /* Buffer with refcount 1 should have writable metadata */
+  fail_unless (gst_buffer_is_metadata_writable (buffer) == TRUE);
+
+  /* Check that a buffer with refcount 2 does not have writable metadata */
+  gst_buffer_ref (buffer);
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 2);
+  fail_unless (gst_buffer_is_metadata_writable (buffer) == FALSE);
+
+  /* Check that make_metadata_writable produces a new sub-buffer with 
+   * writable metadata. */
+  sub1 = gst_buffer_make_metadata_writable (buffer);
+  fail_if (sub1 == buffer);
+  fail_unless (gst_buffer_is_metadata_writable (sub1) == TRUE);
+
+  /* Check that the original metadata is still not writable 
+   * (subbuffer should be holding a reference, and so should we) */
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 2);
+  fail_unless (gst_buffer_is_metadata_writable (buffer) == FALSE);
+
+  /* Drop the subbuffer and check that the metadata is now writable again */
+  ASSERT_BUFFER_REFCOUNT (sub1, "sub1", 1);
+  gst_buffer_unref (sub1);
+  fail_unless (gst_buffer_is_metadata_writable (buffer) == TRUE);
+
+  ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1);
+  gst_buffer_unref (buffer);
+} GST_END_TEST;
+
 Suite *
 gst_test_suite (void)
 {
@@ -281,6 +314,7 @@
   tcase_add_test (tc_chain, test_make_writable);
   tcase_add_test (tc_chain, test_is_span_fast);
   tcase_add_test (tc_chain, test_span);
+  tcase_add_test (tc_chain, test_metadata_writable);
   return s;
 }
 
