summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 0280a3c)
raw | patch | inline | side by side (parent: 0280a3c)
author | Tim-Philipp Müller <tim.muller@collabora.co.uk> | |
Wed, 16 Nov 2011 01:04:45 +0000 (01:04 +0000) | ||
committer | Tim-Philipp Müller <tim.muller@collabora.co.uk> | |
Fri, 25 Nov 2011 17:42:07 +0000 (17:42 +0000) |
Allows people/us to attach arbitrary metadata to buffers.
https://bugzilla.gnome.org/show_bug.cgi?id=664720
API: gst_buffer_set_qdata()
API: get_buffer_get_qdata()
https://bugzilla.gnome.org/show_bug.cgi?id=664720
API: gst_buffer_set_qdata()
API: get_buffer_get_qdata()
index b9500b7d13b3470d56616307d2edff41d44784d8..c0902e5fccf82fd5df7a0b93377bffa0c1d5c806 100644 (file)
gst_buffer_make_metadata_writable
gst_buffer_replace
+gst_buffer_set_qdata
+gst_buffer_get_qdata
+
gst_buffer_get_caps
gst_buffer_set_caps
diff --git a/gst/gstbuffer.c b/gst/gstbuffer.c
index 5a126639d3f19180384db5334030376b28cd4a9b..edc0a6ed7ce069f2011fd55d4a849c9fe5f5a400 100644 (file)
--- a/gst/gstbuffer.c
+++ b/gst/gstbuffer.c
#include "gstminiobject.h"
#include "gstversion.h"
+struct _GstBufferPrivate
+{
+ GList *qdata;
+ /* think about locking buffer->priv etc. when adding more fields */
+};
+
static void gst_buffer_finalize (GstBuffer * buffer);
static GstBuffer *_gst_buffer_copy (GstBuffer * buffer);
klass->mini_object_class.copy = (GstMiniObjectCopyFunction) _gst_buffer_copy;
klass->mini_object_class.finalize =
(GstMiniObjectFinalizeFunction) gst_buffer_finalize;
+
+ g_type_class_add_private (klass, sizeof (GstBufferPrivate));
}
static void
if (buffer->parent)
gst_buffer_unref (buffer->parent);
+ if (G_UNLIKELY (buffer->priv != NULL)) {
+ GstBufferPrivate *priv = buffer->priv;
+
+ while (priv->qdata != NULL) {
+ GstStructure *s = priv->qdata->data;
+
+ gst_structure_set_parent_refcount (s, NULL);
+ gst_structure_free (s);
+ priv->qdata = g_list_delete_link (priv->qdata, priv->qdata);
+ }
+ priv->qdata = NULL;
+ }
+
/* ((GstMiniObjectClass *) */
/* gst_buffer_parent_class)->finalize (GST_MINI_OBJECT_CAST (buffer)); */
}
+static inline GstBufferPrivate *
+gst_buffer_ensure_priv (GstBuffer * buf)
+{
+ GstBufferPrivate *priv = buf->priv;
+
+ if (priv != NULL)
+ return priv;
+
+ priv = buf->priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (buf, GST_TYPE_BUFFER, GstBufferPrivate);
+
+ return priv;
+}
+
+static void
+gst_buffer_copy_qdata (GstBuffer * dest, const GstBuffer * src)
+{
+ GstBufferPrivate *priv;
+ GQueue qdata_copy = G_QUEUE_INIT;
+ GList *l;
+
+ if (G_LIKELY (src->priv == NULL))
+ return;
+
+ for (l = src->priv->qdata; l != NULL; l = l->next) {
+ GstStructure *s = gst_structure_copy (l->data);
+
+ gst_structure_set_parent_refcount (s, &dest->mini_object.refcount);
+ g_queue_push_tail (&qdata_copy, s);
+
+ GST_CAT_TRACE (GST_CAT_BUFFER, "copying qdata '%s' from buffer %p to %p",
+ g_quark_to_string (s->name), src, dest);
+ }
+
+ priv = gst_buffer_ensure_priv (dest);
+ priv->qdata = qdata_copy.head;
+}
+
/**
* gst_buffer_copy_metadata:
* @dest: a destination #GstBuffer
if (flags & GST_BUFFER_COPY_CAPS) {
gst_caps_replace (&GST_BUFFER_CAPS (dest), GST_BUFFER_CAPS (src));
}
+
+ if ((flags & GST_BUFFER_COPY_QDATA)) {
+ GST_CAT_TRACE (GST_CAT_BUFFER, "copying qdata from %p to %p", src, dest);
+ gst_buffer_copy_qdata (dest, src);
+ }
+}
+
+/**
+ * gst_buffer_set_qdata:
+ * @buffer: a #GstBuffer
+ * @quark: name quark of data structure to set or replace
+ * @data: (transfer full) (allow-none): a #GstStructure to store with the
+ * buffer, name must match @quark. Can be NULL to remove an existing
+ * structure. This function takes ownership of the structure passed.
+ *
+ * Set metadata structure for name quark @quark to @data, or remove the
+ * existing metadata structure by that name in case @data is NULL.
+ *
+ * Takes ownership of @data.
+ *
+ * Since: 0.10.36
+ */
+void
+gst_buffer_set_qdata (GstBuffer * buffer, GQuark quark, GstStructure * data)
+{
+ GstBufferPrivate *priv;
+ GList *l;
+
+ g_return_if_fail (GST_IS_BUFFER (buffer));
+ g_return_if_fail (gst_buffer_is_metadata_writable (buffer));
+ g_return_if_fail (data == NULL || quark == gst_structure_get_name_id (data));
+
+ /* locking should not really be required, since the metadata_writable
+ * check ensures that the caller is the only one holding a ref, so as
+ * as a second ref is added everything turns read-only */
+ priv = gst_buffer_ensure_priv (buffer);
+
+ if (data) {
+ gst_structure_set_parent_refcount (data, &buffer->mini_object.refcount);
+ }
+
+ for (l = priv->qdata; l != NULL; l = l->next) {
+ GstStructure *s = l->data;
+
+ if (s->name == quark) {
+ GST_CAT_LOG (GST_CAT_BUFFER, "Replacing qdata '%s' on buffer %p: "
+ "%" GST_PTR_FORMAT " => %" GST_PTR_FORMAT, g_quark_to_string (quark),
+ buffer, s, data);
+ gst_structure_set_parent_refcount (s, NULL);
+ gst_structure_free (s);
+
+ if (data == NULL)
+ priv->qdata = g_list_delete_link (priv->qdata, l);
+ else
+ l->data = data;
+
+ goto done;
+ }
+ }
+
+ GST_CAT_LOG (GST_CAT_BUFFER, "Set qdata '%s' on buffer %p: %" GST_PTR_FORMAT,
+ g_quark_to_string (quark), buffer, data);
+
+ priv->qdata = g_list_prepend (priv->qdata, data);
+
+done:
+
+ return;
+}
+
+/**
+ * gst_buffer_get_qdata:
+ * @buffer: a #GstBuffer
+ * @quark: name quark of data structure to find
+ *
+ * Get metadata structure for name quark @quark.
+ *
+ * Returns: (transfer none): a #GstStructure, or NULL if not found
+ *
+ * Since: 0.10.36
+ */
+const GstStructure *
+gst_buffer_get_qdata (GstBuffer * buffer, GQuark quark)
+{
+ GstStructure *ret = NULL;
+
+ /* no need for locking: if the caller has the only ref, we're safe, and
+ * if the buffer has multiple refs, it's not metadata-writable any longer
+ * and the data can't change */
+
+ GST_CAT_LOG (GST_CAT_BUFFER, "Looking for qdata '%s' on buffer %p",
+ g_quark_to_string (quark), buffer);
+
+ if (buffer->priv != NULL) {
+ GList *l;
+
+ for (l = buffer->priv->qdata; l != NULL; l = l->next) {
+ GstStructure *s = l->data;
+
+ GST_CAT_LOG (GST_CAT_BUFFER, "checking qdata '%s' on buffer %p",
+ g_quark_to_string (s->name), buffer);
+
+ if (s->name == quark) {
+ ret = s;
+ break;
+ }
+ }
+ }
+
+ return ret;
}
static GstBuffer *
if ((caps = GST_BUFFER_CAPS (buffer)))
gst_caps_ref (caps);
GST_BUFFER_CAPS (subbuffer) = caps;
+
+ /* and also the attached qdata */
+ gst_buffer_copy_qdata (subbuffer, buffer);
} else {
GST_BUFFER_DURATION (subbuffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET_END (subbuffer) = GST_BUFFER_OFFSET_NONE;
diff --git a/gst/gstbuffer.h b/gst/gstbuffer.h
index d0893a245acb3b21d4cd75f9c372c37d7703deb4..3125f7fa236e7793007abfaffbb91a6f34d01734 100644 (file)
--- a/gst/gstbuffer.h
+++ b/gst/gstbuffer.h
typedef struct _GstBuffer GstBuffer;
typedef struct _GstBufferClass GstBufferClass;
+typedef struct _GstBufferPrivate GstBufferPrivate;
/**
* GST_BUFFER_TRACE_NAME:
GstBuffer *parent;
/*< private >*/
- gpointer _gst_reserved[GST_PADDING - 2];
+ GstBufferPrivate *priv;
+ gpointer _gst_reserved[GST_PADDING - 3];
};
struct _GstBufferClass {
* @GST_BUFFER_COPY_TIMESTAMPS: flag indicating that buffer timestamp, duration,
* offset and offset_end should be copied
* @GST_BUFFER_COPY_CAPS: flag indicating that buffer caps should be copied
+ * @GST_BUFFER_COPY_QDATA: flag indicating that buffer qdata should be copied
+ * (Since 0.10.36)
*
* A set of flags that can be provided to the gst_buffer_copy_metadata()
* function to specify which metadata fields should be copied.
typedef enum {
GST_BUFFER_COPY_FLAGS = (1 << 0),
GST_BUFFER_COPY_TIMESTAMPS = (1 << 1),
- GST_BUFFER_COPY_CAPS = (1 << 2)
+ GST_BUFFER_COPY_CAPS = (1 << 2),
+ GST_BUFFER_COPY_QDATA = (1 << 3)
} GstBufferCopyFlags;
/**
*
* Since: 0.10.13
*/
-#define GST_BUFFER_COPY_ALL ((GstBufferCopyFlags) (GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_CAPS))
+#define GST_BUFFER_COPY_ALL ((GstBufferCopyFlags) (GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_CAPS | GST_BUFFER_COPY_QDATA))
/* copies metadata into newly allocated buffer */
void gst_buffer_copy_metadata (GstBuffer *dest, const GstBuffer *src,
gboolean gst_buffer_is_metadata_writable (GstBuffer *buf);
GstBuffer* gst_buffer_make_metadata_writable (GstBuffer *buf);
+/* per-buffer user data */
+
+void gst_buffer_set_qdata (GstBuffer * buffer,
+ GQuark quark,
+ GstStructure * data);
+
+const GstStructure * gst_buffer_get_qdata (GstBuffer * buffer,
+ GQuark quark);
+
+
+
/**
* gst_buffer_replace:
* @obuf: (inout) (transfer full): pointer to a pointer to a #GstBuffer to be
index 06cac4c920c51ab3da12e5dfc2d773ddb968d59f..be608ec8d421c5066390c33090dd1c14ee384c56 100644 (file)
GST_END_TEST;
+GST_START_TEST (test_qdata)
+{
+ GstStructure *s;
+ GstBuffer *buf, *buf2, *buf3;
+ GQuark q1, q2, q3;
+
+ q1 = g_quark_from_static_string ("GstFooBar");
+ q2 = g_quark_from_static_string ("MyBorkData");
+ q3 = g_quark_from_static_string ("DoNotExist");
+
+ buf = gst_buffer_new ();
+ ASSERT_CRITICAL (gst_buffer_set_qdata (buf, q1, (s =
+ gst_structure_id_empty_new (q2))));
+ gst_structure_free (s);
+
+ gst_buffer_set_qdata (buf, q1, gst_structure_id_empty_new (q1));
+ gst_buffer_set_qdata (buf, q2, gst_structure_id_empty_new (q2));
+ fail_unless (gst_buffer_get_qdata (buf, q3) == NULL);
+ fail_unless (gst_buffer_get_qdata (buf, q1) != NULL);
+ fail_unless (gst_buffer_get_qdata (buf, q2) != NULL);
+
+ /* full copy */
+ buf2 = gst_buffer_copy (buf);
+
+ /* now back to the original buffer... */
+ gst_buffer_set_qdata (buf, q1, NULL);
+ fail_unless (gst_buffer_get_qdata (buf, q1) == NULL);
+
+ /* force creation of sub-buffer with writable metadata */
+ gst_buffer_ref (buf);
+ buf3 = gst_buffer_make_metadata_writable (buf);
+
+ /* and check the copies/subbuffers.. */
+ fail_unless (gst_buffer_get_qdata (buf2, q3) == NULL);
+ fail_unless (gst_buffer_get_qdata (buf2, q1) != NULL);
+ fail_unless (gst_buffer_get_qdata (buf2, q2) != NULL);
+
+ fail_unless (gst_buffer_get_qdata (buf3, q3) == NULL);
+ fail_unless (gst_buffer_get_qdata (buf3, q1) == NULL);
+ fail_unless (gst_buffer_get_qdata (buf3, q2) != NULL);
+ gst_buffer_set_qdata (buf3, q1, gst_structure_id_empty_new (q1));
+ fail_unless (gst_buffer_get_qdata (buf3, q1) != NULL);
+
+ /* original buffer shouldn't have changed */
+ fail_unless (gst_buffer_get_qdata (buf, q1) == NULL);
+
+ gst_buffer_unref (buf);
+ gst_buffer_unref (buf2);
+ gst_buffer_unref (buf3);
+}
+
+GST_END_TEST;
+
static Suite *
gst_buffer_suite (void)
{
tcase_add_test (tc_chain, test_metadata_writable);
tcase_add_test (tc_chain, test_copy);
tcase_add_test (tc_chain, test_try_new_and_alloc);
+ tcase_add_test (tc_chain, test_qdata);
return s;
}
index 5f2847e383cf0e2fd0a6cb9794af1f3aec33c9c8..f7a7974e4ed782d9ab494d5283141338bca57d8d 100644 (file)
gst_buffer_create_sub
gst_buffer_flag_get_type
gst_buffer_get_caps
+ gst_buffer_get_qdata
gst_buffer_get_type
gst_buffer_is_metadata_writable
gst_buffer_is_span_fast
gst_buffer_new
gst_buffer_new_and_alloc
gst_buffer_set_caps
+ gst_buffer_set_qdata
gst_buffer_span
gst_buffer_stamp
gst_buffer_try_new_and_alloc