event: add construct and parse API for the new STREAM CONFIG event
authorTim-Philipp Müller <tim.muller@collabora.co.uk>
Fri, 27 Jan 2012 17:39:12 +0000 (17:39 +0000)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Fri, 27 Jan 2012 17:42:07 +0000 (17:42 +0000)
codec data and stream headers don't belong into caps, since they
are not negotiated. We signal them using the STREAM CONFIG event
instead.

gst/gstevent.c
gst/gstevent.h
gst/gstquark.c
gst/gstquark.h
tests/check/gst/gstevent.c

index f11af4c..1d1f5d1 100644 (file)
@@ -84,6 +84,7 @@
 #include "gstenumtypes.h"
 #include "gstutils.h"
 #include "gstquark.h"
+#include "gstvalue.h"
 
 GType _gst_event_type = 0;
 
@@ -615,6 +616,213 @@ gst_event_parse_caps (GstEvent * event, GstCaps ** caps)
 }
 
 /**
+ * gst_event_new_stream_config:
+ * @flags: the stream config flags
+ *
+ * Create a new STREAM CONFIG event. The stream config event travels
+ * downstream synchronized with the buffer flow and contains stream
+ * configuration information for the stream, such as stream-headers
+ * or codec-data. It is optional and should be sent after the CAPS
+ * event.
+ *
+ * Returns: (transfer full): the new STREAM CONFIG event.
+ */
+GstEvent *
+gst_event_new_stream_config (GstStreamConfigFlags flags)
+{
+  GstEvent *event;
+
+  GST_CAT_INFO (GST_CAT_EVENT, "creating stream info event, flags=0x%x", flags);
+
+  event = gst_event_new_custom (GST_EVENT_STREAM_CONFIG,
+      gst_structure_new_id (GST_QUARK (EVENT_STREAM_CONFIG),
+          GST_QUARK (FLAGS), GST_TYPE_STREAM_CONFIG_FLAGS, flags, NULL));
+
+  return event;
+}
+
+/**
+ * gst_event_parse_stream_config:
+ * @event: The event to parse
+ * @flags: (out): a pointer to a variable to store the stream config flags
+ *
+ * Get the stream config flags from @event.
+ */
+void
+gst_event_parse_stream_config (GstEvent * event, GstStreamConfigFlags * flags)
+{
+  GstStructure *structure;
+
+  g_return_if_fail (GST_IS_EVENT (event));
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
+
+  structure = GST_EVENT_STRUCTURE (event);
+  if (G_LIKELY (flags != NULL)) {
+    *flags =
+        g_value_get_enum (gst_structure_id_get_value (structure,
+            GST_QUARK (FLAGS)));
+  }
+}
+
+/**
+ * gst_event_set_stream_config_codec_data:
+ * @event: a stream config event
+ * @buf: a #GstBuffer with codec data
+ *
+ * Set codec data on the stream info event to signal out of bound setup data
+ * to downstream elements. Unlike stream headers, codec data contains data
+ * that is required to interpret the data stream, but is not valid as-is
+ * inside the data stream and thus can't just be prepended to or inserted
+ * into the data stream.
+ */
+void
+gst_event_set_stream_config_codec_data (GstEvent * event, GstBuffer * buf)
+{
+  GstStructure *s;
+
+  g_return_if_fail (GST_IS_EVENT (event));
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
+  g_return_if_fail (GST_IS_BUFFER (buf) && gst_buffer_get_size (buf) > 0);
+
+  s = GST_EVENT_STRUCTURE (event);
+  gst_structure_id_set (s, GST_QUARK (CODEC_DATA), GST_TYPE_BUFFER, buf, NULL);
+}
+
+/**
+ * gst_event_set_stream_config_codec_data:
+ * @event: a stream config event
+ * @buf: (transfer none): location where to store the #GstBuffer with codec data
+ *
+ * Extracts the codec data buffer from the stream info event. Will store
+ * %NULL in @buf if the event contains no codec data. The buffer returned
+ * will remain valid as long as @event remains valid. The caller should
+ * acquire a referenceto to @buf if needed.
+ */
+void
+gst_event_parse_stream_config_codec_data (GstEvent * event, GstBuffer ** buf)
+{
+  const GValue *val;
+  GstStructure *s;
+
+  g_return_if_fail (GST_IS_EVENT (event));
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
+  g_return_if_fail (buf != NULL);
+
+  s = GST_EVENT_STRUCTURE (event);
+  val = gst_structure_id_get_value (s, GST_QUARK (CODEC_DATA));
+  if (val != NULL)
+    *buf = g_value_get_boxed (val);
+  else
+    *buf = NULL;
+}
+
+/**
+ * gst_event_add_stream_config_header:
+ * @event: a stream config event
+ * @buf: a #GstBuffer with stream header data
+ *
+ * Adds a stream header to the stream info event to signal stream headers to
+ * to downstream elements such as multifilesink, tcpserversink etc. Stream
+ * headers can be and should usually be prepended to the data stream at any
+ * point in the stream (which requires a streamable format), e.g. to a new
+ * client connecting, or when starting a new file segment. stream header
+ * buffers will all be used together in the order they were added to the
+ * stream config event. Stream headers are sent as buffers at the beginning
+ * of the data flow in addition to the stream config event. Elements that
+ * care about stream headers need to make sure that they don't insert or
+ * interpret these header buffers twice if they interpret them.
+ */
+void
+gst_event_add_stream_config_header (GstEvent * event, GstBuffer * buf)
+{
+  GstStructure *s;
+  GValue buf_val = { 0, };
+  GValue *val;
+
+  g_return_if_fail (GST_IS_EVENT (event));
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
+  g_return_if_fail (GST_IS_BUFFER (buf) && gst_buffer_get_size (buf) > 0);
+
+  g_value_init (&buf_val, GST_TYPE_BUFFER);
+  g_value_set_boxed (&buf_val, buf);
+
+  s = GST_EVENT_STRUCTURE (event);
+  val = (GValue *) gst_structure_id_get_value (s, GST_QUARK (STREAM_HEADERS));
+  if (val == NULL) {
+    GValue new_array = { 0, };
+
+    g_value_init (&new_array, GST_TYPE_ARRAY);
+    gst_value_array_append_value (&new_array, &buf_val);
+    gst_structure_id_take_value (s, GST_QUARK (STREAM_HEADERS), &new_array);
+  } else {
+    gst_value_array_append_value (val, &buf_val);
+  }
+  g_value_unset (&buf_val);
+}
+
+/**
+ * gst_event_get_n_stream_config_headers:
+ * @event: a stream config event
+ *
+ * Extract the number of stream header buffers.
+ *
+ * Returns: the number of stream header buffers attached to the stream info
+ * @event.
+ */
+guint
+gst_event_get_n_stream_config_headers (GstEvent * event)
+{
+  const GValue *val;
+  GstStructure *s;
+  guint num = 0;
+
+  g_return_val_if_fail (GST_IS_EVENT (event), 0);
+  g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG, 0);
+
+  s = GST_EVENT_STRUCTURE (event);
+  val = gst_structure_id_get_value (s, GST_QUARK (STREAM_HEADERS));
+
+  if (val != NULL)
+    num = gst_value_array_get_size (val);
+
+  return num;
+}
+
+/**
+ * gst_event_parse_nth_stream_config_header:
+ * @event: a stream config event
+ * @index: number of the stream header to retrieve
+ * @buf: location where to store the n-th stream header #GstBuffer
+ *
+ * Retrieves the n-th stream header buffer attached to the stream config
+ * event and stores it in @buf. Will store %NULL in @buf if there is no such
+ * stream header.
+ */
+void
+gst_event_parse_nth_stream_config_header (GstEvent * event, guint index,
+    GstBuffer ** buf)
+{
+  const GValue *val, *buf_val;
+  GstStructure *s;
+  GstBuffer *ret = NULL;
+
+  g_return_if_fail (GST_IS_EVENT (event));
+  g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_STREAM_CONFIG);
+  g_return_if_fail (buf != NULL);
+
+  s = GST_EVENT_STRUCTURE (event);
+  val = gst_structure_id_get_value (s, GST_QUARK (STREAM_HEADERS));
+
+  if (val != NULL) {
+    buf_val = gst_value_array_get_value (val, index);
+    if (buf_val != NULL)
+      ret = g_value_get_boxed (buf_val);
+  }
+
+  *buf = ret;
+}
+
+/**
  * gst_event_new_segment:
  * @segment: (transfer none): a #GstSegment
  *
index fc96519..074b80d 100644 (file)
@@ -375,6 +375,17 @@ typedef enum {
 } GstQOSType;
 
 /**
+ * GstStreamConfigFlags:
+ * @GST_STREAM_CONFIG_FLAG_NONE: no flags set
+ *
+ * GstStreamConfigFlags are flags passed with the stream config event, see
+ * gst_event_new_stream_config().
+ */
+typedef enum {
+  GST_STREAM_CONFIG_FLAG_NONE = 0
+} GstStreamConfigFlags;
+
+/**
  * GstEvent:
  * @mini_object: the parent structure
  * @type: the #GstEventType of the event
@@ -483,6 +494,23 @@ GstEvent *      gst_event_new_eos               (void) G_GNUC_MALLOC;
 GstEvent *      gst_event_new_caps              (GstCaps *caps) G_GNUC_MALLOC;
 void            gst_event_parse_caps            (GstEvent *event, GstCaps **caps);
 
+/* Stream config */
+GstEvent *      gst_event_new_stream_config                (GstStreamConfigFlags flags) G_GNUC_MALLOC;
+
+void            gst_event_parse_stream_config              (GstEvent * event, GstStreamConfigFlags * flags);
+
+
+void            gst_event_set_stream_config_codec_data     (GstEvent * event, GstBuffer  * buf);
+
+void            gst_event_parse_stream_config_codec_data   (GstEvent * event, GstBuffer ** buf);
+
+
+void            gst_event_add_stream_config_header         (GstEvent * event, GstBuffer  * buf);
+
+guint           gst_event_get_n_stream_config_headers      (GstEvent * event);
+
+void            gst_event_parse_nth_stream_config_header   (GstEvent * event, guint index, GstBuffer ** buf);
+
 /* segment event */
 GstEvent*       gst_event_new_segment           (const GstSegment *segment) G_GNUC_MALLOC;
 void            gst_event_parse_segment         (GstEvent *event, const GstSegment **segment);
