From 680504cd4d43a7f69dc1e6687ccf3a93e2a9acb1 Mon Sep 17 00:00:00 2001 From: Jaeyun Date: Mon, 16 Sep 2019 20:21:50 +0900 Subject: [PATCH] [Filter] add common functions Add common functions for tensor-filter and filter-single. 1. add struct for common property 2. reduce duplicated code of tensor-filter Signed-off-by: Jaeyun Jung --- api/capi/include/tensor_filter_single.h | 13 +- api/capi/src/tensor_filter_single.c | 361 ++++-------------- gst/nnstreamer/tensor_filter/tensor_filter.c | 422 ++++----------------- gst/nnstreamer/tensor_filter/tensor_filter.h | 21 +- .../tensor_filter/tensor_filter_common.c | 350 ++++++++++++++++- .../tensor_filter/tensor_filter_common.h | 92 ++--- 6 files changed, 541 insertions(+), 718 deletions(-) diff --git a/api/capi/include/tensor_filter_single.h b/api/capi/include/tensor_filter_single.h index 8756db9..aa0ba32 100644 --- a/api/capi/include/tensor_filter_single.h +++ b/api/capi/include/tensor_filter_single.h @@ -28,8 +28,7 @@ #include #include -#include -#include +#include G_BEGIN_DECLS #define G_TYPE_TENSOR_FILTER_SINGLE \ @@ -54,15 +53,7 @@ struct _GTensorFilterSingle { GObject element; /**< This is the parent object */ - void *privateData; /**< NNFW plugin's private data is stored here */ - GstTensorFilterProperties prop; /**< NNFW plugin's properties */ - const GstTensorFilterFramework *fw; /**< The implementation core of the NNFW. NULL if not configured */ - - /* internal properties for tensor_filter_single */ - gboolean silent; /**< Verbose mode if FALSE. int instead of gboolean for non-glib custom plugins */ - gboolean started; /**< filter has been started */ - GstTensorsConfig in_config; /**< input tensor info */ - GstTensorsConfig out_config; /**< output tensor info */ + GstTensorFilterPrivate priv; /**< Internal properties for tensor-filter */ }; /** diff --git a/api/capi/src/tensor_filter_single.c b/api/capi/src/tensor_filter_single.c index dec58ad..ebe0472 100644 --- a/api/capi/src/tensor_filter_single.c +++ b/api/capi/src/tensor_filter_single.c @@ -43,17 +43,13 @@ #include #include -#include -#include -#include - #include "tensor_filter_single.h" /** * @brief Macro for debug mode. */ #ifndef DBG -#define DBG (!self->silent) +#define DBG (!priv->silent) #endif #define silent_debug_info(i,msg) do { \ @@ -118,27 +114,11 @@ g_tensor_filter_single_class_init (GTensorFilterSingleClass * klass) static void g_tensor_filter_single_init (GTensorFilterSingle * self) { - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; - prop = &self->prop; - - /* init NNFW properties */ - prop->fwname = NULL; - prop->fw_opened = FALSE; - prop->input_configured = FALSE; - prop->output_configured = FALSE; - prop->model_file = NULL; - prop->custom_properties = NULL; - gst_tensors_info_init (&prop->input_meta); - gst_tensors_info_init (&prop->output_meta); - - /* init internal properties */ - self->fw = NULL; - self->privateData = NULL; - self->silent = TRUE; - self->started = FALSE; - gst_tensors_config_init (&self->in_config); - gst_tensors_config_init (&self->out_config); + priv = &self->priv; + + gst_tensor_filter_common_init_property (priv); } /** @@ -147,29 +127,18 @@ g_tensor_filter_single_init (GTensorFilterSingle * self) static void g_tensor_filter_single_finalize (GObject * object) { - gboolean status; GTensorFilterSingle *self; - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; self = G_TENSOR_FILTER_SINGLE (object); + priv = &self->priv; /** stop if not already stopped */ - if (self->started == TRUE) { - status = g_tensor_filter_single_stop (self); - g_debug ("Tensor filter single stop status: %d", status); + if (priv->configured == TRUE) { + g_tensor_filter_single_stop (self); } - prop = &self->prop; - - g_free_const (prop->fwname); - g_free_const (prop->model_file); - g_free_const (prop->custom_properties); - - gst_tensors_info_free (&prop->input_meta); - gst_tensors_info_free (&prop->output_meta); - - gst_tensors_info_free (&self->in_config.info); - gst_tensors_info_free (&self->out_config.info); + gst_tensor_filter_common_free_property (priv); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -182,205 +151,15 @@ g_tensor_filter_single_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GTensorFilterSingle *self; - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; self = G_TENSOR_FILTER_SINGLE (object); - prop = &self->prop; + priv = &self->priv; g_debug ("Setting property for prop %d.\n", prop_id); - switch (prop_id) { - case PROP_SILENT: - self->silent = g_value_get_boolean (value); - g_debug ("Debug mode = %d", self->silent); - break; - case PROP_FRAMEWORK: - { - const gchar *fw_name = g_value_get_string (value); - const GstTensorFilterFramework *fw; - - if (self->fw != NULL) { - /* close old framework */ - g_tensor_filter_single_stop (self); - } - - g_debug ("Framework = %s\n", fw_name); - - fw = nnstreamer_filter_find (fw_name); - - /* See if mandatory methods are filled in */ - if (nnstreamer_filter_validate (fw)) { - self->fw = fw; - prop->fwname = g_strdup (fw_name); - } else { - g_warning ("Cannot identify the given neural network framework, %s\n", - fw_name); - } - break; - } - case PROP_MODEL: - { - const gchar *model_files = g_value_get_string (value); - guint model_num; - - if (prop->model_file) { - g_tensor_filter_single_stop (self); - g_free_const (prop->model_file); - prop->model_file = NULL; - } - - if (prop->model_file_sub) { - g_tensor_filter_single_stop (self); - g_free_const (prop->model_file_sub); - prop->model_file_sub = NULL; - } - - /* Once configures, it cannot be changed in runtime */ - g_assert (model_files); - model_num = gst_tensor_filter_parse_modelpaths_string (prop, model_files); - if (model_num == 1) { - g_debug ("Model = %s\n", prop->model_file); - if (!g_file_test (prop->model_file, G_FILE_TEST_IS_REGULAR)) - g_critical ("Cannot find the model file: %s\n", prop->model_file); - } else if (model_num == 2) { - g_debug ("Init Model = %s\n", prop->model_file_sub); - g_debug ("Pred Model = %s\n", prop->model_file); - if (!g_file_test (prop->model_file_sub, G_FILE_TEST_IS_REGULAR)) - g_critical ("Cannot find the init model file: %s\n", - prop->model_file_sub); - if (!g_file_test (prop->model_file, G_FILE_TEST_IS_REGULAR)) - g_critical ("Cannot find the pred model file: %s\n", - prop->model_file); - } else if (model_num > 2) { - /** @todo if the new NN framework requires more than 2 model files, this area will be implemented */ - g_critical - ("There is no NN framework that requires model files more than 2. Current Input model files are :%d\n", - model_num); - } else { - g_critical ("Set model file path first\n"); - } - break; - } - case PROP_INPUT: - g_assert (!prop->input_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_dims; - - num_dims = gst_tensors_info_parse_dimensions_string (&prop->input_meta, - g_value_get_string (value)); - - if (prop->input_meta.num_tensors > 0 && - prop->input_meta.num_tensors != num_dims) { - g_warning - ("Invalid input-dim, given param does not match with old value."); - } - - prop->input_meta.num_tensors = num_dims; - } - break; - case PROP_OUTPUT: - g_assert (!prop->output_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_dims; - - num_dims = gst_tensors_info_parse_dimensions_string (&prop->output_meta, - g_value_get_string (value)); - - if (prop->output_meta.num_tensors > 0 && - prop->output_meta.num_tensors != num_dims) { - g_warning - ("Invalid output-dim, given param does not match with old value."); - } - - prop->output_meta.num_tensors = num_dims; - } - break; - case PROP_INPUTTYPE: - g_assert (!prop->input_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_types; - - num_types = gst_tensors_info_parse_types_string (&prop->input_meta, - g_value_get_string (value)); - - if (prop->input_meta.num_tensors > 0 && - prop->input_meta.num_tensors != num_types) { - g_warning - ("Invalid input-type, given param does not match with old value."); - } - - prop->input_meta.num_tensors = num_types; - } - break; - case PROP_OUTPUTTYPE: - g_assert (!prop->output_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_types; - - num_types = gst_tensors_info_parse_types_string (&prop->output_meta, - g_value_get_string (value)); - - if (prop->output_meta.num_tensors > 0 && - prop->output_meta.num_tensors != num_types) { - g_warning - ("Invalid output-type, given param does not match with old value."); - } - - prop->output_meta.num_tensors = num_types; - } - break; - case PROP_INPUTNAME: - /* INPUTNAME is required by tensorflow to designate the order of tensors */ - g_assert (!prop->input_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_names; - - num_names = gst_tensors_info_parse_names_string (&prop->input_meta, - g_value_get_string (value)); - - if (prop->input_meta.num_tensors > 0 && - prop->input_meta.num_tensors != num_names) { - g_warning - ("Invalid input-name, given param does not match with old value."); - } - - prop->input_meta.num_tensors = num_names; - } - break; - case PROP_OUTPUTNAME: - /* OUTPUTNAME is required by tensorflow to designate the order of tensors */ - g_assert (!prop->output_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_names; - - num_names = gst_tensors_info_parse_names_string (&prop->output_meta, - g_value_get_string (value)); - - if (prop->output_meta.num_tensors > 0 && - prop->output_meta.num_tensors != num_names) { - g_warning - ("Invalid output-name, given param does not match with old value."); - } - - prop->output_meta.num_tensors = num_names; - } - break; - case PROP_CUSTOM: - /* In case updated custom properties in runtime! */ - g_free_const (prop->custom_properties); - prop->custom_properties = g_value_dup_string (value); - g_debug ("Custom Option = %s\n", prop->custom_properties); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + if (!gst_tensor_filter_common_set_property (priv, prop_id, value, pspec)) + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } /** @@ -391,22 +170,15 @@ g_tensor_filter_single_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GTensorFilterSingle *self; - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; self = G_TENSOR_FILTER_SINGLE (object); - prop = &self->prop; + priv = &self->priv; g_debug ("Getting property for prop %d.\n", prop_id); - switch (prop_id) { - case PROP_SILENT: - g_value_set_boolean (value, self->silent); - break; - default: - if (!gst_tensor_filter_common_get_property (prop, prop_id, value, pspec)) - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + if (!gst_tensor_filter_common_get_property (priv, prop_id, value, pspec)) + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } /** @@ -416,10 +188,11 @@ g_tensor_filter_single_get_property (GObject * object, guint prop_id, static gboolean g_tensor_filter_input_configured (GTensorFilterSingle * self) { - if (self->prop.input_configured) - return TRUE; - else - return FALSE; + GstTensorFilterPrivate *priv; + + priv = &self->priv; + + return priv->prop.input_configured; } /** @@ -429,10 +202,11 @@ g_tensor_filter_input_configured (GTensorFilterSingle * self) static gboolean g_tensor_filter_output_configured (GTensorFilterSingle * self) { - if (self->prop.output_configured) - return TRUE; - else - return FALSE; + GstTensorFilterPrivate *priv; + + priv = &self->priv; + + return priv->prop.output_configured; } /** @@ -442,11 +216,13 @@ g_tensor_filter_output_configured (GTensorFilterSingle * self) static void g_tensor_filter_load_tensor_info (GTensorFilterSingle * self) { + GstTensorFilterPrivate *priv; GstTensorFilterProperties *prop; GstTensorsInfo in_info, out_info; int res = -1; - prop = &self->prop; + priv = &self->priv; + prop = &priv->prop; gst_tensors_info_init (&in_info); gst_tensors_info_init (&out_info); @@ -454,9 +230,9 @@ g_tensor_filter_load_tensor_info (GTensorFilterSingle * self) /* supposed fixed in-tensor info if getInputDimension is defined. */ if (!prop->input_configured) { res = -1; - if (self->prop.fw_opened && self->fw && self->fw->getInputDimension) { - res = self->fw->getInputDimension - (&self->prop, &self->privateData, &in_info); + if (priv->prop.fw_opened && priv->fw && priv->fw->getInputDimension) { + res = priv->fw->getInputDimension + (&priv->prop, &priv->privateData, &in_info); } if (res == 0) { @@ -481,9 +257,9 @@ g_tensor_filter_load_tensor_info (GTensorFilterSingle * self) /* supposed fixed out-tensor info if getOutputDimension is defined. */ if (!prop->output_configured) { res = -1; - if (self->prop.fw_opened && self->fw && self->fw->getOutputDimension) { - res = self->fw->getOutputDimension - (&self->prop, &self->privateData, &out_info); + if (priv->prop.fw_opened && priv->fw && priv->fw->getOutputDimension) { + res = priv->fw->getOutputDimension + (&priv->prop, &priv->privateData, &out_info); } if (res == 0) { @@ -518,20 +294,17 @@ done: static gboolean g_tensor_filter_single_start (GTensorFilterSingle * self) { + GstTensorFilterPrivate *priv; + + priv = &self->priv; + /** open framework, load model */ - if (self->fw == NULL) + if (priv->fw == NULL) return FALSE; - if (self->prop.fw_opened == FALSE && self->fw) { - if (self->fw->open != NULL) { - if (self->fw->open (&self->prop, &self->privateData) == 0) - self->prop.fw_opened = TRUE; - } else { - self->prop.fw_opened = TRUE; - } - } + gst_tensor_filter_common_open_fw (priv); - if (self->prop.fw_opened == FALSE) + if (priv->prop.fw_opened == FALSE) return FALSE; g_tensor_filter_load_tensor_info (self); @@ -547,17 +320,12 @@ g_tensor_filter_single_start (GTensorFilterSingle * self) static gboolean g_tensor_filter_single_stop (GTensorFilterSingle * self) { + GstTensorFilterPrivate *priv; + + priv = &self->priv; + /** close framework, unload model */ - if (self->prop.fw_opened) { - if (self->fw && self->fw->close) { - self->fw->close (&self->prop, &self->privateData); - } - self->prop.fw_opened = FALSE; - g_free_const (self->prop.fwname); - self->prop.fwname = NULL; - self->fw = NULL; - self->privateData = NULL; - } + gst_tensor_filter_common_close_fw (priv); return TRUE; } @@ -573,40 +341,41 @@ static gboolean g_tensor_filter_single_invoke (GTensorFilterSingle * self, GstTensorMemory * input, GstTensorMemory * output) { - gboolean status; - int i; + GstTensorFilterPrivate *priv; + guint i; + + priv = &self->priv; - if (G_UNLIKELY (!self->fw) || G_UNLIKELY (!self->fw->invoke_NN)) + if (G_UNLIKELY (!priv->fw) || G_UNLIKELY (!priv->fw->invoke_NN)) return FALSE; - if (G_UNLIKELY (!self->fw->run_without_model) && - G_UNLIKELY (!self->prop.model_file)) + if (G_UNLIKELY (!priv->fw->run_without_model) && + G_UNLIKELY (!priv->prop.model_file)) return FALSE; /** start if not already started */ - if (self->started == FALSE) { - status = g_tensor_filter_single_start (self); - if (status == FALSE) { - return status; + if (priv->configured == FALSE) { + if (!g_tensor_filter_single_start (self)) { + return FALSE; } - self->started = TRUE; + priv->configured = TRUE; } /** Setup output buffer */ - for (i = 0; i < self->prop.output_meta.num_tensors; i++) { + for (i = 0; i < priv->prop.output_meta.num_tensors; i++) { /* allocate memory if allocate_in_invoke is FALSE */ - if (self->fw->allocate_in_invoke == FALSE) { + if (priv->fw->allocate_in_invoke == FALSE) { output[i].data = g_malloc (output[i].size); if (!output[i].data) goto error; } } - if (self->fw->invoke_NN (&self->prop, &self->privateData, input, output) == 0) + if (priv->fw->invoke_NN (&priv->prop, &priv->privateData, input, output) == 0) return TRUE; error: - if (self->fw->allocate_in_invoke == FALSE) - for (i = 0; i < self->prop.output_meta.num_tensors; i++) + if (priv->fw->allocate_in_invoke == FALSE) + for (i = 0; i < priv->prop.output_meta.num_tensors; i++) g_free (output[i].data); return FALSE; } diff --git a/gst/nnstreamer/tensor_filter/tensor_filter.c b/gst/nnstreamer/tensor_filter/tensor_filter.c index 74b582a..a5aecb0 100644 --- a/gst/nnstreamer/tensor_filter/tensor_filter.c +++ b/gst/nnstreamer/tensor_filter/tensor_filter.c @@ -54,19 +54,15 @@ #include #endif -#include -#include -#include #include #include "tensor_filter.h" -#include "tensor_filter_common.h" /** * @brief Macro for debug mode. */ #ifndef DBG -#define DBG (!self->silent) +#define DBG (!priv->silent) #endif /** @@ -108,8 +104,6 @@ } \ } while (0) -#define REGEX_NNAPI_OPTION "(^(true|false)$|^(true|false)([:]?(cpu|gpu|npu)))" - GST_DEBUG_CATEGORY_STATIC (gst_tensor_filter_debug); #define GST_CAT_DEFAULT gst_tensor_filter_debug @@ -159,44 +153,14 @@ static gboolean gst_tensor_filter_transform_size (GstBaseTransform * trans, static gboolean gst_tensor_filter_start (GstBaseTransform * trans); static gboolean gst_tensor_filter_stop (GstBaseTransform * trans); - -/** - * @brief Open nn framework. - */ -#define gst_tensor_filter_open_fw(filter) do { \ - if (filter->prop.fw_opened == FALSE && filter->fw) { \ - if (filter->fw->open != NULL) {\ - if (filter->fw->open (&filter->prop, &filter->privateData) == 0) \ - filter->prop.fw_opened = TRUE; \ - } else {\ - filter->prop.fw_opened = TRUE; \ - } \ - } \ - } while (0) - -/** - * @brief Close nn framework. - */ -#define gst_tensor_filter_close_fw(filter) do { \ - if (filter->prop.fw_opened) { \ - if (filter->fw && filter->fw->close) \ - filter->fw->close (&filter->prop, &filter->privateData); \ - filter->prop.fw_opened = FALSE; \ - g_free_const (filter->prop.fwname); \ - filter->prop.fwname = NULL; \ - filter->fw = NULL; \ - filter->privateData = NULL; \ - } \ - } while (0) - /** * @brief Invoke callbacks of nn framework. Guarantees calling open for the first call. */ -#define gst_tensor_filter_call(filter,ret,funcname,...) do { \ - gst_tensor_filter_open_fw (filter); \ +#define gst_tensor_filter_call(priv,ret,funcname,...) do { \ + gst_tensor_filter_common_open_fw (priv); \ ret = -1; \ - if (filter->prop.fw_opened && filter->fw && filter->fw->funcname) { \ - ret = filter->fw->funcname (&filter->prop, &filter->privateData, __VA_ARGS__); \ + if (priv->prop.fw_opened && priv->fw && priv->fw->funcname) { \ + ret = priv->fw->funcname (&priv->prop, &priv->privateData, __VA_ARGS__); \ } \ } while (0) @@ -264,28 +228,11 @@ gst_tensor_filter_class_init (GstTensorFilterClass * klass) static void gst_tensor_filter_init (GstTensorFilter * self) { - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; + + priv = &self->priv; - prop = &self->prop; - - /* init NNFW properties */ - prop->fwname = NULL; - prop->fw_opened = FALSE; - prop->input_configured = FALSE; - prop->output_configured = FALSE; - prop->model_file = NULL; - prop->nnapi = NULL; - prop->custom_properties = NULL; - gst_tensors_info_init (&prop->input_meta); - gst_tensors_info_init (&prop->output_meta); - - /* init internal properties */ - self->fw = NULL; - self->privateData = NULL; - self->silent = TRUE; - self->configured = FALSE; - gst_tensors_config_init (&self->in_config); - gst_tensors_config_init (&self->out_config); + gst_tensor_filter_common_init_property (priv); } /** @@ -295,22 +242,13 @@ static void gst_tensor_filter_finalize (GObject * object) { GstTensorFilter *self; - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; self = GST_TENSOR_FILTER (object); - prop = &self->prop; + priv = &self->priv; - gst_tensor_filter_close_fw (self); - - g_free_const (prop->fwname); - g_free_const (prop->model_file); - g_free_const (prop->custom_properties); - - gst_tensors_info_free (&prop->input_meta); - gst_tensors_info_free (&prop->output_meta); - - gst_tensors_info_free (&self->in_config.info); - gst_tensors_info_free (&self->out_config.info); + gst_tensor_filter_common_close_fw (priv); + gst_tensor_filter_common_free_property (priv); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -324,11 +262,11 @@ gst_tensor_filter_finalize (GObject * object) static gsize gst_tensor_filter_get_output_size (GstTensorFilter * self, guint index) { + GstTensorFilterPrivate *priv; GstTensorsInfo *info; - g_assert (self->configured); - - info = &self->prop.output_meta; + priv = &self->priv; + info = &priv->prop.output_meta; g_assert (index < info->num_tensors); return gst_tensor_info_get_size (&info->info[index]); @@ -342,219 +280,15 @@ gst_tensor_filter_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstTensorFilter *self; - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; self = GST_TENSOR_FILTER (object); - prop = &self->prop; + priv = &self->priv; silent_debug ("Setting property for prop %d.\n", prop_id); - switch (prop_id) { - case PROP_SILENT: - self->silent = g_value_get_boolean (value); - silent_debug ("Debug mode = %d", self->silent); - break; - case PROP_FRAMEWORK: - { - const gchar *fw_name = g_value_get_string (value); - const GstTensorFilterFramework *fw; - - if (self->fw != NULL) { - /* close old framework */ - gst_tensor_filter_close_fw (self); - } - - silent_debug ("Framework = %s\n", fw_name); - - fw = nnstreamer_filter_find (fw_name); - - /* See if mandatory methods are filled in */ - if (nnstreamer_filter_validate (fw)) { - self->fw = fw; - prop->fwname = g_strdup (fw_name); - } else { - GST_WARNING_OBJECT (self, - "Cannot identify the given neural network framework, %s\n", - fw_name); - } - break; - } - case PROP_MODEL: - { - const gchar *model_files = g_value_get_string (value); - guint model_num; - - if (prop->model_file) { - gst_tensor_filter_close_fw (self); - g_free_const (prop->model_file); - prop->model_file = NULL; - } - - if (prop->model_file_sub) { - gst_tensor_filter_close_fw (self); - g_free_const (prop->model_file_sub); - prop->model_file_sub = NULL; - } - - /* Once configures, it cannot be changed in runtime */ - /** @todo by using `gst_element_get_state()`, reject configurations in RUNNING or other states */ - g_assert (model_files); - model_num = gst_tensor_filter_parse_modelpaths_string (prop, model_files); - if (model_num == 1) { - silent_debug ("Model = %s\n", prop->model_file); - if (!g_file_test (prop->model_file, G_FILE_TEST_IS_REGULAR)) - GST_ERROR_OBJECT (self, "Cannot find the model file: %s\n", - prop->model_file); - } else if (model_num == 2) { - silent_debug ("Init Model = %s\n", prop->model_file_sub); - silent_debug ("Pred Model = %s\n", prop->model_file); - if (!g_file_test (prop->model_file_sub, G_FILE_TEST_IS_REGULAR)) - GST_ERROR_OBJECT (self, "Cannot find the init model file: %s\n", - prop->model_file_sub); - if (!g_file_test (prop->model_file, G_FILE_TEST_IS_REGULAR)) - GST_ERROR_OBJECT (self, "Cannot find the pred model file: %s\n", - prop->model_file); - } else if (model_num > 2) { - /** @todo if the new NN framework requires more than 2 model files, this area will be implemented */ - GST_ERROR_OBJECT (self, - "There is no NN framework that requires model files more than 2. Current Input model files are :%d\n", - model_num); - } else { - GST_ERROR_OBJECT (self, "Set model file path first\n"); - } - break; - } - case PROP_INPUT: - g_assert (!prop->input_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_dims; - - num_dims = gst_tensors_info_parse_dimensions_string (&prop->input_meta, - g_value_get_string (value)); - - if (prop->input_meta.num_tensors > 0 && - prop->input_meta.num_tensors != num_dims) { - GST_WARNING_OBJECT (self, - "Invalid input-dim, given param does not match with old value."); - } - - prop->input_meta.num_tensors = num_dims; - } - break; - case PROP_OUTPUT: - g_assert (!prop->output_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_dims; - - num_dims = gst_tensors_info_parse_dimensions_string (&prop->output_meta, - g_value_get_string (value)); - - if (prop->output_meta.num_tensors > 0 && - prop->output_meta.num_tensors != num_dims) { - GST_WARNING_OBJECT (self, - "Invalid output-dim, given param does not match with old value."); - } - - prop->output_meta.num_tensors = num_dims; - } - break; - case PROP_INPUTTYPE: - g_assert (!prop->input_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_types; - - num_types = gst_tensors_info_parse_types_string (&prop->input_meta, - g_value_get_string (value)); - - if (prop->input_meta.num_tensors > 0 && - prop->input_meta.num_tensors != num_types) { - GST_WARNING_OBJECT (self, - "Invalid input-type, given param does not match with old value."); - } - - prop->input_meta.num_tensors = num_types; - } - break; - case PROP_OUTPUTTYPE: - g_assert (!prop->output_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_types; - - num_types = gst_tensors_info_parse_types_string (&prop->output_meta, - g_value_get_string (value)); - - if (prop->output_meta.num_tensors > 0 && - prop->output_meta.num_tensors != num_types) { - GST_WARNING_OBJECT (self, - "Invalid output-type, given param does not match with old value."); - } - - prop->output_meta.num_tensors = num_types; - } - break; - case PROP_INPUTNAME: - /* INPUTNAME is required by tensorflow to designate the order of tensors */ - g_assert (!prop->input_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_names; - - num_names = gst_tensors_info_parse_names_string (&prop->input_meta, - g_value_get_string (value)); - - if (prop->input_meta.num_tensors > 0 && - prop->input_meta.num_tensors != num_names) { - GST_WARNING_OBJECT (self, - "Invalid input-name, given param does not match with old value."); - } - - prop->input_meta.num_tensors = num_names; - } - break; - case PROP_OUTPUTNAME: - /* OUTPUTNAME is required by tensorflow to designate the order of tensors */ - g_assert (!prop->output_configured && value); - /* Once configures, it cannot be changed in runtime */ - { - guint num_names; - - num_names = gst_tensors_info_parse_names_string (&prop->output_meta, - g_value_get_string (value)); - - if (prop->output_meta.num_tensors > 0 && - prop->output_meta.num_tensors != num_names) { - GST_WARNING_OBJECT (self, - "Invalid output-name, given param does not match with old value."); - } - - prop->output_meta.num_tensors = num_names; - } - break; - case PROP_CUSTOM: - /* In case updated custom properties in runtime! */ - g_free_const (prop->custom_properties); - prop->custom_properties = g_value_dup_string (value); - silent_debug ("Custom Option = %s\n", prop->custom_properties); - break; - case PROP_NNAPI: - prop->nnapi = g_value_dup_string (value); - if (!g_regex_match_simple (REGEX_NNAPI_OPTION, prop->nnapi, 0, 0)) { - gchar *name = gst_object_get_name ((GstObject *) object); - g_critical - ("%s: nnapi: \'%s\' is not valid string: it should be in the form of BOOL:ACCELLERATOR or BOOL with a regex, " - REGEX_NNAPI_OPTION "\n", name, prop->nnapi); - g_free (name); - break; - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + if (!gst_tensor_filter_common_set_property (priv, prop_id, value, pspec)) + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } /** @@ -565,22 +299,15 @@ gst_tensor_filter_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstTensorFilter *self; - GstTensorFilterProperties *prop; + GstTensorFilterPrivate *priv; self = GST_TENSOR_FILTER (object); - prop = &self->prop; + priv = &self->priv; silent_debug ("Getting property for prop %d.\n", prop_id); - switch (prop_id) { - case PROP_SILENT: - g_value_set_boolean (value, self->silent); - break; - default: - if (!gst_tensor_filter_common_get_property (prop, prop_id, value, pspec)) - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + if (!gst_tensor_filter_common_get_property (priv, prop_id, value, pspec)) + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } /** @@ -591,6 +318,7 @@ gst_tensor_filter_transform (GstBaseTransform * trans, GstBuffer * inbuf, GstBuffer * outbuf) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; GstTensorFilterProperties *prop; GstMemory *in_mem[NNS_TENSOR_SIZE_LIMIT]; GstMapInfo in_info[NNS_TENSOR_SIZE_LIMIT]; @@ -602,20 +330,21 @@ gst_tensor_filter_transform (GstBaseTransform * trans, gint ret; self = GST_TENSOR_FILTER_CAST (trans); - prop = &self->prop; + priv = &self->priv; + prop = &priv->prop; - if (G_UNLIKELY (!self->configured)) + if (G_UNLIKELY (!priv->configured)) goto unknown_format; - if (G_UNLIKELY (!self->fw)) + if (G_UNLIKELY (!priv->fw)) goto unknown_framework; - if (G_UNLIKELY (!self->fw->run_without_model) && + if (G_UNLIKELY (!priv->fw->run_without_model) && G_UNLIKELY (!prop->model_file)) goto unknown_model; - if (G_UNLIKELY (!self->fw->invoke_NN)) + if (G_UNLIKELY (!priv->fw->invoke_NN)) goto unknown_invoke; /* 0. Check all properties. */ - silent_debug ("Invoking %s with %s model\n", self->fw->name, + silent_debug ("Invoking %s with %s model\n", priv->fw->name, GST_STR_NULL (prop->model_file)); /* 1. Set input tensors from inbuf. */ @@ -640,7 +369,7 @@ gst_tensor_filter_transform (GstBaseTransform * trans, out_tensors[i].type = prop->output_meta.info[i].type; /* allocate memory if allocate_in_invoke is FALSE */ - if (self->fw->allocate_in_invoke == FALSE) { + if (priv->fw->allocate_in_invoke == FALSE) { out_mem[i] = gst_allocator_alloc (NULL, out_tensors[i].size, NULL); g_assert (gst_memory_map (out_mem[i], &out_info[i], GST_MAP_WRITE)); @@ -649,18 +378,18 @@ gst_tensor_filter_transform (GstBaseTransform * trans, } /* 3. Call the filter-subplugin callback, "invoke" */ - gst_tensor_filter_call (self, ret, invoke_NN, in_tensors, out_tensors); + gst_tensor_filter_call (priv, ret, invoke_NN, in_tensors, out_tensors); /** @todo define enum to indicate status code */ g_assert (ret >= 0); /* 4. Update result and free map info. */ for (i = 0; i < prop->output_meta.num_tensors; i++) { - if (self->fw->allocate_in_invoke) { + if (priv->fw->allocate_in_invoke) { /* filter-subplugin allocated new memory, update this */ out_mem[i] = gst_memory_new_wrapped (0, out_tensors[i].data, out_tensors[i].size, 0, out_tensors[i].size, out_tensors[i].data, - self->fw->destroyNotify ? self->fw->destroyNotify : g_free); + priv->fw->destroyNotify ? priv->fw->destroyNotify : g_free); } else { gst_memory_unmap (out_mem[i], &out_info[i]); } @@ -713,18 +442,20 @@ unknown_invoke: static void gst_tensor_filter_load_tensor_info (GstTensorFilter * self) { + GstTensorFilterPrivate *priv; GstTensorFilterProperties *prop; GstTensorsInfo in_info, out_info; int res; - prop = &self->prop; + priv = &self->priv; + prop = &priv->prop; gst_tensors_info_init (&in_info); gst_tensors_info_init (&out_info); /* supposed fixed in-tensor info if getInputDimension is defined. */ if (!prop->input_configured) { - gst_tensor_filter_call (self, res, getInputDimension, &in_info); + gst_tensor_filter_call (priv, res, getInputDimension, &in_info); if (res == 0) { g_assert (in_info.num_tensors > 0); @@ -747,7 +478,7 @@ gst_tensor_filter_load_tensor_info (GstTensorFilter * self) /* supposed fixed out-tensor info if getOutputDimension is defined. */ if (!prop->output_configured) { - gst_tensor_filter_call (self, res, getOutputDimension, &out_info); + gst_tensor_filter_call (priv, res, getOutputDimension, &out_info); if (res == 0) { g_assert (out_info.num_tensors > 0); @@ -783,13 +514,15 @@ static gboolean gst_tensor_filter_configure_tensor (GstTensorFilter * self, const GstCaps * incaps) { + GstTensorFilterPrivate *priv; GstTensorFilterProperties *prop; GstStructure *structure; GstTensorsConfig in_config, out_config; g_return_val_if_fail (incaps != NULL, FALSE); - prop = &self->prop; + priv = &self->priv; + prop = &priv->prop; gst_tensors_config_init (&in_config); gst_tensors_config_init (&out_config); @@ -828,7 +561,7 @@ gst_tensor_filter_configure_tensor (GstTensorFilter * self, int res; gst_tensors_info_init (&out_info); - gst_tensor_filter_call (self, res, setInputDimension, &in_config.info, + gst_tensor_filter_call (priv, res, setInputDimension, &in_config.info, &out_info); if (res == 0) { @@ -866,27 +599,27 @@ gst_tensor_filter_configure_tensor (GstTensorFilter * self, out_config.rate_n = in_config.rate_n; out_config.rate_d = in_config.rate_d; - if (self->configured) { + if (priv->configured) { /** already configured, compare to old. */ - g_assert (gst_tensors_config_is_equal (&self->in_config, &in_config)); - g_assert (gst_tensors_config_is_equal (&self->out_config, &out_config)); + g_assert (gst_tensors_config_is_equal (&priv->in_config, &in_config)); + g_assert (gst_tensors_config_is_equal (&priv->out_config, &out_config)); } else { - gst_tensors_info_copy (&self->in_config.info, &in_config.info); - self->in_config.rate_n = in_config.rate_n; - self->in_config.rate_d = in_config.rate_d; + gst_tensors_info_copy (&priv->in_config.info, &in_config.info); + priv->in_config.rate_n = in_config.rate_n; + priv->in_config.rate_d = in_config.rate_d; - gst_tensors_info_copy (&self->out_config.info, &out_config.info); - self->out_config.rate_n = out_config.rate_n; - self->out_config.rate_d = out_config.rate_d; + gst_tensors_info_copy (&priv->out_config.info, &out_config.info); + priv->out_config.rate_n = out_config.rate_n; + priv->out_config.rate_d = out_config.rate_d; - self->configured = TRUE; + priv->configured = TRUE; } } done: gst_tensors_info_free (&in_config.info); gst_tensors_info_free (&out_config.info); - return self->configured; + return priv->configured; } /** @@ -935,14 +668,16 @@ gst_tensor_filter_transform_caps (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps, GstCaps * filter) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; GstTensorsConfig config; GstCaps *result; GstStructure *structure; self = GST_TENSOR_FILTER_CAST (trans); + priv = &self->priv; /* Not ready */ - if (self->fw == NULL) + if (priv->fw == NULL) return NULL; gst_tensors_config_init (&config); @@ -966,9 +701,9 @@ gst_tensor_filter_transform_caps (GstBaseTransform * trans, if (direction == GST_PAD_SINK) { /* caps: sink pad. get src pad info */ - if (self->prop.output_configured) { + if (priv->prop.output_configured) { /* fixed tensor info */ - config.info = self->prop.output_meta; + config.info = priv->prop.output_meta; result = gst_tensor_filter_caps_from_config (self, &config); } else { /* check in-tensor info to call setInputDimension */ @@ -978,7 +713,7 @@ gst_tensor_filter_transform_caps (GstBaseTransform * trans, /* call setInputDimension with given input tensor */ gst_tensors_info_init (&out_info); - gst_tensor_filter_call (self, res, setInputDimension, &config.info, + gst_tensor_filter_call (priv, res, setInputDimension, &config.info, &out_info); if (res == 0) { @@ -997,9 +732,9 @@ gst_tensor_filter_transform_caps (GstBaseTransform * trans, } } else { /* caps: src pad. get sink pad info */ - if (self->prop.input_configured) { + if (priv->prop.input_configured) { /* fixed tensor info */ - config.info = self->prop.input_meta; + config.info = priv->prop.input_meta; result = gst_tensor_filter_caps_from_config (self, &config); } else { /* we don't know the exact tensor info from src pad caps */ @@ -1035,9 +770,11 @@ gst_tensor_filter_fixate_caps (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; GstCaps *result; self = GST_TENSOR_FILTER_CAST (trans); + priv = &self->priv; silent_debug ("fixate_caps, direction = %d\n", direction); silent_debug_caps (caps, "caps"); @@ -1064,10 +801,12 @@ gst_tensor_filter_set_caps (GstBaseTransform * trans, GstCaps * incaps, GstCaps * outcaps) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; GstStructure *structure; GstTensorsConfig config; self = GST_TENSOR_FILTER_CAST (trans); + priv = &self->priv; silent_debug_caps (incaps, "incaps"); silent_debug_caps (outcaps, "outcaps"); @@ -1077,12 +816,12 @@ gst_tensor_filter_set_caps (GstBaseTransform * trans, return FALSE; } - if (!gst_tensors_config_validate (&self->in_config)) { + if (!gst_tensors_config_validate (&priv->in_config)) { GST_ERROR_OBJECT (self, "Failed to validate input tensor."); return FALSE; } - if (!gst_tensors_config_validate (&self->out_config)) { + if (!gst_tensors_config_validate (&priv->out_config)) { GST_ERROR_OBJECT (self, "Failed to validate output tensor."); return FALSE; } @@ -1091,7 +830,7 @@ gst_tensor_filter_set_caps (GstBaseTransform * trans, structure = gst_caps_get_structure (outcaps, 0); gst_tensors_config_from_structure (&config, structure); - if (!gst_tensors_config_is_equal (&self->out_config, &config)) { + if (!gst_tensors_config_is_equal (&priv->out_config, &config)) { GST_ERROR_OBJECT (self, "Invalid outcaps."); return FALSE; } @@ -1111,10 +850,12 @@ gst_tensor_filter_transform_size (GstBaseTransform * trans, GstCaps * othercaps, gsize * othersize) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; self = GST_TENSOR_FILTER_CAST (trans); + priv = &self->priv; - g_assert (self->configured); + g_assert (priv->configured); /** * Consider multi-tensors. @@ -1133,18 +874,17 @@ static gboolean gst_tensor_filter_start (GstBaseTransform * trans) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; self = GST_TENSOR_FILTER_CAST (trans); + priv = &self->priv; /* If it is not configured properly, don't allow to start! */ - if (self->fw == NULL) + if (priv->fw == NULL) return FALSE; - gst_tensor_filter_open_fw (self); - - if (self->prop.fw_opened == FALSE) - return FALSE; - return TRUE; + gst_tensor_filter_common_open_fw (priv); + return priv->prop.fw_opened; } /** @@ -1156,9 +896,11 @@ static gboolean gst_tensor_filter_stop (GstBaseTransform * trans) { GstTensorFilter *self; + GstTensorFilterPrivate *priv; self = GST_TENSOR_FILTER_CAST (trans); + priv = &self->priv; - gst_tensor_filter_close_fw (self); + gst_tensor_filter_common_close_fw (priv); return TRUE; } diff --git a/gst/nnstreamer/tensor_filter/tensor_filter.h b/gst/nnstreamer/tensor_filter/tensor_filter.h index c2db4cf..6d6bf40 100644 --- a/gst/nnstreamer/tensor_filter/tensor_filter.h +++ b/gst/nnstreamer/tensor_filter/tensor_filter.h @@ -29,7 +29,6 @@ #ifndef __GST_TENSOR_FILTER_H__ #define __GST_TENSOR_FILTER_H__ -#include #include #include #include @@ -37,6 +36,7 @@ #include "tensor_common.h" #include "nnstreamer_subplugin.h" #include "nnstreamer_plugin_api_filter.h" +#include "tensor_filter_common.h" G_BEGIN_DECLS @@ -62,27 +62,10 @@ struct _GstTensorFilter { GstBaseTransform element; /**< This is the parent object */ - void *privateData; /**< NNFW plugin's private data is stored here */ - GstTensorFilterProperties prop; /**< NNFW plugin's properties */ - const GstTensorFilterFramework *fw; /**< The implementation core of the NNFW. NULL if not configured */ - - /* internal properties for tensor-filter */ - gboolean silent; /**< Verbose mode if FALSE. int instead of gboolean for non-glib custom plugins */ - gboolean configured; /**< True if already successfully configured tensor metadata */ - GstTensorsConfig in_config; /**< input tensor info */ - GstTensorsConfig out_config; /**< output tensor info */ + GstTensorFilterPrivate priv; /**< Internal properties for tensor-filter */ }; /** - * @brief Location of GstTensorFilter from privateData - * @param p the "privateData" pointer of GstTensorFilter - * @return the pointer to GstTensorFilter containing p as privateData - */ -#define GstTensorFilter_of_privateData(p) ({ \ - const void **__mptr = (const void **)(p); \ - (GstTensorFilter *)( (char *)__mptr - offsetof(GstTensorFilter, privateData) );}) - -/** * @brief GstTensorFilterClass inherits GstBaseTransformClass. * * Referring another child (sibiling), GstVideoFilter (abstract class) and diff --git a/gst/nnstreamer/tensor_filter/tensor_filter_common.c b/gst/nnstreamer/tensor_filter/tensor_filter_common.c index b628161..99d082a 100644 --- a/gst/nnstreamer/tensor_filter/tensor_filter_common.c +++ b/gst/nnstreamer/tensor_filter/tensor_filter_common.c @@ -29,10 +29,37 @@ #include "tensor_filter_common.h" +#define REGEX_NNAPI_OPTION "(^(true|false)$|^(true|false)([:]?(cpu|gpu|npu)))" + +/** + * @brief Free memory + */ +#define g_free_const(x) g_free((void*)(long)(x)) + +/** + * @brief GstTensorFilter properties. + */ +enum +{ + PROP_0, + PROP_SILENT, + PROP_FRAMEWORK, + PROP_MODEL, + PROP_INPUT, + PROP_INPUTTYPE, + PROP_INPUTNAME, + PROP_OUTPUT, + PROP_OUTPUTTYPE, + PROP_OUTPUTNAME, + PROP_CUSTOM, + PROP_SUBPLUGINS, + PROP_NNAPI +}; + /** * @brief Validate filter sub-plugin's data. */ -gboolean +static gboolean nnstreamer_filter_validate (const GstTensorFilterFramework * tfsp) { if (!tfsp || !tfsp->name) { @@ -87,14 +114,13 @@ nnstreamer_filter_find (const char *name) return get_subplugin (NNS_SUBPLUGIN_FILTER, name); } - /** * @brief Parse the string of model * @param[out] prop Struct containing the properties of the object * @param[in] model_files the prediction model paths * @return number of parsed model path */ -guint +static guint gst_tensor_filter_parse_modelpaths_string (GstTensorFilterProperties * prop, const gchar * model_files) { @@ -281,20 +307,292 @@ gst_tensor_filter_install_properties (GObjectClass * gobject_class) } /** + * @brief Initialize the properties for tensor-filter. + */ +void +gst_tensor_filter_common_init_property (GstTensorFilterPrivate * priv) +{ + GstTensorFilterProperties *prop; + + prop = &priv->prop; + + /* init NNFW properties */ + prop->fwname = NULL; + prop->fw_opened = FALSE; + prop->input_configured = FALSE; + prop->output_configured = FALSE; + prop->model_file = NULL; + prop->nnapi = NULL; + prop->custom_properties = NULL; + gst_tensors_info_init (&prop->input_meta); + gst_tensors_info_init (&prop->output_meta); + + /* init internal properties */ + priv->fw = NULL; + priv->privateData = NULL; + priv->silent = TRUE; + priv->configured = FALSE; + gst_tensors_config_init (&priv->in_config); + gst_tensors_config_init (&priv->out_config); +} + +/** + * @brief Free the properties for tensor-filter. + */ +void +gst_tensor_filter_common_free_property (GstTensorFilterPrivate * priv) +{ + GstTensorFilterProperties *prop; + + prop = &priv->prop; + + g_free_const (prop->fwname); + g_free_const (prop->model_file); + g_free_const (prop->custom_properties); + + gst_tensors_info_free (&prop->input_meta); + gst_tensors_info_free (&prop->output_meta); + + gst_tensors_info_free (&priv->in_config.info); + gst_tensors_info_free (&priv->out_config.info); +} + +/** + * @brief Set the properties for tensor_filter + * @param[in] priv Struct containing the properties of the object + * @param[in] prop_id Id for the property + * @param[in] value Container to return the asked property + * @param[in] pspec Metadata to specify the parameter + * @return TRUE if prop_id is value, else FALSE + */ +gboolean +gst_tensor_filter_common_set_property (GstTensorFilterPrivate * priv, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstTensorFilterProperties *prop; + + prop = &priv->prop; + + switch (prop_id) { + case PROP_SILENT: + priv->silent = g_value_get_boolean (value); + break; + case PROP_FRAMEWORK: + { + const gchar *fw_name = g_value_get_string (value); + const GstTensorFilterFramework *fw; + + if (priv->fw != NULL) { + /* close old framework */ + gst_tensor_filter_common_close_fw (priv); + } + + g_debug ("Framework = %s\n", fw_name); + + fw = nnstreamer_filter_find (fw_name); + + /* See if mandatory methods are filled in */ + if (nnstreamer_filter_validate (fw)) { + priv->fw = fw; + prop->fwname = g_strdup (fw_name); + } else { + g_warning ("Cannot identify the given neural network framework, %s\n", + fw_name); + } + break; + } + case PROP_MODEL: + { + const gchar *model_files = g_value_get_string (value); + guint model_num; + + if (prop->model_file) { + gst_tensor_filter_common_close_fw (priv); + g_free_const (prop->model_file); + prop->model_file = NULL; + } + + if (prop->model_file_sub) { + gst_tensor_filter_common_close_fw (priv); + g_free_const (prop->model_file_sub); + prop->model_file_sub = NULL; + } + + /* Once configures, it cannot be changed in runtime */ + g_assert (model_files); + model_num = gst_tensor_filter_parse_modelpaths_string (prop, model_files); + if (model_num == 1) { + if (!g_file_test (prop->model_file, G_FILE_TEST_IS_REGULAR)) + g_critical ("Cannot find the model file: %s\n", prop->model_file); + } else if (model_num == 2) { + if (!g_file_test (prop->model_file_sub, G_FILE_TEST_IS_REGULAR)) + g_critical ("Cannot find the init model file: %s\n", + prop->model_file_sub); + if (!g_file_test (prop->model_file, G_FILE_TEST_IS_REGULAR)) + g_critical ("Cannot find the pred model file: %s\n", + prop->model_file); + } else if (model_num > 2) { + /** @todo if the new NN framework requires more than 2 model files, this area will be implemented */ + g_critical + ("There is no NN framework that requires model files more than 2. Current Input model files are :%d\n", + model_num); + } else { + g_critical ("Set model file path first\n"); + } + break; + } + case PROP_INPUT: + g_assert (!prop->input_configured && value); + /* Once configures, it cannot be changed in runtime */ + { + guint num_dims; + + num_dims = gst_tensors_info_parse_dimensions_string (&prop->input_meta, + g_value_get_string (value)); + + if (prop->input_meta.num_tensors > 0 && + prop->input_meta.num_tensors != num_dims) { + g_warning + ("Invalid input-dim, given param does not match with old value."); + } + + prop->input_meta.num_tensors = num_dims; + } + break; + case PROP_OUTPUT: + g_assert (!prop->output_configured && value); + /* Once configures, it cannot be changed in runtime */ + { + guint num_dims; + + num_dims = gst_tensors_info_parse_dimensions_string (&prop->output_meta, + g_value_get_string (value)); + + if (prop->output_meta.num_tensors > 0 && + prop->output_meta.num_tensors != num_dims) { + g_warning + ("Invalid output-dim, given param does not match with old value."); + } + + prop->output_meta.num_tensors = num_dims; + } + break; + case PROP_INPUTTYPE: + g_assert (!prop->input_configured && value); + /* Once configures, it cannot be changed in runtime */ + { + guint num_types; + + num_types = gst_tensors_info_parse_types_string (&prop->input_meta, + g_value_get_string (value)); + + if (prop->input_meta.num_tensors > 0 && + prop->input_meta.num_tensors != num_types) { + g_warning + ("Invalid input-type, given param does not match with old value."); + } + + prop->input_meta.num_tensors = num_types; + } + break; + case PROP_OUTPUTTYPE: + g_assert (!prop->output_configured && value); + /* Once configures, it cannot be changed in runtime */ + { + guint num_types; + + num_types = gst_tensors_info_parse_types_string (&prop->output_meta, + g_value_get_string (value)); + + if (prop->output_meta.num_tensors > 0 && + prop->output_meta.num_tensors != num_types) { + g_warning + ("Invalid output-type, given param does not match with old value."); + } + + prop->output_meta.num_tensors = num_types; + } + break; + case PROP_INPUTNAME: + /* INPUTNAME is required by tensorflow to designate the order of tensors */ + g_assert (!prop->input_configured && value); + /* Once configures, it cannot be changed in runtime */ + { + guint num_names; + + num_names = gst_tensors_info_parse_names_string (&prop->input_meta, + g_value_get_string (value)); + + if (prop->input_meta.num_tensors > 0 && + prop->input_meta.num_tensors != num_names) { + g_warning + ("Invalid input-name, given param does not match with old value."); + } + + prop->input_meta.num_tensors = num_names; + } + break; + case PROP_OUTPUTNAME: + /* OUTPUTNAME is required by tensorflow to designate the order of tensors */ + g_assert (!prop->output_configured && value); + /* Once configures, it cannot be changed in runtime */ + { + guint num_names; + + num_names = gst_tensors_info_parse_names_string (&prop->output_meta, + g_value_get_string (value)); + + if (prop->output_meta.num_tensors > 0 && + prop->output_meta.num_tensors != num_names) { + g_warning + ("Invalid output-name, given param does not match with old value."); + } + + prop->output_meta.num_tensors = num_names; + } + break; + case PROP_CUSTOM: + /* In case updated custom properties in runtime! */ + g_free_const (prop->custom_properties); + prop->custom_properties = g_value_dup_string (value); + g_debug ("Custom Option = %s\n", prop->custom_properties); + break; + case PROP_NNAPI: + prop->nnapi = g_value_dup_string (value); + if (!g_regex_match_simple (REGEX_NNAPI_OPTION, prop->nnapi, 0, 0)) { + g_critical + ("nnapi: \'%s\' is not valid string: it should be in the form of BOOL:ACCELLERATOR or BOOL with a regex, " + REGEX_NNAPI_OPTION "\n", prop->nnapi); + break; + } + break; + default: + return FALSE; + } + + return TRUE; +} + +/** * @brief Get the properties for tensor_filter - * @param[in] prop Struct containing the properties of the object + * @param[in] priv Struct containing the properties of the object * @param[in] prop_id Id for the property * @param[in] value Container to return the asked property * @param[in] pspec Metadata to specify the parameter * @return TRUE if prop_id is value, else FALSE */ gboolean -gst_tensor_filter_common_get_property (GstTensorFilterProperties * prop, +gst_tensor_filter_common_get_property (GstTensorFilterPrivate * priv, guint prop_id, GValue * value, GParamSpec * pspec) { - gboolean ret = TRUE; + GstTensorFilterProperties *prop; + + prop = &priv->prop; switch (prop_id) { + case PROP_SILENT: + g_value_set_boolean (value, priv->silent); + break; case PROP_FRAMEWORK: g_value_set_string (value, prop->fwname); break; @@ -413,9 +711,43 @@ gst_tensor_filter_common_get_property (GstTensorFilterProperties * prop, g_value_set_string (value, prop->nnapi); break; default: - ret = FALSE; - break; + /* unknown property */ + return FALSE; + } + + return TRUE; +} + +/** + * @brief Open NN framework. + */ +void +gst_tensor_filter_common_open_fw (GstTensorFilterPrivate * priv) +{ + if (!priv->prop.fw_opened && priv->fw) { + if (priv->fw->open) { + if (priv->fw->open (&priv->prop, &priv->privateData) == 0) + priv->prop.fw_opened = TRUE; + } else { + priv->prop.fw_opened = TRUE; + } } +} - return ret; +/** + * @brief Close NN framework. + */ +void +gst_tensor_filter_common_close_fw (GstTensorFilterPrivate * priv) +{ + if (priv->prop.fw_opened) { + if (priv->fw && priv->fw->close) { + priv->fw->close (&priv->prop, &priv->privateData); + } + priv->prop.fw_opened = FALSE; + g_free_const (priv->prop.fwname); + priv->prop.fwname = NULL; + priv->fw = NULL; + priv->privateData = NULL; + } } diff --git a/gst/nnstreamer/tensor_filter/tensor_filter_common.h b/gst/nnstreamer/tensor_filter/tensor_filter_common.h index 5b86a35..9b46770 100644 --- a/gst/nnstreamer/tensor_filter/tensor_filter_common.h +++ b/gst/nnstreamer/tensor_filter/tensor_filter_common.h @@ -25,53 +25,25 @@ #ifndef __G_TENSOR_FILTER_COMMON_H__ #define __G_TENSOR_FILTER_COMMON_H__ -#include - #include #include #include /** - * @brief Free memory + * @brief Structure definition for common tensor-filter properties. */ -#define g_free_const(x) g_free((void*)(long)(x)) - -/** - * @brief GstTensorFilter properties. - */ -enum +typedef struct _GstTensorFilterPrivate { - PROP_0, - PROP_SILENT, - PROP_FRAMEWORK, - PROP_MODEL, - PROP_INPUT, - PROP_INPUTTYPE, - PROP_INPUTNAME, - PROP_OUTPUT, - PROP_OUTPUTTYPE, - PROP_OUTPUTNAME, - PROP_CUSTOM, - PROP_SUBPLUGINS, - PROP_NNAPI -}; + void *privateData; /**< NNFW plugin's private data is stored here */ + GstTensorFilterProperties prop; /**< NNFW plugin's properties */ + const GstTensorFilterFramework *fw; /**< The implementation core of the NNFW. NULL if not configured */ -/** - * @brief Validate filter sub-plugin's data. - */ -extern gboolean -nnstreamer_filter_validate (const GstTensorFilterFramework * tfsp); - -/** - * @brief Parse the string of model - * @param[out] prop Struct containing the properties of the object - * @param[in] model_files the prediction model paths - * @return number of parsed model path - * @todo Create a struct list to save multiple model files with key, value pair - */ -extern guint -gst_tensor_filter_parse_modelpaths_string (GstTensorFilterProperties * prop, - const gchar * model_files); + /* internal properties for tensor-filter */ + gboolean silent; /**< Verbose mode if FALSE. int instead of gboolean for non-glib custom plugins */ + gboolean configured; /**< True if already successfully configured tensor metadata */ + GstTensorsConfig in_config; /**< input tensor info */ + GstTensorsConfig out_config; /**< output tensor info */ +} GstTensorFilterPrivate; /** * @brief Printout the comparison results of two tensors. @@ -83,7 +55,6 @@ extern void gst_tensor_filter_compare_tensors (GstTensorsInfo * info1, GstTensorsInfo * info2); - /** * @brief Installs all the properties for tensor_filter * @param[in] gobject_class Glib object class whose properties will be set @@ -91,17 +62,52 @@ gst_tensor_filter_compare_tensors (GstTensorsInfo * info1, extern void gst_tensor_filter_install_properties (GObjectClass * gobject_class); +/** + * @brief Initialize the properties for tensor-filter. + */ +extern void +gst_tensor_filter_common_init_property (GstTensorFilterPrivate * priv); + +/** + * @brief Free the properties for tensor-filter. + */ +extern void +gst_tensor_filter_common_free_property (GstTensorFilterPrivate * priv); + +/** + * @brief Set the properties for tensor_filter + * @param[in] priv Struct containing the properties of the object + * @param[in] prop_id Id for the property + * @param[in] value Container to return the asked property + * @param[in] pspec Metadata to specify the parameter + * @return TRUE if prop_id is value, else FALSE + */ +extern gboolean +gst_tensor_filter_common_set_property (GstTensorFilterPrivate * priv, + guint prop_id, const GValue * value, GParamSpec * pspec); /** * @brief Get the properties for tensor_filter - * @param[in] prop Struct containing the properties of the object + * @param[in] priv Struct containing the properties of the object * @param[in] prop_id Id for the property * @param[in] value Container to return the asked property * @param[in] pspec Metadata to specify the parameter * @return TRUE if prop_id is value, else FALSE */ extern gboolean -gst_tensor_filter_common_get_property (GstTensorFilterProperties *prop, - guint prop_id, GValue *value, GParamSpec *pspec); +gst_tensor_filter_common_get_property (GstTensorFilterPrivate * priv, + guint prop_id, GValue * value, GParamSpec * pspec); + +/** + * @brief Open NN framework. + */ +extern void +gst_tensor_filter_common_open_fw (GstTensorFilterPrivate * priv); + +/** + * @brief Close NN framework. + */ +extern void +gst_tensor_filter_common_close_fw (GstTensorFilterPrivate * priv); #endif /* __G_TENSOR_FILTER_COMMON_H__ */ -- 2.7.4