buffer: Add GstReferenceTimestampMeta
authorSebastian Dröge <sebastian@centricular.com>
Sat, 25 Feb 2017 10:18:14 +0000 (12:18 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Fri, 12 May 2017 09:43:02 +0000 (11:43 +0200)
This is a meta that generically allows to attach additional reference
timestamps to a buffer, that don't have to relate to the pipeline clock
in any way.

Examples of this could be an NTP timestamp when the media was captured,
a frame counter on the capture side or the (local) UNIX timestamp when
the media was captured.

https://bugzilla.gnome.org/show_bug.cgi?id=779213

docs/gst/gstreamer-sections.txt
gst/gstbuffer.c
gst/gstbuffer.h
win32/common/libgstreamer.def

index 582157a..2efe9d2 100644 (file)
@@ -263,6 +263,10 @@ GstParentBufferMeta
 gst_buffer_add_parent_buffer_meta
 gst_buffer_get_parent_buffer_meta
 
+GstReferenceTimestampMeta
+gst_buffer_add_reference_timestamp_meta
+gst_buffer_get_reference_timestamp_meta
+
 gst_buffer_get_flags
 gst_buffer_set_flags
 gst_buffer_unset_flags
index 7d51c6d..3077543 100644 (file)
@@ -2538,3 +2538,172 @@ gst_parent_buffer_meta_get_info (void)
 
   return meta_info;
 }
+
+GST_DEBUG_CATEGORY_STATIC (gst_reference_timestamp_meta_debug);
+
+/**
+ * gst_buffer_add_reference_timestamp_meta:
+ * @buffer: (transfer none): a #GstBuffer
+ * @reference: (transfer none): identifier for the timestamp reference.
+ * @timestamp: timestamp
+ * @duration: duration, or %GST_CLOCK_TIME_NONE
+ *
+ * Add a #GstReferenceTimestampMeta to @buffer that holds a @timestamp and
+ * optionally @duration based on a specific timestamp @reference. See the
+ * documentation of #GstReferenceTimestampMeta for details.
+ *
+ * Returns: (transfer none): The #GstReferenceTimestampMeta that was added to the buffer
+ *
+ * Since: 1.14
+ */
+GstReferenceTimestampMeta *
+gst_buffer_add_reference_timestamp_meta (GstBuffer * buffer,
+    GstCaps * reference, GstClockTime timestamp, GstClockTime duration)
+{
+  GstReferenceTimestampMeta *meta;
+
+  g_return_val_if_fail (GST_IS_CAPS (reference), NULL);
+  g_return_val_if_fail (timestamp != GST_CLOCK_TIME_NONE, NULL);
+
+  meta =
+      (GstReferenceTimestampMeta *) gst_buffer_add_meta (buffer,
+      GST_REFERENCE_TIMESTAMP_META_INFO, NULL);
+
+  if (!meta)
+    return NULL;
+
+  meta->reference = gst_caps_ref (reference);
+  meta->timestamp = timestamp;
+  meta->duration = duration;
+
+  return meta;
+}
+
+/**
+ * gst_buffer_get_reference_timestamp_meta:
+ * @buffer: a #GstBuffer
+ * @reference: (allow-none): a reference #GstCaps
+ *
+ * Find the first #GstReferenceTimestampMeta on @buffer that conforms to
+ * @reference. Conformance is tested by checking if the meta's reference is a
+ * subset of @reference.
+ *
+ * Buffers can contain multiple #GstReferenceTimestampMeta metadata items.
+ *
+ * Returns: (transfer none): the #GstReferenceTimestampMeta or %NULL when there
+ * is no such metadata on @buffer.
+ *
+ * Since: 1.14
+ */
+GstReferenceTimestampMeta *
+gst_buffer_get_reference_timestamp_meta (GstBuffer * buffer,
+    GstCaps * reference)
+{
+  gpointer state = NULL;
+  GstMeta *meta;
+  const GstMetaInfo *info = GST_REFERENCE_TIMESTAMP_META_INFO;
+
+  while ((meta = gst_buffer_iterate_meta (buffer, &state))) {
+    if (meta->info->api == info->api) {
+      GstReferenceTimestampMeta *rmeta = (GstReferenceTimestampMeta *) meta;
+
+      if (!reference)
+        return rmeta;
+      if (gst_caps_is_subset (rmeta->reference, reference))
+        return rmeta;
+    }
+  }
+  return NULL;
+}
+
+static gboolean
+_gst_reference_timestamp_meta_transform (GstBuffer * dest, GstMeta * meta,
+    GstBuffer * buffer, GQuark type, gpointer data)
+{
+  GstReferenceTimestampMeta *dmeta, *smeta;
+
+  /* we copy over the reference timestamp meta, independent of transformation
+   * that happens. If it applied to the original buffer, it still applies to
+   * the new buffer as it refers to the time when the media was captured */
+  smeta = (GstReferenceTimestampMeta *) meta;
+  dmeta =
+      gst_buffer_add_reference_timestamp_meta (dest, smeta->reference,
+      smeta->timestamp, smeta->duration);
+  if (!dmeta)
+    return FALSE;
+
+  GST_CAT_DEBUG (gst_reference_timestamp_meta_debug,
+      "copy reference timestamp metadata from buffer %p to %p", buffer, dest);
+
+  return TRUE;
+}
+
+static void
+_gst_reference_timestamp_meta_free (GstReferenceTimestampMeta * meta,
+    GstBuffer * buffer)
+{
+  if (meta->reference)
+    gst_caps_unref (meta->reference);
+}
+
+static gboolean
+_gst_reference_timestamp_meta_init (GstReferenceTimestampMeta * meta,
+    gpointer params, GstBuffer * buffer)
+{
+  static volatile gsize _init;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_INIT (gst_reference_timestamp_meta_debug,
+        "referencetimestampmeta", 0, "referencetimestampmeta");
+    g_once_init_leave (&_init, 1);
+  }
+
+  meta->reference = NULL;
+  meta->timestamp = GST_CLOCK_TIME_NONE;
+  meta->duration = GST_CLOCK_TIME_NONE;
+
+  return TRUE;
+}
+
+GType
+gst_reference_timestamp_meta_api_get_type (void)
+{
+  static volatile GType type = 0;
+  static const gchar *tags[] = { NULL };
+
+  if (g_once_init_enter (&type)) {
+    GType _type =
+        gst_meta_api_type_register ("GstReferenceTimestampMetaAPI", tags);
+    g_once_init_leave (&type, _type);
+  }
+
+  return type;
+}
+
+/**
+ * gst_reference_timestamp_meta_get_info:
+ *
+ * Get the global #GstMetaInfo describing  the #GstReferenceTimestampMeta meta.
+ *
+ * Returns: (transfer none): The #GstMetaInfo
+ *
+ * Since: 1.14
+ */
+const GstMetaInfo *
+gst_reference_timestamp_meta_get_info (void)
+{
+  static const GstMetaInfo *meta_info = NULL;
+
+  if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
+    const GstMetaInfo *meta =
+        gst_meta_register (gst_reference_timestamp_meta_api_get_type (),
+        "GstReferenceTimestampMeta",
+        sizeof (GstReferenceTimestampMeta),
+        (GstMetaInitFunction) _gst_reference_timestamp_meta_init,
+        (GstMetaFreeFunction) _gst_reference_timestamp_meta_free,
+        _gst_reference_timestamp_meta_transform);
+    g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) meta);
+  }
+
+  return meta_info;
+}
index 916f947..40aaa12 100644 (file)
@@ -27,6 +27,7 @@
 #include <gst/gstminiobject.h>
 #include <gst/gstclock.h>
 #include <gst/gstallocator.h>
