[TensorFilter] Add Add a callback of tensor filter for model update in runtime
authorDongju Chae <dongju.chae@samsung.com>
Mon, 9 Dec 2019 11:17:11 +0000 (20:17 +0900)
committerGeunsik Lim <leemgs@users.noreply.github.com>
Tue, 10 Dec 2019 11:24:20 +0000 (20:24 +0900)
This commit adds a callback, reloadModel(), of tensor filter for model
update in runtime. When the model property is updated, this callback
will be called if is-updatable is TRUE.

Also, it adds an event handler to update a model in the same pipeline.
On receiving a model update event, it calls set_property() of PROP_MODEL.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
gst/nnstreamer/nnstreamer_plugin_api_filter.h
gst/nnstreamer/tensor_filter/tensor_filter.c
gst/nnstreamer/tensor_filter/tensor_filter_common.c
gst/nnstreamer/tensor_filter/tensor_filter_common.h

index 09d18b7..2d3637e 100644 (file)
@@ -202,6 +202,15 @@ typedef struct _GstTensorFilterFramework
        *
        * @param[in] data the data element.
        */
+
+  int (*reloadModel) (const GstTensorFilterProperties * prop, void **private_data);
+      /**< Optional. tensor_filter.c will call it when a model property is newly configured.
+       * @todo add more detail comments.
+       *
+       * @param[in] prop read-only property values
+       * @param[in/out] private_data A subplugin may save its internal private data here. The subplugin is responsible for alloc/free of this pointer. Normally, close() frees private_data and set NULL.
+       * @return 0 if ok. < 0 if error.
+       */
 } GstTensorFilterFramework;
 
 /* extern functions for subplugin management, exist in tensor_filter.c */
index 362caf4..b3827c7 100644 (file)
@@ -58,6 +58,9 @@
 
 #include "tensor_filter.h"
 
+/** @todo rename & move this to better location */
+#define EVENT_NAME_UPDATE_MODEL "evt_update_model"
+
 /**
  * @brief Macro for debug mode.
  */
@@ -152,6 +155,8 @@ static gboolean gst_tensor_filter_transform_size (GstBaseTransform * trans,
     GstCaps * othercaps, gsize * othersize);
 static gboolean gst_tensor_filter_start (GstBaseTransform * trans);
 static gboolean gst_tensor_filter_stop (GstBaseTransform * trans);
+static gboolean gst_tensor_filter_sink_event (GstBaseTransform * trans,
+    GstEvent * event);
 
 /**
  * @brief Invoke callbacks of nn framework. Guarantees calling open for the first call.
@@ -214,6 +219,9 @@ gst_tensor_filter_class_init (GstTensorFilterClass * klass)
   trans_class->transform_size =
       GST_DEBUG_FUNCPTR (gst_tensor_filter_transform_size);
 
+  /* setup sink event */
+  trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_tensor_filter_sink_event);
+
   /* start/stop to call open/close */
   trans_class->start = GST_DEBUG_FUNCPTR (gst_tensor_filter_start);
   trans_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_filter_stop);
@@ -869,6 +877,53 @@ gst_tensor_filter_transform_size (GstBaseTransform * trans,
 }
 
 /**
+ * @brief Event handler for sink pad of tensor filter.
+ * @param trans "this" pointer
+ * @param event a passed event object
+ * @return TRUE if there is no error.
+ */
+static gboolean
+gst_tensor_filter_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstTensorFilter *self;
+  GstTensorFilterPrivate *priv;
+
+  self = GST_TENSOR_FILTER_CAST (trans);
+  priv = &self->priv;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+    {
+      const GstStructure *structure = gst_event_get_structure (event);
+      int ret = -1;
+
+      if (structure == NULL ||
+          !gst_structure_has_name (structure, EVENT_NAME_UPDATE_MODEL))
+        break;
+
+      if (priv->is_updatable) {
+        const GValue *value =
+            gst_structure_get_value (structure, "model_files");
+
+        if (value != NULL) {
+          g_object_set (self, "model", value, NULL);
+          ret = 0;
+        }
+      }
+
+      gst_event_unref (event);
+
+      return (ret == 0);
+    }
+    default:
+      break;
+  }
+
+  /** other events are handled in the default event handler */
+  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
+}
+
+/**
  * @brief Called when the element starts processing. optional vmethod of BaseTransform
  * @param trans "this" pointer
  * @return TRUE if there is no error.
index f84e9d7..6273add 100644 (file)
@@ -67,7 +67,7 @@ enum
   PROP_CUSTOM,
   PROP_SUBPLUGINS,
   PROP_ACCELERATOR,
-  PROP_UPDATABLE_MODEL,
+  PROP_IS_UPDATABLE,
 };
 
 /**
@@ -270,8 +270,8 @@ gst_tensor_filter_install_properties (GObjectClass * gobject_class)
           "list of accelerators determines the backend (ignored with false). "
           "Example, if GPU, NPU can be used but not CPU - true:(GPU,NPU,!CPU).",
           "", G_PARAM_READWRITE));
-  g_object_class_install_property (gobject_class, PROP_UPDATABLE_MODEL,
-      g_param_spec_string ("is-updatable", "Updatable model",
+  g_object_class_install_property (gobject_class, PROP_IS_UPDATABLE,
+      g_param_spec_boolean ("is-updatable", "Updatable model",
           "Indicate whether a given model to this tensor filter is "
           "updatable in runtime. (e.g., with on-device training)",
           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
@@ -388,6 +388,16 @@ gst_tensor_filter_common_set_property (GstTensorFilterPrivate * priv,
               idx, prop->model_files[idx]);
         }
       }
+
+      /* reload model if FW has been already opened */
+      if (priv->prop.fw_opened && priv->is_updatable) {
+        if (priv->fw && priv->fw->reloadModel) {
+          if (priv->fw->reloadModel (&priv->prop, &priv->privateData) != 0) {
+            g_critical ("Fail to reload model\n");
+          }
+        }
+      }
+
       break;
     }
     case PROP_INPUT:
@@ -534,9 +544,10 @@ gst_tensor_filter_common_set_property (GstTensorFilterPrivate * priv,
 
       break;
     }
-    case PROP_UPDATABLE_MODEL:
+    case PROP_IS_UPDATABLE:
     {
-      priv->updatable_model = g_value_get_boolean (value);
+      if (priv->fw->reloadModel != NULL)
+        priv->is_updatable = g_value_get_boolean (value);
       break;
     }
     default:
@@ -704,8 +715,8 @@ gst_tensor_filter_common_get_property (GstTensorFilterPrivate * priv,
         g_value_set_string (value, "");
       }
       break;
-    case PROP_UPDATABLE_MODEL:
-      g_value_set_boolean (value, priv->updatable_model);
+    case PROP_IS_UPDATABLE:
+      g_value_set_boolean (value, priv->is_updatable);
       break;
     default:
       /* unknown property */
index 8ec66bc..66560d8 100644 (file)
@@ -41,7 +41,7 @@ typedef struct _GstTensorFilterPrivate
   /* 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 */
-  gboolean updatable_model; /**<  a given model to the filter is updatable if TRUE */
+  gboolean is_updatable; /**<  a given model to the filter is updatable if TRUE */
   GstTensorsConfig in_config; /**< input tensor info */
   GstTensorsConfig out_config; /**< output tensor info */
 } GstTensorFilterPrivate;