qa: Add a GstQaReporter interface that objects needing reporting can implement

Various type of object should be able to do some reporting, so we have
to make sure all the code to do that is in one place. Creating an interface
makes it simple to share information and it avoid to have a baseclass for
something that is not actually important enough to create a baseclass.

Conflicts:
	gst/qa/gst-qa-pad-monitor.c
This commit is contained in:
Thibault Saunier 2013-07-22 19:17:53 -04:00 committed by Thiago Santos
parent 7508e35b7e
commit 4992249848
9 changed files with 304 additions and 173 deletions

View file

@ -1,3 +1,3 @@
confdir=${sysconfdir}/gstreamer
conf_DATA = simple_seeks.xml
scenariosdir=${datadir}/gstreamer-$(GST_API_VERSION)/qa-scenario
scenarios_DATA = simple_seeks.xml
EXTRA_DIST = simple_seeks.xml

View file

@ -3,6 +3,7 @@ public_headers = \
c_sources = \
gst-qa-runner.c \
gst-qa-reporter.c \
gst-qa-monitor.c \
gst-qa-element-monitor.c \
gst-qa-bin-monitor.c \

View file

@ -20,6 +20,7 @@
*/
#include "gst-qa-monitor.h"
#include "gst-qa-reporter.h"
/**
* SECTION:gst-qa-monitor
@ -41,7 +42,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_qa_monitor_debug);
#define GST_CAT_DEFAULT gst_qa_monitor_debug
#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");
GST_DEBUG_CATEGORY_INIT (gst_qa_monitor_debug, "qa_monitor", 0, "QA Monitor");\
G_IMPLEMENT_INTERFACE (GST_TYPE_QA_REPORTER, NULL)
#define gst_qa_monitor_parent_class parent_class
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstQaMonitor, gst_qa_monitor,
G_TYPE_OBJECT, _do_init);
@ -76,17 +80,13 @@ gst_qa_monitor_dispose (GObject * object)
g_object_weak_unref (G_OBJECT (monitor->target),
(GWeakNotify) _target_freed_cb, monitor);
g_hash_table_unref (monitor->reports);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_qa_monitor_finalize (GObject * object)
{
GstQaMonitor *monitor = GST_QA_MONITOR_CAST (object);
gst_qa_monitor_set_target_name (monitor, NULL);
gst_qa_reporter_set_name (GST_QA_REPORTER (object), NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -133,20 +133,11 @@ gst_qa_monitor_constructor (GType type, guint n_construct_params,
return (GObject *) monitor;
}
static inline gchar *
_qa_report_id (GstQaReport * report)
{
return g_strdup_printf ("%i-%i-%i-%s",
report->level, report->area, report->subarea, report->id);
}
static void
gst_qa_monitor_init (GstQaMonitor * monitor)
{
g_mutex_init (&monitor->mutex);
monitor->reports = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) gst_qa_report_unref);
}
/**
@ -198,7 +189,7 @@ gst_qa_monitor_set_property (GObject * object, guint prop_id,
(GWeakNotify) _target_freed_cb, monitor);
if (monitor->target)
gst_qa_monitor_set_target_name (monitor, g_strdup
gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup
(GST_OBJECT_NAME (monitor->target)));
break;
case PROP_RUNNER:
@ -238,60 +229,3 @@ gst_qa_monitor_get_property (GObject * object, guint prop_id,
break;
}
}
void
gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, va_list var_args)
{
GstQaReport *report;
gchar *message, *report_id = NULL;
message = g_strdup_vprintf (format, var_args);
report = gst_qa_report_new (monitor, level, area, subarea, format, message);
if (repeat == FALSE) {
report_id = _qa_report_id (report);
if (g_hash_table_lookup (monitor->reports, report_id)) {
GST_DEBUG ("Report %s already present", report_id);
g_free (report_id);
return;
}
g_hash_table_insert (monitor->reports, report_id, report);
}
GST_INFO_OBJECT (monitor, "Received error report %d : %d : %d : %s",
level, area, subarea, message);
gst_qa_report_printf (report);
if (GST_QA_MONITOR_GET_RUNNER (monitor)) {
gst_qa_runner_add_report (GST_QA_MONITOR_GET_RUNNER (monitor), report);
} else {
gst_qa_report_unref (report);
}
g_free (message);
}
void
gst_qa_monitor_do_report (GstQaMonitor * monitor, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, ...)
{
va_list var_args;
va_start (var_args, format);
gst_qa_monitor_do_report_valist (monitor, repeat, level, area, subarea,
format, var_args);
va_end (var_args);
}
void
gst_qa_monitor_set_target_name (GstQaMonitor * monitor, gchar * target_name)
{
if (monitor->target_name)
g_free (monitor->target_name);
monitor->target_name = target_name;
}

View file

@ -44,66 +44,6 @@ G_BEGIN_DECLS
#define GST_QA_MONITOR_LOCK(m) (g_mutex_lock (&GST_QA_MONITOR_CAST(m)->mutex))
#define GST_QA_MONITOR_UNLOCK(m) (g_mutex_unlock (&GST_QA_MONITOR_CAST(m)->mutex))
#ifdef G_HAVE_ISO_VARARGS
#define GST_QA_MONITOR_REPORT(m, repeat, status, area, subarea, ...) \
G_STMT_START { \
gst_qa_monitor_do_report (GST_QA_MONITOR (m), repeat, \
GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \
GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \
} G_STMT_END
#define GST_QA_MONITOR_REPORT_CRITICAL(m, repeat, area, subarea, ...) \
G_STMT_START { \
GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \
#area, #subarea, __VA_ARGS__); \
GST_QA_MONITOR_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \
} G_STMT_END
#define GST_QA_MONITOR_REPORT_WARNING(m, repeat, area, subarea, ...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \
#area, #subarea, __VA_ARGS__); \
GST_QA_MONITOR_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \
} G_STMT_END
#define GST_QA_MONITOR_REPORT_ISSUE(m, repeat, area, subarea, ...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \
#area, #subarea, __VA_ARGS__); \
GST_QA_MONITOR_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \
} G_STMT_END
#else /* G_HAVE_GNUC_VARARGS */
#ifdef G_HAVE_GNUC_VARARGS
#define GST_QA_MONITOR_REPORT(m, repeat, status, area, subarea, args...) \
G_STMT_START { \
gst_qa_monitor_do_report (GST_QA_MONITOR (m), \
GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \
GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \
} G_STMT_END
#define GST_QA_MONITOR_REPORT_CRITICAL(m, repeat, area, subarea, args...) \
G_STMT_START { \
GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \
#area, #subarea, ##args); \
GST_QA_MONITOR_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \
} G_STMT_END
#define GST_QA_MONITOR_REPORT_WARNING(m, repeat, area, subarea, args...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \
#area, #subarea, ##args); \
GST_QA_MONITOR_REPORT(m, repeat, WARNING, area, subarea, ##args); \
} G_STMT_END
#define GST_QA_MONITOR_REPORT_ISSUE(m, repeat, area, subarea, args...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \
#area, #subarea, ##args); \
GST_QA_MONITOR_REPORT(m, repeat, ISSUE, area, subarea, ##args); \
} G_STMT_END
#endif /* G_HAVE_ISO_VARARGS */
#endif /* G_HAVE_GNUC_VARARGS */
/* #else TODO Implemen no variadic macros, use inline,
* Problem being:
* GST_QA_REPORT_LEVEL_ ## status
@ -150,18 +90,6 @@ struct _GstQaMonitorClass {
/* normal GObject stuff */
GType gst_qa_monitor_get_type (void);
void gst_qa_monitor_do_report (GstQaMonitor * monitor, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, ...);
void gst_qa_monitor_do_report_valist (GstQaMonitor * monitor, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar *format,
va_list var_args);
void gst_qa_monitor_set_target_name (GstQaMonitor *monitor,
gchar *target_name);
G_END_DECLS
#endif /* __GST_QA_MONITOR_H__ */

View file

@ -21,6 +21,7 @@
#include "gst-qa-pad-monitor.h"
#include "gst-qa-element-monitor.h"
#include "gst-qa-reporter.h"
#include <gst/gst.h>
#include <string.h>
#include <stdarg.h>
@ -156,7 +157,7 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure,
gint rejected_types_index = 0;
if (!gst_structure_has_field (structure, field)) {
GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION,
GST_QA_REPORT_WARNING (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION,
MISSING_FIELD, "%s is missing from structure: %" GST_PTR_FORMAT, field,
structure);
return;
@ -174,7 +175,7 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure,
va_end (var_args);
joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
GST_QA_MONITOR_REPORT_CRITICAL (monitor, FALSE, CAPS_NEGOTIATION,
GST_QA_REPORT_CRITICAL (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION,
BAD_FIELD_TYPE, "%s has wrong type %s in structure '%" GST_PTR_FORMAT
"'. Expected: %s", field,
g_type_name (gst_structure_get_field_type (structure, field)),
@ -444,7 +445,7 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor,
}
if (type_match && !found) {
GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION,
GST_QA_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION,
GET_CAPS,
"Peer pad structure '%" GST_PTR_FORMAT "' has no similar version "
"on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps);
@ -464,7 +465,7 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor,
SerializedEventData *data =
g_ptr_array_index (monitor->serialized_events, i);
if (data->timestamp < ts) {
GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED,
GST_QA_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED,
"Serialized event %" GST_PTR_FORMAT " wasn't pushed before expected "
"timestamp %" GST_TIME_FORMAT " on pad %s:%s", data->event,
GST_TIME_ARGS (data->timestamp),
@ -482,7 +483,7 @@ gst_qa_pad_monitor_check_late_serialized_events (GstQaPadMonitor * monitor,
void
_parent_set_cb (GstObject * object, GstObject * parent, GstQaMonitor * monitor)
{
gst_qa_monitor_set_target_name (monitor, g_strdup_printf ("%s:%s",
gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup_printf ("%s:%s",
GST_DEBUG_PAD_NAME (object)));
}
@ -641,7 +642,7 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor *
return;
}
if (!found) {
GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP,
GST_QA_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP,
"Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
" is out of range of received input", GST_TIME_ARGS (ts),
GST_TIME_ARGS (ts_end));
@ -657,14 +658,14 @@ gst_qa_pad_monitor_check_first_buffer (GstQaPadMonitor * pad_monitor,
if (!pad_monitor->has_segment
&& PAD_IS_IN_PUSH_MODE (GST_QA_PAD_MONITOR_GET_PAD (pad_monitor))) {
GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, EVENT, EXPECTED,
"Received buffer before Segment event");
GST_QA_REPORT_WARNING (GST_QA_REPORTER (pad_monitor), FALSE, EVENT,
EXPECTED, "Received buffer before Segment event");
}
if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer))) {
gint64 running_time = gst_segment_to_running_time (&pad_monitor->segment,
pad_monitor->segment.format, GST_BUFFER_TIMESTAMP (buffer));
if (running_time != 0) {
GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP,
GST_QA_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP,
"First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
GST_TIME_ARGS (running_time));
}
@ -773,7 +774,7 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor,
}
if (aggregated != ret) {
/* TODO review this error code */
GST_QA_MONITOR_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED,
GST_QA_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED,
"Wrong combined flow return %s(%d). Expected: %s(%d)",
gst_flow_get_name (ret), ret,
gst_flow_get_name (aggregated), aggregated);
@ -923,7 +924,7 @@ gst_qa_pad_monitor_add_expected_newsegment (GstQaPadMonitor * monitor,
othermonitor = g_object_get_data ((GObject *) otherpad, "qa-monitor");
GST_QA_MONITOR_LOCK (othermonitor);
if (othermonitor->expected_segment) {
GST_QA_MONITOR_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED,
GST_QA_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED,
"expected newsegment event never pushed");
gst_event_unref (othermonitor->expected_segment);
}
@ -960,7 +961,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor,
if (seqnum == pad_monitor->pending_flush_start_seqnum) {
pad_monitor->pending_flush_start_seqnum = 0;
} else {
GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM,
GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
SEQNUM,
"The expected flush-start seqnum should be the same as the "
"one from the event that caused it (probably a seek). Got: %u."
" Expected: %u", seqnum, pad_monitor->pending_flush_start_seqnum);
@ -968,7 +970,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor,
}
if (pad_monitor->pending_flush_stop) {
GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED,
GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
UNEXPECTED,
"Received flush-start from %" GST_PTR_FORMAT
" when flush-stop was expected", GST_EVENT_SRC (event));
}
@ -981,7 +984,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor,
if (seqnum == pad_monitor->pending_flush_stop_seqnum) {
pad_monitor->pending_flush_stop_seqnum = 0;
} else {
GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, SEQNUM,
GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
SEQNUM,
"The expected flush-stop seqnum should be the same as the "
"one from the event that caused it (probably a seek). Got: %u."
" Expected: %u", seqnum, pad_monitor->pending_flush_stop_seqnum);
@ -989,8 +993,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor,
}
if (!pad_monitor->pending_flush_stop) {
GST_QA_MONITOR_REPORT_ISSUE (pad_monitor, TRUE, EVENT, UNEXPECTED,
"Unexpected flush-stop %p from %" GST_PTR_FORMAT, event,
GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
UNEXPECTED, "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event,
GST_EVENT_SRC (event));
}
pad_monitor->pending_flush_stop = FALSE;
@ -1050,7 +1054,7 @@ gst_qa_pad_monitor_sink_event_check (GstQaPadMonitor * pad_monitor,
|| (exp_rate * exp_applied_rate != rate * applied_rate)
|| exp_start != start || exp_stop != stop
|| exp_position != position) {
GST_QA_MONITOR_REPORT_WARNING (pad_monitor, TRUE, EVENT,
GST_QA_REPORT_WARNING (pad_monitor, TRUE, EVENT,
EXPECTED,
"Expected segment didn't match received segment event");
}
@ -1147,7 +1151,6 @@ gst_qa_pad_monitor_src_event_check (GstQaPadMonitor * pad_monitor,
pad_monitor->pending_newsegment_seqnum = seqnum;
}
break;
/* both flushes are handled by the common event handling function */
case GST_EVENT_FLUSH_START:
case GST_EVENT_FLUSH_STOP:
@ -1317,7 +1320,7 @@ gst_qa_pad_monitor_buffer_probe (GstPad * pad, GstBuffer * buffer,
GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_TIMESTAMP (buffer) +
GST_BUFFER_DURATION (buffer), NULL, NULL)) {
/* TODO is this a timestamp issue? */
GST_QA_MONITOR_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP,
GST_QA_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP,
"buffer is out of segment and shouldn't be pushed. Timestamp: %"
GST_TIME_FORMAT " - duration: %" GST_TIME_FORMAT
". Range: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
@ -1361,7 +1364,7 @@ gst_qa_pad_monitor_event_probe (GstPad * pad, GstEvent * event, gpointer udata)
if (event == stored_event->event
|| GST_EVENT_TYPE (event) == GST_EVENT_TYPE (stored_event->event)) {
GST_QA_MONITOR_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED,
GST_QA_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED,
"Serialized event %" GST_PTR_FORMAT " was pushed out of original "
"serialization order in pad %s:%s", event,
GST_DEBUG_PAD_NAME (GST_QA_PAD_MONITOR_GET_PAD (monitor)));
@ -1432,12 +1435,12 @@ gst_qa_pad_monitor_setcaps_func (GstPad * pad, GstCaps * caps)
gst_structure_get_value (pad_monitor->pending_setcaps_fields, name);
if (v == NULL) {
GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION,
GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION,
MISSING_FIELD,
"Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'",
name, caps);
} else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
GST_QA_MONITOR_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION,
GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION,
MISSING_FIELD,
"Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different "
"from expected value in caps '%" GST_PTR_FORMAT "'", name, caps,
@ -1535,7 +1538,7 @@ gst_qa_pad_monitor_do_setup (GstQaMonitor * monitor)
gst_pad_set_getcaps_function (pad, gst_qa_pad_monitor_getcaps_func);
gst_pad_set_setcaps_function (pad, gst_qa_pad_monitor_setcaps_func);
gst_qa_monitor_set_target_name (monitor, g_strdup_printf ("%s:%s",
gst_qa_reporter_set_name (GST_QA_REPORTER (monitor), g_strdup_printf ("%s:%s",
GST_DEBUG_PAD_NAME (pad)));
g_signal_connect (pad, "parent-set", (GCallback) _parent_set_cb, monitor);

View file

@ -176,7 +176,7 @@ gst_qa_report_check_abort (GstQaReport * report)
}
GstQaReport *
gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level,
gst_qa_report_new (const gchar * source_name, GstQaReportLevel level,
GstQaReportArea area, gint subarea, const gchar * id, const gchar * message)
{
GstQaReport *report = g_slice_new0 (GstQaReport);
@ -184,7 +184,7 @@ gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level,
report->level = level;
report->area = area;
report->subarea = subarea;
report->source_name = g_strdup (monitor->target_name);
report->source_name = g_strdup (source_name);
report->message = g_strdup (message);
report->id = g_strdup (id);
report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time;

View file

@ -108,7 +108,8 @@ typedef struct {
r->message
void gst_qa_report_init (void);
GstQaReport * gst_qa_report_new (GstQaMonitor * monitor, GstQaReportLevel level,
GstQaReport * gst_qa_report_new (const gchar * source_name,
GstQaReportLevel level,
GstQaReportArea area,
gint subarea,
const gchar *format,

View file

@ -0,0 +1,142 @@
/* GStreamer
*
* Copyright (C) 2013 Thibault Saunier <thibault.saunier@collabora.com>
*
* 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 "gst-qa-reporter.h"
#include "gst-qa-report.h"
#define REPORTER_PRIVATE "gst-qa-reporter-private"
typedef struct _GstQaReporterPrivate
{
GstQaRunner *runner;
GHashTable *reports;
char *name;
} GstQaReporterPrivate;
static void
gst_qa_reporter_default_init (GstQaReporterInterface * iface)
{
g_object_interface_install_property (iface,
g_param_spec_object ("qa-runner", "QA Runner", "The QA runner to "
"report errors to", GST_TYPE_QA_RUNNER,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
}
G_DEFINE_INTERFACE (GstQaReporter, gst_qa_reporter, G_TYPE_OBJECT);
static void
_free_priv (GstQaReporterPrivate * priv)
{
g_hash_table_unref (priv->reports);
g_free (priv->name);
}
static inline gchar *
_qa_report_id (GstQaReport * report)
{
return g_strdup_printf ("%i-%i-%i-%s",
report->level, report->area, report->subarea, report->id);
}
static GstQaReporterPrivate *
gst_qa_reporter_get_priv (GstQaReporter * reporter)
{
GstQaReporterPrivate *priv =
g_object_get_data (G_OBJECT (reporter), REPORTER_PRIVATE);
if (priv == NULL) {
priv = g_slice_new0 (GstQaReporterPrivate);
priv->reports = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, (GDestroyNotify) gst_qa_report_unref);
g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv,
(GDestroyNotify) _free_priv);
}
return priv;
}
void
gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, va_list var_args)
{
GstQaReport *report;
gchar *message, *report_id = NULL;
GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter);
message = g_strdup_vprintf (format, var_args);
report = gst_qa_report_new (priv->name, level, area, subarea,
format, message);
if (repeat == FALSE) {
report_id = _qa_report_id (report);
if (g_hash_table_lookup (priv->reports, report_id)) {
GST_DEBUG ("Report %s already present", report_id);
g_free (report_id);
return;
}
g_hash_table_insert (priv->reports, report_id, report);
}
GST_INFO_OBJECT (reporter, "Received error report %d : %d : %d : %s",
level, area, subarea, message);
gst_qa_report_printf (report);
if (priv->runner) {
gst_qa_runner_add_report (priv->runner, report);
} else {
gst_qa_report_unref (report);
}
g_free (message);
}
void
gst_qa_report (GstQaReporter * reporter, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, ...)
{
va_list var_args;
va_start (var_args, format);
gst_qa_report_valist (reporter, repeat, level, area, subarea,
format, var_args);
va_end (var_args);
}
void
gst_qa_reporter_set_name (GstQaReporter * reporter, const gchar * name)
{
GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter);
if (priv->name)
g_free (priv->name);
priv->name = g_strdup (name);
}
GstQaRunner *
gst_qa_reporter_get_runner (GstQaReporter * reporter)
{
GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter);
return priv->runner;
}

View file

@ -0,0 +1,122 @@
/* GStreamer
*
* Copyright (C) 2013 Thibault Saunier <thibault.saunier@collabora.com>
*
* 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_QA_REPORTER_
#define _GST_QA_REPORTER_
#include <glib-object.h>
#include "gst-qa-runner.h"
G_BEGIN_DECLS
typedef struct _GstQaReporter GstQaReporter;
typedef struct _GstQaReporterInterface GstQaReporterInterface;
/* GstQaReporter interface declarations */
#define GST_TYPE_QA_REPORTER (gst_qa_reporter_get_type ())
#define GST_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_QA_REPORTER, GstQaReporter))
#define GST_IS_QA_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_QA_REPORTER))
#define GST_QA_REPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_QA_REPORTER, GESExtractableInterface))
#ifdef G_HAVE_ISO_VARARGS
#define GST_QA_REPORT(m, repeat, status, area, subarea, ...) \
G_STMT_START { \
gst_qa_report (GST_QA_REPORTER (m), repeat, \
GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \
GST_QA_AREA_ ## area ## _ ## subarea, __VA_ARGS__ ); \
} G_STMT_END
#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, ...) \
G_STMT_START { \
GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \
#area, #subarea, __VA_ARGS__); \
GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, __VA_ARGS__); \
} G_STMT_END
#define GST_QA_REPORT_WARNING(m, repeat, area, subarea, ...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \
#area, #subarea, __VA_ARGS__); \
GST_QA_REPORT(m, repeat, WARNING, area, subarea, __VA_ARGS__); \
} G_STMT_END
#define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, ...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \
#area, #subarea, __VA_ARGS__); \
GST_QA_REPORT(m, repeat, ISSUE, area, subarea, __VA_ARGS__); \
} G_STMT_END
#else /* G_HAVE_GNUC_VARARGS */
#ifdef G_HAVE_GNUC_VARARGS
#define GST_QA_REPORT(m, repeat, status, area, subarea, args...) \
G_STMT_START { \
gst_qa_reporter_do_report (GST_QA_REPORTER (m), \
GST_QA_REPORT_LEVEL_ ## status, GST_QA_AREA_ ## area, \
GST_QA_AREA_ ## area ## _ ## subarea, ##args ); \
} G_STMT_END
#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, args...) \
G_STMT_START { \
GST_ERROR_OBJECT (m, "Critical report: %s: %s: %s", \
#area, #subarea, ##args); \
GST_QA_REPORT(m, repeat, CRITICAL, area, subarea, ##args); \
} G_STMT_END
#define GST_QA_REPORT_WARNING(m, repeat, area, subarea, args...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Warning report: %s: %s: %s", \
#area, #subarea, ##args); \
GST_QA_REPORT(m, repeat, WARNING, area, subarea, ##args); \
} G_STMT_END
#define GST_QA_REPORT_ISSUE(m, repeat, area, subarea, args...) \
G_STMT_START { \
GST_WARNING_OBJECT (m, "Issue report: %s: %s: %s", \
#area, #subarea, ##args); \
GST_QA_REPORT(m, repeat, ISSUE, area, subarea, ##args); \
} G_STMT_END
#endif /* G_HAVE_ISO_VARARGS */
#endif /* G_HAVE_GNUC_VARARGS */
GType gst_qa_reporter_get_type (void);
/**
* GstQaReporter:
*/
struct _GstQaReporterInterface
{
GTypeInterface parent;
};
void gst_qa_reporter_set_name (GstQaReporter * reporter,
const gchar * name);
GstQaRunner * gst_qa_reporter_get_runner (GstQaReporter *reporter);
void gst_qa_reporter_init (GstQaReporter * reporter, const gchar *name);
void gst_qa_report (GstQaReporter * reporter, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, ...);
void gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, va_list var_args);
G_END_DECLS
#endif /* _GST_QA_REPORTER_ */