From af166b5b227f2f07c02453e789dec44aaf04848d Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Mon, 30 Jul 2018 14:57:23 +1000 Subject: [PATCH] urisourcebin: add a statistics property for queueing It contains the minimum/maximum/average byte and time levels of the queues inside this urisourcebin https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/60 --- gst/playback/gsturisourcebin.c | 71 ++++++++++++++++++++++++ tests/check/Makefile.am | 6 ++- tests/check/elements/.gitignore | 1 + tests/check/elements/urisourcebin.c | 84 +++++++++++++++++++++++++++++ tests/check/meson.build | 1 + 5 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 tests/check/elements/urisourcebin.c diff --git a/gst/playback/gsturisourcebin.c b/gst/playback/gsturisourcebin.c index e8f8ecda3a..20aebf331c 100644 --- a/gst/playback/gsturisourcebin.c +++ b/gst/playback/gsturisourcebin.c @@ -229,6 +229,7 @@ enum PROP_RING_BUFFER_MAX_SIZE, PROP_LOW_WATERMARK, PROP_HIGH_WATERMARK, + PROP_STATISTICS, }; #define CUSTOM_EOS_QUARK _custom_eos_quark_get () @@ -279,6 +280,7 @@ static GstPad *create_output_pad (GstURISourceBin * urisrc, GstPad * pad); static void remove_buffering_msgs (GstURISourceBin * bin, GstObject * src); static void update_queue_values (GstURISourceBin * urisrc); +static GstStructure *get_queue_statistics (GstURISourceBin * urisrc); static void gst_uri_source_bin_class_init (GstURISourceBinClass * klass) @@ -384,6 +386,25 @@ gst_uri_source_bin_class_init (GstURISourceBinClass * klass) 0.0, 1.0, DEFAULT_HIGH_WATERMARK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GstURISourceBin::statistics + * + * A GStructure containing the following values based on the values from + * all the queue's contained in this urisourcebin. + * + * "minimum-byte-level" G_TYPE_UINT Minimum of the current byte levels + * "maximum-byte-level" G_TYPE_UINT Maximum of the current byte levels + * "average-byte-level" G_TYPE_UINT Average of the current byte levels + * "minimum-time-level" G_TYPE_UINT64 Minimum of the current time levels + * "maximum-time-level" G_TYPE_UINT64 Maximum of the current time levels + * "average-time-level" G_TYPE_UINT64 Average of the current time levels + */ + g_object_class_install_property (gobject_class, PROP_STATISTICS, + g_param_spec_boxed ("statistics", "Queue Statistics", + "A set of statistics over all the queue-like elements contained in " + "this element", GST_TYPE_STRUCTURE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** * GstURISourceBin::drained: * @@ -580,6 +601,9 @@ gst_uri_source_bin_get_property (GObject * object, guint prop_id, case PROP_HIGH_WATERMARK: g_value_set_double (value, urisrc->high_watermark); break; + case PROP_STATISTICS: + g_value_take_boxed (value, get_queue_statistics (dec)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -892,6 +916,53 @@ pre_queue_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) return ret; } +static GstStructure * +get_queue_statistics (GstURISourceBin * urisrc) +{ + GstStructure *ret = NULL; + guint min_byte_level = 0, max_byte_level = 0; + guint64 min_time_level = 0, max_time_level = 0; + gdouble avg_byte_level = 0., avg_time_level = 0.; + guint i = 0; + GSList *cur; + + GST_URI_SOURCE_BIN_LOCK (urisrc); + + for (cur = urisrc->out_slots; cur != NULL; cur = g_slist_next (cur)) { + OutputSlotInfo *slot = (OutputSlotInfo *) (cur->data); + guint byte_limit = 0; + guint64 time_limit = 0; + + g_object_get (slot->queue, "current-level-bytes", &byte_limit, + "current-level-time", &time_limit, NULL); + + if (byte_limit < min_byte_level) + min_byte_level = byte_limit; + if (byte_limit > max_byte_level) + max_byte_level = byte_limit; + avg_byte_level = (avg_byte_level * i + byte_limit) / (gdouble) (i + 1); + + if (time_limit < min_time_level) + min_time_level = time_limit; + if (time_limit > max_time_level) + max_time_level = time_limit; + avg_time_level = (avg_time_level * i + time_limit) / (gdouble) (i + 1); + + i++; + } + GST_URI_SOURCE_BIN_UNLOCK (urisrc); + + ret = gst_structure_new ("application/x-urisourcebin-stats", + "minimum-byte-level", G_TYPE_UINT, (guint) min_byte_level, + "maximum-byte-level", G_TYPE_UINT, (guint) max_byte_level, + "average-byte-level", G_TYPE_UINT, (guint) avg_byte_level, + "minimum-time-level", G_TYPE_UINT64, (guint64) min_time_level, + "maximum-time-level", G_TYPE_UINT64, (guint64) max_time_level, + "average-time-level", G_TYPE_UINT64, (guint64) avg_time_level, NULL); + + return ret; +} + static void update_queue_values (GstURISourceBin * urisrc) { diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index f80920c872..8fe1122151 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -103,7 +103,8 @@ endif if USE_PLUGIN_PLAYBACK check_playback = elements/decodebin elements/playbin \ elements/playbin-complex elements/streamsynchronizer \ - elements/playsink + elements/playsink \ + elements/urisourcebin else check_playback = endif @@ -712,6 +713,9 @@ elements_playbin_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) elements_playbin_complex_LDADD = $(top_builddir)/gst-libs/gst/audio/libgstaudio-@GST_API_VERSION@.la $(top_builddir)/gst-libs/gst/video/libgstvideo-@GST_API_VERSION@.la $(GST_BASE_LIBS) $(LDADD) elements_playbin_complex_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(AM_CFLAGS) +elements_urisourcebin_LDADD = $(GST_BASE_LIBS) $(LDADD) +elements_urisourcebin_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) + elements_decodebin_LDADD = $(GST_BASE_LIBS) $(LDADD) elements_decodebin_CFLAGS = $(GST_BASE_CFLAGS) $(AM_CFLAGS) diff --git a/tests/check/elements/.gitignore b/tests/check/elements/.gitignore index a914803d64..3537acd134 100644 --- a/tests/check/elements/.gitignore +++ b/tests/check/elements/.gitignore @@ -36,3 +36,4 @@ streamsynchronizer subparse rawaudioparse rawvideoparse +urisourcebin diff --git a/tests/check/elements/urisourcebin.c b/tests/check/elements/urisourcebin.c new file mode 100644 index 0000000000..3b684cdb1f --- /dev/null +++ b/tests/check/elements/urisourcebin.c @@ -0,0 +1,84 @@ +/* GStreamer unit tests for playsink + * Copyright (C) 2015 Matthew Waters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + + +GST_START_TEST (test_initial_statistics) +{ + GstElement *urisrc; + GstStructure *stats = NULL; + guint min_bytes, max_bytes, avg_bytes; + guint64 min_time, max_time, avg_time; + + urisrc = gst_element_factory_make ("urisourcebin", NULL); + fail_unless (urisrc != NULL); + + g_object_get (urisrc, "statistics", &stats, NULL); + + fail_unless (stats != NULL); + fail_unless (g_strcmp0 (gst_structure_get_name (stats), + "application/x-urisourcebin-stats") == 0); + fail_unless_equals_int (6, gst_structure_n_fields (stats)); + + fail_unless_equals_int (TRUE, gst_structure_get_uint (stats, + "minimum-byte-level", &min_bytes)); + fail_unless_equals_int (0, min_bytes); + fail_unless_equals_int (TRUE, gst_structure_get_uint (stats, + "maximum-byte-level", &max_bytes)); + fail_unless_equals_int (0, max_bytes); + fail_unless_equals_int (TRUE, gst_structure_get_uint (stats, + "average-byte-level", &avg_bytes)); + fail_unless_equals_int (0, avg_bytes); + + fail_unless_equals_int (TRUE, gst_structure_get_uint64 (stats, + "minimum-time-level", &min_time)); + fail_unless_equals_int (0, min_time); + fail_unless_equals_int (TRUE, gst_structure_get_uint64 (stats, + "maximum-time-level", &max_time)); + fail_unless_equals_int (0, max_time); + fail_unless_equals_int (TRUE, gst_structure_get_uint64 (stats, + "average-time-level", &avg_time)); + fail_unless_equals_int (0, avg_time); + + gst_structure_free (stats); + gst_object_unref (urisrc); +} + +GST_END_TEST; + + +static Suite * +urisourcebin_suite (void) +{ + Suite *s = suite_create ("urisourcebin"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + + tcase_add_test (tc_chain, test_initial_statistics); + + return s; +} + +GST_CHECK_MAIN (urisourcebin); diff --git a/tests/check/meson.build b/tests/check/meson.build index 375a98878f..7cace1698c 100644 --- a/tests/check/meson.build +++ b/tests/check/meson.build @@ -51,6 +51,7 @@ base_tests = [ [ 'elements/streamsynchronizer.c' ], [ 'elements/subparse.c' ], [ 'elements/textoverlay.c', not pango_dep.found() ], + [ 'elements/urisourcebin.c' ], [ 'elements/videoconvert.c' ], [ 'elements/videorate.c' ], [ 'elements/videoscale.c' ],