gstreamer/validate/gst/validate/validate.c

343 lines
8.4 KiB
C

/* GStreamer
*
* Copyright (C) 2013 Collabora Ltd.
* Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
*
* 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 <string.h>
/* For g_stat () */
#include <glib/gstdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#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 <windows.h> /* 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;
}