index b687095..b619dc0 100644 (file)
@@ -55,7 +55,8 @@ static const gchar *_quark_strings[] = {
   "GstQueryAllocation", "need-pool", "meta", "pool", "GstEventCaps",
   "GstEventReconfigure", "segment", "GstQueryScheduling", "pull-mode",
   "allocator", "GstEventFlushStop", "options", "GstQueryAcceptCaps",
-  "result", "GstQueryCaps", "filter", "modes"
+  "result", "GstQueryCaps", "filter", "modes", "GstEventStreamConfig",
+  "codec-data", "stream-headers"
 };
 
 GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index 758345c..ed71d69 100644 (file)
@@ -158,8 +158,10 @@ typedef enum _GstQuarkId
   GST_QUARK_QUERY_CAPS = 129,
   GST_QUARK_FILTER = 130,
   GST_QUARK_MODES = 131,
-
-  GST_QUARK_MAX = 132
+  GST_QUARK_EVENT_STREAM_CONFIG = 132,
+  GST_QUARK_CODEC_DATA = 133,
+  GST_QUARK_STREAM_HEADERS = 134,
+  GST_QUARK_MAX = 135
 } GstQuarkId;
 
 extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index 7bb9303..561e420 100644 (file)
@@ -91,6 +91,72 @@ GST_START_TEST (create_events)
     gst_event_unref (event);
   }
 
