message: add QoS message to inform apps of lost data
authorRobert Swain <robert.swain@collabora.co.uk>
Wed, 17 Mar 2010 18:16:42 +0000 (19:16 +0100)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 17 Mar 2010 18:16:42 +0000 (19:16 +0100)
This has been implemented as per part-qos.txt and partially addresses
bug #322947

docs/gst/gstreamer-sections.txt
gst/gstmessage.c
gst/gstmessage.h
gst/gstquark.c
gst/gstquark.h
tests/check/gst/gstmessage.c
win32/common/libgstreamer.def

index b846173..aa7d3f4 100644 (file)
@@ -1167,6 +1167,12 @@ gst_message_parse_async_start
 gst_message_new_async_done
 gst_message_new_step_start
 gst_message_parse_step_start
+gst_message_new_qos
+gst_message_set_qos_values
+gst_message_set_qos_stats
+gst_message_parse_qos
+gst_message_parse_qos_values
+gst_message_parse_qos_stats
 
 GstStructureChangeType
 gst_message_new_structure_change
index c30f738..3376d9a 100644 (file)
@@ -111,6 +111,7 @@ static GstMessageQuarks message_quarks[] = {
   {GST_MESSAGE_ASYNC_DONE, "async-done", 0},
   {GST_MESSAGE_REQUEST_STATE, "request-state", 0},
   {GST_MESSAGE_STEP_START, "step-start", 0},
+  {GST_MESSAGE_QOS, "qos", 0},
   {0, NULL, 0}
 };
 
@@ -1793,3 +1794,215 @@ gst_message_parse_step_start (GstMessage * message, gboolean * active,
       GST_QUARK (FLUSH), G_TYPE_BOOLEAN, flush,
       GST_QUARK (INTERMEDIATE), G_TYPE_BOOLEAN, intermediate, NULL);
 }
