tensor_transform
tensor_filter
tensor_repopush
+ tensor_repopop
)
ADD_SUBDIRECTORY(nnstreamer_example)
NNSTREAMER_PLUGIN (tensor_transform);
NNSTREAMER_PLUGIN (tensor_filter);
NNSTREAMER_PLUGIN (tensor_repopush);
+NNSTREAMER_PLUGIN (tensor_repopop);
#define NNSTREAMER_INIT(name, plugin) \
do { \
NNSTREAMER_INIT (tensor_transform, plugin);
NNSTREAMER_INIT (tensor_filter, plugin);
NNSTREAMER_INIT (tensor_repopush, plugin);
+ NNSTREAMER_INIT (tensor_repopop, plugin);
return TRUE;
}
#include <stdio.h>
#ifndef DBG
-#define DBG TRUE
+#define DBG FALSE
#endif
#define _print_log(...) if (DBG) g_message(__VA_ARGS__)
* @brief add GstTensorData into repo
*/
gboolean
-gst_tensor_repo_add_data (GstTensorData * data, guint myid)
+gst_tensor_repo_add_data (guint myid)
{
gboolean ret = FALSE;
-
- if (!_repo.initialized)
- gst_tensor_repo_init ();
+ GstTensorData *new;
GST_REPO_LOCK ();
- ret = g_hash_table_insert (_repo.hash, GINT_TO_POINTER (myid), data);
+ gpointer *check = g_hash_table_lookup (_repo.hash, GINT_TO_POINTER (myid));
+
+ if (check != NULL) {
+ return TRUE;
+ }
+
+ new = g_new (GstTensorData, 1);
+ new->eos = FALSE;
+ new->buffer = NULL;
+ g_cond_init (&new->cond);
+ g_mutex_init (&new->lock);
+
+ ret = g_hash_table_insert (_repo.hash, GINT_TO_POINTER (myid), new);
g_assert (ret);
_print_log ("Successfully added in hash table with key[%d]", myid);
g_return_val_if_fail (data != NULL, FALSE);
data->buffer = buffer;
- _print_log ("Buffer Updated : Buffer Size[%lu]\n",
+ _print_log ("Pushed [%d] (size : %lu)\n", nth,
gst_buffer_get_size (data->buffer));
- GST_TENSOR_REPO_BROADCAST (nth);
+
+ GST_TENSOR_REPO_SIGNAL (nth);
GST_TENSOR_REPO_UNLOCK (nth);
return TRUE;
}
/**
+ * @brief check eos of slot
+ */
+gboolean
+gst_tensor_repo_check_eos (guint nth)
+{
+ GST_TENSOR_REPO_LOCK (nth);
+ GstTensorData *data = gst_tensor_repo_get_tensor (nth);
+ GST_TENSOR_REPO_UNLOCK (nth);
+ return data->eos;
+}
+
+/**
+ * @brief set eos of slot
+ */
+gboolean
+gst_tensor_repo_set_eos (guint nth)
+{
+ GST_TENSOR_REPO_LOCK (nth);
+ GstTensorData *data = gst_tensor_repo_get_tensor (nth);
+ data->eos = TRUE;
+ GST_TENSOR_REPO_UNLOCK (nth);
+ return data->eos;
+}
+
+
+/**
* @brief pop GstTensorData from repo
*/
-GstTensorData *
+GstBuffer *
gst_tensor_repopop_buffer (guint nth)
{
- GST_TENSOR_REPO_LOCK (nth);
- GstTensorData *current_data, *data;
+ GstTensorData *current_data;
+ GstBuffer *buf;
current_data = gst_tensor_repo_get_tensor (nth);
- while (!current_data)
+ GST_TENSOR_REPO_LOCK (nth);
+ while (!current_data->buffer)
GST_TENSOR_REPO_WAIT (nth);
- data = current_data;
- current_data = NULL;
+ buf = gst_buffer_copy_deep (current_data->buffer);
+ _print_log ("Popped [ %d ] (size: %lu)\n", nth, gst_buffer_get_size (buf));
+ current_data->buffer = NULL;
GST_TENSOR_REPO_UNLOCK (nth);
- return data;
+ return buf;
}
/**
void
gst_tensor_repo_init ()
{
+ if (_repo.initialized)
+ return;
+
_repo.num_data = 0;
g_mutex_init (&_repo.repo_lock);
+ g_cond_init (&_repo.repo_cond);
+ GST_REPO_LOCK ();
_repo.hash = g_hash_table_new (g_direct_hash, g_direct_equal);
_repo.initialized = TRUE;
+ GST_REPO_BROADCAST ();
+ GST_REPO_UNLOCK ();
+}
+
+/**
+ * @brief wait for finish of initialization
+ */
+gboolean
+gst_tensor_repo_wait ()
+{
+ GST_REPO_LOCK ();
+ while (!_repo.initialized)
+ GST_REPO_WAIT ();
+ GST_REPO_UNLOCK ();
+ return TRUE;
}
typedef struct
{
- GstTensorConfig *config;
GstBuffer *buffer;
GCond cond;
GMutex lock;
+ gboolean eos;
} GstTensorData;
/**
{
gint num_data;
GMutex repo_lock;
+ GCond repo_cond;
GHashTable* hash;
gboolean initialized;
} GstTensorRepo;
*/
/* guint */
gboolean
-gst_tensor_repo_add_data (GstTensorData * data, guint myid);
+gst_tensor_repo_add_data (guint myid);
/**
* @brief push GstBuffer into repo
gst_tensor_repo_push_buffer (guint nth, GstBuffer * buffer);
/**
+ * @brief get EOS
+ */
+gboolean
+gst_tensor_repo_check_eos(guint nth);
+
+/**
+ * @brief set EOS
+ */
+gboolean
+gst_tensor_repo_set_eos(guint nth);
+
+/**
* @brief pop GstTensorData from repo
*/
-GstTensorData *
+GstBuffer *
gst_tensor_repopop_buffer (guint nth);
/**
void
gst_tensor_repo_init ();
+/**
+ * @brief Wait for the repo initialization
+ */
+gboolean
+gst_tensor_repo_wait();
+
/**
* @brief Macro for Lock & Cond
#define GST_TENSOR_REPO_LOCK(id) (g_mutex_lock(GST_TENSOR_REPO_GET_LOCK(id)))
#define GST_TENSOR_REPO_UNLOCK(id) (g_mutex_unlock(GST_TENSOR_REPO_GET_LOCK(id)))
#define GST_TENSOR_REPO_WAIT(id) (g_cond_wait(GST_TENSOR_REPO_GET_COND(id), GST_TENSOR_REPO_GET_LOCK(id)))
-#define GST_TENSOR_REPO_BROADCAST(id) (g_cond_broadcast (GST_TENSOR_REPO_GET_COND(id)))
+#define GST_TENSOR_REPO_SIGNAL(id) (g_cond_signal (GST_TENSOR_REPO_GET_COND(id)))
#define GST_REPO_LOCK()(g_mutex_lock(&_repo.repo_lock))
#define GST_REPO_UNLOCK()(g_mutex_unlock(&_repo.repo_lock))
+#define GST_REPO_WAIT() (g_cond_wait(&_repo.repo_cond, &_repo.repo_lock))
+#define GST_REPO_BROADCAST() (g_cond_broadcast (&_repo.repo_cond))
G_END_DECLS
#endif /* __GST_TENSOR_REPO_H__ */
{
PROP_0,
PROP_CAPS,
+ PROP_SLOT_ID,
PROP_SILENT
};
#define DEFAULT_SILENT TRUE
+#define DEFAULT_INDEX 0
+/**
+ * @brief external repo
+ */
extern GstTensorRepo _repo;
/**
static void gst_tensor_repopop_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_tensor_repopop_dispose (GObject * object);
-static gboolean gst_tensor_repopop_query (GstBaseSrc * src, GstQuery * query);
static GstCaps *gst_tensor_repopop_getcaps (GstBaseSrc * src, GstCaps * filter);
+static GstFlowReturn gst_tensor_repopop_create (GstPushSrc * src,
+ GstBuffer ** buffer);
#define gst_tensor_repopop_parent_class parent_class
G_DEFINE_TYPE (GstTensorRepoPop, gst_tensor_repopop, GST_TYPE_PUSH_SRC);
+/**
+ * @brief class initialization of tensor_repopop
+ */
static void
gst_tensor_repopop_class_init (GstTensorRepoPopClass * klass)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (kalss);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
- GstBaseSrcClass *basesrc_class = GST_BASE_SRC_CLASS (kalss);
+ GstBaseSrcClass *basesrc_class = GST_BASE_SRC_CLASS (klass);
gobject_class->set_property = gst_tensor_repopop_set_property;
gobject_class->get_property = gst_tensor_repopop_get_property;
g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_SLOT_ID,
+ g_param_spec_uint ("slot-index", "Slot Index", "repository slot index",
+ 0, UINT_MAX, DEFAULT_INDEX,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gobject_class->dispose = gst_tensor_repopop_dispose;
basesrc_class->get_caps = gst_tensor_repopop_getcaps;
- basesrc_class->query = gst_tensor_repopop_query;
-
pushsrc_class->create = gst_tensor_repopop_create;
gst_element_class_set_static_metadata (element_class,
gst_element_class_add_static_pad_template (element_class, &src_template);
}
+/**
+ * @brief object initialization of tensor_repopop
+ */
static void
gst_tensor_repopop_init (GstTensorRepoPop * self)
{
self->silent = TRUE;
-
+ self->ini = FALSE;
+ gst_tensors_config_init (&self->config);
+ self->caps = NULL;
}
+/**
+ * @brief object dispose of tensor_repopop
+ */
+static void
+gst_tensor_repopop_dispose (GObject * object)
+{
+ gboolean ret;
+ GstTensorRepoPop *self = GST_TENSOR_REPOPOP (object);
+ ret = gst_tensor_repo_remove_data (self->myid);
+ if (!ret)
+ GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
+ ("Cannot remove [key: %d] in repo", self->myid), NULL);
+ if (self->caps)
+ gst_caps_unref (self->caps);
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+/**
+ * @brief get cap of tensor_repopop
+ */
+static GstCaps *
+gst_tensor_repopop_getcaps (GstBaseSrc * src, GstCaps * filter)
+{
+ GstCaps *cap;
+ GstTensorRepoPop *self = GST_TENSOR_REPOPOP (src);
+
+ GST_DEBUG_OBJECT (self, "returning %" GST_PTR_FORMAT, self->caps);
+
+ if (self->caps) {
+ if (filter) {
+ cap =
+ gst_caps_intersect_full (filter, self->caps,
+ GST_CAPS_INTERSECT_FIRST);
+ } else
+ cap = gst_caps_ref (self->caps);
+ } else {
+ if (filter) {
+ cap = gst_caps_ref (filter);
+ } else
+ cap = gst_caps_new_any ();
+ }
+
+ return cap;
+}
+/**
+ * @brief set property of tensor_repopop
+ */
+static void
+gst_tensor_repopop_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstTensorRepoPop *self = GST_TENSOR_REPOPOP (object);
+
+ switch (prop_id) {
+ case PROP_SILENT:
+ self->silent = g_value_get_boolean (value);
+ break;
+ case PROP_SLOT_ID:
+ self->myid = g_value_get_uint (value);
+ break;
+ case PROP_CAPS:
+ {
+ GstStructure *st = NULL;
+ const GstCaps *caps = gst_value_get_caps (value);
+ GstCaps *new_caps;
+
+ if (caps == NULL) {
+ new_caps = gst_caps_new_any ();
+ } else {
+ new_caps = gst_caps_copy (caps);
+ }
+ gst_caps_replace (&self->caps, new_caps);
+ gst_pad_set_caps (GST_BASE_SRC_PAD (self), new_caps);
+ st = gst_caps_get_structure (new_caps, 0);
+
+ gst_tensors_config_from_structure (&self->config, st);
+
+ if (new_caps && gst_caps_get_size (new_caps) == 1 && st
+ && gst_structure_get_fraction (st, "framerate", &self->fps_n,
+ &self->fps_d)) {
+ GST_INFO_OBJECT (self, "Seting framerate to %d/%d", self->fps_n,
+ self->fps_d);
+ } else {
+ self->fps_n = -1;
+ self->fps_d = -1;
+ }
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+/**
+ * @brief get property of tensor_repopop
+ */
+static void
+gst_tensor_repopop_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstTensorRepoPop *self = GST_TENSOR_REPOPOP (object);
+
+ switch (prop_id) {
+ case PROP_SILENT:
+ g_value_set_boolean (value, self->silent);
+ break;
+ case PROP_SLOT_ID:
+ g_value_set_uint (value, self->myid);
+ break;
+ case PROP_CAPS:
+ gst_value_set_caps (value, self->caps);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+/**
+ * @brief create func of tensor_repopop
+ */
+static GstFlowReturn
+gst_tensor_repopop_create (GstPushSrc * src, GstBuffer ** buffer)
+{
+ GstTensorRepoPop *self;
+ GstBuffer *buf;
+ self = GST_TENSOR_REPOPOP (src);
+ gst_tensor_repo_wait ();
+ if (gst_tensor_repo_check_eos (self->myid))
+ return GST_FLOW_EOS;
+ if (!self->ini) {
+ int i;
+ guint num_tensors = self->config.info.num_tensors;
+ gsize size = 0;
+ for (i = 0; i < num_tensors; i++)
+ size += gst_tensor_info_get_size (&self->config.info.info[i]);
+ buf = gst_buffer_new_and_alloc (size);
+ gst_buffer_memset (buf, 0, 0, size);
+ self->ini = TRUE;
+ } else {
+ buf = gst_tensor_repopop_buffer (self->myid);
+ }
+ *buffer = buf;
-
-
-
-
-
-
-
-
-
-
+ return GST_FLOW_OK;
+}
/**
* @brief Function to initialize the plugin.
return gst_element_register (plugin, "tensor_repopop",
GST_RANK_NONE, GST_TYPE_TENSOR_REPOPOP);
}
-
-#ifndef SINGLE_BINARY
-/**
- * @brief Definition for identifying tensor_repopop plugin.
- *
- * PACKAGE: this is usually set by autotools depending on some _INIT macro
- * in configure.ac and then written into and defined in config.h, but we can
- * just set it ourselves here in case someone doesn't use autotools to
- * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined.
- */
-#ifndef PACKAGE
-#define PACKAGE "nnstreamer"
-#endif
-
-/**
- * @brief Macro to define the entry point of the plugin.
- */
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- tensor_repopop,
- "Pop element to handle tensor repository",
- gst_tensor_repopop_plugin_init, VERSION, "LGPL", "nnstreamer",
- "https://github.com/nnsuite/nnstreamer");
-#endif
*/
struct _GstTensorRepoPop
{
+ GstPushSrc parent;
GstBaseSink element;
-
+ GstTensorsConfig config;
gboolean silent;
- GstCaps *caps;
- GstTensorData data;
guint myid;
+ GstCaps *caps;
+ gboolean ini;
+ gint fps_n, fps_d;
};
/**
*/
struct _GstTensorRepoPopClass
{
- GstBaseSinkClass parent_class;
+ GstPushSrcClass parent_class;
};
/**
static gboolean gst_tensor_repopush_start (GstBaseSink * sink);
static gboolean gst_tensor_repopush_stop (GstBaseSink * sink);
+static gboolean gst_tensor_repopush_event (GstBaseSink * sink,
+ GstEvent * event);
static gboolean gst_tensor_repopush_query (GstBaseSink * sink,
GstQuery * query);
static GstFlowReturn gst_tensor_repopush_render (GstBaseSink * sink,
basesink_class->start = GST_DEBUG_FUNCPTR (gst_tensor_repopush_start);
basesink_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_repopush_stop);
+ basesink_class->event = GST_DEBUG_FUNCPTR (gst_tensor_repopush_event);
basesink_class->query = GST_DEBUG_FUNCPTR (gst_tensor_repopush_query);
basesink_class->render = GST_DEBUG_FUNCPTR (gst_tensor_repopush_render);
basesink_class->render_list =
static void
gst_tensor_repopush_init (GstTensorRepoPush * self)
{
- gboolean ret = FALSE;
GstBaseSink *basesink;
basesink = GST_BASE_SINK (self);
- self->data.config = NULL;
- self->data.buffer = NULL;
+ gst_tensor_repo_init ();
- g_mutex_init (&self->data.lock);
- g_cond_init (&self->data.cond);
-
- ret = gst_tensor_repo_add_data (&self->data, self->myid);
- g_assert (ret);
-
-<<<<<<< HEAD
-=======
- silent_debug ("GstTensorData is sucessfully added : key[%d]", self->myid);
->>>>>>> [Repo/Push] Use Has Table to handle repo & add slot_id property
+ silent_debug ("GstTensorRepo is sucessfully initailzed");
self->silent = DEFAULT_SILENT;
self->signal_rate = DEFAULT_SIGNAL_RATE;
break;
case PROP_SLOT:
self->myid = g_value_get_uint (value);
+ gst_tensor_repo_add_data (self->myid);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
static void
gst_tensor_repopush_dispose (GObject * object)
{
- gboolean ret;
GstTensorRepoPush *self;
self = GST_TENSOR_REPOPUSH (object);
- ret = gst_tensor_repo_remove_data (self->myid);
- if (!ret)
- GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
- ("Cannot remove [key: %d] in repo", self->myid), NULL);
+ if (self->in_caps)
+ gst_caps_unref (self->in_caps);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
/**
}
/**
+ * @brief Handle events.
+ *
+ * GstBaseSink method implementation.
+ */
+static gboolean
+gst_tensor_repopush_event (GstBaseSink * sink, GstEvent * event)
+{
+ GstTensorRepoPush *self;
+ GstEventType type;
+
+ self = GST_TENSOR_REPOPUSH (sink);
+ type = GST_EVENT_TYPE (event);
+
+ silent_debug ("received event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (type) {
+ case GST_EVENT_EOS:
+ gst_tensor_repo_set_eos (self->myid);
+ break;
+
+ default:
+ break;
+ }
+
+ return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
+}
+
+/**
* @brief query vmethod implementation
*/
static gboolean
GstTensorRepoPush *self;
self = GST_TENSOR_REPOPUSH (sink);
+
gst_tensor_repopush_render_buffer (self, buffer);
return GST_FLOW_OK;
}
GstTensorRepoPush *self;
self = GST_TENSOR_REPOPUSH (sink);
-
- GST_TENSOR_REPO_LOCK (self->myid);
gst_caps_replace (&self->in_caps, caps);
- GST_TENSOR_REPO_UNLOCK (self->myid);
return TRUE;
}
self = GST_TENSOR_REPOPUSH (sink);
- GST_TENSOR_REPO_LOCK (self->myid);
caps = self->in_caps;
if (caps) {
gst_caps_ref (caps);
}
}
- GST_TENSOR_REPO_UNLOCK (self->myid);
return caps;
}
guint signal_rate;
GstClockTime last_render_time;
GstCaps *in_caps;
- GstTensorData data;
guint myid;
- guint slot_index;
-
};
/**