event: Add new stream-id field to the stream-start event
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Sat, 28 Jul 2012 06:37:00 +0000 (08:37 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Mon, 6 Aug 2012 12:00:56 +0000 (14:00 +0200)
This is supposed to allow uniquely identifying a single stream.

docs/gst/gstreamer-sections.txt
gst/gstevent.c
gst/gstevent.h
gst/gstquark.c
gst/gstquark.h
gst/gstutils.c
gst/gstutils.h

index fa92929..760feb8 100644 (file)
@@ -974,6 +974,7 @@ gst_event_new_gap
 gst_event_parse_gap
 
 gst_event_new_stream_start
+gst_event_parse_stream_start
 
 gst_event_new_segment
 gst_event_parse_segment
@@ -1786,6 +1787,8 @@ gst_pad_iterate_internal_links_default
 gst_pad_set_element_private
 gst_pad_get_element_private
 
+gst_pad_create_stream_id
+
 GstPadForwardFunction
 gst_pad_forward
 <SUBSECTION Core>
index ac7fa71..bee382e 100644 (file)
@@ -1593,6 +1593,7 @@ gst_event_parse_sink_message (GstEvent * event, GstMessage ** msg)
 
 /**
  * gst_event_new_stream_start:
+ * @stream_id: Identifier for this stream
  *
  * Create a new STREAM_START event. The stream start event can only
  * travel downstream synchronized with the buffer flow. It is expected
@@ -1605,12 +1606,48 @@ gst_event_parse_sink_message (GstEvent * event, GstMessage ** msg)
  * combining multiple streams must ensure that this event is only forwarded
  * downstream once and not for every single input stream.
  *
+ * The @stream_id should be a unique string that consists of the upstream
+ * stream-id, / as separator and a unique stream-id for this specific
+ * stream. A new stream-id should only be created for a stream if the upstream
+ * stream is split into (potentially) multiple new streams, e.g. in a demuxer,
+ * but not for every single element in the pipeline.
+ * gst_util_create_stream_id() can be used to create a stream-id.
+ *
  * Returns: (transfer full): the new STREAM_START event.
  */
 GstEvent *
-gst_event_new_stream_start (void)
+gst_event_new_stream_start (const gchar * stream_id)
+{
+  GstStructure *s;
+
+  g_return_val_if_fail (stream_id != NULL, NULL);
+
+  s = gst_structure_new_id (GST_QUARK (EVENT_STREAM_START),
+      GST_QUARK (STREAM_ID), G_TYPE_STRING, stream_id, NULL);
+
+  return gst_event_new_custom (GST_EVENT_STREAM_START, s);
+}
+
+/**
+ * gst_event_parse_stream_start:
+ * @event: a stream-start event.
+ * @stream_id: (out): pointer to store the stream-id
+ *
+ * Parse a stream-id @event and store the result in the given @stream_id location.
+ */
+void
+gst_event_parse_stream_start (GstEvent * event, const gchar ** stream_id)
 {
-  return gst_event_new_custom (GST_EVENT_STREAM_START, NULL);
+  const GstStructure *structure;
+
+  g_return_if_fail (event != NULL);
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_START);
+
+  structure = gst_event_get_structure (event);
+
+  if (stream_id)
+    gst_structure_id_get (structure,
+        GST_QUARK (STREAM_ID), G_TYPE_STRING, stream_id, NULL);
 }
 
 /**
index 21b992f..39af270 100644 (file)
@@ -472,7 +472,8 @@ guint32         gst_event_get_seqnum            (GstEvent *event);
 void            gst_event_set_seqnum            (GstEvent *event, guint32 seqnum);
 
 /* Stream start event */
-GstEvent *      gst_event_new_stream_start      (void) G_GNUC_MALLOC;
+GstEvent *      gst_event_new_stream_start      (const gchar *stream_id) G_GNUC_MALLOC;
+void            gst_event_parse_stream_start    (GstEvent *event, const gchar **stream_id);
 
 /* flush events */
 GstEvent *      gst_event_new_flush_start       (void) G_GNUC_MALLOC;
index 85a7896..dc439ed 100644 (file)
@@ -64,7 +64,8 @@ static const gchar *_quark_strings[] = {
   "uid", "tags", "sub-entries", "info", "GstMessageTag", "GstEventTag",
   "GstMessageResetTime",
   "GstMessageToc", "GstEventTocGlobal", "GstEventTocCurrent",
-  "GstEventSegmentDone"
+  "GstEventSegmentDone",
+  "GstEventStreamStart", "stream-id"
 };
 
 GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index bc9321f..e77af84 100644 (file)