+
+/**
+ * gst_message_new_qos:
+ * @src: The object originating the message.
+ * @live: if the message was generated by a live element
+ * @running_time: the running time of the buffer that generated the message
+ * @stream_time: the stream time of the buffer that generated the message
+ * @timestamp: the timestamps of the buffer that generated the message
+ * @duration: the duration of the buffer that generated the message
+ *
+ * A QOS message is posted on the bus whenever an element decides to:
+ *
+ * - drop a buffer because of QoS reasons
+ * - change its processing strategy because of QoS reasons (quality)
+ *
+ * This message can be posted by an element that performs synchronisation against the
+ * clock (live) or it could be dropped by an element that performs QoS because of QOS
+ * events received from a downstream element (!live).
+ *
+ * @running_time, @stream_time, @timestamp, @duration should be set to the
+ * respective running-time, stream-time, timestamp and duration of the (dropped)
+ * buffer that generated the QoS event. Values can be left to
+ * GST_CLOCK_TIME_NONE when unknown.
+ *
+ * Returns: The new qos message.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.29
+ */
+GstMessage *
+gst_message_new_qos (GstObject * src, gboolean live, guint64 running_time,
+    guint64 stream_time, guint64 timestamp, guint64 duration)
+{
+  GstMessage *message;
+  GstStructure *structure;
+
+  structure = gst_structure_id_new (GST_QUARK (MESSAGE_QOS),
+      GST_QUARK (LIVE), G_TYPE_BOOLEAN, live,
+      GST_QUARK (RUNNING_TIME), G_TYPE_UINT64, running_time,
+      GST_QUARK (STREAM_TIME), G_TYPE_UINT64, stream_time,
+      GST_QUARK (TIMESTAMP), G_TYPE_UINT64, timestamp,
+      GST_QUARK (DURATION), G_TYPE_UINT64, duration,
+      GST_QUARK (JITTER), G_TYPE_INT64, (gint64) 0,
+      GST_QUARK (PROPORTION), G_TYPE_DOUBLE, (gdouble) 1.0,
+      GST_QUARK (QUALITY), G_TYPE_INT, (gint) 1000000,
+      GST_QUARK (FORMAT), GST_TYPE_FORMAT, GST_FORMAT_UNDEFINED,
+      GST_QUARK (PROCESSED), G_TYPE_UINT64, (guint64) - 1,
+      GST_QUARK (DROPPED), G_TYPE_UINT64, (guint64) - 1, NULL);
+  message = gst_message_new_custom (GST_MESSAGE_QOS, src, structure);
+
+  return message;
+}
+
+/**
+ * gst_message_set_qos_values:
+ * @message: A valid #GstMessage of type GST_MESSAGE_QOS.
+ * @jitter: The difference of the running-time against the deadline.
+ * @proportion: Long term prediction of the ideal rate relative to normal rate
+ * to get optimal quality.
+ * @quality: An element dependent integer value that specifies the current
+ * quality level of the element. The default maximum quality is 1000000.
+ *
+ * Set the QoS values that have been calculated/analysed from the QoS data
+ *
+ * MT safe.
+ *
+ * Since: 0.10.29
+ */
+void
+gst_message_set_qos_values (GstMessage * message, gint64 jitter,
+    gdouble proportion, gint quality)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS);
+
+  gst_structure_id_set (message->structure,
+      GST_QUARK (JITTER), G_TYPE_INT64, jitter,
+      GST_QUARK (PROPORTION), G_TYPE_DOUBLE, proportion,
+      GST_QUARK (QUALITY), G_TYPE_INT, quality, NULL);
+}
+
+/**
+ * gst_message_set_qos_stats:
+ * @message: A valid #GstMessage of type GST_MESSAGE_QOS.
+ * @format: Units of the 'processed' and 'dropped' fields. Video sinks and video
+ * filters will use GST_FORMAT_BUFFERS (frames). Audio sinks and audio filters
+ * will likely use GST_FORMAT_DEFAULT (samples).
+ * @processed: Total number of units correctly processed since the last state
+ * change to READY or a flushing operation.
+ * @dropped: Total number of units dropped since the last state change to READY
+ * or a flushing operation.
+ *
+ * Set the QoS stats representing the history of the current continuous pipeline
+ * playback period.
+ *
+ * When @format is @GST_FORMAT_UNDEFINED both @dropped and @processed are
+ * invalid. Values of -1 for either @processed or @dropped mean unknown values.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.29
+ */
+void
+gst_message_set_qos_stats (GstMessage * message, GstFormat format,
+    guint64 processed, guint64 dropped)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS);
+
+  gst_structure_id_set (message->structure,
+      GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
+      GST_QUARK (PROCESSED), G_TYPE_UINT64, processed,
+      GST_QUARK (DROPPED), G_TYPE_UINT64, dropped, NULL);
+}
+
+/**
+ * gst_message_parse_qos:
+ * @message: A valid #GstMessage of type GST_MESSAGE_QOS.
+ * @live: if the message was generated by a live element
+ * @running_time: the running time of the buffer that generated the message
+ * @stream_time: the stream time of the buffer that generated the message
+ * @timestamp: the timestamps of the buffer that generated the message
+ * @duration: the duration of the buffer that generated the message
+ *
+ * Extract the timestamps and live status from the QoS message.
+ *
+ * The returned values give the running_time, stream_time, timestamp and
+ * duration of the dropped buffer. Values of GST_CLOCK_TIME_NONE mean unknown
+ * values.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.29
+ */
+void
+gst_message_parse_qos (GstMessage * message, gboolean * live,
+    guint64 * running_time, guint64 * stream_time, guint64 * timestamp,
+    guint64 * duration)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS);
+
+  gst_structure_id_get (message->structure,
+      GST_QUARK (LIVE), G_TYPE_BOOLEAN, live,
+      GST_QUARK (RUNNING_TIME), G_TYPE_UINT64, running_time,
+      GST_QUARK (STREAM_TIME), G_TYPE_UINT64, stream_time,
+      GST_QUARK (TIMESTAMP), G_TYPE_UINT64, timestamp,
+      GST_QUARK (DURATION), G_TYPE_UINT64, duration, NULL);
+}
+
+/**
+ * gst_message_parse_qos_values:
+ * @message: A valid #GstMessage of type GST_MESSAGE_QOS.
+ * @jitter: The difference of the running-time against the deadline.
+ * @proportion: Long term prediction of the ideal rate relative to normal rate
+ * to get optimal quality.
+ * @quality: An element dependent integer value that specifies the current
+ * quality level of the element. The default maximum quality is 1000000.
+ *
+ * Extract the QoS values that have been calculated/analysed from the QoS data
+ *
+ * MT safe.
+ *
+ * Since: 0.10.29
+ */
+void
+gst_message_parse_qos_values (GstMessage * message, gint64 * jitter,
+    gdouble * proportion, gint * quality)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS);
+
+  gst_structure_id_get (message->structure,
+      GST_QUARK (JITTER), G_TYPE_INT64, jitter,
+      GST_QUARK (PROPORTION), G_TYPE_DOUBLE, proportion,
+      GST_QUARK (QUALITY), G_TYPE_INT, quality, NULL);
+}
+
+/**
+ * gst_message_parse_qos_stats:
+ * @message: A valid #GstMessage of type GST_MESSAGE_QOS.
+ * @format: Units of the 'processed' and 'dropped' fields. Video sinks and video
+ * filters will use GST_FORMAT_BUFFERS (frames). Audio sinks and audio filters
+ * will likely use GST_FORMAT_DEFAULT (samples).
+ * @processed: Total number of units correctly processed since the last state
+ * change to READY or a flushing operation.
+ * @dropped: Total number of units dropped since the last state change to READY
+ * or a flushing operation.
+ *
+ * Extract the QoS stats representing the history of the current continuous
+ * pipeline playback period.
+ *
+ * When @format is @GST_FORMAT_UNDEFINED both @dropped and @processed are
+ * invalid. Values of -1 for either @processed or @dropped mean unknown values.
+ *
+ * MT safe.
+ *
+ * Since: 0.10.29
+ */
+void
+gst_message_parse_qos_stats (GstMessage * message, GstFormat * format,
+    guint64 * processed, guint64 * dropped)
+{
+  g_return_if_fail (GST_IS_MESSAGE (message));
+  g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS);
+
+  gst_structure_id_get (message->structure,
+      GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
+      GST_QUARK (PROCESSED), G_TYPE_UINT64, processed,
+      GST_QUARK (DROPPED), G_TYPE_UINT64, dropped, NULL);
+}
index 695c02f..9a07f6e 100644 (file)
@@ -86,6 +86,8 @@ typedef struct _GstMessageClass GstMessageClass;
  * change state. This message is a suggestion to the application which can
  * decide to perform the state change on (part of) the pipeline. Since: 0.10.23.
  * @GST_MESSAGE_STEP_START: A stepping operation was started.
