qa-report: splitting a GstQaReport into a GstQaIssue and GstQaReport

Reports now point to Issues, that are uniquely identified and have
translatable descriptions. This way we are going to be able to uniquely
identify the issues and applications can enable/disable checks for
specific elements.
This commit is contained in:
Thiago Santos 2013-07-25 23:25:22 -03:00
parent 1e1e0b922e
commit 773d8adc5e
6 changed files with 323 additions and 257 deletions

View file

@ -157,8 +157,9 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure,
gint rejected_types_index = 0;
if (!gst_structure_has_field (structure, field)) {
GST_QA_REPORT_WARNING (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION,
MISSING_FIELD, "%s is missing from structure: %" GST_PTR_FORMAT, field,
GST_QA_REPORT (monitor,
GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD,
"Field '%s' is missing from structure: %" GST_PTR_FORMAT, field,
structure);
return;
}
@ -175,8 +176,9 @@ _check_field_type (GstQaPadMonitor * monitor, GstStructure * structure,
va_end (var_args);
joined_types = g_strjoinv (" / ", (gchar **) rejected_types);
GST_QA_REPORT_CRITICAL (GST_QA_REPORTER (monitor), FALSE, CAPS_NEGOTIATION,
BAD_FIELD_TYPE, "%s has wrong type %s in structure '%" GST_PTR_FORMAT
GST_QA_REPORT (monitor,
GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE,
"Field '%s' has wrong type %s in structure '%" GST_PTR_FORMAT
"'. Expected: %s", field,
g_type_name (gst_structure_get_field_type (structure, field)),
structure, joined_types);
@ -445,8 +447,7 @@ gst_qa_pad_monitor_check_caps_fields_proxied (GstQaPadMonitor * monitor,
}
if (type_match && !found) {
GST_QA_REPORT_WARNING (monitor, FALSE, CAPS_NEGOTIATION,
GET_CAPS,
GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS,
"Peer pad structure '%" GST_PTR_FORMAT "' has no similar version "
"on pad's caps '%" GST_PTR_FORMAT "'", otherstructure, caps);
}
@ -465,7 +466,8 @@ 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_REPORT_WARNING (monitor, FALSE, EVENT, EXPECTED,
GST_QA_REPORT (monitor,
GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
"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),
@ -642,7 +644,8 @@ gst_qa_pad_monitor_check_buffer_timestamp_in_received_range (GstQaPadMonitor *
return;
}
if (!found) {
GST_QA_REPORT_WARNING (monitor, FALSE, BUFFER, TIMESTAMP,
GST_QA_REPORT (monitor,
GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
"Timestamp %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT
" is out of range of received input", GST_TIME_ARGS (ts),
GST_TIME_ARGS (ts_end));
@ -658,14 +661,16 @@ 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_REPORT_WARNING (GST_QA_REPORTER (pad_monitor), FALSE, EVENT,
EXPECTED, "Received buffer before Segment event");
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT,
"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_REPORT_WARNING (pad_monitor, FALSE, BUFFER, TIMESTAMP,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
"First buffer running time is not 0, it is: %" GST_TIME_FORMAT,
GST_TIME_ARGS (running_time));
}
@ -773,8 +778,7 @@ gst_qa_pad_monitor_check_aggregated_return (GstQaPadMonitor * monitor,
return;
}
if (aggregated != ret) {
/* TODO review this error code */
GST_QA_REPORT_CRITICAL (monitor, TRUE, BUFFER, UNEXPECTED,
GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_WRONG_FLOW_RETURN,
"Wrong combined flow return %s(%d). Expected: %s(%d)",
gst_flow_get_name (ret), ret,
gst_flow_get_name (aggregated), aggregated);
@ -924,8 +928,8 @@ 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_REPORT_WARNING (othermonitor, FALSE, EVENT, EXPECTED,
"expected newsegment event never pushed");
GST_QA_REPORT (othermonitor,
GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED, NULL);
gst_event_unref (othermonitor->expected_segment);
}
othermonitor->expected_segment = gst_event_ref (event);
@ -961,8 +965,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_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
SEQNUM,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_EVENT_HAS_WRONG_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);
@ -970,8 +974,8 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor,
}
if (pad_monitor->pending_flush_stop) {
GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
UNEXPECTED,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED,
"Received flush-start from %" GST_PTR_FORMAT
" when flush-stop was expected", GST_EVENT_SRC (event));
}
@ -984,8 +988,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_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
SEQNUM,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_EVENT_HAS_WRONG_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);
@ -993,8 +997,9 @@ gst_qa_pad_monitor_common_event_check (GstQaPadMonitor * pad_monitor,
}
if (!pad_monitor->pending_flush_stop) {
GST_QA_REPORT_ISSUE (GST_QA_REPORTER (pad_monitor), TRUE, EVENT,
UNEXPECTED, "Unexpected flush-stop %p from %" GST_PTR_FORMAT, event,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED,
"Unexpected flush-stop %p from %" GST_PTR_FORMAT, event,
GST_EVENT_SRC (event));
}
pad_monitor->pending_flush_stop = FALSE;
@ -1054,8 +1059,8 @@ 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_REPORT_WARNING (pad_monitor, TRUE, EVENT,
EXPECTED,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH,
"Expected segment didn't match received segment event");
}
}
@ -1320,7 +1325,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_REPORT_ISSUE (monitor, FALSE, BUFFER, TIMESTAMP,
GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT,
"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,
@ -1364,7 +1369,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_REPORT_WARNING (monitor, FALSE, EVENT, UNEXPECTED,
GST_QA_REPORT (monitor, GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER,
"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)));
@ -1435,13 +1440,13 @@ 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_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION,
MISSING_FIELD,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND,
"Field %s is missing from setcaps caps '%" GST_PTR_FORMAT "'",
name, caps);
} else if (gst_value_compare (v, otherv) != GST_VALUE_EQUAL) {
GST_QA_REPORT_WARNING (pad_monitor, FALSE, CAPS_NEGOTIATION,
MISSING_FIELD,
GST_QA_REPORT (pad_monitor,
GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE,
"Field %s from setcaps caps '%" GST_PTR_FORMAT "' is different "
"from expected value in caps '%" GST_PTR_FORMAT "'", name, caps,
pad_monitor->pending_setcaps_fields);

View file

@ -1,7 +1,7 @@
/* GStreamer
* Copyright (C) 2013 Thiago Santos <thiago.sousa.santos@collabora.com>
*
* gst-qa-monitor-preload.c - QA Element monitors preload functions
* gst-qa-monitor-report.c - QA report/issues functions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -19,17 +19,154 @@
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include <gst/gst-i18n-lib.h>
#include "gst-qa-report.h"
#include "gst-qa-reporter.h"
#include "gst-qa-monitor.h"
static GstClockTime _gst_qa_report_start_time = 0;
static GstQaDebugFlags _gst_qa_flags = 0;
static GHashTable *_gst_qa_issues = NULL;
G_DEFINE_BOXED_TYPE (GstQaReport, gst_qa_report,
(GBoxedCopyFunc) gst_qa_report_ref, (GBoxedFreeFunc) gst_qa_report_unref);
GstQaIssueId
gst_qa_issue_get_id (GstQaIssue * issue)
{
return issue->issue_id;
}
static GstQaIssue *
gst_qa_issue_new (GstQaIssueId issue_id, gchar * summary,
gchar * description, GstQaReportLevel default_level)
{
GstQaIssue *issue = g_slice_new (GstQaIssue);
issue->issue_id = issue_id;
issue->summary = summary;
issue->description = description;
issue->default_level = default_level;
return issue;
}
static void
gst_qa_issue_free (GstQaIssue * issue)
{
g_free (issue->summary);
g_free (issue->description);
g_slice_free (GstQaIssue, issue);
}
static void
gst_qa_issue_register (GstQaIssue * issue)
{
g_hash_table_insert (_gst_qa_issues, (gpointer) gst_qa_issue_get_id (issue),
issue);
}
#define REGISTER_QA_ISSUE(id,sum,desc,lvl) gst_qa_issue_register (gst_qa_issue_new (id, sum, desc, lvl))
static void
gst_qa_report_load_issues (void)
{
g_return_if_fail (_gst_qa_issues == NULL);
_gst_qa_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify) gst_qa_issue_free);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT,
_("buffer was received before a segment"),
_("in push mode, a segment event must be received before a buffer"),
GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT,
_("buffer is out of the segment range"),
_("buffer being pushed is out of the current segment's start-stop "
" range. Meaning it is going to be discarded downstream without "
"any use"), GST_QA_REPORT_LEVEL_ISSUE);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
_("buffer timestamp is out of the received buffer timestamps' range"),
_("a buffer leaving an element should have its timestamps in the range "
"of the received buffers timestamps. i.e. If an element received "
"buffers with timestamps from 0s to 10s, it can't push a buffer with "
"with a 11s timestamp, because it doesn't have data for that"),
GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO,
_("first buffer's running time isn't 0"),
_("the first buffer's received running time is expected to be 0"),
GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_WRONG_FLOW_RETURN, _("flow return from pad push doesn't match expected value"), _("flow return from a 1:1 sink/src pad element is as simple as " "returning what downstream returned. For elements that have multiple " "src pads, flow returns should be properly combined"), /* TODO fill me more */
GST_QA_REPORT_LEVEL_CRITICAL);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD,
_("caps is missing a required field for its type"),
_("some caps types are expected to contain a set of basic fields. "
"For example, raw video should have 'width', 'height', 'framerate' "
"and 'pixel-aspect-ratio'"), GST_QA_REPORT_LEVEL_ISSUE);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE,
_("caps field has an unexpected type"),
_("some common caps fields should always use the same expected types"),
GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND,
_("caps expected field wasn't present"),
_("a field that should be present in the caps wasn't found. "
"Fields sets on a sink pad caps should be propagated downstream "
"when it makes sense to do so"), GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS,
_("getcaps function isn't proxying downstream fields correctly"),
_("elements should set downstream caps restrictions on its caps when "
"replying upstream's getcaps queries to avoid upstream sending data"
" in an unsupported format"), GST_QA_REPORT_LEVEL_CRITICAL);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE,
_("a field in caps has an unexpected value"),
_("fields set on a sink pad should be propagated downstream via "
"set caps"), GST_QA_REPORT_LEVEL_CRITICAL);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED,
_("new segment event wasn't propagated downstream"),
_("segments received from upstream should be pushed downstream"),
GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
_("a serialized event received should be pushed in the same 'time' "
"as it was received"),
_("serialized events should be pushed in the same order they are "
"received and serialized with buffers. If an event is received after"
" a buffer with timestamp end 'X', it should be pushed right after "
"buffers with timestamp end 'X'"), GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM,
_("events that are part of the same pipeline 'operation' should "
"have the same seqnum"),
_("when events/messages are created from another event/message, "
"they should have their seqnums set to the original event/message "
"seqnum"), GST_QA_REPORT_LEVEL_ISSUE);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER,
_("a serialized event received should be pushed in the same order "
"as it was received"),
_("serialized events should be pushed in the same order they are "
"received."), GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH,
_("a new segment event has different value than the received one"),
_("when receiving a new segment, an element should push an equivalent"
"segment downstream"), GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED,
_("received an unexpected flush start event"),
NULL, GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED,
_("received an unexpected flush stop event"),
NULL, GST_QA_REPORT_LEVEL_WARNING);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
_("seek event wasn't handled"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
REGISTER_QA_ISSUE (GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG,
_("position after a seek is wrong"), NULL, GST_QA_REPORT_LEVEL_CRITICAL);
}
void
gst_qa_report_init (void)
{
@ -48,9 +185,16 @@ gst_qa_report_init (void)
if (var && strlen (var) > 0) {
_gst_qa_flags = g_parse_debug_string (var, keys, 3);
}
gst_qa_report_load_issues ();
}
}
GstQaIssue *
gst_qa_issue_from_id (GstQaIssueId issue_id)
{
return g_hash_table_lookup (_gst_qa_issues, (gpointer) issue_id);
}
/* TODO how are these functions going to work with extensions */
const gchar *
@ -78,7 +222,7 @@ gst_qa_report_area_get_name (GstQaReportArea area)
return "buffer";
case GST_QA_AREA_QUERY:
return "query";
case GST_QA_AREA_CAPS_NEGOTIATION:
case GST_QA_AREA_CAPS:
return "caps";
case GST_QA_AREA_SEEK:
return "seek";
@ -90,119 +234,35 @@ gst_qa_report_area_get_name (GstQaReportArea area)
}
}
const gchar *
gst_qa_area_event_get_subarea_name (GstQaReportAreaEvent subarea)
{
switch (subarea) {
case GST_QA_AREA_EVENT_SEQNUM:
return "seqnum";
case GST_QA_AREA_EVENT_UNEXPECTED:
return "unexpected";
case GST_QA_AREA_EVENT_EXPECTED:
return "expected";
default:
return "unknown";
}
}
const gchar *
gst_qa_area_buffer_get_subarea_name (GstQaReportAreaEvent subarea)
{
switch (subarea) {
case GST_QA_AREA_BUFFER_TIMESTAMP:
return "timestamp";
case GST_QA_AREA_BUFFER_DURATION:
return "duration";
case GST_QA_AREA_BUFFER_FLAGS:
return "flags";
case GST_QA_AREA_BUFFER_UNEXPECTED:
return "unexpected";
default:
return "unknown";
}
}
const gchar *
gst_qa_area_query_get_subarea_name (GstQaReportAreaEvent subarea)
{
switch (subarea) {
case GST_QA_AREA_QUERY_UNEXPECTED:
return "unexpected";
default:
return "unknown";
}
}
const gchar *
gst_qa_area_caps_get_subarea_name (GstQaReportAreaEvent subarea)
{
switch (subarea) {
case GST_QA_AREA_CAPS_NEGOTIATION:
return "negotiation";
default:
return "unknown";
}
}
const gchar *
gst_qa_area_seek_get_subarea_name (GstQaReportAreaEvent subarea)
{
switch (subarea) {
case GST_QA_AREA_SEEK_TIMING:
return "timing";
default:
return "unknown";
}
}
const gchar *
gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea)
{
switch (area) {
case GST_QA_AREA_EVENT:
return gst_qa_area_event_get_subarea_name (subarea);
case GST_QA_AREA_BUFFER:
return gst_qa_area_buffer_get_subarea_name (subarea);
case GST_QA_AREA_QUERY:
return gst_qa_area_query_get_subarea_name (subarea);
case GST_QA_AREA_CAPS_NEGOTIATION:
return gst_qa_area_caps_get_subarea_name (subarea);
case GST_QA_AREA_SEEK:
return gst_qa_area_seek_get_subarea_name (subarea);
case GST_QA_AREA_OTHER:
return "unknown";
default:
g_assert_not_reached ();
break;
}
}
static void
gst_qa_report_check_abort (GstQaReport * report)
{
if ((report->level == GST_QA_REPORT_LEVEL_ISSUE &&
if ((report->issue->default_level == GST_QA_REPORT_LEVEL_ISSUE &&
_gst_qa_flags & GST_QA_FATAL_ISSUES) ||
(report->level == GST_QA_REPORT_LEVEL_WARNING &&
(report->issue->default_level == GST_QA_REPORT_LEVEL_WARNING &&
_gst_qa_flags & GST_QA_FATAL_WARNINGS) ||
(report->level == GST_QA_REPORT_LEVEL_CRITICAL &&
(report->issue->default_level == GST_QA_REPORT_LEVEL_CRITICAL &&
_gst_qa_flags & GST_QA_FATAL_CRITICALS)) {
g_error ("Fatal report received: %" GST_QA_ERROR_REPORT_PRINT_FORMAT,
GST_QA_REPORT_PRINT_ARGS (report));
}
}
GstQaIssueId
gst_qa_report_get_issue_id (GstQaReport * report)
{
return gst_qa_issue_get_id (report->issue);
}
GstQaReport *
gst_qa_report_new (const gchar * source_name, GstQaReportLevel level,
GstQaReportArea area, gint subarea, const gchar * id, const gchar * message)
gst_qa_report_new (GstQaIssue * issue, GstQaReporter * reporter,
const gchar * message)
{
GstQaReport *report = g_slice_new0 (GstQaReport);
report->level = level;
report->area = area;
report->subarea = subarea;
report->source_name = g_strdup (source_name);
report->issue = issue;
report->reporter = reporter; /* TODO should we ref? */
report->message = g_strdup (message);
report->id = g_strdup (id);
report->timestamp = gst_util_get_timestamp () - _gst_qa_report_start_time;
/* we might abort here if asked */
@ -216,8 +276,6 @@ gst_qa_report_unref (GstQaReport * report)
{
if (G_UNLIKELY (g_atomic_int_dec_and_test (&report->refcount))) {
g_free (report->message);
g_free (report->id);
g_free (report->source_name);
g_slice_free (GstQaReport, report);
}
}

View file

@ -28,7 +28,7 @@
G_BEGIN_DECLS
/* forward declaration */
typedef struct _GstQaMonitor GstQaMonitor;
typedef struct _GstQaReporter GstQaReporter;
GType gst_qa_report_get_type (void);
#define GST_TYPE_QA_REPORT (gst_qa_report_get_type ())
@ -44,87 +44,118 @@ typedef enum {
GST_QA_REPORT_LEVEL_CRITICAL,
GST_QA_REPORT_LEVEL_WARNING,
GST_QA_REPORT_LEVEL_ISSUE,
GST_QA_REPORT_LEVEL_IGNORE,
GST_QA_REPORT_LEVEL_NUM_ENTRIES,
} GstQaReportLevel;
typedef enum {
GST_QA_AREA_EVENT=0,
GST_QA_AREA_EVENT=1,
GST_QA_AREA_BUFFER,
GST_QA_AREA_QUERY,
GST_QA_AREA_CAPS_NEGOTIATION,
GST_QA_AREA_CAPS,
GST_QA_AREA_SEEK,
GST_QA_AREA_OTHER=100,
} GstQaReportArea;
typedef enum {
GST_QA_AREA_EVENT_SEQNUM,
GST_QA_AREA_EVENT_UNEXPECTED,
GST_QA_AREA_EVENT_EXPECTED,
typedef guint64 GstQaIssueId;
#define GST_QA_ISSUE_ID_UNKNOWN 0
GST_QA_AREA_EVENT_NUM_ENTRIES
} GstQaReportAreaEvent;
#define GST_QA_ISSUE_ID_BUFFER_BEFORE_SEGMENT (((guint64) GST_QA_AREA_BUFFER) << 32 | 1)
#define GST_QA_ISSUE_ID_BUFFER_IS_OUT_OF_SEGMENT (((guint64) GST_QA_AREA_BUFFER) << 32 | 2)
#define GST_QA_ISSUE_ID_BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE (((guint64) GST_QA_AREA_BUFFER) << 32 | 3)
#define GST_QA_ISSUE_ID_FIRST_BUFFER_RUNNING_TIME_IS_NOT_ZERO (((guint64) GST_QA_AREA_BUFFER) << 32 | 4)
#define GST_QA_ISSUE_ID_WRONG_FLOW_RETURN (((guint64) GST_QA_AREA_BUFFER) << 32 | 5)
typedef enum {
GST_QA_AREA_BUFFER_TIMESTAMP,
GST_QA_AREA_BUFFER_DURATION,
GST_QA_AREA_BUFFER_FLAGS,
GST_QA_AREA_BUFFER_UNEXPECTED,
#define GST_QA_ISSUE_ID_CAPS_IS_MISSING_FIELD (((guint64) GST_QA_AREA_CAPS) << 32 | 1)
#define GST_QA_ISSUE_ID_CAPS_FIELD_HAS_BAD_TYPE (((guint64) GST_QA_AREA_CAPS) << 32 | 2)
#define GST_QA_ISSUE_ID_CAPS_EXPECTED_FIELD_NOT_FOUND (((guint64) GST_QA_AREA_CAPS) << 32 | 3)
#define GST_QA_ISSUE_ID_GET_CAPS_NOT_PROXYING_FIELDS (((guint64) GST_QA_AREA_CAPS) << 32 | 4)
#define GST_QA_ISSUE_ID_CAPS_FIELD_UNEXPECTED_VALUE (((guint64) GST_QA_AREA_CAPS) << 32 | 5)
GST_QA_AREA_BUFFER_NUM_ENTRIES
} GstQaReportAreaBuffer;
#define GST_QA_ISSUE_ID_EVENT_NEWSEGMENT_NOT_PUSHED (((guint64) GST_QA_AREA_EVENT) << 32 | 1)
#define GST_QA_ISSUE_ID_SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME (((guint64) GST_QA_AREA_EVENT) << 32 | 2)
#define GST_QA_ISSUE_ID_EVENT_HAS_WRONG_SEQNUM (((guint64) GST_QA_AREA_EVENT) << 32 | 3)
#define GST_QA_ISSUE_ID_EVENT_SERIALIZED_OUT_OF_ORDER (((guint64) GST_QA_AREA_EVENT) << 32 | 4)
#define GST_QA_ISSUE_ID_EVENT_NEW_SEGMENT_MISMATCH (((guint64) GST_QA_AREA_EVENT) << 32 | 5)
#define GST_QA_ISSUE_ID_EVENT_FLUSH_START_UNEXPECTED (((guint64) GST_QA_AREA_EVENT) << 32 | 6)
#define GST_QA_ISSUE_ID_EVENT_FLUSH_STOP_UNEXPECTED (((guint64) GST_QA_AREA_EVENT) << 32 | 7)
typedef enum {
GST_QA_AREA_SEEK_TIMING,
GST_QA_AREA_SEEK_UNKNOWN
} GstQaReportAreaSeek;
#define GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED (((guint64) GST_QA_AREA_SEEK) << 32 | 1)
#define GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG (((guint64) GST_QA_AREA_SEEK) << 32 | 2)
typedef enum {
GST_QA_AREA_QUERY_UNEXPECTED,
#define GST_QA_ISSUE_ID_AREA(id) ((guint32)(id >> 32))
GST_QA_AREA_QUERY_NUM_ENTRIES
} GstQaReportAreaQuery;
typedef struct {
GstQaIssueId issue_id;
typedef enum {
GST_QA_AREA_CAPS_NEGOTIATION_MISSING_FIELD,
GST_QA_AREA_CAPS_NEGOTIATION_BAD_FIELD_TYPE,
GST_QA_AREA_CAPS_NEGOTIATION_GET_CAPS,
/* Summary: one-liner translatable description of the issue */
gchar *summary;
/* description: multi-line translatable description of:
* * what the issue is (and why it's an issue)
* * what the source problem could be
* * pointers to fixing the issue
*/
gchar *description;
GST_QA_AREA_CAPS_NEGOTIATION_NUM_ENTRIES
} GstQaReportAreaCapsNegotiation;
/* default_level: The default level of severity for this
* issue. */
GstQaReportLevel default_level;
/* repeat: whether the issue might be triggered
* multiple times but only remembered once */
gboolean repeat;
} GstQaIssue;
#define GST_QA_ISSUE_AREA(i) (GST_QA_ISSUE_ID_AREA (gst_qa_issue_get_id (i)))
typedef struct {
gint refcount;
GstQaReportLevel level;
GstQaReportArea area;
gint subarea;
/* issue: The issue this report corresponds to (to get dsecription, summary,...) */
GstQaIssue *issue;
/* The reporter that reported the issue (to get names, info, ...) */
GstQaReporter *reporter;
/* timestamp: The time at which this issue happened since
* the process start (to stay in sync with gst logging) */
GstClockTime timestamp;
/* message: issue-specific message. Gives more detail on the actual
* issue. Can be NULL */
gchar *message;
gchar *id;
gchar *source_name;
guint64 timestamp;
} GstQaReport;
#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " (%s): %s, %s(%d)) %s(%d): %s"
#define GST_QA_ISSUE_FORMAT G_GUINT64_FORMAT " (%s) : %s(%u): %s"
#define GST_QA_ISSUE_ARGS(i) gst_qa_issue_get_id (i), gst_qa_report_level_get_name (i->default_level), \
gst_qa_report_area_get_name (GST_QA_ISSUE_AREA (i)), GST_QA_ISSUE_AREA (i), \
i->summary
#define GST_QA_ERROR_REPORT_PRINT_FORMAT GST_TIME_FORMAT " <%s>: %" GST_QA_ISSUE_FORMAT ": %s"
#define GST_QA_REPORT_PRINT_ARGS(r) GST_TIME_ARGS (r->timestamp), \
gst_qa_report_level_get_name (r->level), \
r->source_name, \
gst_qa_report_area_get_name(r->area), r->area, \
gst_qa_report_subarea_get_name(r->area, r->subarea), r->subarea, \
gst_qa_reporter_get_name (r->reporter), \
GST_QA_ISSUE_ARGS (r->issue), \
r->message
void gst_qa_report_init (void);
GstQaReport * gst_qa_report_new (const gchar * source_name,
GstQaReportLevel level,
GstQaReportArea area,
gint subarea,
const gchar *format,
GstQaIssue * gst_qa_issue_from_id (GstQaIssueId issue_id);
GstQaIssueId gst_qa_issue_get_id (GstQaIssue * issue);
GstQaReport * gst_qa_report_new (GstQaIssue * issue,
GstQaReporter * reporter,
const gchar * message);
void gst_qa_report_unref (GstQaReport * report);
GstQaReport * gst_qa_report_ref (GstQaReport * report);
GstQaIssueId gst_qa_report_get_issue_id (GstQaReport * report);
void gst_qa_report_printf (GstQaReport * report);
const gchar * gst_qa_report_level_get_name (GstQaReportLevel level);
const gchar * gst_qa_report_area_get_name (GstQaReportArea area);
const gchar * gst_qa_report_subarea_get_name (GstQaReportArea area, gint subarea);
G_END_DECLS
#endif /* __GST_QA_REPORT_H__ */

View file

@ -53,13 +53,6 @@ _free_priv (GstQaReporterPrivate * priv)
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)
{
@ -68,8 +61,8 @@ gst_qa_reporter_get_priv (GstQaReporter * reporter)
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);
priv->reports = g_hash_table_new_full (g_direct_hash,
g_direct_equal, g_free, (GDestroyNotify) gst_qa_report_unref);
g_object_set_data_full (G_OBJECT (reporter), REPORTER_PRIVATE, priv,
(GDestroyNotify) _free_priv);
@ -79,42 +72,45 @@ gst_qa_reporter_get_priv (GstQaReporter * reporter)
}
void
gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, va_list var_args)
gst_qa_report_valist (GstQaReporter * reporter,
GstQaIssueId issue_id, const gchar * format, va_list var_args)
{
GstQaReport *report;
gchar *message, *report_id = NULL;
gchar *message;
GstQaIssue *issue;
GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter);
issue = gst_qa_issue_from_id (issue_id);
g_return_if_fail (issue != NULL);
message = g_strdup_vprintf (format, var_args);
report = gst_qa_report_new (priv->name, level, area, subarea,
format, message);
report = gst_qa_report_new (issue, reporter, message);
if (repeat == FALSE) {
report_id = _qa_report_id (report);
if (issue->repeat == FALSE) {
GstQaIssueId issue_id = gst_qa_issue_get_id (issue);
if (g_hash_table_lookup (priv->reports, report_id)) {
GST_DEBUG ("Report %s already present", report_id);
g_free (report_id);
if (g_hash_table_lookup (priv->reports, (gconstpointer) issue_id)) {
GST_DEBUG ("Report %d:%s already present", issue_id, issue->summary);
return;
}
g_hash_table_insert (priv->reports, report_id, report);
g_hash_table_insert (priv->reports, (gpointer) issue_id, report);
}
if (level == GST_QA_REPORT_LEVEL_CRITICAL)
if (issue->default_level == GST_QA_REPORT_LEVEL_CRITICAL)
GST_ERROR ("<%s>: %s", priv->name, message);
else if (level == GST_QA_REPORT_LEVEL_WARNING)
else if (issue->default_level == GST_QA_REPORT_LEVEL_WARNING)
GST_WARNING ("<%s>: %s", priv->name, message);
else if (level == GST_QA_REPORT_LEVEL_ISSUE)
else if (issue->default_level == GST_QA_REPORT_LEVEL_ISSUE)
GST_LOG ("<%s>: %s", priv->name, message);
else
GST_DEBUG ("<%s>: %s", priv->name, message);
GST_INFO_OBJECT (reporter, "Received error report %d : %d : %d : %s",
level, area, subarea, message);
GST_INFO_OBJECT (reporter, "Received error report %" GST_QA_ISSUE_FORMAT
" : %s", GST_QA_ISSUE_ARGS (issue), message);
gst_qa_report_printf (report);
if (priv->runner) {
gst_qa_runner_add_report (priv->runner, report);
} else {
@ -125,15 +121,13 @@ gst_qa_report_valist (GstQaReporter * reporter, gboolean repeat,
}
void
gst_qa_report (GstQaReporter * reporter, gboolean repeat,
GstQaReportLevel level, GstQaReportArea area,
gint subarea, const gchar * format, ...)
gst_qa_report (GstQaReporter * reporter, GstQaIssueId issue_id,
const gchar * format, ...)
{
va_list var_args;
va_start (var_args, format);
gst_qa_report_valist (reporter, repeat, level, area, subarea,
format, var_args);
gst_qa_report_valist (reporter, issue_id, format, var_args);
va_end (var_args);
}
@ -148,6 +142,14 @@ gst_qa_reporter_set_name (GstQaReporter * reporter, gchar * name)
priv->name = name;
}
const gchar *
gst_qa_reporter_get_name (GstQaReporter * reporter)
{
GstQaReporterPrivate *priv = gst_qa_reporter_get_priv (reporter);
return priv->name;
}
GstQaRunner *
gst_qa_reporter_get_runner (GstQaReporter * reporter)
{

View file

@ -22,6 +22,7 @@
#include <glib-object.h>
#include "gst-qa-runner.h"
#include "gst-qa-report.h"
G_BEGIN_DECLS
@ -35,50 +36,20 @@ typedef struct _GstQaReporterInterface GstQaReporterInterface;
#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__ ); \
#define GST_QA_REPORT(m, issue_id, ...) \
G_STMT_START { \
gst_qa_report (GST_QA_REPORTER (m), issue_id, \
__VA_ARGS__ ); \
} G_STMT_END
#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, ...) \
G_STMT_START { \
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_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_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 ); \
#define GST_QA_REPORT(m, issue_id, args...) \
G_STMT_START { \
gst_qa_reporter_do_report (GST_QA_REPORTER (m), \
issue_id, ##args ); \
} G_STMT_END
#define GST_QA_REPORT_CRITICAL(m, repeat, area, subarea, args...) \
G_STMT_START { \
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_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_QA_REPORT(m, repeat, ISSUE, area, subarea, ##args); \
} G_STMT_END
#endif /* G_HAVE_ISO_VARARGS */
#endif /* G_HAVE_GNUC_VARARGS */
@ -94,14 +65,13 @@ struct _GstQaReporterInterface
void gst_qa_reporter_set_name (GstQaReporter * reporter,
gchar * name);
const gchar * gst_qa_reporter_get_name (GstQaReporter * reporter);
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);
void gst_qa_report (GstQaReporter * reporter, GstQaIssueId issue_id,
const gchar * format, ...);
void gst_qa_report_valist (GstQaReporter * reporter, GstQaIssueId issue_id,
const gchar * format, va_list var_args);
void gst_qa_reporter_set_runner (GstQaReporter * reporter,
GstQaRunner *runner);

View file

@ -207,7 +207,7 @@ get_position (GstQaScenario * scenario)
&& (position <= (seek->seeking_time + priv->seek_pos_tol))) {
if (GST_CLOCK_TIME_IS_VALID (priv->seeked_position))
GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, TIMING,
GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
"Previous seek to %" GST_TIME_FORMAT " was not handled",
GST_TIME_ARGS (priv->seeked_position));
@ -218,7 +218,7 @@ get_position (GstQaScenario * scenario)
seek->format, seek->flags,
seek->start_type, seek->start,
seek->stop_type, seek->stop) == FALSE) {
GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, UNKNOWN,
GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_NOT_HANDLED,
"Could not seek to position %" GST_TIME_FORMAT,
GST_TIME_ARGS (priv->seeked_position));
}
@ -248,7 +248,7 @@ async_done_cb (GstBus * bus, GstMessage * message, GstQaScenario * scenario)
position < (MAX (0,
((gint64) (priv->seeked_position - priv->seek_pos_tol))))) {
GST_QA_REPORT_ISSUE (scenario, TRUE, SEEK, TIMING,
GST_QA_REPORT (scenario, GST_QA_ISSUE_ID_EVENT_SEEK_RESULT_POSITION_WRONG,
"Seeked position %" GST_TIME_FORMAT
"not in the expected range [%" GST_TIME_FORMAT " -- %"
GST_TIME_FORMAT, GST_TIME_ARGS (position),