From: David I. Lehn Date: Wed, 24 Oct 2001 22:42:40 +0000 (+0000) Subject: basic statistics element X-Git-Tag: BRANCH-BUILD1-ROOT~46 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=2408c618b22499cf4837a6ad6abd574bb6da6104;p=platform%2Fupstream%2Fgstreamer.git basic statistics element Original commit message from CVS: basic statistics element --- diff --git a/gst/elements/Makefile.am b/gst/elements/Makefile.am index 1e165b8..64b75fc 100644 --- a/gst/elements/Makefile.am +++ b/gst/elements/Makefile.am @@ -25,6 +25,7 @@ libgstelements_la_SOURCES = \ gstpipefilter.c \ gsttee.c \ gstaggregator.c \ + gststatistics.c \ $(GSTHTTPSRC) noinst_HEADERS = \ @@ -39,7 +40,8 @@ noinst_HEADERS = \ gstfdsink.h \ gstpipefilter.h \ gsttee.h \ - gstaggregator.h + gstaggregator.h \ + gststatistics.h CFLAGS += -O2 -Wall LDFLAGS += -lm diff --git a/gst/elements/gstelements.c b/gst/elements/gstelements.c index 0b21e99..3125983 100644 --- a/gst/elements/gstelements.c +++ b/gst/elements/gstelements.c @@ -34,6 +34,7 @@ #include "gstpipefilter.h" #include "gsttee.h" #include "gstaggregator.h" +#include "gststatistics.h" #if HAVE_LIBGHTTP #include @@ -64,6 +65,7 @@ static struct _elements_entry _elements[] = { { "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL }, { "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init }, { "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init }, + { "statistics", gst_statistics_get_type, &gst_statistics_details, NULL }, #if HAVE_LIBGHTTP { "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL }, diff --git a/gst/elements/gststatistics.c b/gst/elements/gststatistics.c new file mode 100644 index 0000000..398c119 --- /dev/null +++ b/gst/elements/gststatistics.c @@ -0,0 +1,404 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gststatistics.c: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include + + +GstElementDetails gst_statistics_details = { + "Statistics", + "Filter", + "Statistics on buffers/bytes/events", + VERSION, + "David I. Lehn ", + "(C) 2001", +}; + + +/* Statistics signals and args */ +enum { + SIGNAL_UPDATE, + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_BUFFERS, + ARG_BYTES, + ARG_EVENTS, + ARG_BUFFER_UPDATE_FREQ, + ARG_BYTES_UPDATE_FREQ, + ARG_EVENT_UPDATE_FREQ, + ARG_UPDATE_ON_EOS, + ARG_UPDATE, + ARG_SILENT, +}; + + +static void gst_statistics_class_init (GstStatisticsClass *klass); +static void gst_statistics_init (GstStatistics *statistics); + +static void gst_statistics_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_statistics_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_statistics_chain (GstPad *pad, GstBuffer *buf); +static void gst_statistics_reset (GstStatistics *statistics); +static void gst_statistics_print (GstStatistics *statistics); + +static GstElementClass *parent_class = NULL; +static guint gst_statistics_signals[LAST_SIGNAL] = { 0 }; + +static stats zero_stats = { 0, }; + +GType +gst_statistics_get_type (void) +{ + static GType statistics_type = 0; + + if (!statistics_type) { + static const GTypeInfo statistics_info = { + sizeof(GstStatisticsClass), NULL, + NULL, + (GClassInitFunc)gst_statistics_class_init, + NULL, + NULL, + sizeof(GstStatistics), + 0, + (GInstanceInitFunc)gst_statistics_init, + }; + statistics_type = g_type_register_static (GST_TYPE_ELEMENT, "GstStatistics", &statistics_info, 0); + } + return statistics_type; +} + +static void +gst_statistics_class_init (GstStatisticsClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFERS, + g_param_spec_int64 ("buffers", "buffers", "total buffers count", + 0, G_MAXINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES, + g_param_spec_int64 ("bytes", "bytes", "total bytes count", + 0, G_MAXINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENTS, + g_param_spec_int64 ("events", "events", "total event count", + 0, G_MAXINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFER_UPDATE_FREQ, + g_param_spec_int64 ("buffer_update_freq", "buffer update freq", "buffer update frequency", + 0, G_MAXINT64, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES_UPDATE_FREQ, + g_param_spec_int64 ("bytes_update_freq", "bytes update freq", "bytes update frequency", + 0, G_MAXINT64, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENT_UPDATE_FREQ, + g_param_spec_int64 ("event_update_freq", "event update freq", "event update frequency", + 0, G_MAXINT64, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_ON_EOS, + g_param_spec_boolean ("update_on_eos", "update on EOS", "update on EOS event", + TRUE,G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE, + g_param_spec_boolean ("update", "update", "update", + TRUE,G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT, + g_param_spec_boolean ("silent", "silent", "silent", + TRUE,G_PARAM_READWRITE)); + + gst_statistics_signals[SIGNAL_UPDATE] = + g_signal_new ("update", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstStatisticsClass, update), NULL, NULL, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 0); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property); +} + +static GstBufferPool* +gst_statistics_get_bufferpool (GstPad *pad) +{ + GstStatistics *statistics; + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + return gst_pad_get_bufferpool (statistics->srcpad); +} + +static GstPadNegotiateReturn +gst_statistics_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstStatistics *statistics; + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, statistics->sinkpad, caps); +} + +static GstPadNegotiateReturn +gst_statistics_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstStatistics *statistics; + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, statistics->srcpad, caps); +} + +static void +gst_statistics_init (GstStatistics *statistics) +{ + statistics->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad); + gst_pad_set_chain_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_chain)); + gst_pad_set_bufferpool_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_get_bufferpool)); + gst_pad_set_negotiate_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_sink)); + + statistics->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad); + gst_pad_set_negotiate_function (statistics->srcpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_src)); + + statistics->timer = NULL; + statistics->last_timer = NULL; + gst_statistics_reset(statistics); +} + +static void +gst_statistics_reset (GstStatistics *statistics) +{ + g_return_if_fail (statistics != NULL); + g_return_if_fail (GST_IS_STATISTICS (statistics)); + + statistics->stats.buffers = 0; + statistics->stats.bytes = 0; + statistics->stats.events = 0; + + statistics->last_stats.buffers = 0; + statistics->last_stats.bytes = 0; + statistics->last_stats.events = 0; + + statistics->update_count.buffers = 0; + statistics->update_count.bytes = 0; + statistics->update_count.events = 0; + + statistics->update_freq.buffers = 0; + statistics->update_freq.bytes = 0; + statistics->update_freq.events = 0; + + statistics->update_on_eos = TRUE; + statistics->update = TRUE; + statistics->silent = FALSE; + + if (!statistics->timer) { + statistics->timer = g_timer_new(); + } + if (!statistics->last_timer) { + statistics->last_timer = g_timer_new(); + } +} + +static void +print_stats(gboolean first, const gchar *name, const gchar *type, stats *base, stats *final, double time) +{ + const gchar *header0 = "statistics"; + const gchar *headerN = " "; + stats delta; + + delta.buffers = final->buffers - base->buffers; + delta.bytes = final->bytes - base->bytes; + delta.events = final->events - base->events; + + g_print("%s: (%s) %s: s:%g buffers:%lld bytes:%lld events:%lld\n", + first ? header0 : headerN, + name, type, time, + final->buffers, + final->bytes, + final->events); + g_print("%s: (%s) %s: buf/s:%g B/s:%g e/s:%g B/buf:%g\n", + headerN, + name, type, + delta.buffers/time, + delta.bytes/time, + delta.events/time, + ((double)delta.bytes/(double)delta.buffers)); +} + +static void +gst_statistics_print (GstStatistics *statistics) +{ + const gchar *name; + double elapsed; + double last_elapsed; + + g_return_if_fail (statistics != NULL); + g_return_if_fail (GST_IS_STATISTICS (statistics)); + + name = gst_object_get_name(GST_OBJECT(statistics)); + if (!name) { + name = ""; + } + + elapsed = g_timer_elapsed(statistics->timer, NULL); + last_elapsed = g_timer_elapsed(statistics->last_timer, NULL); + + print_stats(1, name, "total", &zero_stats, &statistics->stats, elapsed); + print_stats(0, name, "last", &statistics->last_stats, &statistics->stats, last_elapsed); + statistics->last_stats = statistics->stats; + g_timer_reset(statistics->last_timer); +} + +static void +gst_statistics_chain (GstPad *pad, GstBuffer *buf) +{ + GstStatistics *statistics; + gboolean update = FALSE; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + if (GST_IS_EVENT(buf)) { + GstEvent *event = GST_EVENT (buf); + gst_element_set_state (GST_ELEMENT (statistics), GST_STATE_PAUSED); + statistics->stats.events += 1; + if (statistics->update_on_eos && (GST_EVENT_TYPE(event) == GST_EVENT_EOS)) { + update = TRUE; + } + if (statistics->update_freq.events) { + statistics->update_count.events += 1; + if (statistics->update_count.events == statistics->update_freq.events) { + statistics->update_count.events = 0; + update = TRUE; + } + } + } else { + statistics->stats.buffers += 1; + if (statistics->update_freq.buffers) { + statistics->update_count.buffers += 1; + if (statistics->update_count.buffers == statistics->update_freq.buffers) { + statistics->update_count.buffers = 0; + update = TRUE; + } + } + + statistics->stats.bytes += GST_BUFFER_SIZE(buf); + if (statistics->update_freq.bytes) { + statistics->update_count.bytes += GST_BUFFER_SIZE(buf); + if (statistics->update_count.bytes >= statistics->update_freq.bytes) { + statistics->update_count.bytes = 0; + update = TRUE; + } + } + } + + if (update) { + if (statistics->update) { + g_signal_emit (G_OBJECT (statistics), gst_statistics_signals[SIGNAL_UPDATE], 0); + } + if (!statistics->silent) { + gst_statistics_print(statistics); + } + } + gst_pad_push (statistics->srcpad, buf); +} + +static void +gst_statistics_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstStatistics *statistics; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_STATISTICS (object)); + + statistics = GST_STATISTICS (object); + + switch (prop_id) { + case ARG_BUFFER_UPDATE_FREQ: + statistics->update_freq.buffers = g_value_get_int64 (value); + break; + case ARG_BYTES_UPDATE_FREQ: + statistics->update_freq.bytes = g_value_get_int64 (value); + break; + case ARG_EVENT_UPDATE_FREQ: + statistics->update_freq.events = g_value_get_int64 (value); + break; + case ARG_UPDATE_ON_EOS: + statistics->update_on_eos = g_value_get_boolean (value); + break; + case ARG_UPDATE: + statistics->update = g_value_get_boolean (value); + break; + case ARG_SILENT: + statistics->silent = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gst_statistics_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + GstStatistics *statistics; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_STATISTICS (object)); + + statistics = GST_STATISTICS (object); + + switch (prop_id) { + case ARG_BUFFERS: + g_value_set_int64 (value, statistics->stats.buffers); + break; + case ARG_BYTES: + g_value_set_int64 (value, statistics->stats.bytes); + break; + case ARG_EVENTS: + g_value_set_int64 (value, statistics->stats.events); + break; + case ARG_BUFFER_UPDATE_FREQ: + g_value_set_int64 (value, statistics->update_freq.buffers); + break; + case ARG_BYTES_UPDATE_FREQ: + g_value_set_int64 (value, statistics->update_freq.bytes); + break; + case ARG_EVENT_UPDATE_FREQ: + g_value_set_int64 (value, statistics->update_freq.events); + break; + case ARG_UPDATE_ON_EOS: + g_value_set_boolean (value, statistics->update_on_eos); + break; + case ARG_UPDATE: + g_value_set_boolean (value, statistics->update); + break; + case ARG_SILENT: + g_value_set_boolean (value, statistics->silent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/elements/gststatistics.h b/gst/elements/gststatistics.h new file mode 100644 index 0000000..8a4d9fd --- /dev/null +++ b/gst/elements/gststatistics.h @@ -0,0 +1,95 @@ +/* GStreamer + * Copyright (C) 2001 David I. Lehn + * + * gststatistics.h: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_STATISTICS_H__ +#define __GST_STATISTICS_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +GstElementDetails gst_statistics_details; + + +#define GST_TYPE_STATISTICS \ + (gst_statistics_get_type()) +#define GST_STATISTICS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STATISTICS,GstStatistics)) +#define GST_STATISTICS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STATISTICS,GstStatisticsClass)) +#define GST_IS_STATISTICS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STATISTICS)) +#define GST_IS_STATISTICS_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STATISTICS)) + +typedef struct _GstStatistics GstStatistics; +typedef struct _GstStatisticsClass GstStatisticsClass; + +typedef struct _stats stats; + +struct _stats { + gint64 buffers; + gint64 bytes; + gint64 events; +}; + +struct _GstStatistics { + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; + + GTimer *timer; + GTimer *last_timer; + + stats stats; + stats last_stats; + stats update_count; + stats update_freq; + + gboolean update_on_eos; + gboolean update; + gboolean silent; +}; + +struct _GstStatisticsClass { + GstElementClass parent_class; + + /* signals */ + void (*update) (GstElement *element); +}; + +GType gst_statistics_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STATISTICS_H__ */ diff --git a/plugins/elements/Makefile.am b/plugins/elements/Makefile.am index 1e165b8..64b75fc 100644 --- a/plugins/elements/Makefile.am +++ b/plugins/elements/Makefile.am @@ -25,6 +25,7 @@ libgstelements_la_SOURCES = \ gstpipefilter.c \ gsttee.c \ gstaggregator.c \ + gststatistics.c \ $(GSTHTTPSRC) noinst_HEADERS = \ @@ -39,7 +40,8 @@ noinst_HEADERS = \ gstfdsink.h \ gstpipefilter.h \ gsttee.h \ - gstaggregator.h + gstaggregator.h \ + gststatistics.h CFLAGS += -O2 -Wall LDFLAGS += -lm diff --git a/plugins/elements/gstelements.c b/plugins/elements/gstelements.c index 0b21e99..3125983 100644 --- a/plugins/elements/gstelements.c +++ b/plugins/elements/gstelements.c @@ -34,6 +34,7 @@ #include "gstpipefilter.h" #include "gsttee.h" #include "gstaggregator.h" +#include "gststatistics.h" #if HAVE_LIBGHTTP #include @@ -64,6 +65,7 @@ static struct _elements_entry _elements[] = { { "pipefilter", gst_pipefilter_get_type, &gst_pipefilter_details, NULL }, { "tee", gst_tee_get_type, &gst_tee_details, gst_tee_factory_init }, { "aggregator", gst_aggregator_get_type, &gst_aggregator_details, gst_aggregator_factory_init }, + { "statistics", gst_statistics_get_type, &gst_statistics_details, NULL }, #if HAVE_LIBGHTTP { "httpsrc", gst_httpsrc_get_type, &gst_httpsrc_details, NULL }, diff --git a/plugins/elements/gststatistics.c b/plugins/elements/gststatistics.c new file mode 100644 index 0000000..398c119 --- /dev/null +++ b/plugins/elements/gststatistics.c @@ -0,0 +1,404 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gststatistics.c: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include + + +GstElementDetails gst_statistics_details = { + "Statistics", + "Filter", + "Statistics on buffers/bytes/events", + VERSION, + "David I. Lehn ", + "(C) 2001", +}; + + +/* Statistics signals and args */ +enum { + SIGNAL_UPDATE, + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_BUFFERS, + ARG_BYTES, + ARG_EVENTS, + ARG_BUFFER_UPDATE_FREQ, + ARG_BYTES_UPDATE_FREQ, + ARG_EVENT_UPDATE_FREQ, + ARG_UPDATE_ON_EOS, + ARG_UPDATE, + ARG_SILENT, +}; + + +static void gst_statistics_class_init (GstStatisticsClass *klass); +static void gst_statistics_init (GstStatistics *statistics); + +static void gst_statistics_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_statistics_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + +static void gst_statistics_chain (GstPad *pad, GstBuffer *buf); +static void gst_statistics_reset (GstStatistics *statistics); +static void gst_statistics_print (GstStatistics *statistics); + +static GstElementClass *parent_class = NULL; +static guint gst_statistics_signals[LAST_SIGNAL] = { 0 }; + +static stats zero_stats = { 0, }; + +GType +gst_statistics_get_type (void) +{ + static GType statistics_type = 0; + + if (!statistics_type) { + static const GTypeInfo statistics_info = { + sizeof(GstStatisticsClass), NULL, + NULL, + (GClassInitFunc)gst_statistics_class_init, + NULL, + NULL, + sizeof(GstStatistics), + 0, + (GInstanceInitFunc)gst_statistics_init, + }; + statistics_type = g_type_register_static (GST_TYPE_ELEMENT, "GstStatistics", &statistics_info, 0); + } + return statistics_type; +} + +static void +gst_statistics_class_init (GstStatisticsClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFERS, + g_param_spec_int64 ("buffers", "buffers", "total buffers count", + 0, G_MAXINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES, + g_param_spec_int64 ("bytes", "bytes", "total bytes count", + 0, G_MAXINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENTS, + g_param_spec_int64 ("events", "events", "total event count", + 0, G_MAXINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFER_UPDATE_FREQ, + g_param_spec_int64 ("buffer_update_freq", "buffer update freq", "buffer update frequency", + 0, G_MAXINT64, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BYTES_UPDATE_FREQ, + g_param_spec_int64 ("bytes_update_freq", "bytes update freq", "bytes update frequency", + 0, G_MAXINT64, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENT_UPDATE_FREQ, + g_param_spec_int64 ("event_update_freq", "event update freq", "event update frequency", + 0, G_MAXINT64, 0, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE_ON_EOS, + g_param_spec_boolean ("update_on_eos", "update on EOS", "update on EOS event", + TRUE,G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPDATE, + g_param_spec_boolean ("update", "update", "update", + TRUE,G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT, + g_param_spec_boolean ("silent", "silent", "silent", + TRUE,G_PARAM_READWRITE)); + + gst_statistics_signals[SIGNAL_UPDATE] = + g_signal_new ("update", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstStatisticsClass, update), NULL, NULL, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 0); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_statistics_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_statistics_get_property); +} + +static GstBufferPool* +gst_statistics_get_bufferpool (GstPad *pad) +{ + GstStatistics *statistics; + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + return gst_pad_get_bufferpool (statistics->srcpad); +} + +static GstPadNegotiateReturn +gst_statistics_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstStatistics *statistics; + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, statistics->sinkpad, caps); +} + +static GstPadNegotiateReturn +gst_statistics_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) +{ + GstStatistics *statistics; + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + return gst_pad_negotiate_proxy (pad, statistics->srcpad, caps); +} + +static void +gst_statistics_init (GstStatistics *statistics) +{ + statistics->sinkpad = gst_pad_new ("sink", GST_PAD_SINK); + gst_element_add_pad (GST_ELEMENT (statistics), statistics->sinkpad); + gst_pad_set_chain_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_chain)); + gst_pad_set_bufferpool_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_get_bufferpool)); + gst_pad_set_negotiate_function (statistics->sinkpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_sink)); + + statistics->srcpad = gst_pad_new ("src", GST_PAD_SRC); + gst_element_add_pad (GST_ELEMENT (statistics), statistics->srcpad); + gst_pad_set_negotiate_function (statistics->srcpad, GST_DEBUG_FUNCPTR (gst_statistics_negotiate_src)); + + statistics->timer = NULL; + statistics->last_timer = NULL; + gst_statistics_reset(statistics); +} + +static void +gst_statistics_reset (GstStatistics *statistics) +{ + g_return_if_fail (statistics != NULL); + g_return_if_fail (GST_IS_STATISTICS (statistics)); + + statistics->stats.buffers = 0; + statistics->stats.bytes = 0; + statistics->stats.events = 0; + + statistics->last_stats.buffers = 0; + statistics->last_stats.bytes = 0; + statistics->last_stats.events = 0; + + statistics->update_count.buffers = 0; + statistics->update_count.bytes = 0; + statistics->update_count.events = 0; + + statistics->update_freq.buffers = 0; + statistics->update_freq.bytes = 0; + statistics->update_freq.events = 0; + + statistics->update_on_eos = TRUE; + statistics->update = TRUE; + statistics->silent = FALSE; + + if (!statistics->timer) { + statistics->timer = g_timer_new(); + } + if (!statistics->last_timer) { + statistics->last_timer = g_timer_new(); + } +} + +static void +print_stats(gboolean first, const gchar *name, const gchar *type, stats *base, stats *final, double time) +{ + const gchar *header0 = "statistics"; + const gchar *headerN = " "; + stats delta; + + delta.buffers = final->buffers - base->buffers; + delta.bytes = final->bytes - base->bytes; + delta.events = final->events - base->events; + + g_print("%s: (%s) %s: s:%g buffers:%lld bytes:%lld events:%lld\n", + first ? header0 : headerN, + name, type, time, + final->buffers, + final->bytes, + final->events); + g_print("%s: (%s) %s: buf/s:%g B/s:%g e/s:%g B/buf:%g\n", + headerN, + name, type, + delta.buffers/time, + delta.bytes/time, + delta.events/time, + ((double)delta.bytes/(double)delta.buffers)); +} + +static void +gst_statistics_print (GstStatistics *statistics) +{ + const gchar *name; + double elapsed; + double last_elapsed; + + g_return_if_fail (statistics != NULL); + g_return_if_fail (GST_IS_STATISTICS (statistics)); + + name = gst_object_get_name(GST_OBJECT(statistics)); + if (!name) { + name = ""; + } + + elapsed = g_timer_elapsed(statistics->timer, NULL); + last_elapsed = g_timer_elapsed(statistics->last_timer, NULL); + + print_stats(1, name, "total", &zero_stats, &statistics->stats, elapsed); + print_stats(0, name, "last", &statistics->last_stats, &statistics->stats, last_elapsed); + statistics->last_stats = statistics->stats; + g_timer_reset(statistics->last_timer); +} + +static void +gst_statistics_chain (GstPad *pad, GstBuffer *buf) +{ + GstStatistics *statistics; + gboolean update = FALSE; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + statistics = GST_STATISTICS (gst_pad_get_parent (pad)); + + if (GST_IS_EVENT(buf)) { + GstEvent *event = GST_EVENT (buf); + gst_element_set_state (GST_ELEMENT (statistics), GST_STATE_PAUSED); + statistics->stats.events += 1; + if (statistics->update_on_eos && (GST_EVENT_TYPE(event) == GST_EVENT_EOS)) { + update = TRUE; + } + if (statistics->update_freq.events) { + statistics->update_count.events += 1; + if (statistics->update_count.events == statistics->update_freq.events) { + statistics->update_count.events = 0; + update = TRUE; + } + } + } else { + statistics->stats.buffers += 1; + if (statistics->update_freq.buffers) { + statistics->update_count.buffers += 1; + if (statistics->update_count.buffers == statistics->update_freq.buffers) { + statistics->update_count.buffers = 0; + update = TRUE; + } + } + + statistics->stats.bytes += GST_BUFFER_SIZE(buf); + if (statistics->update_freq.bytes) { + statistics->update_count.bytes += GST_BUFFER_SIZE(buf); + if (statistics->update_count.bytes >= statistics->update_freq.bytes) { + statistics->update_count.bytes = 0; + update = TRUE; + } + } + } + + if (update) { + if (statistics->update) { + g_signal_emit (G_OBJECT (statistics), gst_statistics_signals[SIGNAL_UPDATE], 0); + } + if (!statistics->silent) { + gst_statistics_print(statistics); + } + } + gst_pad_push (statistics->srcpad, buf); +} + +static void +gst_statistics_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstStatistics *statistics; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_STATISTICS (object)); + + statistics = GST_STATISTICS (object); + + switch (prop_id) { + case ARG_BUFFER_UPDATE_FREQ: + statistics->update_freq.buffers = g_value_get_int64 (value); + break; + case ARG_BYTES_UPDATE_FREQ: + statistics->update_freq.bytes = g_value_get_int64 (value); + break; + case ARG_EVENT_UPDATE_FREQ: + statistics->update_freq.events = g_value_get_int64 (value); + break; + case ARG_UPDATE_ON_EOS: + statistics->update_on_eos = g_value_get_boolean (value); + break; + case ARG_UPDATE: + statistics->update = g_value_get_boolean (value); + break; + case ARG_SILENT: + statistics->silent = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void gst_statistics_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + GstStatistics *statistics; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_STATISTICS (object)); + + statistics = GST_STATISTICS (object); + + switch (prop_id) { + case ARG_BUFFERS: + g_value_set_int64 (value, statistics->stats.buffers); + break; + case ARG_BYTES: + g_value_set_int64 (value, statistics->stats.bytes); + break; + case ARG_EVENTS: + g_value_set_int64 (value, statistics->stats.events); + break; + case ARG_BUFFER_UPDATE_FREQ: + g_value_set_int64 (value, statistics->update_freq.buffers); + break; + case ARG_BYTES_UPDATE_FREQ: + g_value_set_int64 (value, statistics->update_freq.bytes); + break; + case ARG_EVENT_UPDATE_FREQ: + g_value_set_int64 (value, statistics->update_freq.events); + break; + case ARG_UPDATE_ON_EOS: + g_value_set_boolean (value, statistics->update_on_eos); + break; + case ARG_UPDATE: + g_value_set_boolean (value, statistics->update); + break; + case ARG_SILENT: + g_value_set_boolean (value, statistics->silent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/plugins/elements/gststatistics.h b/plugins/elements/gststatistics.h new file mode 100644 index 0000000..8a4d9fd --- /dev/null +++ b/plugins/elements/gststatistics.h @@ -0,0 +1,95 @@ +/* GStreamer + * Copyright (C) 2001 David I. Lehn + * + * gststatistics.h: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_STATISTICS_H__ +#define __GST_STATISTICS_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +GstElementDetails gst_statistics_details; + + +#define GST_TYPE_STATISTICS \ + (gst_statistics_get_type()) +#define GST_STATISTICS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_STATISTICS,GstStatistics)) +#define GST_STATISTICS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_STATISTICS,GstStatisticsClass)) +#define GST_IS_STATISTICS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_STATISTICS)) +#define GST_IS_STATISTICS_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_STATISTICS)) + +typedef struct _GstStatistics GstStatistics; +typedef struct _GstStatisticsClass GstStatisticsClass; + +typedef struct _stats stats; + +struct _stats { + gint64 buffers; + gint64 bytes; + gint64 events; +}; + +struct _GstStatistics { + GstElement element; + + GstPad *sinkpad; + GstPad *srcpad; + + GTimer *timer; + GTimer *last_timer; + + stats stats; + stats last_stats; + stats update_count; + stats update_freq; + + gboolean update_on_eos; + gboolean update; + gboolean silent; +}; + +struct _GstStatisticsClass { + GstElementClass parent_class; + + /* signals */ + void (*update) (GstElement *element); +}; + +GType gst_statistics_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_STATISTICS_H__ */