+ * @GST_MESSAGE_QOS: A buffer was dropped or an element changed its processing
+ * strategy for Quality of Service reasons.
  * @GST_MESSAGE_ANY: mask for all of the above messages.
  *
  * The different message types that are available.
@@ -120,6 +122,7 @@ typedef enum
   GST_MESSAGE_ASYNC_DONE        = (1 << 21),
   GST_MESSAGE_REQUEST_STATE     = (1 << 22),
   GST_MESSAGE_STEP_START        = (1 << 23),
+  GST_MESSAGE_QOS               = (1 << 24),
   GST_MESSAGE_ANY               = ~0
 } GstMessageType;
 
@@ -474,6 +477,20 @@ void            gst_message_parse_step_start    (GstMessage * message, gboolean
                                                  guint64 *amount, gdouble *rate, gboolean *flush,
                                                  gboolean *intermediate);
 
+/* QOS */
+GstMessage *    gst_message_new_qos             (GstObject * src, gboolean live, guint64 running_time,
+                                                 guint64 stream_time, guint64 timestamp, guint64 duration);
+void            gst_message_set_qos_values      (GstMessage * message, gint64 jitter, gdouble proportion,
+                                                 gint quality);
+void            gst_message_set_qos_stats       (GstMessage * message, GstFormat format, guint64 processed,
+                                                 guint64 dropped);
+void            gst_message_parse_qos           (GstMessage * message, gboolean * live, guint64 * running_time,
+                                                 guint64 * stream_time, guint64 * timestamp, guint64 * duration);
+void            gst_message_parse_qos_values    (GstMessage * message, gint64 * jitter, gdouble * proportion,
+                                                 gint * quality);
+void            gst_message_parse_qos_stats     (GstMessage * message, GstFormat * format, guint64 * processed,
+                                                 guint64 * dropped);
+
 /* custom messages */
 GstMessage *    gst_message_new_custom          (GstMessageType type,
                                                  GstObject    * src,
index 273edb2..a4253a9 100644 (file)
@@ -48,7 +48,8 @@ static const gchar *_quark_strings[] = {
   "GstQuerySegment", "GstQuerySeeking", "GstQueryFormats", "GstQueryBuffering",
   "GstQueryURI", "GstEventStep", "GstMessageStepDone", "amount", "flush",
   "intermediate", "GstMessageStepStart", "active", "eos", "sink-message",
-  "message"
+  "message", "GstMessageQOS", "running-time", "stream-time", "jitter",
+  "quality", "processed", "dropped"
 };
 
 GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index 616e122..8273c3d 100644 (file)
@@ -119,8 +119,15 @@ typedef enum _GstQuarkId
   GST_QUARK_EOS = 90,
   GST_QUARK_EVENT_SINK_MESSAGE = 91,
   GST_QUARK_MESSAGE = 92,
+  GST_QUARK_MESSAGE_QOS = 93,
+  GST_QUARK_RUNNING_TIME = 94,
+  GST_QUARK_STREAM_TIME = 95,
+  GST_QUARK_JITTER = 96,
+  GST_QUARK_QUALITY = 97,
+  GST_QUARK_PROCESSED = 98,
+  GST_QUARK_DROPPED = 99,
 
-  GST_QUARK_MAX = 93
+  GST_QUARK_MAX = 100
 } GstQuarkId;
 
 extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
