diff --git a/validate/gst/qa/gst-qa-pad-monitor.c b/validate/gst/qa/gst-qa-pad-monitor.c index 9373d336bd..733e3066e0 100644 --- a/validate/gst/qa/gst-qa-pad-monitor.c +++ b/validate/gst/qa/gst-qa-pad-monitor.c @@ -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); diff --git a/validate/gst/qa/gst-qa-report.c b/validate/gst/qa/gst-qa-report.c index 9d8c36070c..b27f388e42 100644 --- a/validate/gst/qa/gst-qa-report.c +++ b/validate/gst/qa/gst-qa-report.c @@ -1,7 +1,7 @@ /* GStreamer * Copyright (C) 2013 Thiago Santos * - * 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 +#include #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); } } diff --git a/validate/gst/qa/gst-qa-report.h b/validate/gst/qa/gst-qa-report.h index b4a5d8bc05..bf1bf6fa0e 100644 --- a/validate/gst/qa/gst-qa-report.h +++ b/validate/gst/qa/gst-qa-report.h @@ -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__ */ diff --git a/validate/gst/qa/gst-qa-reporter.c b/validate/gst/qa/gst-qa-reporter.c index 472e4d3bd8..4f754228d9 100644 --- a/validate/gst/qa/gst-qa-reporter.c +++ b/validate/gst/qa/gst-qa-reporter.c @@ -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) { diff --git a/validate/gst/qa/gst-qa-reporter.h b/validate/gst/qa/gst-qa-reporter.h index b45601ca81..ff82b18eab 100644 --- a/validate/gst/qa/gst-qa-reporter.h +++ b/validate/gst/qa/gst-qa-reporter.h @@ -22,6 +22,7 @@ #include #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); diff --git a/validate/gst/qa/gst-qa-scenario.c b/validate/gst/qa/gst-qa-scenario.c index cafb47dfe3..0ccfc94b39 100644 --- a/validate/gst/qa/gst-qa-scenario.c +++ b/validate/gst/qa/gst-qa-scenario.c @@ -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),