+  /* STREAM CONFIG */
+  {
+    GstStreamConfigFlags flags = 0x987654;
+    GstBuffer *buf, *cd, *sh1, *sh2;
+    gpointer dummy;
+
+    event = gst_event_new_stream_config (GST_STREAM_CONFIG_FLAG_NONE);
+
+    gst_event_parse_stream_config (event, &flags);
+    fail_unless_equals_int (flags, GST_STREAM_CONFIG_FLAG_NONE);
+
+    fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 0);
+
+    /* set buf to something random but guaranteed to be non-NULL */
+    buf = (GstBuffer *) & dummy;
+    gst_event_parse_stream_config_codec_data (event, &buf);
+    fail_unless (buf == NULL);
+
+    buf = (GstBuffer *) & dummy;
+    gst_event_parse_nth_stream_config_header (event, 0, &buf);
+    fail_unless (buf == NULL);
+
+    buf = (GstBuffer *) & dummy;
+    gst_event_parse_nth_stream_config_header (event, 98416, &buf);
+    fail_unless (buf == NULL);
+
+    ASSERT_CRITICAL (gst_event_set_stream_config_codec_data (event, NULL));
+    ASSERT_CRITICAL (gst_event_add_stream_config_header (event, NULL));
+
+    cd = gst_buffer_new_wrapped_full ((gpointer) "SetMeUpScottie", NULL, 0, 14);
+    gst_event_set_stream_config_codec_data (event, cd);
+    gst_buffer_unref (cd);
+
+    buf = (GstBuffer *) & dummy;
+    gst_event_parse_nth_stream_config_header (event, 0, &buf);
+    fail_unless (buf == NULL);
+    gst_event_parse_stream_config_codec_data (event, &buf);
+    fail_unless (buf == cd);
+    fail_unless (GST_IS_BUFFER (buf));
+
+    gst_event_unref (event);
+
+    event = gst_event_new_stream_config (GST_STREAM_CONFIG_FLAG_NONE);
+    fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 0);
+    sh1 = gst_buffer_new_wrapped_full ((gpointer) "Strea", NULL, 0, 5);
+    gst_event_add_stream_config_header (event, sh1);
+    gst_buffer_unref (sh1);
+    fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 1);
+    sh2 = gst_buffer_new_wrapped_full ((gpointer) "mHeader", NULL, 0, 7);
+    gst_event_add_stream_config_header (event, sh2);
+    gst_buffer_unref (sh2);
+    fail_unless_equals_int (gst_event_get_n_stream_config_headers (event), 2);
+
+    buf = (GstBuffer *) & dummy;
+    gst_event_parse_nth_stream_config_header (event, 1, &buf);
+    fail_unless (buf == sh2);
+    fail_unless (GST_IS_BUFFER (buf));
+
+    buf = (GstBuffer *) & dummy;
+    gst_event_parse_nth_stream_config_header (event, 0, &buf);
+    fail_unless (buf == sh1);
+    fail_unless (GST_IS_BUFFER (buf));
+
+    gst_event_unref (event);
+  }
+
   /* TAGS */
   {
     GstTagList *taglist = gst_tag_list_new_empty ();