index dc9a571..2bdb585 100644 (file)
@@ -259,6 +259,69 @@ GST_START_TEST (test_parsing)
 
     gst_message_unref (message);
   }
+  /* GST_MESSAGE_QOS   */
+  {
+    gboolean live;
+    GstClockTime running_time;
+    GstClockTime stream_time;
+    GstClockTime timestamp, duration;
+    gint64 jitter;
+    gdouble proportion;
+    gint quality;
+    GstFormat format;
+    guint64 processed;
+    guint64 dropped;
+
+    running_time = 1 * GST_SECOND;
+    stream_time = 2 * GST_SECOND;
+    timestamp = 3 * GST_SECOND;
+    duration = 4 * GST_SECOND;
+
+    message =
+        gst_message_new_qos (NULL, TRUE, running_time, stream_time, timestamp,
+        duration);
+    fail_if (message == NULL);
+    fail_unless (GST_MESSAGE_TYPE (message) == GST_MESSAGE_QOS);
+    fail_unless (GST_MESSAGE_SRC (message) == NULL);
+
+    /* check defaults */
+    gst_message_parse_qos_values (message, &jitter, &proportion, &quality);
+    fail_unless (jitter == 0);
+    fail_unless (proportion == 1.0);
+    fail_unless (quality == 1000000);
+
+    gst_message_parse_qos_stats (message, &format, &processed, &dropped);
+    fail_unless (format == GST_FORMAT_UNDEFINED);
+    fail_unless (processed == -1);
+    fail_unless (dropped == -1);
+
+    /* set some wrong values to check if the parse method overwrites them
+     * with the good values */
+    running_time = stream_time = timestamp = duration = 5 * GST_SECOND;
+    live = FALSE;
+    gst_message_parse_qos (message, &live, &running_time, &stream_time,
+        &timestamp, &duration);
+    fail_unless (live == TRUE);
+    fail_unless (running_time == 1 * GST_SECOND);
+    fail_unless (stream_time == 2 * GST_SECOND);
+    fail_unless (timestamp == 3 * GST_SECOND);
+    fail_unless (duration == 4 * GST_SECOND);
+
+    /* change some values */
+    gst_message_set_qos_values (message, -10, 2.0, 5000);
+    gst_message_parse_qos_values (message, &jitter, &proportion, &quality);
+    fail_unless (jitter == -10);
+    fail_unless (proportion == 2.0);
+    fail_unless (quality == 5000);
+
+    gst_message_set_qos_stats (message, GST_FORMAT_DEFAULT, 1030, 65);
+    gst_message_parse_qos_stats (message, &format, &processed, &dropped);
+    fail_unless (format == GST_FORMAT_DEFAULT);
+    fail_unless (processed == 1030);
+    fail_unless (dropped == 65);
+
+    gst_message_unref (message);
+  }
 }
 
 GST_END_TEST;
index 04c59a5..ee2e131 100644 (file)
@@ -496,6 +496,7 @@ EXPORTS
        gst_message_new_info
        gst_message_new_latency
        gst_message_new_new_clock
+       gst_message_new_qos
        gst_message_new_request_state
        gst_message_new_segment_done
        gst_message_new_segment_start
@@ -517,6 +518,9 @@ EXPORTS
        gst_message_parse_error
        gst_message_parse_info
        gst_message_parse_new_clock
+       gst_message_parse_qos
+       gst_message_parse_qos_stats
+       gst_message_parse_qos_values
        gst_message_parse_request_state
        gst_message_parse_segment_done
        gst_message_parse_segment_start
@@ -529,6 +533,8 @@ EXPORTS
        gst_message_parse_tag_full
        gst_message_parse_warning
        gst_message_set_buffering_stats
+       gst_message_set_qos_stats
+       gst_message_set_qos_values
        gst_message_set_seqnum
        gst_message_set_stream_status_object
        gst_message_type_get_name