diff --git a/docs/gst/gstreamer-sections.txt b/docs/gst/gstreamer-sections.txt index b846173b7e..aa7d3f4a13 100644 --- a/docs/gst/gstreamer-sections.txt +++ b/docs/gst/gstreamer-sections.txt @@ -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 diff --git a/gst/gstmessage.c b/gst/gstmessage.c index c30f738d32..3376d9a7fa 100644 --- a/gst/gstmessage.c +++ b/gst/gstmessage.c @@ -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); +} diff --git a/gst/gstmessage.h b/gst/gstmessage.h index 695c02f570..9a07f6e2a7 100644 --- a/gst/gstmessage.h +++ b/gst/gstmessage.h @@ -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, diff --git a/gst/gstquark.c b/gst/gstquark.c index 273edb29b7..a4253a9cc5 100644 --- a/gst/gstquark.c +++ b/gst/gstquark.c @@ -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]; diff --git a/gst/gstquark.h b/gst/gstquark.h index 616e1220a4..8273c3d841 100644 --- a/gst/gstquark.h +++ b/gst/gstquark.h @@ -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]; diff --git a/tests/check/gst/gstmessage.c b/tests/check/gst/gstmessage.c index dc9a571435..2bdb585423 100644 --- a/tests/check/gst/gstmessage.c +++ b/tests/check/gst/gstmessage.c @@ -257,6 +257,69 @@ GST_START_TEST (test_parsing) gst_message_parse_request_state (message, &state); fail_unless (state == GST_STATE_PAUSED); + 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, + ×tamp, &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); } } diff --git a/win32/common/libgstreamer.def b/win32/common/libgstreamer.def index 04c59a56b8..ee2e13137a 100644 --- a/win32/common/libgstreamer.def +++ b/win32/common/libgstreamer.def @@ -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