[Filter] add common functions
authorJaeyun <jy1210.jung@samsung.com>
Mon, 16 Sep 2019 11:21:50 +0000 (20:21 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Wed, 18 Sep 2019 01:21:51 +0000 (10:21 +0900)
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 <jy1210.jung@samsung.com>
api/capi/include/tensor_filter_single.h
api/capi/src/tensor_filter_single.c
gst/nnstreamer/tensor_filter/tensor_filter.c
gst/nnstreamer/tensor_filter/tensor_filter.h
gst/nnstreamer/tensor_filter/tensor_filter_common.c
gst/nnstreamer/tensor_filter/tensor_filter_common.h

index 8756db9..aa0ba32 100644 (file)
@@ -28,8 +28,7 @@
 #include <stdint.h>
 #include <glib-object.h>
 
-#include <nnstreamer/nnstreamer_subplugin.h>
-#include <nnstreamer/nnstreamer_plugin_api_filter.h>
+#include <nnstreamer/tensor_filter/tensor_filter_common.h>
 
 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 */
 };
 
 /**
index dec58ad..ebe0472 100644 (file)
 #include <glib.h>
 #include <string.h>
 
-#include <nnstreamer/nnstreamer_plugin_api.h>
-#include <nnstreamer/tensor_typedef.h>
-#include <nnstreamer/tensor_filter/tensor_filter_common.h>
-
 #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;
 }
index 74b582a..a5aecb0 100644 (file)
 #include <config.h>
 #endif
 
-#include <gst/gstinfo.h>
-#include <gst/gst.h>
-#include <glib.h>
 #include <string.h>
 
 #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
 
 /**
   } \
 } 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;
 }
index c2db4cf..6d6bf40 100644 (file)
@@ -29,7 +29,6 @@
 #ifndef __GST_TENSOR_FILTER_H__
 #define __GST_TENSOR_FILTER_H__
 
-#include <stdint.h>
 #include <gst/gst.h>
 #include <gst/gstinfo.h>
 #include <gst/base/gstbasetransform.h>
@@ -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
index b628161..99d082a 100644 (file)
 
 #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;
+  }
 }
index 5b86a35..9b46770 100644 (file)
 #ifndef __G_TENSOR_FILTER_COMMON_H__
 #define __G_TENSOR_FILTER_COMMON_H__
 
-#include <glib-object.h>
-
 #include <nnstreamer_subplugin.h>
 #include <nnstreamer_plugin_api.h>
 #include <nnstreamer_plugin_api_filter.h>
 
 /**
- * @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__ */