--- /dev/null
+/**
+ * NNStreamer Subplugin Manager
+ * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * 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 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.
+ *
+ */
+/**
+ * @file nnstreamer_subplugin.c
+ * @date 27 Nov 2018
+ * @brief Subplugin Manager for NNStreamer
+ * @see http://github.com/nnsuite/nnstreamer
+ * @author MyungJoo Ham <myungjoo.ham@samsung.com>
+ * @bug No known bugs except for NYI items
+ *
+ */
+
+#include <dlfcn.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <gst/gstinfo.h>
+#include "nnstreamer_subplugin.h"
+#include "nnstreamer_conf.h"
+
+typedef struct
+{
+ char *name; /**< The name of subplugin */
+ const void *data; /**< subplugin specific data forwarded from the subplugin */
+ void *handle; /**< dlopen'ed handle */
+} subpluginData;
+
+static GHashTable *subplugins[NNS_SUBPLUGIN_END] = { 0 };
+
+G_LOCK_DEFINE_STATIC (splock);
+
+/** @brief Private function for g_hash_table data destructor, GDestroyNotify */
+static void
+_spdata_destroy (gpointer _data)
+{
+ subpluginData *data = _data;
+ g_free (data->name);
+ if (data->handle)
+ dlclose (data->handle);
+ g_free (data);
+}
+
+/** @brief Public function defined in the header */
+const void *
+get_subplugin (subpluginType type, const char *name)
+{
+ GHashTable *table;
+ subpluginData *data;
+ void *handle;
+
+ G_LOCK (splock);
+
+ if (subplugins[type] == NULL)
+ subplugins[type] =
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ _spdata_destroy);
+
+ table = subplugins[type];
+ data = g_hash_table_lookup (table, name);
+
+ if (data == NULL) {
+ /* Search and register if found with the conf */
+ const gchar *fullpath = nnsconf_get_fullpath (name, type);
+ char *dlsym_error;
+ nnstreamer_subplugin_data *nsdata;
+
+ if (fullpath == NULL)
+ goto error; /* No Such Thing !!! */
+
+ handle = dlopen (fullpath, RTLD_NOW);
+ if (NULL == handle) {
+ GST_ERROR ("Cannot dlopen %s (%s).", name, fullpath);
+ goto error;
+ }
+
+ nsdata = (nnstreamer_subplugin_data *)
+ dlsym (handle, "nnstreamer_subplugin");
+ dlsym_error = dlerror ();
+
+ if (NULL == nsdata) {
+ GST_ERROR ("nnstreamer_subplugin does not exists in %s (%s)", name,
+ fullpath);
+ goto error_handle;
+ }
+ if (dlsym_error) {
+ GST_ERROR ("Loading nnstreamer_subplugin in %s (%s) incurs: %s", name,
+ fullpath, dlsym_error);
+ goto error_handle;
+ }
+
+ if (nsdata->checker != NNS_SUBPLUGIN_CHECKER) {
+ GST_ERROR ("nnstreamer_subplugin of %s (%s) is broken (first bytes)",
+ name, fullpath);
+ goto error_handle;
+ }
+
+ if (nsdata->type != type) {
+ GST_ERROR ("nnstreamer_subplugin of %s (%s) is broken (type mismatch)",
+ name, fullpath);
+ goto error_handle;
+ }
+
+ if (g_strcmp0 (nsdata->name, name)) {
+ GST_ERROR ("nnstreamer_subplugin of %s (%s) is broken (name mismatch)",
+ name, fullpath);
+ goto error_handle;
+ }
+
+ g_assert (TRUE == register_subplugin (type, name, nsdata->data));
+ g_assert ((data = g_hash_table_lookup (table, name)) != NULL);
+ data->handle = handle;
+ }
+ G_UNLOCK (splock);
+ return data->data;
+
+error_handle:
+ dlclose (handle);
+error:
+ G_UNLOCK (splock);
+ return NULL;
+}
+
+/** @brief Public function defined in the header */
+gboolean
+register_subplugin (subpluginType type, const char *name, const void *data)
+{
+ /** @todo data out of scope at add */
+ subpluginData *spdata = g_new (subpluginData, 1);
+ gboolean ret;
+
+ spdata->name = g_strdup (name);
+ spdata->data = data;
+ spdata->handle = NULL;
+
+ if (subplugins[type] == NULL)
+ subplugins[type] =
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+ _spdata_destroy);
+
+ G_LOCK (splock);
+ ret = g_hash_table_insert (subplugins[type], g_strdup (name), spdata);
+ G_UNLOCK (splock);
+
+ return ret;
+}
+
+/** @brief Public function defined in the header */
+gboolean
+unregister_subplugin (subpluginType type, const char *name)
+{
+ gboolean ret;
+ if (subplugins[type] == NULL)
+ return FALSE;
+
+ G_LOCK (splock);
+ ret = g_hash_table_remove (subplugins[type], name);
+ G_UNLOCK (splock);
+
+ return ret;
+}
--- /dev/null
+/**
+ * NNStreamer Subplugin Manager
+ * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * 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 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.
+ *
+ */
+/**
+ * @file nnstreamer_subplugin.h
+ * @date 27 Nov 2018
+ * @brief Subplugin Manager for NNStreamer
+ * @see http://github.com/nnsuite/nnstreamer
+ * @author MyungJoo Ham <myungjoo.ham@samsung.com>
+ * @bug No known bugs except for NYI items
+ *
+ * To Packagers:
+ *
+ * This fils it to be packaged as "devel" package for NN developers. (subplugin writers)
+ *
+ * @note Any independent subplugin (existing as an independent .so)
+ * should have an exported variable "nnstreamer_subplugin",
+ * whose type is nnstreamer_subplugin_data.
+ * A built-in subplugin (existing in libnnstreamer.so) does not
+ * need this.
+ */
+#ifndef __GST_NNSTREAMER_SUBPLUGIN_H__
+#define __GST_NNSTREAMER_SUBPLUGIN_H__
+
+#include <stdint.h>
+#include "nnstreamer_conf.h"
+
+typedef enum {
+ NNS_SUBPLUGIN_FILTER = NNSCONF_FILTERS,
+ NNS_SUBPLUGIN_DECODER = NNSCONF_DECODERS,
+
+ NNS_SUBPLUGIN_END,
+} subpluginType;
+
+#define NNS_SUBPLUGIN_CHECKER (0xdeadbeef)
+
+/**
+ * @brief Any independent shared object subplugin must export this as
+ * "nnstreamer_subplugin"
+ */
+typedef struct {
+ uint32_t checker; /**< This MUST be 0xdeadbeef (NNS_SUBPLUGIN_CHECKER) */
+ subpluginType type; /**< The subplugin type */
+ const char *name; /**< The name of subplugin. The resulting .so file should be ${prefix}${name}.so */
+ void *data; /**< Subplugin specific data (usually funcptr callbacks), forwarded to subplugin's corresponding handler */
+} nnstreamer_subplugin_data;
+
+/**
+ * @brief Retrieve the resigered data with the subplugin name.
+ * @param[in] type Subplugin Type
+ * @param[in] name Subplugin Name. The filename should be libnnstreamer_${type}_${name}.so
+ * @return The registered data
+ */
+extern const void *
+get_subplugin (subpluginType type, const char *name);
+
+/**
+ * @brief Register the subplugin. If duplicated name exists, it is rejected.
+ * @param[in] type Subplugin Type
+ * @param[in] name Subplugin Name. The filename should be subplugin_prefixes[type]${name}.so
+ * @param[in] data The registered data
+ * @return TRUE if regitered as new. FALSE if duplicated (overwritten/updated).
+ */
+extern gboolean
+register_subplugin (subpluginType type, const char *name, const void *data);
+
+/**
+ * @brief Unregister the subplugin.
+ * @param[in] type Subplugin type
+ * @param[in] name Subplugin Name. The filename should be subplugin_prefixes[type]${name}.so
+ * @return TRUE if unregitered. FALSE if rejected or error.
+ *
+ * @warning Subplugins checked out with get_subplugins can still be used after unregister.
+ */
+extern gboolean
+unregister_subplugin (subpluginType type, const char *name);
+
+#endif /* __GST_NNSTREAMER_SUBPLUGIN_H__ */