3 * Copyright (C) 2013 Collabora Ltd.
4 * Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
6 * gst-validate-monitor-report.c - Validate report/issues functions
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
29 #include <stdlib.h> /* exit */
30 #include <stdio.h> /* fprintf */
31 #include <glib/gstdio.h>
35 #include "gst-validate-i18n-lib.h"
36 #include "gst-validate-internal.h"
38 #include "gst-validate-report.h"
39 #include "gst-validate-reporter.h"
40 #include "gst-validate-monitor.h"
41 #include "gst-validate-scenario.h"
43 static GstClockTime _gst_validate_report_start_time = 0;
44 static GstValidateDebugFlags _gst_validate_flags = 0;
45 static GHashTable *_gst_validate_issues = NULL;
46 static FILE **log_files = NULL;
47 static gboolean output_is_tty = TRUE;
49 /* Tcp server for communications with gst-validate-launcher */
50 GSocketClient *socket_client = NULL;
51 GSocketConnection *server_connection = NULL;
52 GOutputStream *server_ostream = NULL;
54 static GType _gst_validate_report_type = 0;
57 gst_validate_report_serialize (GstValidateReport * report)
59 JsonNode *node = json_node_alloc ();
60 JsonObject *jreport = json_object_new ();
62 json_object_set_string_member (jreport, "type", "report");
63 json_object_set_string_member (jreport, "issue-id",
64 g_quark_to_string (report->issue->issue_id));
65 json_object_set_string_member (jreport, "summary", report->issue->summary);
66 json_object_set_string_member (jreport, "level",
67 gst_validate_report_level_get_name (report->level));
68 json_object_set_string_member (jreport, "detected-on", report->reporter_name);
69 json_object_set_string_member (jreport, "details", report->message);
71 node = json_node_init_object (node, jreport);
72 json_object_unref (jreport);
78 gst_validate_report_get_type (void)
80 if (_gst_validate_report_type == 0) {
81 _gst_validate_report_type =
82 g_boxed_type_register_static (g_intern_static_string
83 ("GstValidateReport"), (GBoxedCopyFunc) gst_mini_object_ref,
84 (GBoxedFreeFunc) gst_mini_object_unref);
86 json_boxed_register_serialize_func (_gst_validate_report_type,
88 (JsonBoxedSerializeFunc) gst_validate_report_serialize);
91 return _gst_validate_report_type;
95 GRegex *newline_regex = NULL;
97 GST_DEBUG_CATEGORY_STATIC (gst_validate_report_debug);
98 #undef GST_CAT_DEFAULT
99 #define GST_CAT_DEFAULT gst_validate_report_debug
101 #define GST_VALIDATE_REPORT_SHADOW_REPORTS_LOCK(r) \
103 (g_mutex_lock (&((GstValidateReport *) r)->shadow_reports_lock)); \
106 #define GST_VALIDATE_REPORT_SHADOW_REPORTS_UNLOCK(r) \
108 (g_mutex_unlock (&((GstValidateReport *) r)->shadow_reports_lock)); \
111 static GstValidateIssue *
112 gst_validate_issue_ref (GstValidateIssue * issue)
114 g_return_val_if_fail (issue != NULL, NULL);
116 g_atomic_int_inc (&issue->refcount);
122 gst_validate_issue_unref (GstValidateIssue * issue)
124 if (G_UNLIKELY (g_atomic_int_dec_and_test (&issue->refcount))) {
125 g_free (issue->summary);
126 g_free (issue->description);
128 /* We are using an string array for area and name */
129 g_strfreev (&issue->area);
131 g_slice_free (GstValidateIssue, issue);
136 G_DEFINE_BOXED_TYPE (GstValidateIssue, gst_validate_issue,
137 (GBoxedCopyFunc) gst_validate_issue_ref,
138 (GBoxedFreeFunc) gst_validate_issue_unref);
141 gst_validate_issue_get_id (GstValidateIssue * issue)
143 return issue->issue_id;
147 * gst_validate_issue_new_full:
148 * @issue_id: The ID of the issue, should be a GQuark
149 * @summary: A summary of the issue
150 * @description: A more complete description of the issue
151 * @default_level: The level at which the issue will be reported by default
152 * @flags: The flags to determine behaviour of the issue
154 * Returns: (transfer full): The newly created #GstValidateIssue
157 gst_validate_issue_new_full (GstValidateIssueId issue_id, const gchar * summary,
158 const gchar * description, GstValidateReportLevel default_level,
159 GstValidateIssueFlags flags)
161 GstValidateIssue *issue;
162 gchar **area_name = g_strsplit (g_quark_to_string (issue_id), "::", 2);
164 if (!(area_name[0] != NULL && area_name[1] != NULL && area_name[2] == NULL)) {
165 g_warning ("Wrong issue ID: %s (should be in the form: area::name)",
166 g_quark_to_string (issue_id));
167 g_strfreev (area_name);
172 issue = g_slice_new (GstValidateIssue);
173 issue->issue_id = issue_id;
174 issue->summary = g_strdup (summary);
175 issue->description = g_strdup (description);
176 issue->default_level = default_level;
177 issue->area = area_name[0];
178 issue->name = area_name[1];
179 issue->flags = flags;
186 * gst_validate_issue_new:
187 * @issue_id: The ID of the issue, should be a GQuark
188 * @summary: A summary of the issue
189 * @description: A more complete description of the issue
190 * @default_level: The level at which the issue will be reported by default
192 * Returns: (transfer full): The newly created #GstValidateIssue
195 gst_validate_issue_new (GstValidateIssueId issue_id, const gchar * summary,
196 const gchar * description, GstValidateReportLevel default_level)
198 GstValidateIssue *issue;
199 gchar **area_name = g_strsplit (g_quark_to_string (issue_id), "::", 2);
201 if (!(area_name[0] != NULL && area_name[1] != NULL && area_name[2] == NULL)) {
202 g_warning ("Wrong issue ID: %s (should be in the form: area::name)",
203 g_quark_to_string (issue_id));
204 g_strfreev (area_name);
209 issue = g_slice_new (GstValidateIssue);
210 issue->issue_id = issue_id;
211 issue->summary = g_strdup (summary);
212 issue->description = g_strdup (description);
213 issue->default_level = default_level;
214 issue->area = area_name[0];
215 issue->name = area_name[1];
216 issue->flags = GST_VALIDATE_ISSUE_FLAGS_NONE;
223 gst_validate_issue_set_default_level (GstValidateIssue * issue,
224 GstValidateReportLevel default_level)
226 GST_INFO ("Setting issue %s::%s default level to %s",
227 issue->area, issue->name,
228 gst_validate_report_level_get_name (default_level));
230 issue->default_level = default_level;
234 * gst_validate_issue_register:
235 * @issue: (transfer none): The #GstValidateIssue to register
237 * Registers @issue in the issue type system
240 gst_validate_issue_register (GstValidateIssue * issue)
242 g_return_if_fail (g_hash_table_lookup (_gst_validate_issues,
243 (gpointer) gst_validate_issue_get_id (issue)) == NULL);
245 g_hash_table_insert (_gst_validate_issues,
246 (gpointer) gst_validate_issue_get_id (issue), issue);
249 #define REGISTER_VALIDATE_ISSUE(lvl,id,sum,desc) \
250 gst_validate_issue_register (gst_validate_issue_new (id, \
251 sum, desc, GST_VALIDATE_REPORT_LEVEL_##lvl))
253 #define REGISTER_VALIDATE_ISSUE_FULL(lvl,id,sum,desc,flags) \
254 gst_validate_issue_register (gst_validate_issue_new_full (id, \
255 sum, desc, GST_VALIDATE_REPORT_LEVEL_##lvl, flags))
257 gst_validate_report_load_issues (void)
259 g_return_if_fail (_gst_validate_issues == NULL);
261 _gst_validate_issues = g_hash_table_new_full (g_direct_hash, g_direct_equal,
262 NULL, (GDestroyNotify) gst_validate_issue_unref);
265 * WARNING: The `summary` is used to define known issues in the testsuites.
266 * Avoid changing them or **make sure** to at least update the validate test
267 * suite if you do so.
269 REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_BEFORE_SEGMENT,
270 "buffer was received before a segment",
271 _("in push mode, a segment event must be received before a buffer"));
272 REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_IS_OUT_OF_SEGMENT,
273 "buffer is out of the segment range",
274 _("buffer being pushed is out of the current segment's start-stop "
275 "range. Meaning it is going to be discarded downstream without "
277 REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_TIMESTAMP_OUT_OF_RECEIVED_RANGE,
278 "buffer timestamp is out of the received buffer timestamps' range",
279 _("a buffer leaving an element should have its timestamps in the range "
280 "of the received buffers timestamps. i.e. If an element received "
281 "buffers with timestamps from 0s to 10s, it can't push a buffer with "
282 "a 11s timestamp, because it doesn't have data for that"));
283 REGISTER_VALIDATE_ISSUE (WARNING, WRONG_BUFFER,
284 "Received buffer does not correspond to wanted one.",
285 _("When checking playback of a file against a MediaInfo file"
286 " all buffers coming into the decoders might be checked"
287 " and should have the exact expected metadatas and hash of the"
289 REGISTER_VALIDATE_ISSUE (CRITICAL, WRONG_FLOW_RETURN,
290 "flow return from pad push doesn't match expected value",
291 _("flow return from a 1:1 sink/src pad element is as simple as "
292 "returning what downstream returned. For elements that have multiple "
293 "src pads, flow returns should be properly combined"));
294 REGISTER_VALIDATE_ISSUE (ISSUE, BUFFER_AFTER_EOS,
295 "buffer was received after EOS",
296 _("a pad shouldn't receive any more buffers after it gets EOS"));
297 REGISTER_VALIDATE_ISSUE (WARNING, FLOW_ERROR_WITHOUT_ERROR_MESSAGE,
298 "GST_FLOW_ERROR returned without posting an ERROR on the bus",
299 _("Element MUST post a GST_MESSAGE_ERROR with GST_ELEMENT_ERROR before"
300 " returning GST_FLOW_ERROR"));
301 REGISTER_VALIDATE_ISSUE (WARNING, BUFFER_MISSING_DISCONT,
302 _("Buffer didn't have expected DISCONT flag"),
303 _("Buffers after SEGMENT and FLUSH must have a DISCONT flag"));
305 REGISTER_VALIDATE_ISSUE (ISSUE, CAPS_IS_MISSING_FIELD,
306 "caps is missing a required field for its type",
307 _("some caps types are expected to contain a set of basic fields. "
308 "For example, raw video should have 'width', 'height', 'framerate' "
309 "and 'pixel-aspect-ratio'"));
310 REGISTER_VALIDATE_ISSUE (WARNING, CAPS_FIELD_HAS_BAD_TYPE,
311 "caps field has an unexpected type",
312 _("some common caps fields should always use the same expected types"));
313 REGISTER_VALIDATE_ISSUE (WARNING, CAPS_EXPECTED_FIELD_NOT_FOUND,
314 "caps expected field wasn't present",
315 _("a field that should be present in the caps wasn't found. "
316 "Fields sets on a sink pad caps should be propagated downstream "
317 "when it makes sense to do so"));
318 REGISTER_VALIDATE_ISSUE (CRITICAL, GET_CAPS_NOT_PROXYING_FIELDS,
319 "getcaps function isn't proxying downstream fields correctly",
320 _("elements should set downstream caps restrictions on its caps when "
321 "replying upstream's getcaps queries to avoid upstream sending data"
322 " in an unsupported format"));
323 REGISTER_VALIDATE_ISSUE (CRITICAL, CAPS_FIELD_UNEXPECTED_VALUE,
324 "a field in caps has an unexpected value",
325 _("fields set on a sink pad should be propagated downstream via "
328 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEWSEGMENT_NOT_PUSHED,
329 "new segment event wasn't propagated downstream",
330 _("segments received from upstream should be pushed downstream"));
331 REGISTER_VALIDATE_ISSUE (WARNING, SERIALIZED_EVENT_WASNT_PUSHED_IN_TIME,
332 "a serialized event received should be pushed in the same 'time' "
333 "as it was received",
334 _("serialized events should be pushed in the same order they are "
335 "received and serialized with buffers. If an event is received after"
336 " a buffer with timestamp end 'X', it should be pushed right after "
337 "buffers with timestamp end 'X'"));
338 REGISTER_VALIDATE_ISSUE (ISSUE, EOS_HAS_WRONG_SEQNUM,
339 "EOS events that are part of the same pipeline 'operation' should "
340 "have the same seqnum",
341 _("when events/messages are created from another event/message, "
342 "they should have their seqnums set to the original event/message "
344 REGISTER_VALIDATE_ISSUE (ISSUE, FLUSH_START_HAS_WRONG_SEQNUM,
345 "FLUSH_START events that are part of the same pipeline 'operation' should "
346 "have the same seqnum",
347 _("when events/messages are created from another event/message, "
348 "they should have their seqnums set to the original event/message "
350 REGISTER_VALIDATE_ISSUE (ISSUE, FLUSH_STOP_HAS_WRONG_SEQNUM,
351 "FLUSH_STOP events that are part of the same pipeline 'operation' should "
352 "have the same seqnum",
353 _("when events/messages are created from another event/message, "
354 "they should have their seqnums set to the original event/message "
356 REGISTER_VALIDATE_ISSUE (ISSUE, SEGMENT_HAS_WRONG_SEQNUM,
357 "SEGMENT events that are part of the same pipeline 'operation' should "
358 "have the same seqnum",
359 _("when events/messages are created from another event/message, "
360 "they should have their seqnums set to the original event/message "
362 REGISTER_VALIDATE_ISSUE (CRITICAL, SEGMENT_HAS_WRONG_START,
363 "A segment doesn't have the proper time value after an ACCURATE seek",
364 _("If a seek with the ACCURATE flag was accepted, the following segment "
365 "should have a time value corresponding exactly to the requested start "
367 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_SERIALIZED_OUT_OF_ORDER,
368 "a serialized event received should be pushed in the same order "
369 "as it was received",
370 _("serialized events should be pushed in the same order they are "
372 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_NEW_SEGMENT_MISMATCH,
373 "a new segment event has different value than the received one",
374 _("when receiving a new segment, an element should push an equivalent "
375 "segment downstream"));
376 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_START_UNEXPECTED,
377 "received an unexpected flush start event", NULL);
378 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_FLUSH_STOP_UNEXPECTED,
379 "received an unexpected flush stop event", NULL);
380 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_CAPS_DUPLICATE,
381 "received the same caps twice", NULL);
383 REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_NOT_HANDLED,
384 "seek event wasn't handled", NULL);
385 REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_RESULT_POSITION_WRONG,
386 "position after a seek is wrong", NULL);
387 REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_SEEK_INVALID_SEQNUM,
388 "segments after a seek don't have the same seqnum", NULL);
390 REGISTER_VALIDATE_ISSUE (WARNING, EVENT_EOS_WITHOUT_SEGMENT,
391 "EOS received without segment event before",
392 _("A segment event should always be sent before data flow"
393 " EOS being some kind of data flow, there is no exception"
396 REGISTER_VALIDATE_ISSUE (CRITICAL, EVENT_INVALID_SEQNUM,
397 "Event has an invalid seqnum",
398 _("An event is using GST_SEQNUM_INVALID. This should never happen"));
400 REGISTER_VALIDATE_ISSUE (CRITICAL, STATE_CHANGE_FAILURE,
401 "state change failed", NULL);
403 REGISTER_VALIDATE_ISSUE (WARNING, FILE_SIZE_INCORRECT,
404 "resulting file size wasn't within the expected values", NULL);
405 REGISTER_VALIDATE_ISSUE (WARNING, FILE_DURATION_INCORRECT,
406 "resulting file duration wasn't within the expected values", NULL);
407 REGISTER_VALIDATE_ISSUE (WARNING, FILE_SEEKABLE_INCORRECT,
408 "resulting file wasn't seekable or not seekable as expected", NULL);
409 REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_PROFILE_INCORRECT,
410 "resulting file stream profiles didn't match expected values", NULL);
411 REGISTER_VALIDATE_ISSUE (ISSUE, FILE_TAG_DETECTION_INCORRECT,
412 "detected tags are different than expected ones", NULL);
413 REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_FRAMES_INCORRECT,
414 "resulting file frames are not as expected", NULL);
415 REGISTER_VALIDATE_ISSUE (CRITICAL, FILE_SEGMENT_INCORRECT,
416 "resulting segment is not as expected", NULL);
417 REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_INFO,
418 "the discoverer could not determine the stream info", NULL);
419 REGISTER_VALIDATE_ISSUE (WARNING, FILE_NO_STREAM_ID,
420 "the discoverer found a stream that had no stream ID", NULL);
423 REGISTER_VALIDATE_ISSUE (CRITICAL, ALLOCATION_FAILURE,
424 "a memory allocation failed during Validate run", NULL);
425 REGISTER_VALIDATE_ISSUE (CRITICAL, MISSING_PLUGIN,
426 "a gstreamer plugin is missing and prevented Validate from running",
428 REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED,
429 "a NOT NEGOTIATED message has been posted on the bus.", NULL);
430 REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS,
431 "We got a WARNING message on the bus", NULL);
432 REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS,
433 "We got an ERROR message on the bus", NULL);
434 REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_SUPERIOR_DURATION,
435 "Query position reported a value superior than what query duration "
437 REGISTER_VALIDATE_ISSUE (WARNING, QUERY_POSITION_OUT_OF_SEGMENT,
438 "Query position reported a value outside of the current expected "
440 REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_NOT_ENDED,
441 "The program stopped before some actions were executed", NULL);
442 REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_ACTION_TIMEOUT,
443 "The execution of an action timed out", NULL);
444 REGISTER_VALIDATE_ISSUE (CRITICAL, SCENARIO_FILE_MALFORMED,
445 "The scenario file was malformed", NULL);
446 REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, SCENARIO_ACTION_EXECUTION_ERROR,
447 "The execution of an action did not properly happen", NULL,
448 GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE |
449 GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS);
450 REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, SCENARIO_ACTION_CHECK_ERROR,
451 "A check action failed", NULL,
452 GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE |
453 GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS);
454 REGISTER_VALIDATE_ISSUE (ISSUE, SCENARIO_ACTION_EXECUTION_ISSUE,
455 "An issue happened during the execution of a scenario", NULL);
456 REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_LATENCY_TOO_HIGH,
457 "The pipeline latency is higher than the maximum allowed by the scenario",
459 REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_TOO_MANY_BUFFERS_DROPPED,
460 "The number of dropped buffers is higher than the maximum allowed by the scenario",
462 REGISTER_VALIDATE_ISSUE (CRITICAL, CONFIG_BUFFER_FREQUENCY_TOO_LOW,
464 ("Pad buffers push frequency is lower than the minimum required by the config"),
466 REGISTER_VALIDATE_ISSUE_FULL (WARNING, G_LOG_WARNING,
467 _("We got a g_log warning"), NULL,
468 GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE |
469 GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS);
470 REGISTER_VALIDATE_ISSUE_FULL (CRITICAL, G_LOG_CRITICAL,
471 "We got a g_log critical issue", NULL,
472 GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE |
473 GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS);
474 REGISTER_VALIDATE_ISSUE_FULL (ISSUE, G_LOG_ISSUE, "We got a g_log issue",
476 GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE |
477 GST_VALIDATE_ISSUE_FLAGS_FULL_DETAILS);
479 REGISTER_VALIDATE_ISSUE (CRITICAL, PULL_RANGE_FROM_WRONG_THREAD,
480 "gst_pad_pull_range called from wrong thread",
481 _("gst_pad_pull_range has to be called from the sinkpad task thread."));
485 gst_validate_send (JsonNode * root)
487 gboolean res = FALSE;
489 gsize message_length;
490 gchar *object, *message;
491 GError *error = NULL;
496 jgen = json_generator_new ();
497 json_generator_set_root (jgen, root);
499 object = json_generator_to_data (jgen, &message_length);
500 message = g_malloc0 (message_length + 5);
501 GST_WRITE_UINT32_BE (message, message_length);
502 strcpy (&message[4], object);
505 res = g_output_stream_write_all (server_ostream, message, message_length + 4,
509 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) {
510 GST_DEBUG ("Stream was busy, trying again later.");
513 g_object_unref (jgen);
515 g_error_free (error);
516 g_idle_add ((GSourceFunc) gst_validate_send, root);
517 return G_SOURCE_REMOVE;
520 GST_ERROR ("ERROR: Can't write to remote: %s", error->message);
521 } else if (!g_output_stream_flush (server_ostream, NULL, &error)) {
522 GST_ERROR ("ERROR: Can't flush stream: %s", error->message);
526 g_object_unref (jgen);
528 g_error_free (error);
531 json_node_free (root);
533 return G_SOURCE_REMOVE;
537 gst_validate_report_init (void)
539 const gchar *var, *file_env, *server_env, *uuid;
540 const GDebugKey keys[] = {
541 {"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS},
542 {"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS},
543 {"fatal_issues", GST_VALIDATE_FATAL_ISSUES},
544 {"print_issues", GST_VALIDATE_PRINT_ISSUES},
545 {"print_warnings", GST_VALIDATE_PRINT_WARNINGS},
546 {"print_criticals", GST_VALIDATE_PRINT_CRITICALS}
549 GST_DEBUG_CATEGORY_INIT (gst_validate_report_debug, "gstvalidatereport",
550 GST_DEBUG_FG_YELLOW, "Gst validate reporting");
552 _gst_validate_report_type = gst_validate_report_get_type ();
554 if (_gst_validate_report_start_time == 0) {
555 _gst_validate_report_start_time = gst_util_get_timestamp ();
557 /* init the debug flags */
558 var = g_getenv ("GST_VALIDATE");
559 if (var && strlen (var) > 0) {
560 _gst_validate_flags =
561 g_parse_debug_string (var, keys, G_N_ELEMENTS (keys));
564 gst_validate_report_load_issues ();
567 output_is_tty = isatty (1);
570 server_env = g_getenv ("GST_VALIDATE_SERVER");
571 uuid = g_getenv ("GST_VALIDATE_UUID");
573 if (server_env && !uuid) {
574 GST_INFO ("No GST_VALIDATE_UUID specified !");
575 } else if (server_env) {
576 GstUri *server_uri = gst_uri_from_string (server_env);
578 if (server_uri && !g_strcmp0 (gst_uri_get_scheme (server_uri), "tcp")) {
579 JsonBuilder *jbuilder;
581 socket_client = g_socket_client_new ();
583 server_connection = g_socket_client_connect_to_host (socket_client,
584 gst_uri_get_host (server_uri), gst_uri_get_port (server_uri),
587 if (!server_connection) {
588 g_clear_error (&err);
589 g_clear_object (&socket_client);
593 g_io_stream_get_output_stream (G_IO_STREAM (server_connection));
594 jbuilder = json_builder_new ();
595 json_builder_begin_object (jbuilder);
596 json_builder_set_member_name (jbuilder, "uuid");
597 json_builder_add_string_value (jbuilder, uuid);
598 json_builder_set_member_name (jbuilder, "started");
599 json_builder_add_boolean_value (jbuilder, TRUE);
600 json_builder_end_object (jbuilder);
602 gst_validate_send (json_builder_get_root (jbuilder));
603 g_object_unref (jbuilder);
606 gst_uri_unref (server_uri);
608 GST_ERROR ("Server URI not valid: %s", server_env);
612 file_env = g_getenv ("GST_VALIDATE_FILE");
613 if (file_env != NULL && *file_env != '\0') {
615 gchar **wanted_files;
616 wanted_files = g_strsplit (file_env, G_SEARCHPATH_SEPARATOR_S, 0);
618 /* FIXME: Make sure it is freed in the deinit function when that is
621 g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1));
622 for (i = 0; i < g_strv_length (wanted_files); i++) {
624 if (g_strcmp0 (wanted_files[i], "stderr") == 0) {
626 } else if (g_strcmp0 (wanted_files[i], "stdout") == 0) {
629 log_file = g_fopen (wanted_files[i], "w");
632 if (log_file == NULL) {
633 g_printerr ("Could not open log file '%s' for writing: %s\n", file_env,
638 log_files[i] = log_file;
641 g_strfreev (wanted_files);
643 log_files = g_malloc0 (sizeof (FILE *) * 2);
644 log_files[0] = stdout;
647 #ifndef GST_DISABLE_GST_DEBUG
650 g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL);
655 gst_validate_report_deinit (void)
657 if (server_ostream) {
658 g_output_stream_close (server_ostream, NULL, NULL);
659 server_ostream = NULL;
662 g_clear_object (&socket_client);
663 g_clear_object (&server_connection);
667 gst_validate_issue_from_id (GstValidateIssueId issue_id)
669 return g_hash_table_lookup (_gst_validate_issues, (gpointer) issue_id);
672 /* TODO how are these functions going to work with extensions */
674 gst_validate_report_level_get_name (GstValidateReportLevel level)
677 case GST_VALIDATE_REPORT_LEVEL_CRITICAL:
679 case GST_VALIDATE_REPORT_LEVEL_WARNING:
681 case GST_VALIDATE_REPORT_LEVEL_ISSUE:
683 case GST_VALIDATE_REPORT_LEVEL_IGNORE:
685 case GST_VALIDATE_REPORT_LEVEL_EXPECTED:
694 GstValidateReportLevel
695 gst_validate_report_level_from_name (const gchar * level_name)
697 if (g_strcmp0 (level_name, "critical") == 0)
698 return GST_VALIDATE_REPORT_LEVEL_CRITICAL;
700 else if (g_strcmp0 (level_name, "warning") == 0)
701 return GST_VALIDATE_REPORT_LEVEL_WARNING;
703 else if (g_strcmp0 (level_name, "issue") == 0)
704 return GST_VALIDATE_REPORT_LEVEL_ISSUE;
706 else if (g_strcmp0 (level_name, "ignore") == 0)
707 return GST_VALIDATE_REPORT_LEVEL_IGNORE;
709 return GST_VALIDATE_REPORT_LEVEL_UNKNOWN;
713 gst_validate_report_should_print (GstValidateReport * report)
715 if ((!(_gst_validate_flags & GST_VALIDATE_PRINT_ISSUES) &&
716 !(_gst_validate_flags & GST_VALIDATE_PRINT_WARNINGS) &&
717 !(_gst_validate_flags & GST_VALIDATE_PRINT_CRITICALS))) {
721 if ((report->level <= GST_VALIDATE_REPORT_LEVEL_ISSUE &&
722 _gst_validate_flags & GST_VALIDATE_PRINT_ISSUES) ||
723 (report->level <= GST_VALIDATE_REPORT_LEVEL_WARNING &&
724 _gst_validate_flags & GST_VALIDATE_PRINT_WARNINGS) ||
725 (report->level <= GST_VALIDATE_REPORT_LEVEL_CRITICAL &&
726 _gst_validate_flags & GST_VALIDATE_PRINT_CRITICALS)) {
735 gst_validate_report_check_abort (GstValidateReport * report)
737 if ((report->level <= GST_VALIDATE_REPORT_LEVEL_ISSUE &&
738 _gst_validate_flags & GST_VALIDATE_FATAL_ISSUES) ||
739 (report->level <= GST_VALIDATE_REPORT_LEVEL_WARNING &&
740 _gst_validate_flags & GST_VALIDATE_FATAL_WARNINGS) ||
741 (report->level <= GST_VALIDATE_REPORT_LEVEL_CRITICAL &&
742 _gst_validate_flags & GST_VALIDATE_FATAL_CRITICALS)) {
751 gst_validate_report_get_issue_id (GstValidateReport * report)
753 return gst_validate_issue_get_id (report->issue);
757 _report_free (GstValidateReport * report)
759 g_free (report->message);
760 g_free (report->reporter_name);
761 g_free (report->trace);
762 g_free (report->dotfile_name);
763 g_list_free_full (report->shadow_reports,
764 (GDestroyNotify) gst_validate_report_unref);
765 g_list_free_full (report->repeated_reports,
766 (GDestroyNotify) gst_validate_report_unref);
767 g_mutex_clear (&report->shadow_reports_lock);
768 g_slice_free (GstValidateReport, report);
772 gst_validate_report_should_generate_backtrace (GstValidateIssue * issue,
773 GstValidateReport * report,
774 GstValidateReportingDetails default_details,
775 GstValidateReportingDetails issue_type_details,
776 GstValidateReportingDetails reporter_details)
778 if (issue->flags & GST_VALIDATE_ISSUE_FLAGS_FORCE_BACKTRACE)
781 if (issue->flags & GST_VALIDATE_ISSUE_FLAGS_NO_BACKTRACE)
784 if (default_details == GST_VALIDATE_SHOW_ALL)
787 if (issue_type_details == GST_VALIDATE_SHOW_ALL)
790 if (gst_validate_report_check_abort (report))
793 if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
800 gst_validate_report_new (GstValidateIssue * issue,
801 GstValidateReporter * reporter, const gchar * message)
803 GstValidateReport *report = g_slice_new0 (GstValidateReport);
804 GstValidateReportingDetails reporter_details, default_details,
806 GstValidateRunner *runner = gst_validate_reporter_get_runner (reporter);
808 gst_mini_object_init (((GstMiniObject *) report), 0,
809 _gst_validate_report_type, NULL, NULL,
810 (GstMiniObjectFreeFunction) _report_free);
811 GST_MINI_OBJECT_FLAG_SET (report, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
813 report->issue = issue;
814 /* The reporter is owning a ref on the report so it doesn't keep a ref to
815 * avoid reference cycles. But the report can also be used by
816 * GstValidateRunner *after* that the reporter has been destroyed, so we
817 * cache the reporter name to avoid crashing in
818 * gst_validate_report_print_detected_on if the reporter has been destroyed.
820 report->reporter = reporter;
821 report->reporter_name = g_strdup (gst_validate_reporter_get_name (reporter));
822 report->message = g_strdup (message);
823 g_mutex_init (&report->shadow_reports_lock);
825 gst_util_get_timestamp () - _gst_validate_report_start_time;
826 report->level = issue->default_level;
827 report->reporting_level = GST_VALIDATE_SHOW_UNKNOWN;
829 reporter_details = gst_validate_reporter_get_reporting_level (reporter);
830 issue_type_details = gst_validate_runner_get_reporting_level_for_name (runner,
831 g_quark_to_string (issue->issue_id));
832 default_details = gst_validate_runner_get_default_reporting_details (runner);
833 gst_object_unref (runner);
834 if (reporter_details != GST_VALIDATE_SHOW_ALL &&
835 reporter_details != GST_VALIDATE_SHOW_UNKNOWN)
838 if (gst_validate_report_should_generate_backtrace (issue, report,
839 default_details, issue_type_details, reporter_details))
840 report->trace = gst_debug_get_stack_trace (GST_STACK_TRACE_SHOW_FULL);
846 gst_validate_report_unref (GstValidateReport * report)
848 gst_mini_object_unref (GST_MINI_OBJECT (report));
852 gst_validate_report_ref (GstValidateReport * report)
854 return (GstValidateReport *) gst_mini_object_ref (GST_MINI_OBJECT (report));
858 gst_validate_printf (gpointer source, const gchar * format, ...)
862 va_start (var_args, format);
863 gst_validate_printf_valist (source, format, var_args);
872 } PrintActionFieldData;
875 _append_value (GQuark field_id, const GValue * value, PrintActionFieldData * d)
877 gchar *val_str = NULL;
878 const gchar *fieldname = g_quark_to_string (field_id);
880 if (g_str_has_prefix (fieldname, "__") && g_str_has_suffix (fieldname, "__"))
883 if (g_strcmp0 (fieldname, "repeat") == 0)
887 if (G_VALUE_TYPE (value) == GST_TYPE_CLOCK_TIME)
888 val_str = g_strdup_printf ("%" GST_TIME_FORMAT,
889 GST_TIME_ARGS (g_value_get_uint64 (value)));
891 val_str = gst_value_serialize (value);
893 g_string_append_printf (d->str, "\n%*c - ", d->indent, ' ');
894 g_string_append (d->str, fieldname);
895 g_string_append_len (d->str, "=", 1);
896 g_string_append (d->str, val_str);
904 * gst_validate_print_action:
905 * @action: (allow-none): The source object to log
906 * @message: The message to print out in the GstValidate logging system
908 * Print @message to the GstValidate logging system
911 gst_validate_print_action (GstValidateAction * action, const gchar * message)
913 GString *string = NULL;
915 if (message == NULL) {
916 gint indent = (gst_validate_action_get_level (action) * 2);
917 PrintActionFieldData d = { NULL, indent, 0 };
918 d.str = string = g_string_new (NULL);
920 g_string_append_printf (string, "`%s` at %s:%d", action->type,
921 GST_VALIDATE_ACTION_FILENAME (action),
922 GST_VALIDATE_ACTION_LINENO (action));
924 if (GST_VALIDATE_ACTION_N_REPEATS (action))
925 g_string_append_printf (string, " [%s=%d/%d]",
926 GST_VALIDATE_ACTION_RANGE_NAME (action) ?
927 GST_VALIDATE_ACTION_RANGE_NAME (action) : "repeat", action->repeat,
928 GST_VALIDATE_ACTION_N_REPEATS (action));
930 g_string_append (string, " ( ");
931 gst_structure_foreach (action->structure,
932 (GstStructureForeachFunc) _append_value, &d);
934 g_string_append_printf (string, "\n%*c)\n", indent, ' ');
936 g_string_append (string, ")\n");
937 message = string->str;
940 gst_validate_printf (action, "%s", message);
943 g_string_free (string, TRUE);
947 print_action_parameter (GString * string, GstValidateActionType * type,
948 GstValidateActionParameter * param)
951 g_string_append_printf (string, "\n\n* `%s`:(%s): ", param->name,
952 param->mandatory ? "mandatory" : "optional");
954 if (g_strcmp0 (param->description, "")) {
955 desc = g_strdup (param->description);
957 desc = g_strdup ("__No description__");
960 g_string_append (string, desc);
963 if (param->possible_variables) {
965 g_regex_replace (newline_regex,
966 param->possible_variables, -1, 0, "\n\n * ", 0, NULL);
967 g_string_append_printf (string, "\n\n Possible variables:\n\n * %s",
972 g_string_append_printf (string, "\n\n Possible types: `%s`", param->types);
974 if (!param->mandatory)
975 g_string_append_printf (string, "\n\n Default: %s", param->def);
980 print_action_parameter_prototype (GString * string,
981 GstValidateActionParameter * param, gboolean is_first)
984 g_string_append (string, ",");
985 g_string_append (string, "\n ");
987 if (!param->mandatory)
988 g_string_append (string, "[");
990 g_string_append (string, param->name);
992 g_string_append_printf (string, "=(%s)", param->types);
994 if (!param->mandatory)
995 g_string_append (string, "]");
999 sort_parameters (const GstValidateActionParameter * param1,
1000 const GstValidateActionParameter * param2)
1002 if (param1->mandatory && !param2->mandatory)
1005 if (!param1->mandatory && param2->mandatory)
1008 return g_strcmp0 (param1->name, param2->name);
1012 gst_validate_printf_valist (gpointer source, const gchar * format, va_list args)
1016 GString *string = g_string_new (NULL);
1019 if (*(GType *) source == GST_TYPE_VALIDATE_ACTION) {
1020 GstValidateAction *action = (GstValidateAction *) source;
1021 gint indent = gst_validate_action_get_level (action) * 2;
1023 if (_action_check_and_set_printed (action))
1027 g_string_assign (string, "Executing ");
1029 g_string_append_printf (string, "%*c↳ Executing ", indent - 2, ' ');
1030 } else if (*(GType *) source == GST_TYPE_VALIDATE_ACTION_TYPE) {
1033 gboolean has_parameters = FALSE;
1034 gboolean is_first = TRUE;
1036 GstValidateActionParameter playback_time_param = {
1037 .name = "playback-time",
1038 .description = "The playback time at which the action will be executed",
1040 .types = "double,string",
1041 .possible_variables =
1042 "`position`: The current position in the stream\n"
1043 "`duration`: The duration of the stream",
1047 GstValidateActionParameter on_message_param = {
1048 .name = "on-message",
1050 "Specify on what message type the action will be executed.\n"
1051 " If both 'playback-time' and 'on-message' is specified, the action will be executed\n"
1052 " on whatever happens first.",
1055 .possible_variables = NULL,
1060 GstValidateActionType *type = GST_VALIDATE_ACTION_TYPE (source);
1062 /* Ignore private action types */
1063 if (g_str_has_prefix (type->name, "priv_"))
1066 g_string_append_printf (string, "\n## %s\n\n", type->name);
1068 g_string_append_printf (string, "\n``` validate-scenario\n%s,",
1071 for (n_params = 0; type->parameters[n_params].name != NULL; n_params++);
1072 qsort (type->parameters, n_params, sizeof (GstValidateActionParameter),
1073 (GCompareFunc) sort_parameters);
1074 for (i = 0; type->parameters[i].name; i++) {
1075 print_action_parameter_prototype (string, &type->parameters[i],
1080 if (!IS_CONFIG_ACTION_TYPE (type->flags)) {
1081 print_action_parameter_prototype (string, &playback_time_param,
1086 g_string_append (string, ";\n```\n");
1088 g_string_append_printf (string, "\n%s", type->description);
1089 g_string_append_printf (string,
1090 "\n * Implementer namespace: %s", type->implementer_namespace);
1092 if (IS_CONFIG_ACTION_TYPE (type->flags))
1093 g_string_append_printf (string,
1094 "\n * Is config action (meaning it will be executing right "
1095 "at the beginning of the execution of the pipeline)");
1098 if (type->parameters || !IS_CONFIG_ACTION_TYPE (type->flags))
1099 g_string_append_printf (string, "\n\n### Parameters");
1101 if (type->parameters) {
1102 has_parameters = TRUE;
1103 for (i = 0; type->parameters[i].name; i++) {
1104 print_action_parameter (string, type, &type->parameters[i]);
1108 if (!IS_CONFIG_ACTION_TYPE (type->flags)) {
1109 print_action_parameter (string, type, &playback_time_param);
1110 print_action_parameter (string, type, &on_message_param);
1114 if ((type->flags & GST_VALIDATE_ACTION_TYPE_CAN_BE_OPTIONAL)) {
1115 has_parameters = TRUE;
1116 g_string_append_printf (string,
1118 "Don't raise an error if this action hasn't been executed or failed"
1119 "\n%-32s ### Possible types:"
1120 "\n%-32s boolean" "\n%-32s Default: false", "", "", "");
1123 if (!has_parameters)
1124 g_string_append_printf (string, "\n\n ### No Parameters");
1125 } else if (GST_IS_VALIDATE_REPORTER (source) &&
1126 gst_validate_reporter_get_name (source)) {
1127 g_string_printf (string, "\n%s --> ",
1128 gst_validate_reporter_get_name (source));
1129 } else if (GST_IS_OBJECT (source)) {
1130 g_string_printf (string, "\n%s --> ", GST_OBJECT_NAME (source));
1131 } else if (G_IS_OBJECT (source)) {
1132 g_string_printf (string, "\n<%s@%p> --> ", G_OBJECT_TYPE_NAME (source),
1137 tmp = gst_info_strdup_vprintf (format, args);
1138 g_string_append (string, tmp);
1143 g_regex_new ("\n", G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, NULL);
1145 #ifndef GST_DISABLE_GST_DEBUG
1149 str = g_regex_replace (newline_regex, string->str, string->len, 0,
1153 GST_INFO ("%s", str);
1155 GST_DEBUG ("%s", str);
1161 for (i = 0; log_files[i]; i++) {
1162 fprintf (log_files[i], "%s", string->str);
1163 fflush (log_files[i]);
1167 g_string_free (string, TRUE);
1171 gst_validate_report_set_master_report (GstValidateReport * report,
1172 GstValidateReport * master_report)
1175 gboolean add_shadow_report = TRUE;
1177 if (master_report->reporting_level >= GST_VALIDATE_SHOW_MONITOR &&
1178 master_report->reporting_level != GST_VALIDATE_SHOW_SMART) {
1182 report->master_report = master_report;
1184 GST_VALIDATE_REPORT_SHADOW_REPORTS_LOCK (master_report);
1185 for (tmp = master_report->shadow_reports; tmp; tmp = tmp->next) {
1186 GstValidateReport *shadow_report = (GstValidateReport *) tmp->data;
1187 if (report->reporter == shadow_report->reporter) {
1188 add_shadow_report = FALSE;
1192 if (add_shadow_report)
1193 master_report->shadow_reports =
1194 g_list_append (master_report->shadow_reports,
1195 gst_validate_report_ref (report));
1196 GST_VALIDATE_REPORT_SHADOW_REPORTS_UNLOCK (master_report);
1202 gst_validate_report_print_level (GstValidateReport * report)
1204 gst_validate_printf (NULL, "%10s : %s\n",
1205 gst_validate_report_level_get_name (report->level),
1206 report->issue->summary);
1210 gst_validate_report_print_detected_on (GstValidateReport * report)
1214 gst_validate_printf (NULL, "%*s Detected on <%s",
1215 12, "", report->reporter_name);
1216 for (tmp = report->shadow_reports; tmp; tmp = tmp->next) {
1217 GstValidateReport *shadow_report = (GstValidateReport *) tmp->data;
1218 gst_validate_printf (NULL, ", %s", shadow_report->reporter_name);
1220 gst_validate_printf (NULL, ">\n");
1224 gst_validate_report_print_details (GstValidateReport * report)
1226 if (report->message) {
1228 gchar **lines = g_strsplit (report->message, "\n", -1);
1230 gst_validate_printf (NULL, "%*s Details : %s\n", 12, "", lines[0]);
1231 for (i = 1; lines[i]; i++)
1232 gst_validate_printf (NULL, "%*s%s\n", 21, "", lines[i]);
1238 gst_validate_report_print_trace (GstValidateReport * report)
1240 if (report->trace) {
1242 gchar **lines = g_strsplit (report->trace, "\n", -1);
1244 gst_validate_printf (NULL, "%*s backtrace :\n", 12, "");
1245 for (i = 0; lines[i]; i++)
1246 gst_validate_printf (NULL, "%*s%s\n", 15, "", lines[i]);
1252 gst_validate_report_print_dotfile (GstValidateReport * report)
1254 const gchar *dotdir = g_getenv ("GST_DEBUG_DUMP_DOT_DIR");
1255 const gchar *doturl = g_getenv ("GST_VALIDATE_DEBUG_DUMP_DOT_URL");
1257 if (!report->dotfile_name)
1261 gst_validate_printf (NULL, "%*s dotfile : %s%s%s.dot\n", 12, "",
1262 doturl, G_DIR_SEPARATOR_S, report->dotfile_name);
1264 gst_validate_printf (NULL, "%*s dotfile : %s%s%s.dot\n", 12, "",
1265 dotdir, G_DIR_SEPARATOR_S, report->dotfile_name);
1267 gst_validate_printf (NULL,
1268 "%*s dotfile : no dotfile produced as GST_DEBUG_DUMP_DOT_DIR is not set.\n",
1273 gst_validate_report_print_description (GstValidateReport * report)
1275 if (report->issue->description)
1276 gst_validate_printf (NULL, "%*s Description : %s\n", 12, "",
1277 report->issue->description);
1281 gst_validate_report_printf (GstValidateReport * report)
1285 gst_validate_report_print_level (report);
1286 gst_validate_report_print_detected_on (report);
1287 gst_validate_report_print_details (report);
1288 for (tmp = report->repeated_reports; tmp; tmp = tmp->next) {
1289 gst_validate_report_print_details (tmp->data);
1291 gst_validate_report_print_dotfile (report);
1292 gst_validate_report_print_trace (report);
1294 gst_validate_report_print_description (report);
1295 gst_validate_printf (NULL, "\n");
1299 gst_validate_report_set_reporting_level (GstValidateReport * report,
1300 GstValidateReportingDetails level)
1302 report->reporting_level = level;
1306 gst_validate_report_add_repeated_report (GstValidateReport * report,
1307 GstValidateReport * repeated_report)
1309 report->repeated_reports =
1310 g_list_append (report->repeated_reports,
1311 gst_validate_report_ref (repeated_report));
1316 gst_validate_print_position (GstClockTime position, GstClockTime duration,
1317 gdouble rate, gchar * extra_info)
1319 JsonBuilder *jbuilder;
1321 gst_validate_printf (NULL,
1322 "<position: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT
1323 " speed: %f %s/>%c", GST_TIME_ARGS (position), GST_TIME_ARGS (duration),
1324 rate, extra_info ? extra_info : "", output_is_tty ? '\r' : '\n');
1326 if (!server_ostream)
1329 jbuilder = json_builder_new ();
1330 json_builder_begin_object (jbuilder);
1331 json_builder_set_member_name (jbuilder, "type");
1332 json_builder_add_string_value (jbuilder, "position");
1333 json_builder_set_member_name (jbuilder, "position");
1334 json_builder_add_int_value (jbuilder, position);
1335 json_builder_set_member_name (jbuilder, "duration");
1336 json_builder_add_int_value (jbuilder, duration);
1337 json_builder_set_member_name (jbuilder, "speed");
1338 json_builder_add_double_value (jbuilder, rate);
1339 json_builder_end_object (jbuilder);
1341 gst_validate_send (json_builder_get_root (jbuilder));
1342 g_object_unref (jbuilder);
1344 g_free (extra_info);
1348 gst_validate_skip_test (const gchar * format, ...)
1350 JsonBuilder *jbuilder;
1354 va_start (va_args, format);
1355 tmp = gst_info_strdup_vprintf (format, va_args);
1358 if (!server_ostream) {
1359 gchar *f = g_strconcat ("ok 1 # SKIP ", tmp, NULL);
1362 gst_validate_printf (NULL, "%s", f);
1366 jbuilder = json_builder_new ();
1367 json_builder_begin_object (jbuilder);
1368 json_builder_set_member_name (jbuilder, "type");
1369 json_builder_add_string_value (jbuilder, "skip-test");
1370 json_builder_set_member_name (jbuilder, "details");
1371 json_builder_add_string_value (jbuilder, tmp);
1372 json_builder_end_object (jbuilder);
1375 gst_validate_send (json_builder_get_root (jbuilder));
1376 g_object_unref (jbuilder);
1380 print_issue (gpointer key, GstValidateIssue * issue, gpointer user_data)
1382 gst_validate_printf (NULL, "\n# `%s` (%" G_GUINTPTR_FORMAT ")\n\n",
1383 g_quark_to_string (issue->issue_id), issue->issue_id);
1384 gst_validate_printf (NULL, "%c%s\n\n", g_ascii_toupper (issue->summary[0]),
1385 &issue->summary[1]);
1386 if (issue->description)
1387 gst_validate_printf (NULL, "%c%s\n\n",
1388 g_ascii_toupper (issue->description[0]), &issue->description[1]);
1389 gst_validate_printf (NULL, "Area: %s\n", issue->area);
1390 gst_validate_printf (NULL, "Name: %s\n", issue->name);
1391 gst_validate_printf (NULL, "Default severity: %s\n\n",
1392 gst_validate_report_level_get_name (issue->default_level));
1396 gst_validate_print_issues (void)
1398 g_return_if_fail (_gst_validate_issues);
1400 g_hash_table_foreach (_gst_validate_issues, (GHFunc) print_issue, NULL);
1404 gst_validate_error_structure (gpointer structure, const gchar * format, ...)
1406 gchar *filename = NULL;
1408 gchar *tmp, *debug = NULL;
1409 GString *f = g_string_new (NULL);
1411 gchar *color = NULL;
1413 const gchar *endcolor = "";
1415 if (g_log_writer_supports_color (fileno (stderr))) {
1416 color = gst_debug_construct_term_color (GST_DEBUG_FG_RED);
1417 endcolor = "\033[0m";
1421 if (GST_IS_STRUCTURE (structure)) {
1423 g_strdup (gst_structure_get_string (structure, "__filename__"));
1424 debug = g_strdup (gst_structure_get_string (structure, "__debug__"));
1425 gst_structure_get_int (structure, "__lineno__", &lineno);
1426 /* We are going to assert... we can boutcher the struct! */
1427 gst_structure_remove_fields (structure, "__filename__", "__lineno__",
1430 filename = g_strdup (GST_VALIDATE_ACTION_FILENAME (structure));
1431 debug = g_strdup (GST_VALIDATE_ACTION_DEBUG (structure));
1432 lineno = GST_VALIDATE_ACTION_LINENO (structure);
1436 va_start (var_args, format);
1437 tmp = gst_info_strdup_vprintf (format, var_args);
1440 g_string_append_printf (f, "%s:%d: %s\n",
1441 filename ? filename : "Unknown", lineno, tmp);
1444 g_string_append (f, debug);
1446 g_print ("Bail out! %sERROR%s: %s\n\n", color ? color : "", endcolor, f->str);
1447 g_string_free (f, TRUE);
1457 gst_validate_abort (const gchar * format, ...)
1462 va_start (var_args, format);
1463 tmp = gst_info_strdup_vprintf (format, var_args);
1466 g_print ("Bail out! %s\n", tmp);
1473 return output_is_tty;