[Android] private data to set metadata
authorJaeyun <jy1210.jung@samsung.com>
Wed, 3 Jun 2020 05:19:06 +0000 (14:19 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Mon, 8 Jun 2020 04:30:03 +0000 (13:30 +0900)
Each invoke callback gets/returns tensor data object including metadata.
To improve performance, Cache tensor metadata object and avoid duplicated conversion.

Signed-off-by: Jaeyun <jy1210.jung@samsung.com>
api/android/api/src/main/jni/nnstreamer-native-api.c
api/android/api/src/main/jni/nnstreamer-native-customfilter.c
api/android/api/src/main/jni/nnstreamer-native-pipeline.c
api/android/api/src/main/jni/nnstreamer-native-singleshot.c
api/android/api/src/main/jni/nnstreamer-native.h

index 2a9135d..d89ff2f 100644 (file)
@@ -113,6 +113,12 @@ nns_free_element_data (gpointer data)
   element_data_s *item = (element_data_s *) data;
 
   if (item) {
+    /* release private data */
+    if (item->priv_data) {
+      JNIEnv *env = nns_get_jni_env (item->pipe_info);
+      item->priv_destroy_func (item->priv_data, env);
+    }
+
     switch (item->type) {
 #if !defined (NNS_SINGLE_ONLY)
       case NNS_ELEMENT_TYPE_SRC:
@@ -266,6 +272,8 @@ nns_destroy_pipe_info (pipeline_info_s * pipe_info, JNIEnv * env)
       pipe_info->priv_destroy_func (pipe_info->priv_data, env);
     else
       g_free (pipe_info->priv_data);
+
+    pipe_info->priv_data = NULL;
   }
 
   g_hash_table_destroy (pipe_info->element_handles);
@@ -379,7 +387,7 @@ nns_add_element_handle (pipeline_info_s * pipe_info, const gchar * name,
  */
 gboolean
 nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
-    ml_tensors_data_h data_h, ml_tensors_info_h info_h, jobject * result)
+    ml_tensors_data_h data_h, jobject obj_info, jobject * result)
 {
   guint i;
   data_class_info_s *dcls_info;
@@ -400,18 +408,9 @@ nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env,
     goto done;
   }
 
-  if (info_h) {
-    jobject obj_info = NULL;
-
-    if (!nns_convert_tensors_info (pipe_info, env, info_h, &obj_info)) {
-      nns_loge ("Failed to convert tensors info.");
-      (*env)->DeleteLocalRef (env, obj_data);
-      obj_data = NULL;
-      goto done;
-    }
-
+  /* set tensors info */
+  if (obj_info) {
     (*env)->CallVoidMethod (env, obj_data, dcls_info->mid_set_info, obj_info);
-    (*env)->DeleteLocalRef (env, obj_info);
   }
 
   for (i = 0; i < data->num_tensors; i++) {
index 66dbccc..ac3a6a1 100644 (file)
@@ -30,6 +30,8 @@ typedef struct
 {
   jmethodID mid_invoke;
   jmethodID mid_info;
+  ml_tensors_info_h in_info;
+  jobject in_info_obj;
 } customfilter_priv_data_s;
 
 /**
@@ -45,11 +47,50 @@ nns_customfilter_priv_free (gpointer data, JNIEnv * env)
 {
   customfilter_priv_data_s *priv = (customfilter_priv_data_s *) data;
 
-  /* nothing to free */
+  ml_tensors_info_destroy (priv->in_info);
+  if (priv->in_info_obj)
+    (*env)->DeleteGlobalRef (env, priv->in_info_obj);
+
   g_free (priv);
 }
 
 /**
+ * @brief Update input info in private data.
+ */
+static gboolean
+nns_customfilter_priv_set_in_info (pipeline_info_s * pipe_info, JNIEnv * env,
+    ml_tensors_info_h in_info)
+{
+  customfilter_priv_data_s *priv;
+  jobject obj_info = NULL;
+
+  priv = (customfilter_priv_data_s *) pipe_info->priv_data;
+
+  if (priv->in_info && ml_tensors_info_is_equal (in_info, priv->in_info)) {
+    /* do nothing, tensors info is equal. */
+    return TRUE;
+  }
+
+  if (!nns_convert_tensors_info (pipe_info, env, in_info, &obj_info)) {
+    nns_loge ("Failed to convert tensors info.");
+    return FALSE;
+  }
+
+  if (priv->in_info_obj)
+    (*env)->DeleteGlobalRef (env, priv->in_info_obj);
+
+  if (priv->in_info)
+    ml_tensors_info_free (priv->in_info);
+  else
+    ml_tensors_info_create (&priv->in_info);
+
+  ml_tensors_info_clone (priv->in_info, in_info);
+  priv->in_info_obj = (*env)->NewGlobalRef (env, obj_info);
+  (*env)->DeleteLocalRef (env, obj_info);
+  return TRUE;
+}
+
+/**
  * @brief The mandatory callback for GstTensorFilterFramework.
  * @param prop The property of tensor_filter instance
  * @param private_data Sub-plugin's private data
@@ -103,9 +144,12 @@ nns_customfilter_invoke (const GstTensorFilterProperties * prop,
   }
 
   ml_tensors_info_copy_from_gst (in_info, &prop->input_meta);
+  if (!nns_customfilter_priv_set_in_info (pipe_info, env, in_info)) {
+    goto done;
+  }
 
   /* convert to data object */
-  if (!nns_convert_tensors_data (pipe_info, env, in_data, in_info,
+  if (!nns_convert_tensors_data (pipe_info, env, in_data, priv->in_info_obj,
           &obj_in_data)) {
     nns_loge ("Failed to convert input data to data-object.");
     goto done;
index 8f03d4d..a7c7285 100644 (file)
@@ -33,6 +33,15 @@ typedef struct
 } pipeline_priv_data_s;
 
 /**
+ * @brief Private data for sink node.
+ */
+typedef struct
+{
+  ml_tensors_info_h out_info;
+  jobject out_info_obj;
+} pipeline_sink_priv_data_s;
+
+/**
  * @brief Release private data in pipeline info.
  */
 static void
@@ -45,6 +54,62 @@ nns_pipeline_priv_free (gpointer data, JNIEnv * env)
 }
 
 /**
+ * @brief Release private data in sink node.
+ */
+static void
+nns_pipeline_sink_priv_free (gpointer data, JNIEnv * env)
+{
+  pipeline_sink_priv_data_s *priv = (pipeline_sink_priv_data_s *) data;
+
+  ml_tensors_info_destroy (priv->out_info);
+  if (priv->out_info_obj)
+    (*env)->DeleteGlobalRef (env, priv->out_info_obj);
+
+  g_free (priv);
+}
+
+/**
+ * @brief Update output info in sink node data.
+ */
+static gboolean
+nns_pipeline_sink_priv_set_out_info (element_data_s * item, JNIEnv * env,
+    const ml_tensors_info_h out_info)
+{
+  pipeline_sink_priv_data_s *priv;
+  jobject obj_info = NULL;
+
+  if ((priv = item->priv_data) == NULL) {
+    priv = g_new0 (pipeline_sink_priv_data_s, 1);
+
+    item->priv_data = priv;
+    item->priv_destroy_func = nns_pipeline_sink_priv_free;
+  }
+
+  if (priv->out_info && ml_tensors_info_is_equal (out_info, priv->out_info)) {
+    /* do nothing, tensors info is equal. */
+    return TRUE;
+  }
+
+  if (!nns_convert_tensors_info (item->pipe_info, env, out_info, &obj_info)) {
+    nns_loge ("Failed to convert output info.");
+    return FALSE;
+  }
+
+  if (priv->out_info_obj)
+    (*env)->DeleteGlobalRef (env, priv->out_info_obj);
+
+  if (priv->out_info)
+    ml_tensors_info_free (priv->out_info);
+  else
+    ml_tensors_info_create (&priv->out_info);
+
+  ml_tensors_info_clone (priv->out_info, out_info);
+  priv->out_info_obj = (*env)->NewGlobalRef (env, obj_info);
+  (*env)->DeleteLocalRef (env, obj_info);
+  return TRUE;
+}
+
+/**
  * @brief Pipeline state change callback.
  */
 static void
@@ -79,23 +144,32 @@ static void
 nns_sink_data_cb (const ml_tensors_data_h data, const ml_tensors_info_h info,
     void *user_data)
 {
-  element_data_s *cb_data;
+  element_data_s *item;
   pipeline_info_s *pipe_info;
   pipeline_priv_data_s *priv;
+  pipeline_sink_priv_data_s *priv_sink;
   jobject obj_data = NULL;
   JNIEnv *env;
 
-  cb_data = (element_data_s *) user_data;
-  pipe_info = cb_data->pipe_info;
-  priv = (pipeline_priv_data_s *) pipe_info->priv_data;
+  item = (element_data_s *) user_data;
+  pipe_info = item->pipe_info;
 
   if ((env = nns_get_jni_env (pipe_info)) == NULL) {
     nns_logw ("Cannot get jni env in the sink callback.");
     return;
   }
 
-  if (nns_convert_tensors_data (pipe_info, env, data, info, &obj_data)) {
-    jstring sink_name = (*env)->NewStringUTF (env, cb_data->name);
+  /* cache output tensors info */
+  if (!nns_pipeline_sink_priv_set_out_info (item, env, info)) {
+    return;
+  }
+
+  priv = (pipeline_priv_data_s *) pipe_info->priv_data;
+  priv_sink = (pipeline_sink_priv_data_s *) item->priv_data;
+
+  if (nns_convert_tensors_data (pipe_info, env, data, priv_sink->out_info_obj,
+          &obj_data)) {
+    jstring sink_name = (*env)->NewStringUTF (env, item->name);
 
     (*env)->CallVoidMethod (env, pipe_info->instance, priv->mid_sink_cb,
         sink_name, obj_data);
index e898a0c..29353b4 100644 (file)
 #include "nnstreamer-native.h"
 
 /**
+ * @brief Private data for SingleShot class.
+ */
+typedef struct
+{
+  ml_tensors_info_h out_info;
+  jobject out_info_obj;
+} singleshot_priv_data_s;
+
+/**
+ * @brief Release private data in pipeline info.
+ */
+static void
+nns_singleshot_priv_free (gpointer data, JNIEnv * env)
+{
+  singleshot_priv_data_s *priv = (singleshot_priv_data_s *) data;
+
+  ml_tensors_info_destroy (priv->out_info);
+  if (priv->out_info_obj)
+    (*env)->DeleteGlobalRef (env, priv->out_info_obj);
+
+  g_free (priv);
+}
+
+/**
+ * @brief Update output info in private data.
+ */
+static gboolean
+nns_singleshot_priv_set_out_info (pipeline_info_s * pipe_info, JNIEnv * env,
+    ml_tensors_info_h out_info)
+{
+  singleshot_priv_data_s *priv;
+  jobject obj_info = NULL;
+
+  priv = (singleshot_priv_data_s *) pipe_info->priv_data;
+
+  if (priv->out_info && ml_tensors_info_is_equal (out_info, priv->out_info)) {
+    /* do nothing, tensors info is equal. */
+    return TRUE;
+  }
+
+  if (!nns_convert_tensors_info (pipe_info, env, out_info, &obj_info)) {
+    nns_loge ("Failed to convert output info.");
+    return FALSE;
+  }
+
+  if (priv->out_info_obj)
+    (*env)->DeleteGlobalRef (env, priv->out_info_obj);
+
+  if (priv->out_info)
+    ml_tensors_info_free (priv->out_info);
+  else
+    ml_tensors_info_create (&priv->out_info);
+
+  ml_tensors_info_clone (priv->out_info, out_info);
+  priv->out_info_obj = (*env)->NewGlobalRef (env, obj_info);
+  (*env)->DeleteLocalRef (env, obj_info);
+  return TRUE;
+}
+
+/**
  * @brief Native method for single-shot API.
  */
 jlong
@@ -113,7 +173,19 @@ done:
   g_free (info.models);
   g_free (info.custom_option);
 
-  if (!opened) {
+  if (opened) {
+    singleshot_priv_data_s *priv;
+    ml_tensors_info_h out_info;
+
+    priv = g_new0 (singleshot_priv_data_s, 1);
+    nns_set_priv_data (pipe_info, priv, nns_singleshot_priv_free);
+
+    /* set output info */
+    if (ml_single_get_output_info (single, &out_info) == ML_ERROR_NONE) {
+      nns_singleshot_priv_set_out_info (pipe_info, env, out_info);
+      ml_tensors_info_destroy (out_info);
+    }
+  } else {
     nns_destroy_pipe_info (pipe_info, env);
     pipe_info = NULL;
   }
@@ -143,6 +215,7 @@ Java_org_nnsuite_nnstreamer_SingleShot_nativeInvoke (JNIEnv * env,
     jobject thiz, jlong handle, jobject in)
 {
   pipeline_info_s *pipe_info;
+  singleshot_priv_data_s *priv;
   ml_single_h single;
   ml_tensors_info_h cur_info, in_info, out_info;
   ml_tensors_data_h in_data, out_data;
@@ -150,6 +223,7 @@ Java_org_nnsuite_nnstreamer_SingleShot_nativeInvoke (JNIEnv * env,
   jobject result = NULL;
 
   pipe_info = CAST_TO_TYPE (handle, pipeline_info_s *);
+  priv = (singleshot_priv_data_s *) pipe_info->priv_data;
   single = pipe_info->pipeline_handle;
   cur_info = in_info = out_info = NULL;
   in_data = out_data = NULL;
@@ -184,8 +258,13 @@ Java_org_nnsuite_nnstreamer_SingleShot_nativeInvoke (JNIEnv * env,
     goto done;
   }
 
-  if (!nns_convert_tensors_data (pipe_info, env, out_data, out_info, &result)) {
-    nns_loge ("Failed to convert the result to data.");
+  if (!nns_singleshot_priv_set_out_info (pipe_info, env, out_info)) {
+    goto done;
+  }
+
+  if (!nns_convert_tensors_data (pipe_info, env, out_data, priv->out_info_obj,
+          &result)) {
+    nns_loge ("Failed to convert the result to data-object.");
     result = NULL;
   }
 
index 8bf70da..188cee4 100644 (file)
@@ -142,6 +142,9 @@ typedef struct
   nns_element_type_e type;
   gpointer handle;
   pipeline_info_s *pipe_info;
+
+  gpointer priv_data;
+  nns_priv_destroy priv_destroy_func;
 } element_data_s;
 
 /**
@@ -196,7 +199,7 @@ nns_add_element_handle (pipeline_info_s * pipe_info, const gchar * name, element
  * @brief Convert tensors data to TensorsData object.
  */
 extern gboolean
-nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env, ml_tensors_data_h data_h, ml_tensors_info_h info_h, jobject * result);
+nns_convert_tensors_data (pipeline_info_s * pipe_info, JNIEnv * env, ml_tensors_data_h data_h, jobject obj_info, jobject * result);
 
 /**
  * @brief Parse tensors data from TensorsData object.