2 * Copyright (C) <2009> Руслан Ижбулатов <lrn1986 _at_ gmail _dot_ com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
21 * SECTION:element-measurecollector
23 * This plugin collects measurements from measuring elemtns and calculates
24 * total measure for the whole sequence and also outputs measurements to a file
25 * <classname>"GstMeasureCollector"</classname>.
28 * Last reviewed on 2009-03-15 (0.10.?)
35 #include <gst/gst-i18n-plugin.h>
37 #include "gstvideomeasure_collector.h"
43 #include <gst/video/video.h>
45 /* GstMeasureCollector signals and args */
54 GST_DEBUG_CATEGORY_STATIC (measure_collector_debug);
55 #define GST_CAT_DEFAULT measure_collector_debug
57 static GstStaticPadTemplate gst_measure_collector_src_template =
58 GST_STATIC_PAD_TEMPLATE ("src",
63 static GstStaticPadTemplate gst_measure_collector_sink_template =
64 GST_STATIC_PAD_TEMPLATE ("sink",
69 //static GstBaseTransformClass *parent_class = NULL;
71 static void gst_measure_collector_finalize (GObject * object);
72 static gboolean gst_measure_collector_event (GstBaseTransform * base,
74 static void gst_measure_collector_save_csv (GstMeasureCollector * mc);
76 static void gst_measure_collector_post_message (GstMeasureCollector * mc);
78 GST_BOILERPLATE (GstMeasureCollector, gst_measure_collector, GstBaseTransform,
79 GST_TYPE_BASE_TRANSFORM);
82 gst_measure_collector_collect (GstMeasureCollector * mc, GstEvent * gstevent)
84 const GstStructure *str;
85 const gchar *event, *metric;
86 guint64 framenumber = G_MAXUINT64;
87 const GValue *framenumber_v;
89 str = gst_event_get_structure (gstevent);
91 event = gst_structure_get_string (str, "event");
92 metric = gst_structure_get_string (str, "metric");
94 if (strcmp (event, "frame-measured") == 0 && metric != NULL) {
96 cpy = gst_structure_copy (str);
98 framenumber_v = gst_structure_get_value (str, "offset");
100 if (G_VALUE_TYPE (framenumber_v) == G_TYPE_UINT64)
101 framenumber = g_value_get_uint64 (framenumber_v);
102 else if (G_VALUE_TYPE (framenumber_v) == G_TYPE_INT64)
103 framenumber = g_value_get_int64 (framenumber_v);
106 if (framenumber == G_MAXUINT64)
107 framenumber = mc->nextoffset++;
109 if (mc->measurements->len <= framenumber)
110 g_ptr_array_set_size (mc->measurements, framenumber + 1);
111 g_ptr_array_index (mc->measurements, framenumber) = cpy;
113 mc->nextoffset = framenumber + 1;
116 mc->metric = g_strdup (metric);
121 gst_measure_collector_post_message (GstMeasureCollector * mc)
126 g_return_if_fail (mc->metric);
128 if (strcmp (mc->metric, "SSIM") == 0) {
132 mc->result = g_new0 (GValue, 1);
133 g_value_init (mc->result, G_TYPE_FLOAT);
134 mlen = mc->measurements->len;
135 for (i = 0; i < mc->measurements->len; i++) {
138 (GstStructure *) g_ptr_array_index (mc->measurements, i);
140 v = gst_structure_get_value (str, "mean");
141 dresult += g_value_get_float (v);
143 GST_WARNING_OBJECT (mc,
144 "No measurement info for frame %" G_GUINT64_FORMAT, i);
148 g_value_set_float (mc->result, dresult / mlen);
151 m = gst_message_new_element (GST_OBJECT_CAST (mc),
152 gst_structure_new ("GstMeasureCollector",
153 "measure-result", G_TYPE_VALUE, mc->result, NULL));
155 gst_element_post_message (GST_ELEMENT_CAST (mc), m);
159 gst_measure_collector_set_property (GObject * object, guint prop_id,
160 const GValue * value, GParamSpec * pspec)
162 GstMeasureCollector *measurecollector;
164 measurecollector = GST_MEASURE_COLLECTOR (object);
168 measurecollector->flags = g_value_get_uint64 (value);
171 measurecollector->filename = g_value_dup_string (value);
174 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
180 gst_measure_collector_get_property (GObject * object, guint prop_id,
181 GValue * value, GParamSpec * pspec)
183 GstMeasureCollector *measurecollector;
185 measurecollector = GST_MEASURE_COLLECTOR (object);
189 g_value_set_uint64 (value, measurecollector->flags);
192 g_value_set_string (value, measurecollector->filename);
195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201 gst_measure_collector_event (GstBaseTransform * base, GstEvent * event)
203 GstMeasureCollector *mc = GST_MEASURE_COLLECTOR (base);
205 switch (GST_EVENT_TYPE (event)) {
206 case GST_EVENT_CUSTOM_DOWNSTREAM:
207 if (gst_event_has_name (event, GST_EVENT_VIDEO_MEASURE))
208 gst_measure_collector_collect (mc, event);
211 gst_measure_collector_post_message (mc);
212 gst_measure_collector_save_csv (mc);
218 return parent_class->event (base, event);
222 gst_measure_collector_save_csv (GstMeasureCollector * mc)
229 g_value_init (&tmp, G_TYPE_STRING);
231 if (!(mc->flags & GST_MEASURE_COLLECTOR_WRITE_CSV))
234 if (mc->measurements->len <= 0)
238 if (mc->filename == NULL || mc->filename[0] == '\0')
241 name_local = g_filename_from_utf8 ((const gchar *) mc->filename,
242 -1, NULL, NULL, NULL);
245 if (name_local == NULL || name_local[0] == '\0')
246 goto not_good_filename;
249 /* FIXME, can we use g_fopen here? some people say that the FILE object is
250 * local to the .so that performed the fopen call, which would not be us when
252 file = fopen (name_local, "wb");
259 str = (GstStructure *) g_ptr_array_index (mc->measurements, 0);
261 for (j = 0; j < gst_structure_n_fields (str); j++) {
262 const gchar *fieldname;
263 fieldname = gst_structure_nth_field_name (str, j);
264 if (G_LIKELY (j > 0))
266 fprintf (file, "%s", fieldname);
269 for (i = 0; i < mc->measurements->len; i++) {
270 fprintf (file, "\n");
271 str = (GstStructure *) g_ptr_array_index (mc->measurements, i);
273 for (j = 0; j < gst_structure_n_fields (str); j++) {
274 const gchar *fieldname;
275 fieldname = gst_structure_nth_field_name (str, j);
276 if (G_LIKELY (j > 0))
278 if (G_LIKELY (g_value_transform (gst_structure_get_value (str,
280 fprintf (file, "%s", g_value_get_string (&tmp));
282 fprintf (file, "<untranslatable>");
296 GST_ELEMENT_ERROR (mc, RESOURCE, NOT_FOUND,
297 (_("No file name specified for writing.")), (NULL));
302 GST_ELEMENT_ERROR (mc, RESOURCE, NOT_FOUND,
303 (_("Given file name \"%s\" can't be converted to local file name \
304 encoding."), mc->filename), (NULL));
309 GST_ELEMENT_ERROR (mc, RESOURCE, OPEN_WRITE,
310 (_("Could not open file \"%s\" for writing."), mc->filename),
317 gst_measure_collector_base_init (gpointer g_class)
319 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
321 gst_element_class_set_details_simple (element_class,
322 "Video measure collector", "Filter/Effect/Video",
323 "Collect measurements from a measuring element",
324 "Руслан Ижбулатов <lrn _at_ gmail _dot_ com>");
326 gst_element_class_add_static_pad_template (element_class,
327 &gst_measure_collector_sink_template);
328 gst_element_class_add_static_pad_template (element_class,
329 &gst_measure_collector_src_template);
333 gst_measure_collector_class_init (GstMeasureCollectorClass * klass)
335 GObjectClass *gobject_class;
336 GstBaseTransformClass *trans_class;
338 gobject_class = G_OBJECT_CLASS (klass);
339 trans_class = GST_BASE_TRANSFORM_CLASS (klass);
341 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "measurecollect", 0,
342 "measurement collector");
344 gobject_class->set_property = gst_measure_collector_set_property;
345 gobject_class->get_property = gst_measure_collector_get_property;
346 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_measure_collector_finalize);
348 g_object_class_install_property (gobject_class, PROP_FLAGS,
349 g_param_spec_uint64 ("flags", "Flags",
350 "Flags that control the operation of the element",
352 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
354 g_object_class_install_property (gobject_class, PROP_FILENAME,
355 g_param_spec_string ("filename", "Output file name",
356 "A name of a file into which element will write the measurement"
358 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
360 trans_class->event = GST_DEBUG_FUNCPTR (gst_measure_collector_event);
362 trans_class->passthrough_on_same_caps = TRUE;
367 gst_measure_collector_init (GstMeasureCollector * instance,
368 GstMeasureCollectorClass * g_class)
370 GstMeasureCollector *measurecollector;
372 measurecollector = GST_MEASURE_COLLECTOR (instance);
374 GST_DEBUG_OBJECT (measurecollector, "gst_measure_collector_init");
376 gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (measurecollector),
379 measurecollector->measurements = g_ptr_array_new ();
380 measurecollector->metric = NULL;
381 measurecollector->inited = TRUE;
382 measurecollector->filename = NULL;
383 measurecollector->flags = 0;
384 measurecollector->nextoffset = 0;
385 measurecollector->result = NULL;
389 gst_measure_collector_finalize (GObject * object)
392 GstMeasureCollector *mc = GST_MEASURE_COLLECTOR (object);
394 for (i = 0; i < mc->measurements->len; i++) {
395 if (g_ptr_array_index (mc->measurements, i) != NULL)
396 gst_structure_free ((GstStructure *) g_ptr_array_index (mc->measurements,
400 g_ptr_array_free (mc->measurements, TRUE);
401 mc->measurements = NULL;
409 g_free (mc->filename);
412 G_OBJECT_CLASS (parent_class)->finalize (object);