/* GStreamer * * Copyright (C) 2013 Collabora Ltd. * Author: Thiago Sousa Santos * * validate.c - Validate generic functions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /** * SECTION:validate * @short_description: Initialize GstValidate */ #ifdef HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include /* For g_stat () */ #include #include #include #include "validate.h" #include "gst-validate-utils.h" #include "gst-validate-internal.h" #ifdef G_OS_WIN32 #define WIN32_LEAN_AND_MEAN /* prevents from including too many things */ #include /* GetStdHandle, windows console */ HMODULE _priv_gstvalidate_dll_handle = NULL; #endif /* G_OS_WIN32 */ GST_DEBUG_CATEGORY (gstvalidate_debug); static GMutex _gst_validate_registry_mutex; static GstRegistry *_gst_validate_registry_default = NULL; static GList *core_config = NULL; static gboolean validate_initialized = FALSE; GstClockTime _priv_start_time; #ifdef G_OS_WIN32 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { if (fdwReason == DLL_PROCESS_ATTACH) _priv_gstvalidate_dll_handle = (HMODULE) hinstDLL; return TRUE; } #endif /* G_OS_WIN32 */ static GstRegistry * gst_validate_registry_get (void) { GstRegistry *registry; g_mutex_lock (&_gst_validate_registry_mutex); if (G_UNLIKELY (!_gst_validate_registry_default)) { _gst_validate_registry_default = g_object_new (GST_TYPE_REGISTRY, NULL); gst_object_ref_sink (GST_OBJECT_CAST (_gst_validate_registry_default)); } registry = _gst_validate_registry_default; g_mutex_unlock (&_gst_validate_registry_mutex); return registry; } #define GST_VALIDATE_PLUGIN_CONFIG "gst-validate-plugin-config" static void _free_plugin_config (gpointer data) { g_list_free_full (data, (GDestroyNotify) gst_structure_free); } static GList * create_config (const gchar * path, const gchar * suffix) { GList *structures = NULL, *tmp, *result = NULL; if (!suffix) return NULL; structures = gst_validate_utils_structs_parse_from_filename (path); for (tmp = structures; tmp; tmp = tmp->next) { GstStructure *structure = tmp->data; if (gst_structure_has_name (structure, suffix)) result = g_list_append (result, structure); else gst_structure_free (structure); } g_list_free (structures); return result; } /* Copied from gststructure.c to avoid assertion */ static gboolean gst_structure_validate_name (const gchar * name) { const gchar *s; g_return_val_if_fail (name != NULL, FALSE); if (G_UNLIKELY (!g_ascii_isalpha (*name))) { GST_INFO ("Invalid character '%c' at offset 0 in structure name: %s", *name, name); return FALSE; } /* FIXME: test name string more */ s = &name[1]; while (*s && (g_ascii_isalnum (*s) || strchr ("/-_.:+", *s) != NULL)) s++; if (*s == ',') return TRUE; if (G_UNLIKELY (*s != '\0')) { GST_INFO ("Invalid character '%c' at offset %" G_GUINTPTR_FORMAT " in" " structure name: %s", *s, ((guintptr) s - (guintptr) name), name); return FALSE; } return TRUE; } /** * gst_validate_plugin_get_config: * @plugin, a #GstPlugin, or #NULL * * Return the configuration specific to @plugin, or the "core" one if @plugin * is #NULL * * Returns: (transfer none) (element-type GstStructure): a list of #GstStructure */ GList * gst_validate_plugin_get_config (GstPlugin * plugin) { GList *plugin_conf = NULL; const gchar *suffix; const gchar *config; GStrv tmp; guint i; if (plugin) { if ((plugin_conf = g_object_get_data (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG))) return plugin_conf; suffix = gst_plugin_get_name (plugin); } else { if (core_config) return core_config; suffix = "core"; } config = g_getenv ("GST_VALIDATE_CONFIG"); if (!config) return NULL; tmp = g_strsplit (config, G_SEARCHPATH_SEPARATOR_S, -1); for (i = 0; tmp[i] != NULL; i++) { GList *l; l = create_config (tmp[i], suffix); if (l) plugin_conf = g_list_concat (plugin_conf, l); } g_strfreev (tmp); if (!plugin_conf) { GstCaps *confs = NULL; if (gst_structure_validate_name (config)) confs = gst_caps_from_string (config); if (confs) { gint i; for (i = 0; i < gst_caps_get_size (confs); i++) { GstStructure *structure = gst_caps_get_structure (confs, i); if (gst_structure_has_name (structure, suffix)) plugin_conf = g_list_append (plugin_conf, gst_structure_copy (structure)); } gst_caps_unref (confs); } } if (plugin) g_object_set_data_full (G_OBJECT (plugin), GST_VALIDATE_PLUGIN_CONFIG, plugin_conf, _free_plugin_config); else core_config = plugin_conf; return plugin_conf; } static void gst_validate_init_plugins (void) { GstRegistry *registry; const gchar *plugin_path; gst_registry_fork_set_enabled (FALSE); registry = gst_validate_registry_get (); plugin_path = g_getenv ("GST_VALIDATE_PLUGIN_PATH"); if (plugin_path) { char **list; int i; GST_DEBUG ("GST_VALIDATE_PLUGIN_PATH set to %s", plugin_path); list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0); for (i = 0; list[i]; i++) { gst_registry_scan_path (registry, list[i]); } g_strfreev (list); } else { GST_DEBUG ("GST_VALIDATE_PLUGIN_PATH not set"); } if (plugin_path == NULL) { char *home_plugins; /* plugins in the user's home directory take precedence over * system-installed ones */ home_plugins = g_build_filename (g_get_user_data_dir (), "gstreamer-" GST_API_VERSION, "plugins", NULL); GST_DEBUG ("scanning home plugins %s", home_plugins); gst_registry_scan_path (registry, home_plugins); g_free (home_plugins); /* add the main (installed) library path */ #ifdef G_OS_WIN32 { char *base_dir; char *dir; base_dir = g_win32_get_package_installation_directory_of_module (_priv_gstvalidate_dll_handle); dir = g_build_filename (base_dir, "lib", "gstreamer-" GST_API_VERSION, "validate", NULL); GST_DEBUG ("scanning DLL dir %s", dir); gst_registry_scan_path (registry, dir); g_free (dir); g_free (base_dir); } #else gst_registry_scan_path (registry, VALIDATEPLUGINDIR); #endif } gst_registry_fork_set_enabled (TRUE); } /** * gst_validate_init: * * Initializes GstValidate. Call this before any usage of GstValidate. * You should take care of initializing GStreamer before calling this * function. */ void gst_validate_init (void) { if (validate_initialized) { return; } GST_DEBUG_CATEGORY_INIT (gstvalidate_debug, "validate", 0, "Validation library"); _priv_start_time = gst_util_get_timestamp (); /* init the report system (can be called multiple times) */ gst_validate_report_init (); /* Init the scenario system */ init_scenarios (); /* Ensure we load overrides before any use of a monitor */ gst_validate_override_registry_preload (); validate_initialized = TRUE; gst_validate_init_plugins (); gst_validate_init_runner (); } void gst_validate_deinit (void) { g_mutex_lock (&_gst_validate_registry_mutex); _free_plugin_config (core_config); gst_validate_deinit_runner (); gst_validate_scenario_deinit (); g_clear_object (&_gst_validate_registry_default); _priv_validate_override_registry_deinit (); core_config = NULL; validate_initialized = FALSE; gst_validate_report_deinit (); g_mutex_unlock (&_gst_validate_registry_mutex); g_mutex_clear (&_gst_validate_registry_mutex); } gboolean gst_validate_is_initialized (void) { return validate_initialized; }