@@ -186,7 +186,9 @@ typedef enum _GstQuarkId
   GST_QUARK_EVENT_TOC_GLOBAL = 157,
   GST_QUARK_EVENT_TOC_CURRENT = 158,
   GST_QUARK_EVENT_SEGMENT_DONE = 159,
-  GST_QUARK_MAX = 160
+  GST_QUARK_EVENT_STREAM_START = 160,
+  GST_QUARK_STREAM_ID = 161,
+  GST_QUARK_MAX = 162
 } GstQuarkId;
 
 extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index 53866dc..d94ec7c 100644 (file)
@@ -3535,3 +3535,172 @@ gst_util_fraction_compare (gint a_n, gint a_d, gint b_n, gint b_d)
   /* Should not happen because a_d and b_d are not 0 */
   g_return_val_if_reached (0);
 }
+
+/** gst_pad_create_stream_id:
+ * @pad: A source #GstPad
+ * @parent: Parent #GstElement of @pad
+ * @stream_id: (allow-none): The stream-id
+ * @var_args: parameters for the @stream_id format string
+ *
+ * Creates a stream-id for the source #GstPad @pad by combining the
+ * upstream information with the optional @stream_id of the stream
+ * of @pad. @pad must have a parent #GstElement and which must have zero
+ * or one sinkpad. @stream_id can only be %NULL if the parent element
+ * of @pad has only a single source pad.
+ *
+ * This function generates an unique stream-id by getting the upstream
+ * stream-start event stream ID and appending @stream_id to it. If the
+ * element has no sinkpad it will generate an upstream stream-id by
+ * doing an URI query on the element and in the worst case just uses
+ * a random number. Source elements that don't implement the URI
+ * handler interface should ideally generate a unique, deterministic
+ * stream-id manually instead.
+ *
+ * Returns: A stream-id for @pad. g_free() after usage.
+ */
+gchar *
+gst_pad_create_stream_id_printf_valist (GstPad * pad, GstElement * parent,
+    const gchar * stream_id, va_list var_args)
+{
+  GstEvent *upstream_event;
+  gchar *upstream_stream_id = NULL, *new_stream_id;
+  GstPad *sinkpad;
+
+  g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+  g_return_val_if_fail (GST_PAD_IS_SRC (pad), NULL);
+  g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
+
+  g_return_val_if_fail (parent->numsinkpads <= 1, NULL);
+
+  /* If the element has multiple source pads it must
+   * provide a stream-id for every source pad, otherwise
+   * all source pads will have the same and are not
+   * distinguishable */
+  g_return_val_if_fail (parent->numsrcpads == 1 || stream_id, NULL);
+
+  /* First try to get the upstream stream-start stream-id from the sinkpad.
+   * This will only work for non-source elements */
+  sinkpad = gst_element_get_static_pad (parent, "sink");
+  if (sinkpad) {
+    upstream_event =
+        gst_pad_get_sticky_event (sinkpad, GST_EVENT_STREAM_START, 0);
+    if (upstream_event) {
+      const gchar *tmp;
+
+      gst_event_parse_stream_start (upstream_event, &tmp);
+      if (tmp)
+        upstream_stream_id = g_strdup (tmp);
+      gst_event_unref (upstream_event);
+    }
+    gst_object_unref (sinkpad);
+  }
+
+  /* The only case where we don't have an upstream start-start event
+   * here is for source elements */
+  if (!upstream_stream_id) {
+    GstQuery *query;
+
+    /* Try to generate one from the URI query and
+     * if it fails take a random number instead */
+    query = gst_query_new_uri ();
+    if (gst_element_query (parent, query)) {
+      GChecksum *cs;
+      gchar *uri;
+
+      gst_query_parse_uri (query, &uri);
+
+      /* And then generate an SHA256 sum of the URI */
+      cs = g_checksum_new (G_CHECKSUM_SHA256);
+      g_checksum_update (cs, (const guchar *) uri, strlen (uri));
+      g_free (uri);
+      upstream_stream_id = g_strdup (g_checksum_get_string (cs));
+      g_checksum_free (cs);
+    } else {
+      /* Just get some random number if the URI query fails */
+      GST_WARNING_OBJECT (pad, "Creating random stream-id, consider "
+          "implementing a deterministic way of creating a stream-id");
+      upstream_stream_id =
+          g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
+          g_random_int (), g_random_int ());
+    }
+
+    gst_query_unref (query);
+  }
+
+  if (stream_id) {
+    gchar *expanded = g_strdup_vprintf (stream_id, var_args);
+    new_stream_id = g_strconcat (upstream_stream_id, "/", expanded, NULL);
+    g_free (expanded);
+  } else {
+    new_stream_id = g_strdup (upstream_stream_id);
+  }
+
+  g_free (upstream_stream_id);
+
+  return new_stream_id;
+}
+
+/** gst_pad_create_stream_id:
+ * @pad: A source #GstPad
+ * @parent: Parent #GstElement of @pad
+ * @stream_id: (allow-none): The stream-id
+ * @...: parameters for the @stream_id format string
+ *
+ * Creates a stream-id for the source #GstPad @pad by combining the
+ * upstream information with the optional @stream_id of the stream
+ * of @pad. @pad must have a parent #GstElement and which must have zero
+ * or one sinkpad. @stream_id can only be %NULL if the parent element
+ * of @pad has only a single source pad.
+ *
+ * This function generates an unique stream-id by getting the upstream
+ * stream-start event stream ID and appending @stream_id to it. If the
+ * element has no sinkpad it will generate an upstream stream-id by
+ * doing an URI query on the element and in the worst case just uses
+ * a random number. Source elements that don't implement the URI
+ * handler interface should ideally generate a unique, deterministic
+ * stream-id manually instead.
+ *
+ * Returns: A stream-id for @pad. g_free() after usage.
+ */
+gchar *
+gst_pad_create_stream_id_printf (GstPad * pad, GstElement * parent,
+    const gchar * stream_id, ...)
+{
+  va_list var_args;
+  gchar *new_stream_id;
+
+  va_start (var_args, stream_id);
+  new_stream_id =
+      gst_pad_create_stream_id_printf_valist (pad, parent, stream_id, var_args);
+  va_end (var_args);
+
+  return new_stream_id;
+}
+
+/** gst_pad_create_stream_id:
+ * @pad: A source #GstPad
+ * @parent: Parent #GstElement of @pad
+ * @stream_id: (allow-none): The stream-id
+ *
+ * Creates a stream-id for the source #GstPad @pad by combining the
+ * upstream information with the optional @stream_id of the stream
+ * of @pad. @pad must have a parent #GstElement and which must have zero
+ * or one sinkpad. @stream_id can only be %NULL if the parent element
+ * of @pad has only a single source pad.
+ *
+ * This function generates an unique stream-id by getting the upstream
+ * stream-start event stream ID and appending @stream_id to it. If the
+ * element has no sinkpad it will generate an upstream stream-id by
+ * doing an URI query on the element and in the worst case just uses
+ * a random number. Source elements that don't implement the URI
+ * handler interface should ideally generate a unique, deterministic
+ * stream-id manually instead.
+ *
+ * Returns: A stream-id for @pad. g_free() after usage.
+ */
+gchar *
+gst_pad_create_stream_id (GstPad * pad, GstElement * parent,
+    const gchar * stream_id)
+{
+  return gst_pad_create_stream_id_printf (pad, parent, stream_id, NULL);
+}
index 627a92e..269b375 100644 (file)
@@ -888,6 +888,10 @@ gboolean                gst_pad_peer_query_convert      (GstPad *pad, GstFormat
 GstCaps *               gst_pad_peer_query_caps         (GstPad * pad, GstCaps *filter);
 gboolean                gst_pad_peer_query_accept_caps  (GstPad * pad, GstCaps *caps);
 
+gchar *                 gst_pad_create_stream_id               (GstPad * pad, GstElement * parent, const gchar *stream_id);
+gchar *                 gst_pad_create_stream_id_printf        (GstPad * pad, GstElement * parent, const gchar *stream_id, ...);
+gchar *                 gst_pad_create_stream_id_printf_valist (GstPad * pad, GstElement * parent, const gchar *stream_id, va_list var_args);
+
 /* bin functions */
 void                    gst_bin_add_many                (GstBin *bin, GstElement *element_1, ...) G_GNUC_NULL_TERMINATED;
 void                    gst_bin_remove_many             (GstBin *bin, GstElement *element_1, ...) G_GNUC_NULL_TERMINATED;