+#include <gst/gstcaps.h>
 
 G_BEGIN_DECLS
 
@@ -632,6 +633,48 @@ const GstMetaInfo *gst_parent_buffer_meta_get_info (void);
 GstParentBufferMeta *gst_buffer_add_parent_buffer_meta (GstBuffer *buffer,
     GstBuffer *ref);
 
+typedef struct _GstReferenceTimestampMeta GstReferenceTimestampMeta;
+
+/**
+ * GstReferenceTimestampMeta:
+ * @parent: the parent #GstMeta structure
+ * @reference: identifier for the timestamp reference.
+ * @timestamp: timestamp
+ * @duration: duration, or %GST_CLOCK_TIME_NONE
+ *
+ * #GstReferenceTimestampMeta can be used to attach alternative timestamps and
+ * possibly durations to a #GstBuffer. These are generally not according to
+ * the pipeline clock and could be e.g. the NTP timestamp when the media was
+ * captured.
+ *
+ * The reference is stored as a #GstCaps in @reference. Examples of valid
+ * references would be "timestamp/x-drivername-stream" for timestamps that are locally
+ * generated by some driver named "drivername" when generating the stream,
+ * e.g. based on a frame counter, or "timestamp/x-ntp, host=pool.ntp.org,
+ * port=123" for timestamps based on a specific NTP server.
+ *
+ * Since: 1.14
+ */
+struct _GstReferenceTimestampMeta
+{
+  GstMeta parent;
+
+  /*< public >*/
+  GstCaps *reference;
+  GstClockTime timestamp, duration;
+};
+
+GType gst_reference_timestamp_meta_api_get_type (void);
+#define GST_REFERENCE_TIMESTAMP_META_API_TYPE (gst_reference_timestamp_meta_api_get_type())
+
+const GstMetaInfo *gst_reference_timestamp_meta_get_info (void);
+#define GST_REFERENCE_TIMESTAMP_META_INFO (gst_reference_timestamp_meta_get_info())
+
+/* implementation */
+GstReferenceTimestampMeta *gst_buffer_add_reference_timestamp_meta (GstBuffer *buffer,
+    GstCaps *reference, GstClockTime timestamp, GstClockTime duration);
+GstReferenceTimestampMeta *gst_buffer_get_reference_timestamp_meta (GstBuffer * buffer, GstCaps * reference);
+
 #ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstBuffer, gst_buffer_unref)
 #endif
index 389f528..3fe1b46 100644 (file)
@@ -116,6 +116,7 @@ EXPORTS
        gst_buffer_add_meta
        gst_buffer_add_parent_buffer_meta
        gst_buffer_add_protection_meta
+       gst_buffer_add_reference_timestamp_meta
        gst_buffer_append
        gst_buffer_append_memory
        gst_buffer_append_region
@@ -135,6 +136,7 @@ EXPORTS
        gst_buffer_get_memory
        gst_buffer_get_memory_range
        gst_buffer_get_meta
+       gst_buffer_get_reference_timestamp_meta
        gst_buffer_get_size
        gst_buffer_get_sizes
        gst_buffer_get_sizes_range
@@ -1173,6 +1175,8 @@ EXPORTS
        gst_query_type_to_quark
        gst_query_writable_structure
        gst_rank_get_type
+       gst_reference_timestamp_meta_api_get_type
+       gst_reference_timestamp_meta_get_info
        gst_registry_add_feature
        gst_registry_add_plugin
        gst_registry_check_feature_version