mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 06:54:49 +00:00
validate: Pass information about GstValidate execution over a socket
Instead of trying to parsing stdout, generate json messages and send them over a socket so that gst-validate-launcher can properly have informations about gst-validate subprocess execution.
This commit is contained in:
parent
29e5ac1362
commit
2fff14e469
11 changed files with 333 additions and 117 deletions
|
@ -201,6 +201,10 @@ if test "x$HAVE_CAIRO" != "xyes"; then
|
||||||
AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool])
|
AC_MSG_NOTICE([Cairo is needed for the gst-validate-images-tool])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(JSON_GLIB, json-glib-1.0)
|
||||||
|
AC_SUBST(JSON_GLIB_LIBS)
|
||||||
|
AC_SUBST(JSON_GLIB_CFLAGS)
|
||||||
|
|
||||||
dnl checks for gstreamer
|
dnl checks for gstreamer
|
||||||
|
|
||||||
AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no)
|
AG_GST_CHECK_GST_CHECK($GST_API_VERSION, [$GST_REQ], no)
|
||||||
|
|
|
@ -50,14 +50,14 @@ lib_LTLIBRARIES = libgstvalidate-@GST_API_VERSION@.la
|
||||||
libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c)
|
libgstvalidate_@GST_API_VERSION@_la_SOURCES = $(source_c)
|
||||||
libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h)
|
libgstvalidate_@GST_API_VERSION@include_HEADERS = $(source_h)
|
||||||
libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\
|
libgstvalidate_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\
|
||||||
$(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \
|
$(JSON_GLIB_CFLAGS) $(GIO_CFLAGS) $(GST_PBUTILS_CFLAGS) \
|
||||||
-DGST_USE_UNSTABLE_API
|
-DGST_USE_UNSTABLE_API
|
||||||
libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
|
libgstvalidate_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
|
||||||
$(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS)
|
$(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS)
|
||||||
libgstvalidate_@GST_API_VERSION@_la_LIBADD = \
|
libgstvalidate_@GST_API_VERSION@_la_LIBADD = \
|
||||||
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
||||||
$(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \
|
$(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \
|
||||||
$(GLIB_LIBS) $(LIBM)
|
$(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM)
|
||||||
|
|
||||||
libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate
|
libgstvalidate_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/validate
|
||||||
|
|
||||||
|
@ -71,9 +71,9 @@ libgstvalidateplugin_@GST_API_VERSION@_la_CFLAGS = $(GST_ALL_CFLAGS)\
|
||||||
libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
|
libgstvalidateplugin_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) \
|
||||||
$(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS)
|
$(GST_LT_LDFLAGS) $(GIO_LDFLAGS) $(GST_PBUTILS_LDFAGS)
|
||||||
libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \
|
libgstvalidateplugin_@GST_API_VERSION@_la_LIBADD = \
|
||||||
$(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
$(JSON_GLIB_CFLAGS) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
|
||||||
$(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \
|
$(GST_ALL_LIBS) $(GIO_LIBS) $(GST_PBUTILS_LIBS) \
|
||||||
$(GLIB_LIBS) $(LIBM)
|
$(JSON_GLIB_LIBS) $(GLIB_LIBS) $(LIBM)
|
||||||
|
|
||||||
CLEANFILES =
|
CLEANFILES =
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
#include "gst-validate-scenario.h"
|
#include "gst-validate-scenario.h"
|
||||||
#include "gst-validate-monitor.h"
|
#include "gst-validate-monitor.h"
|
||||||
|
#include <json-glib/json-glib.h>
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug);
|
GST_DEBUG_CATEGORY_EXTERN (gstvalidate_debug);
|
||||||
#define GST_CAT_DEFAULT gstvalidate_debug
|
#define GST_CAT_DEFAULT gstvalidate_debug
|
||||||
|
@ -49,5 +50,6 @@ G_GNUC_INTERNAL void _priv_validate_override_registry_deinit (void);
|
||||||
G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object);
|
G_GNUC_INTERNAL GstValidateMonitor * gst_validate_get_monitor (GObject *object);
|
||||||
G_GNUC_INTERNAL void gst_validate_init_runner (void);
|
G_GNUC_INTERNAL void gst_validate_init_runner (void);
|
||||||
G_GNUC_INTERNAL void gst_validate_deinit_runner (void);
|
G_GNUC_INTERNAL void gst_validate_deinit_runner (void);
|
||||||
|
G_GNUC_INTERNAL void gst_validate_report_deinit (void);
|
||||||
|
gboolean gst_validate_send (JsonNode * root);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -90,6 +90,7 @@ print_position (GstValidateMonitor * monitor)
|
||||||
{
|
{
|
||||||
GstQuery *query;
|
GstQuery *query;
|
||||||
gint64 position, duration;
|
gint64 position, duration;
|
||||||
|
JsonBuilder *jbuilder;
|
||||||
GstElement *pipeline =
|
GstElement *pipeline =
|
||||||
GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor));
|
GST_ELEMENT (GST_VALIDATE_MONITOR_GET_OBJECT (monitor));
|
||||||
|
|
||||||
|
@ -114,6 +115,21 @@ print_position (GstValidateMonitor * monitor)
|
||||||
gst_query_parse_segment (query, &rate, NULL, NULL, NULL);
|
gst_query_parse_segment (query, &rate, NULL, NULL, NULL);
|
||||||
gst_query_unref (query);
|
gst_query_unref (query);
|
||||||
|
|
||||||
|
jbuilder = json_builder_new ();
|
||||||
|
json_builder_begin_object (jbuilder);
|
||||||
|
json_builder_set_member_name (jbuilder, "type");
|
||||||
|
json_builder_add_string_value (jbuilder, "position");
|
||||||
|
json_builder_set_member_name (jbuilder, "position");
|
||||||
|
json_builder_add_int_value (jbuilder, position);
|
||||||
|
json_builder_set_member_name (jbuilder, "duration");
|
||||||
|
json_builder_add_int_value (jbuilder, duration);
|
||||||
|
json_builder_set_member_name (jbuilder, "speed");
|
||||||
|
json_builder_add_double_value (jbuilder, rate);
|
||||||
|
json_builder_end_object (jbuilder);
|
||||||
|
|
||||||
|
gst_validate_send (json_builder_get_root (jbuilder));
|
||||||
|
g_object_unref (jbuilder);
|
||||||
|
|
||||||
gst_validate_printf (NULL,
|
gst_validate_printf (NULL,
|
||||||
"<position: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT
|
"<position: %" GST_TIME_FORMAT " duration: %" GST_TIME_FORMAT
|
||||||
" speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration),
|
" speed: %f />\r", GST_TIME_ARGS (position), GST_TIME_ARGS (duration),
|
||||||
|
@ -423,15 +439,21 @@ _bus_handler (GstBus * bus, GstMessage * message,
|
||||||
}
|
}
|
||||||
case GST_MESSAGE_BUFFERING:
|
case GST_MESSAGE_BUFFERING:
|
||||||
{
|
{
|
||||||
|
JsonBuilder *jbuilder = json_builder_new ();
|
||||||
GstBufferingMode mode;
|
GstBufferingMode mode;
|
||||||
gint percent;
|
gint percent;
|
||||||
|
|
||||||
gst_message_parse_buffering (message, &percent);
|
gst_message_parse_buffering (message, &percent);
|
||||||
gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
|
gst_message_parse_buffering_stats (message, &mode, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
json_builder_begin_object (jbuilder);
|
||||||
|
json_builder_set_member_name (jbuilder, "type");
|
||||||
|
json_builder_add_string_value (jbuilder, "buffering");
|
||||||
|
json_builder_set_member_name (jbuilder, "state");
|
||||||
if (percent == 100) {
|
if (percent == 100) {
|
||||||
/* a 100% message means buffering is done */
|
/* a 100% message means buffering is done */
|
||||||
gst_validate_printf (NULL, "\nDone buffering\n");
|
gst_validate_printf (NULL, "\nDone buffering\n");
|
||||||
|
json_builder_add_string_value (jbuilder, "done");
|
||||||
if (monitor->buffering) {
|
if (monitor->buffering) {
|
||||||
monitor->print_pos_srcid =
|
monitor->print_pos_srcid =
|
||||||
g_timeout_add (PRINT_POSITION_TIMEOUT,
|
g_timeout_add (PRINT_POSITION_TIMEOUT,
|
||||||
|
@ -443,13 +465,22 @@ _bus_handler (GstBus * bus, GstMessage * message,
|
||||||
if (!monitor->buffering) {
|
if (!monitor->buffering) {
|
||||||
monitor->buffering = TRUE;
|
monitor->buffering = TRUE;
|
||||||
gst_validate_printf (NULL, "\nStart buffering\n");
|
gst_validate_printf (NULL, "\nStart buffering\n");
|
||||||
|
json_builder_add_string_value (jbuilder, "started");
|
||||||
if (monitor->print_pos_srcid
|
if (monitor->print_pos_srcid
|
||||||
&& g_source_remove (monitor->print_pos_srcid)) {
|
&& g_source_remove (monitor->print_pos_srcid)) {
|
||||||
monitor->print_pos_srcid = 0;
|
monitor->print_pos_srcid = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
json_builder_add_string_value (jbuilder, "progress");
|
||||||
}
|
}
|
||||||
gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent);
|
gst_validate_printf (NULL, "%s %d%% \r", "Buffering...", percent);
|
||||||
}
|
}
|
||||||
|
json_builder_set_member_name (jbuilder, "position");
|
||||||
|
json_builder_add_int_value (jbuilder, percent);
|
||||||
|
json_builder_end_object (jbuilder);
|
||||||
|
|
||||||
|
gst_validate_send (json_builder_get_root (jbuilder));
|
||||||
|
g_object_unref (jbuilder);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GST_MESSAGE_STREAM_COLLECTION:
|
case GST_MESSAGE_STREAM_COLLECTION:
|
||||||
|
|
|
@ -43,8 +43,48 @@ static GstValidateDebugFlags _gst_validate_flags = 0;
|
||||||
static GHashTable *_gst_validate_issues = NULL;
|
static GHashTable *_gst_validate_issues = NULL;
|
||||||
static FILE **log_files = NULL;
|
static FILE **log_files = NULL;
|
||||||
|
|
||||||
GType _gst_validate_report_type;
|
/* Tcp server for communications with gst-validate-launcher */
|
||||||
GST_DEFINE_MINI_OBJECT_TYPE (GstValidateReport, gst_validate_report);
|
GSocketClient *socket_client = NULL;
|
||||||
|
GSocketConnection *server_connection = NULL;
|
||||||
|
GOutputStream *server_ostream = NULL;
|
||||||
|
|
||||||
|
GType _gst_validate_report_type = 0;
|
||||||
|
|
||||||
|
static JsonNode *
|
||||||
|
gst_validate_report_serialize (GstValidateReport * report)
|
||||||
|
{
|
||||||
|
JsonNode *node = json_node_alloc ();
|
||||||
|
JsonObject *jreport = json_object_new ();
|
||||||
|
|
||||||
|
json_object_set_string_member (jreport, "type", "report");
|
||||||
|
json_object_set_string_member (jreport, "summary", report->issue->summary);
|
||||||
|
json_object_set_string_member (jreport, "level",
|
||||||
|
gst_validate_report_level_get_name (report->level));
|
||||||
|
json_object_set_string_member (jreport, "detected-on", report->reporter_name);
|
||||||
|
json_object_set_string_member (jreport, "details", report->message);
|
||||||
|
|
||||||
|
node = json_node_init_object (node, jreport);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_validate_report_get_type (void)
|
||||||
|
{
|
||||||
|
if (_gst_validate_report_type == 0) {
|
||||||
|
_gst_validate_report_type =
|
||||||
|
g_boxed_type_register_static (g_intern_static_string
|
||||||
|
("GstValidateReport"), (GBoxedCopyFunc) gst_mini_object_ref,
|
||||||
|
(GBoxedFreeFunc) gst_mini_object_unref);
|
||||||
|
|
||||||
|
json_boxed_register_serialize_func (_gst_validate_report_type,
|
||||||
|
JSON_NODE_OBJECT,
|
||||||
|
(JsonBoxedSerializeFunc) gst_validate_report_serialize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _gst_validate_report_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GRegex *newline_regex = NULL;
|
GRegex *newline_regex = NULL;
|
||||||
|
|
||||||
|
@ -319,8 +359,7 @@ gst_validate_report_load_issues (void)
|
||||||
_("a gstreamer plugin is missing and prevented Validate from running"),
|
_("a gstreamer plugin is missing and prevented Validate from running"),
|
||||||
NULL);
|
NULL);
|
||||||
REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED,
|
REGISTER_VALIDATE_ISSUE (CRITICAL, NOT_NEGOTIATED,
|
||||||
_("a NOT NEGOTIATED message has been emitted on the bus."),
|
_("a NOT NEGOTIATED message has been posted on the bus."), NULL);
|
||||||
NULL);
|
|
||||||
REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS,
|
REGISTER_VALIDATE_ISSUE (WARNING, WARNING_ON_BUS,
|
||||||
_("We got a WARNING message on the bus"), NULL);
|
_("We got a WARNING message on the bus"), NULL);
|
||||||
REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS,
|
REGISTER_VALIDATE_ISSUE (CRITICAL, ERROR_ON_BUS,
|
||||||
|
@ -348,10 +387,58 @@ gst_validate_report_load_issues (void)
|
||||||
REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL);
|
REGISTER_VALIDATE_ISSUE (ISSUE, G_LOG_ISSUE, _("We got a g_log issue"), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_validate_send (JsonNode * root)
|
||||||
|
{
|
||||||
|
gboolean res = FALSE;
|
||||||
|
JsonGenerator *jgen;
|
||||||
|
gsize message_length;
|
||||||
|
gchar *object, *message;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!server_ostream)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
jgen = json_generator_new ();
|
||||||
|
json_generator_set_root (jgen, root);
|
||||||
|
|
||||||
|
object = json_generator_to_data (jgen, &message_length);
|
||||||
|
message = g_malloc0 (message_length + 5);
|
||||||
|
GST_WRITE_UINT32_BE (message, message_length);
|
||||||
|
strcpy (&message[4], object);
|
||||||
|
g_free (object);
|
||||||
|
|
||||||
|
res = g_output_stream_write_all (server_ostream, message, message_length + 4,
|
||||||
|
NULL, NULL, &error);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING)) {
|
||||||
|
GST_ERROR ("Stream was busy, trying again later.");
|
||||||
|
|
||||||
|
g_free (message);
|
||||||
|
g_object_unref (jgen);
|
||||||
|
g_idle_add ((GSourceFunc) gst_validate_send, root);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_ERROR ("ERROR: Can't write to remote: %s", error->message);
|
||||||
|
} else if (!g_output_stream_flush (server_ostream, NULL, &error)) {
|
||||||
|
GST_ERROR ("ERROR: Can't flush stream: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (message);
|
||||||
|
g_object_unref (jgen);
|
||||||
|
|
||||||
|
done:
|
||||||
|
json_node_free (root);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gst_validate_report_init (void)
|
gst_validate_report_init (void)
|
||||||
{
|
{
|
||||||
const gchar *var, *file_env;
|
const gchar *var, *file_env, *server_env;
|
||||||
const GDebugKey keys[] = {
|
const GDebugKey keys[] = {
|
||||||
{"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS},
|
{"fatal_criticals", GST_VALIDATE_FATAL_CRITICALS},
|
||||||
{"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS},
|
{"fatal_warnings", GST_VALIDATE_FATAL_WARNINGS},
|
||||||
|
@ -379,6 +466,42 @@ gst_validate_report_init (void)
|
||||||
gst_validate_report_load_issues ();
|
gst_validate_report_load_issues ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
server_env = g_getenv ("GST_VALIDATE_SERVER");
|
||||||
|
if (server_env) {
|
||||||
|
GstUri *server_uri = gst_uri_from_string (server_env);
|
||||||
|
|
||||||
|
if (server_uri && !g_strcmp0 (gst_uri_get_scheme (server_uri), "tcp")) {
|
||||||
|
JsonBuilder *jbuilder;
|
||||||
|
GError *err = NULL;
|
||||||
|
socket_client = g_socket_client_new ();
|
||||||
|
|
||||||
|
server_connection = g_socket_client_connect_to_host (socket_client,
|
||||||
|
gst_uri_get_host (server_uri), gst_uri_get_port (server_uri),
|
||||||
|
NULL, &err);
|
||||||
|
|
||||||
|
if (!server_connection) {
|
||||||
|
g_clear_error (&err);
|
||||||
|
g_clear_object (&socket_client);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
server_ostream =
|
||||||
|
g_io_stream_get_output_stream (G_IO_STREAM (server_connection));
|
||||||
|
jbuilder = json_builder_new ();
|
||||||
|
json_builder_begin_object (jbuilder);
|
||||||
|
json_builder_set_member_name (jbuilder, "started");
|
||||||
|
json_builder_add_boolean_value (jbuilder, TRUE);
|
||||||
|
json_builder_end_object (jbuilder);
|
||||||
|
|
||||||
|
gst_validate_send (json_builder_get_root (jbuilder));
|
||||||
|
g_object_unref (jbuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_uri_unref (server_uri);
|
||||||
|
} else {
|
||||||
|
GST_ERROR ("Server URI not valid: %s", server_env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
file_env = g_getenv ("GST_VALIDATE_FILE");
|
file_env = g_getenv ("GST_VALIDATE_FILE");
|
||||||
if (file_env != NULL && *file_env != '\0') {
|
if (file_env != NULL && *file_env != '\0') {
|
||||||
gint i;
|
gint i;
|
||||||
|
@ -391,12 +514,11 @@ gst_validate_report_init (void)
|
||||||
g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1));
|
g_malloc0 (sizeof (FILE *) * (g_strv_length (wanted_files) + 1));
|
||||||
for (i = 0; i < g_strv_length (wanted_files); i++) {
|
for (i = 0; i < g_strv_length (wanted_files); i++) {
|
||||||
FILE *log_file;
|
FILE *log_file;
|
||||||
|
|
||||||
if (g_strcmp0 (wanted_files[i], "stderr") == 0) {
|
if (g_strcmp0 (wanted_files[i], "stderr") == 0) {
|
||||||
log_file = stderr;
|
log_file = stderr;
|
||||||
} else if (g_strcmp0 (wanted_files[i], "stdout") == 0)
|
} else if (g_strcmp0 (wanted_files[i], "stdout") == 0) {
|
||||||
log_file = stdout;
|
log_file = stdout;
|
||||||
else {
|
} else {
|
||||||
log_file = g_fopen (wanted_files[i], "w");
|
log_file = g_fopen (wanted_files[i], "w");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,6 +544,16 @@ gst_validate_report_init (void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_validate_report_deinit (void)
|
||||||
|
{
|
||||||
|
if (server_ostream)
|
||||||
|
g_output_stream_close (server_ostream, NULL, NULL);
|
||||||
|
g_clear_object (&socket_client);
|
||||||
|
g_clear_object (&server_connection);
|
||||||
|
g_clear_object (&server_ostream);
|
||||||
|
}
|
||||||
|
|
||||||
GstValidateIssue *
|
GstValidateIssue *
|
||||||
gst_validate_issue_from_id (GstValidateIssueId issue_id)
|
gst_validate_issue_from_id (GstValidateIssueId issue_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -538,6 +538,8 @@ gst_validate_runner_add_report (GstValidateRunner * runner,
|
||||||
GstValidateReportingDetails reporter_level =
|
GstValidateReportingDetails reporter_level =
|
||||||
gst_validate_reporter_get_reporting_level (report->reporter);
|
gst_validate_reporter_get_reporting_level (report->reporter);
|
||||||
|
|
||||||
|
gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE (report),
|
||||||
|
report));
|
||||||
/* Let's use our own reporting strategy */
|
/* Let's use our own reporting strategy */
|
||||||
if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) {
|
if (reporter_level == GST_VALIDATE_SHOW_UNKNOWN) {
|
||||||
gst_validate_report_set_reporting_level (report,
|
gst_validate_report_set_reporting_level (report,
|
||||||
|
@ -633,18 +635,23 @@ _do_report_synthesis (GstValidateRunner * runner)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
report = (GstValidateReport *) (reports->data);
|
report = (GstValidateReport *) (reports->data);
|
||||||
|
|
||||||
gst_validate_report_print_level (report);
|
gst_validate_report_print_level (report);
|
||||||
gst_validate_report_print_detected_on (report);
|
gst_validate_report_print_detected_on (report);
|
||||||
|
|
||||||
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
|
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
|
||||||
criticals = g_list_append (criticals, report);
|
criticals = g_list_append (criticals, report);
|
||||||
|
gst_validate_report_print_details (report);
|
||||||
|
}
|
||||||
|
|
||||||
for (tmp = g_list_next (reports); tmp; tmp = tmp->next) {
|
for (tmp = g_list_next (reports); tmp; tmp = tmp->next) {
|
||||||
report = (GstValidateReport *) (tmp->data);
|
report = (GstValidateReport *) (tmp->data);
|
||||||
gst_validate_report_print_detected_on (report);
|
gst_validate_report_print_detected_on (report);
|
||||||
|
|
||||||
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL)
|
if (report->level == GST_VALIDATE_REPORT_LEVEL_CRITICAL) {
|
||||||
criticals = g_list_append (criticals, report);
|
criticals = g_list_append (criticals, report);
|
||||||
|
gst_validate_report_print_details (report);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
report = (GstValidateReport *) (reports->data);
|
report = (GstValidateReport *) (reports->data);
|
||||||
gst_validate_report_print_description (report);
|
gst_validate_report_print_description (report);
|
||||||
|
|
|
@ -188,7 +188,7 @@ G_DEFINE_TYPE_WITH_CODE (GstValidateScenario, gst_validate_scenario,
|
||||||
_reporter_iface_init));
|
_reporter_iface_init));
|
||||||
|
|
||||||
/* GstValidateAction implementation */
|
/* GstValidateAction implementation */
|
||||||
GType _gst_validate_action_type;
|
GType _gst_validate_action_type = 0;
|
||||||
|
|
||||||
struct _GstValidateActionPrivate
|
struct _GstValidateActionPrivate
|
||||||
{
|
{
|
||||||
|
@ -204,7 +204,42 @@ struct _GstValidateActionPrivate
|
||||||
GWeakRef scenario;
|
GWeakRef scenario;
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_DEFINE_MINI_OBJECT_TYPE (GstValidateAction, gst_validate_action);
|
static JsonNode *
|
||||||
|
gst_validate_action_serialize (GstValidateAction * action)
|
||||||
|
{
|
||||||
|
JsonNode *node = json_node_alloc ();
|
||||||
|
JsonObject *jreport = json_object_new ();
|
||||||
|
gchar *action_args = gst_structure_to_string (action->structure);
|
||||||
|
|
||||||
|
json_object_set_string_member (jreport, "type", "action");
|
||||||
|
json_object_set_string_member (jreport, "action-type", action->type);
|
||||||
|
json_object_set_int_member (jreport, "playback-time",
|
||||||
|
(gint64) action->playback_time);
|
||||||
|
json_object_set_string_member (jreport, "args", action_args);
|
||||||
|
g_free (action_args);
|
||||||
|
|
||||||
|
node = json_node_init_object (node, jreport);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_validate_action_get_type (void)
|
||||||
|
{
|
||||||
|
if (_gst_validate_action_type == 0) {
|
||||||
|
_gst_validate_action_type =
|
||||||
|
g_boxed_type_register_static (g_intern_static_string
|
||||||
|
("GstValidateAction"), (GBoxedCopyFunc) gst_mini_object_ref,
|
||||||
|
(GBoxedFreeFunc) gst_mini_object_unref);
|
||||||
|
|
||||||
|
json_boxed_register_serialize_func (_gst_validate_action_type,
|
||||||
|
JSON_NODE_OBJECT,
|
||||||
|
(JsonBoxedSerializeFunc) gst_validate_action_serialize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _gst_validate_action_type;
|
||||||
|
}
|
||||||
|
|
||||||
static GstValidateAction *gst_validate_action_new (GstValidateScenario *
|
static GstValidateAction *gst_validate_action_new (GstValidateScenario *
|
||||||
scenario, GstValidateActionType * type);
|
scenario, GstValidateActionType * type);
|
||||||
static gboolean execute_next_action (GstValidateScenario * scenario);
|
static gboolean execute_next_action (GstValidateScenario * scenario);
|
||||||
|
@ -294,6 +329,9 @@ gboolean
|
||||||
_action_check_and_set_printed (GstValidateAction * action)
|
_action_check_and_set_printed (GstValidateAction * action)
|
||||||
{
|
{
|
||||||
if (action->priv->printed == FALSE) {
|
if (action->priv->printed == FALSE) {
|
||||||
|
gst_validate_send (json_boxed_serialize (GST_MINI_OBJECT_TYPE
|
||||||
|
(action), action));
|
||||||
|
|
||||||
action->priv->printed = TRUE;
|
action->priv->printed = TRUE;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -46,7 +46,7 @@ gstvalidate = shared_library('gstvalidate',
|
||||||
install: true,
|
install: true,
|
||||||
c_args : [gst_c_args],
|
c_args : [gst_c_args],
|
||||||
dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep,
|
dependencies : [gst_dep, glib_dep, gio_dep, gmodule_dep,
|
||||||
gst_pbutils_dep, mathlib])
|
gst_pbutils_dep, mathlib, json_dep])
|
||||||
|
|
||||||
validate_gen_sources = []
|
validate_gen_sources = []
|
||||||
if build_gir
|
if build_gir
|
||||||
|
|
|
@ -276,6 +276,7 @@ gst_validate_deinit (void)
|
||||||
_priv_validate_override_registry_deinit ();
|
_priv_validate_override_registry_deinit ();
|
||||||
core_config = NULL;
|
core_config = NULL;
|
||||||
validate_initialized = FALSE;
|
validate_initialized = FALSE;
|
||||||
|
gst_validate_report_deinit ();
|
||||||
|
|
||||||
g_mutex_unlock (&_gst_validate_registry_mutex);
|
g_mutex_unlock (&_gst_validate_registry_mutex);
|
||||||
g_mutex_clear (&_gst_validate_registry_mutex);
|
g_mutex_clear (&_gst_validate_registry_mutex);
|
||||||
|
|
|
@ -19,9 +19,12 @@
|
||||||
|
|
||||||
""" Class representing tests and test managers. """
|
""" Class representing tests and test managers. """
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
|
import SocketServer
|
||||||
|
import struct
|
||||||
import time
|
import time
|
||||||
import utils
|
import utils
|
||||||
import signal
|
import signal
|
||||||
|
@ -441,6 +444,33 @@ class Test(Loggable):
|
||||||
return self.result
|
return self.result
|
||||||
|
|
||||||
|
|
||||||
|
class GstValidateListener(SocketServer.BaseRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
"""Implements BaseRequestHandler handle method"""
|
||||||
|
while True:
|
||||||
|
raw_len = self.request.recv(4)
|
||||||
|
if raw_len == '':
|
||||||
|
return
|
||||||
|
msglen = struct.unpack('>I', raw_len)[0]
|
||||||
|
msg = self.request.recv(msglen)
|
||||||
|
if msg == '':
|
||||||
|
return
|
||||||
|
|
||||||
|
obj = json.loads(msg)
|
||||||
|
test = getattr(self.server, "test")
|
||||||
|
|
||||||
|
obj_type = obj.get("type", '')
|
||||||
|
if obj_type == 'position':
|
||||||
|
test.set_position(obj['position'], obj['duration'],
|
||||||
|
obj['speed'])
|
||||||
|
elif obj_type == 'buffering':
|
||||||
|
test.set_position(obj['position'], 100)
|
||||||
|
elif obj_type == 'action':
|
||||||
|
test.add_action_execution(obj)
|
||||||
|
elif obj_type == 'report':
|
||||||
|
test.add_report(obj)
|
||||||
|
|
||||||
|
|
||||||
class GstValidateTest(Test):
|
class GstValidateTest(Test):
|
||||||
|
|
||||||
""" A class representing a particular test. """
|
""" A class representing a particular test. """
|
||||||
|
@ -474,6 +504,11 @@ class GstValidateTest(Test):
|
||||||
if p:
|
if p:
|
||||||
application_name = p
|
application_name = p
|
||||||
|
|
||||||
|
self.reports = []
|
||||||
|
self.position = -1
|
||||||
|
self.duration = -1
|
||||||
|
self.speed = 1.0
|
||||||
|
self.actions_infos = []
|
||||||
self.media_descriptor = media_descriptor
|
self.media_descriptor = media_descriptor
|
||||||
|
|
||||||
override_path = self.get_override_file(media_descriptor)
|
override_path = self.get_override_file(media_descriptor)
|
||||||
|
@ -500,6 +535,57 @@ class GstValidateTest(Test):
|
||||||
self.scenario = None
|
self.scenario = None
|
||||||
else:
|
else:
|
||||||
self.scenario = scenario
|
self.scenario = scenario
|
||||||
|
self.server = None
|
||||||
|
|
||||||
|
def stop_server(self):
|
||||||
|
if self.server:
|
||||||
|
self.server.server_close()
|
||||||
|
self.server.shutdown()
|
||||||
|
self.server_thread.join()
|
||||||
|
self.server = None
|
||||||
|
|
||||||
|
def kill_subprocess(self):
|
||||||
|
Test.kill_subprocess(self)
|
||||||
|
self.stop_server()
|
||||||
|
|
||||||
|
def add_report(self, report):
|
||||||
|
self.reports.append(report)
|
||||||
|
|
||||||
|
def set_position(self, position, duration, speed=None):
|
||||||
|
self.position = position
|
||||||
|
self.duration = duration
|
||||||
|
if speed:
|
||||||
|
self.speed = speed
|
||||||
|
|
||||||
|
def add_action_execution(self, action_infos):
|
||||||
|
if action_infos['action-type'] == 'eos':
|
||||||
|
self._sent_eos_pos = time.time()
|
||||||
|
self.actions_infos.append(action_infos)
|
||||||
|
|
||||||
|
def server_wrapper(self, ready):
|
||||||
|
self.server = SocketServer.TCPServer(('localhost', 0), GstValidateListener)
|
||||||
|
self.server.socket.settimeout(0.0)
|
||||||
|
self.server.test = self
|
||||||
|
self.serverport = self.server.socket.getsockname()[1]
|
||||||
|
self.info("%s server port: %s" % (self, self.serverport))
|
||||||
|
ready.set()
|
||||||
|
|
||||||
|
# Activate the server; this will keep running until you
|
||||||
|
# interrupt the program with Ctrl-C
|
||||||
|
self.server.serve_forever()
|
||||||
|
|
||||||
|
def test_start(self, queue):
|
||||||
|
ready = threading.Event()
|
||||||
|
self.server_thread = threading.Thread(target=self.server_wrapper,
|
||||||
|
kwargs={'ready': ready})
|
||||||
|
self.server_thread.start()
|
||||||
|
ready.wait()
|
||||||
|
|
||||||
|
Test.test_start(self, queue)
|
||||||
|
|
||||||
|
def test_end(self):
|
||||||
|
Test.test_end(self)
|
||||||
|
self.stop_server()
|
||||||
|
|
||||||
def get_override_file(self, media_descriptor):
|
def get_override_file(self, media_descriptor):
|
||||||
if media_descriptor:
|
if media_descriptor:
|
||||||
|
@ -510,10 +596,12 @@ class GstValidateTest(Test):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_current_position(self):
|
||||||
|
return self.position
|
||||||
|
|
||||||
def get_current_value(self):
|
def get_current_value(self):
|
||||||
if self.scenario:
|
if self.scenario:
|
||||||
sent_eos = self.sent_eos_position()
|
if self._sent_eos_pos is not None:
|
||||||
if sent_eos is not None:
|
|
||||||
t = time.time()
|
t = time.time()
|
||||||
if ((t - sent_eos)) > 30:
|
if ((t - sent_eos)) > 30:
|
||||||
if self.media_descriptor.get_protocol() == Protocols.HLS:
|
if self.media_descriptor.get_protocol() == Protocols.HLS:
|
||||||
|
@ -528,7 +616,7 @@ class GstValidateTest(Test):
|
||||||
|
|
||||||
return Result.FAILED
|
return Result.FAILED
|
||||||
|
|
||||||
return self.get_current_position()
|
return self.position
|
||||||
|
|
||||||
def get_subproc_env(self):
|
def get_subproc_env(self):
|
||||||
self.validatelogs = self.logfile + '.validate.logs'
|
self.validatelogs = self.logfile + '.validate.logs'
|
||||||
|
@ -541,6 +629,7 @@ class GstValidateTest(Test):
|
||||||
|
|
||||||
utils.touch(self.validatelogs)
|
utils.touch(self.validatelogs)
|
||||||
subproc_env["GST_VALIDATE_FILE"] = logfiles
|
subproc_env["GST_VALIDATE_FILE"] = logfiles
|
||||||
|
subproc_env["GST_VALIDATE_SERVER"] = "tcp://localhost:%s" % self.serverport
|
||||||
self.extra_logfiles.append(self.validatelogs)
|
self.extra_logfiles.append(self.validatelogs)
|
||||||
|
|
||||||
if 'GST_DEBUG' in os.environ and not self.options.redirect_logs:
|
if 'GST_DEBUG' in os.environ and not self.options.redirect_logs:
|
||||||
|
@ -598,21 +687,15 @@ class GstValidateTest(Test):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_validate_criticals_errors(self):
|
def get_validate_criticals_errors(self):
|
||||||
ret = "["
|
ret = []
|
||||||
errors = []
|
for report in self.reports:
|
||||||
for l in open(self.validatelogs, 'r').readlines():
|
if report['level'] == 'critical':
|
||||||
if "critical : " in l:
|
ret.append(report['summary'])
|
||||||
error = l.split("critical : ")[1].replace("\n", '')
|
|
||||||
if error not in errors:
|
|
||||||
if ret != "[":
|
|
||||||
ret += ", "
|
|
||||||
ret += error
|
|
||||||
errors.append(error)
|
|
||||||
|
|
||||||
if ret == "[":
|
if not ret:
|
||||||
return None
|
return None
|
||||||
else:
|
|
||||||
return ret + "]"
|
return str(ret)
|
||||||
|
|
||||||
def check_results(self):
|
def check_results(self):
|
||||||
if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT:
|
if self.result is Result.FAILED or self.result is Result.PASSED or self.result is Result.TIMEOUT:
|
||||||
|
@ -638,89 +721,6 @@ class GstValidateTest(Test):
|
||||||
else:
|
else:
|
||||||
self.set_result(Result.PASSED)
|
self.set_result(Result.PASSED)
|
||||||
|
|
||||||
def _parse_position(self, p):
|
|
||||||
self.log("Parsing %s" % p)
|
|
||||||
times = self.findpos_regex.findall(p)
|
|
||||||
|
|
||||||
if len(times) != 1:
|
|
||||||
self.warning("Got a unparsable value: %s" % p)
|
|
||||||
return 0, 0
|
|
||||||
|
|
||||||
return (utils.gsttime_from_tuple(times[0][:4]),
|
|
||||||
utils.gsttime_from_tuple(times[0][4:]))
|
|
||||||
|
|
||||||
def _parse_buffering(self, b):
|
|
||||||
return b.lower().split("buffering... ")[1].split("%")[0], 100
|
|
||||||
|
|
||||||
def _get_position(self):
|
|
||||||
position = duration = -1
|
|
||||||
|
|
||||||
self.debug("Getting position")
|
|
||||||
m = None
|
|
||||||
for l in reversed(open(self.validatelogs, 'r').readlines()):
|
|
||||||
l = l.lower()
|
|
||||||
if "<position:" in l or "buffering" in l:
|
|
||||||
m = l
|
|
||||||
break
|
|
||||||
|
|
||||||
if m is None:
|
|
||||||
self.debug("Could not fine any positionning info")
|
|
||||||
return position, duration
|
|
||||||
|
|
||||||
for j in m.split("\r"):
|
|
||||||
j = j.lstrip().rstrip()
|
|
||||||
if j.startswith("<position:") and j.endswith("/>"):
|
|
||||||
position, duration = self._parse_position(j)
|
|
||||||
elif j.startswith("buffering") and j.endswith("%"):
|
|
||||||
position, duration = self._parse_buffering(j)
|
|
||||||
else:
|
|
||||||
self.log("No info in %s" % j)
|
|
||||||
|
|
||||||
return position, duration
|
|
||||||
|
|
||||||
def _get_last_seek_values(self):
|
|
||||||
m = None
|
|
||||||
rate = start = stop = None
|
|
||||||
|
|
||||||
for l in reversed(open(self.validatelogs, 'r').readlines()):
|
|
||||||
l = l.lower()
|
|
||||||
if "seeking to: " in l:
|
|
||||||
m = l
|
|
||||||
break
|
|
||||||
|
|
||||||
if m is None:
|
|
||||||
self.debug("Could not fine any seeking info")
|
|
||||||
return start, stop, rate
|
|
||||||
|
|
||||||
values = self.findlastseek_regex.findall(m)
|
|
||||||
if len(values) != 1:
|
|
||||||
self.warning("Got an unparsable seek value %s", m)
|
|
||||||
return start, stop, rate
|
|
||||||
|
|
||||||
v = values[0]
|
|
||||||
return (utils.gsttime_from_tuple(v[:4]),
|
|
||||||
utils.gsttime_from_tuple(v[4:8]),
|
|
||||||
float(str(v[8]) + "." + str(v[9])))
|
|
||||||
|
|
||||||
def sent_eos_position(self):
|
|
||||||
if self._sent_eos_pos is not None:
|
|
||||||
return self._sent_eos_pos
|
|
||||||
|
|
||||||
for l in reversed(open(self.validatelogs, 'r').readlines()):
|
|
||||||
l = l.lower()
|
|
||||||
if "sending eos" in l:
|
|
||||||
self._sent_eos_pos = time.time()
|
|
||||||
return self._sent_eos_pos
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_current_position(self):
|
|
||||||
position, duration = self._get_position()
|
|
||||||
if position == -1:
|
|
||||||
return position
|
|
||||||
|
|
||||||
return position
|
|
||||||
|
|
||||||
def get_valgrind_suppression_file(self, subdir, name):
|
def get_valgrind_suppression_file(self, subdir, name):
|
||||||
p = get_data_file(subdir, name)
|
p = get_data_file(subdir, name)
|
||||||
if p:
|
if p:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
inc_dirs = include_directories('.')
|
inc_dirs = include_directories('.')
|
||||||
|
|
||||||
|
json_dep = dependency('json-glib-1.0')
|
||||||
cdata = configuration_data()
|
cdata = configuration_data()
|
||||||
cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion))
|
cdata.set('GST_API_VERSION', '"@0@"'.format(apiversion))
|
||||||
cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir')))
|
cdata.set('VALIDATEPLUGINDIR', '"@0@/@1@/gstreamer-1.0/validate"'.format(get_option('prefix'),get_option('libdir')))
|
||||||
|
|
Loading…
Reference in a new issue