[Tizen/Api] change callback param for tensors
authorJaeyun <jy1210.jung@samsung.com>
Mon, 10 Jun 2019 00:57:16 +0000 (09:57 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Tue, 11 Jun 2019 01:03:37 +0000 (10:03 +0900)
Change tensors data struct and set callback with tensors data (sink and appsrc)

Signed-off-by: Jaeyun Jung <jy1210.jung@samsung.com>
tests/tizen_capi/unittest_tizen_capi.cpp
tizen-api/include/nnstreamer-single.h
tizen-api/include/nnstreamer.h
tizen-api/include/tizen-api-private.h
tizen-api/src/nnstreamer-single.c
tizen-api/src/tizen-api-pipeline.c

index e03476c..90fc3c8 100644 (file)
@@ -281,18 +281,18 @@ TEST (nnstreamer_capi_valve, failure_01)
  * @brief A tensor-sink callback for sink handle in a pipeline
  */
 static void
-test_sink_callback_dm01 (const char *buf[], const size_t size[],
-    const ml_tensors_info_s * tensorsinfo, void *pdata)
+test_sink_callback_dm01 (const ml_tensors_data_s * data,
+    const ml_tensors_info_s * info, void *pdata)
 {
   gchar *filepath = (gchar *) pdata;
   FILE *fp = g_fopen (filepath, "a");
   if (fp == NULL)
     return;
 
-  int i, num = tensorsinfo->num_tensors;
+  int i, num = info->num_tensors;
 
   for (i = 0; i < num; i++) {
-    fwrite (buf[i], size[i], 1, fp);
+    fwrite (data->tensors[i].tensor, data->tensors[i].size, 1, fp);
   }
 
   fclose (fp);
@@ -302,8 +302,8 @@ test_sink_callback_dm01 (const char *buf[], const size_t size[],
  * @brief A tensor-sink callback for sink handle in a pipeline
  */
 static void
-test_sink_callback_count (const char *buf[], const size_t size[],
-    const ml_tensors_info_s * tensorsinfo, void *pdata)
+test_sink_callback_count (const ml_tensors_data_s * data,
+    const ml_tensors_info_s * info, void *pdata)
 {
   guint *count = (guint *) pdata;
 
@@ -542,16 +542,17 @@ TEST (nnstreamer_capi_src, dummy_01)
   ml_pipeline_h handle;
   ml_pipeline_state_e state;
   ml_pipeline_src_h srchandle;
-  int status = ml_pipeline_construct (pipeline, &handle);
+  int status;
   ml_tensors_info_s tensorsinfo;
+  ml_tensors_data_s data1, data2;
 
   int i;
   char *uintarray2[10];
   uint8_t *content;
   gboolean r;
   gsize len;
-  const size_t size[1] = { 4 };
 
+  status = ml_pipeline_construct (pipeline, &handle);
   EXPECT_EQ (status, ML_ERROR_NONE);
   EXPECT_TRUE (dir != NULL);
   for (i = 0; i < 10; i++) {
@@ -596,15 +597,19 @@ TEST (nnstreamer_capi_src, dummy_01)
   tensorsinfo.info[0].dimension[2] = 1;
   tensorsinfo.info[0].dimension[3] = 1;
 
-  status = ml_pipeline_src_input_data (srchandle, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE,
-      &(uia_index[0]), size, 1);
+  data1.num_tensors = 1;
+  data1.tensors[0].tensor = uia_index[0];
+  data1.tensors[0].size = 4;
+
+  status = ml_pipeline_src_input_data (srchandle, &data1, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE);
   EXPECT_EQ (status, ML_ERROR_NONE);
-  status = ml_pipeline_src_input_data (srchandle, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE,
-      &(uia_index[0]), size, 1);
+
+  status = ml_pipeline_src_input_data (srchandle, &data1, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE);
   EXPECT_EQ (status, ML_ERROR_NONE);
 
   status = ml_pipeline_src_put_handle (srchandle);
   EXPECT_EQ (status, ML_ERROR_NONE);
+
   status = ml_pipeline_src_get_handle (handle, "srcx", &tensorsinfo, &srchandle);
   EXPECT_EQ (status, ML_ERROR_NONE);
 
@@ -615,13 +620,17 @@ TEST (nnstreamer_capi_src, dummy_01)
   EXPECT_EQ (tensorsinfo.info[0].dimension[2], 1);
   EXPECT_EQ (tensorsinfo.info[0].dimension[3], 1);
 
-
   for (i = 0; i < 10; i++) {
-    status = ml_pipeline_src_input_data (srchandle, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE,
-        &(uia_index[i]), size, 1);
+    data1.num_tensors = 1;
+    data1.tensors[0].tensor = uia_index[i];
+    data1.tensors[0].size = 4;
+    status = ml_pipeline_src_input_data (srchandle, &data1, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE);
     EXPECT_EQ (status, ML_ERROR_NONE);
-    status = ml_pipeline_src_input_data (srchandle, ML_PIPELINE_BUF_POLICY_AUTO_FREE,
-        &(uintarray2[i]), size, 1);
+
+    data2.num_tensors = 1;
+    data2.tensors[0].tensor = uintarray2[i];
+    data2.tensors[0].size = 4;
+    status = ml_pipeline_src_input_data (srchandle, &data2, ML_PIPELINE_BUF_POLICY_AUTO_FREE);
     EXPECT_EQ (status, ML_ERROR_NONE);
   }
 
@@ -723,11 +732,12 @@ TEST (nnstreamer_capi_src, failure_03)
   ml_pipeline_h handle;
   ml_tensors_info_s tensorsinfo;
   ml_pipeline_src_h srchandle;
-  const size_t tensor_size[1] = { num_dims };
-  char *pbuffer[num_tensors];
+  ml_tensors_data_s data;
 
-  for (int i = 0; i < num_tensors; ++i)
-    pbuffer[i] = (char *) g_malloc0 (sizeof (char) * num_dims);
+  for (int i = 0; i < ML_TENSOR_SIZE_LIMIT; ++i) {
+    data.tensors[i].tensor = g_malloc0 (sizeof (char) * num_dims);
+    data.tensors[i].size = num_dims;
+  }
 
   int status = ml_pipeline_construct (pipeline, &handle);
   EXPECT_EQ (status, ML_ERROR_NONE);
@@ -738,12 +748,18 @@ TEST (nnstreamer_capi_src, failure_03)
   status = ml_pipeline_src_get_handle (handle, "srcx", &tensorsinfo, &srchandle);
   EXPECT_EQ (status, ML_ERROR_NONE);
 
-  status = ml_pipeline_src_input_data (srchandle, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE,
-      &(pbuffer[0]), tensor_size, num_tensors);
+  /* null data */
+  status = ml_pipeline_src_input_data (srchandle, NULL, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE);
+  EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
+
+  /* invalid number of tensors (max size) */
+  data.num_tensors = num_tensors;
+  status = ml_pipeline_src_input_data (srchandle, &data, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
-  status = ml_pipeline_src_input_data (srchandle, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE,
-      &(pbuffer[0]), tensor_size, 0);
+  /* invalid number of tensors (size is 0) */
+  data.num_tensors = 0;
+  status = ml_pipeline_src_input_data (srchandle, &data, ML_PIPELINE_BUF_POLICY_DO_NOT_FREE);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
   status = ml_pipeline_src_put_handle (srchandle);
@@ -755,8 +771,8 @@ TEST (nnstreamer_capi_src, failure_03)
   status = ml_pipeline_destroy (handle);
   EXPECT_EQ (status, ML_ERROR_NONE);
 
-  for (int i = 0; i < num_tensors; ++i)
-    g_free (pbuffer[i]);
+  for (int i = 0; i < ML_TENSOR_SIZE_LIMIT; ++i)
+    g_free (data.tensors[i].tensor);
 }
 
 /**
@@ -991,7 +1007,7 @@ TEST (nnstreamer_capi_singleshot, invoke_01)
   ml_simpleshot_model_h model;
   ml_tensors_info_s in_info, out_info;
   ml_tensors_info_s in_res, out_res;
-  ml_tensor_data_s *input, *output1, *output2;
+  ml_tensors_data_s *input, *output1, *output2;
   int status;
 
   const gchar *root_path = g_getenv ("NNSTREAMER_BUILD_ROOT_PATH");
@@ -1051,22 +1067,22 @@ TEST (nnstreamer_capi_singleshot, invoke_01)
   }
 
   /* generate dummy data */
-  input = ml_model_allocate_tensor_data (&in_info);
+  input = ml_model_allocate_tensors_data (&in_info);
   EXPECT_TRUE (input != NULL);
 
   output1 = ml_model_inference (model, input, NULL);
   EXPECT_TRUE (output1 != NULL);
-  ml_model_free_tensor_data (output1);
+  ml_model_free_tensors_data (output1);
 
-  output2 = ml_model_allocate_tensor_data (&out_info);
+  output2 = ml_model_allocate_tensors_data (&out_info);
   EXPECT_TRUE (output2 != NULL);
 
   output1 = ml_model_inference (model, input, output2);
   EXPECT_TRUE (output1 != NULL);
   EXPECT_TRUE (output1 == output2);
-  ml_model_free_tensor_data (output2);
+  ml_model_free_tensors_data (output2);
 
-  ml_model_free_tensor_data (input);
+  ml_model_free_tensors_data (input);
 
   status = ml_model_close (model);
   EXPECT_EQ (status, ML_ERROR_NONE);
@@ -1082,7 +1098,7 @@ TEST (nnstreamer_capi_singleshot, invoke_02)
 {
   ml_simpleshot_model_h model;
   ml_tensors_info_s in_info, out_info;
-  ml_tensor_data_s *input, *output1, *output2;
+  ml_tensors_data_s *input, *output1, *output2;
   int status;
 
   const gchar *root_path = g_getenv ("NNSTREAMER_BUILD_ROOT_PATH");
@@ -1111,22 +1127,22 @@ TEST (nnstreamer_capi_singleshot, invoke_02)
   EXPECT_EQ (status, ML_ERROR_NONE);
 
   /* generate dummy data */
-  input = ml_model_allocate_tensor_data (&in_info);
+  input = ml_model_allocate_tensors_data (&in_info);
   EXPECT_TRUE (input != NULL);
 
   output1 = ml_model_inference (model, input, NULL);
   EXPECT_TRUE (output1 != NULL);
-  ml_model_free_tensor_data (output1);
+  ml_model_free_tensors_data (output1);
 
-  output2 = ml_model_allocate_tensor_data (&out_info);
+  output2 = ml_model_allocate_tensors_data (&out_info);
   EXPECT_TRUE (output2 != NULL);
 
   output1 = ml_model_inference (model, input, output2);
   EXPECT_TRUE (output1 != NULL);
   EXPECT_TRUE (output1 == output2);
-  ml_model_free_tensor_data (output2);
+  ml_model_free_tensors_data (output2);
 
-  ml_model_free_tensor_data (input);
+  ml_model_free_tensors_data (input);
 
   status = ml_model_close (model);
   EXPECT_EQ (status, ML_ERROR_NONE);
index 2c48a69..e2c34e4 100644 (file)
@@ -127,8 +127,8 @@ int ml_model_close (ml_simpleshot_model_h model);
  *         input data frames of an instance of a model should share the
  *         same dimension.
  */
-ml_tensor_data_s * ml_model_inference (ml_simpleshot_model_h model,
-    const ml_tensor_data_s *input, ml_tensor_data_s *output);
+ml_tensors_data_s * ml_model_inference (ml_simpleshot_model_h model,
+    const ml_tensors_data_s *input, ml_tensors_data_s *output);
 
 /*************
  * UTILITIES *
@@ -193,19 +193,18 @@ void ml_model_free_tensors_info (ml_tensors_info_s *type);
 /**
  * @brief Free the tensors data pointer.
  * @since_tizen 5.5
- * @param[in] tensor the tensors data pointer to be freed.
+ * @param[in] data The tensors data pointer to be freed.
  */
-void ml_model_free_tensor_data (ml_tensor_data_s *tensor);
+void ml_model_free_tensors_data (ml_tensors_data_s *data);
 
 /**
  * @brief Allocate a tensor data frame with the given tensors type.
  * @since_tizen 5.5
  * @param[in] info The tensors information for the allocation
  * @return @c Tensors data pointer allocated. Null if error.
- * @retval NULL there is an error. call get_last_result() to get specific
- *         error numbers.
+ * @retval NULL there is an error. call ml_get_last_result() to get specific error numbers.
  */
-ml_tensor_data_s *ml_model_allocate_tensor_data (const ml_tensors_info_s *info);
+ml_tensors_data_s *ml_model_allocate_tensors_data (const ml_tensors_info_s *info);
 
 /**
  * @brief Check the availability of the given execution environments.
index 20898f4..d5bce53 100644 (file)
@@ -184,26 +184,32 @@ typedef struct {
 } ml_tensors_info_s;
 
 /**
+ * @brief An instance of a single input or output frame.
+ * @since_tizen 5.5
+ */
+typedef struct {
+  void *tensor; /**< The instance of tensor data. */
+  size_t size; /**< The size of tensor. */
+} ml_tensor_data_s;
+
+/**
  * @brief An instance of input or output frames. ml_tensors_info_s is the metadata.
  * @since_tizen 5.5
  */
 typedef struct {
   unsigned int num_tensors; /**< The number of tensors. */
-  void *tensor[ML_TENSOR_SIZE_LIMIT]; /**< The list of tensor data. NULL for unused tensors. */
-  size_t size[ML_TENSOR_SIZE_LIMIT]; /**< The size of each tensor. */
-} ml_tensor_data_s;
+  ml_tensor_data_s tensors[ML_TENSOR_SIZE_LIMIT]; /**< The list of tensor data. NULL for unused tensors. */
+} ml_tensors_data_s;
 
 /**
  * @brief Callback for sink element of nnstreamer pipelines (pipeline's output)
  * @detail If an application wants to accept data outputs of an nnstreamer stream, use this callback to get data from the stream. Note that the buffer may be deallocated after the return and this is synchronously called. Thus, if you need the data afterwards, copy the data to another buffer and return fast. Do not hold too much time in the callback. It is recommended to use very small tensors at sinks.
  * @since_tizen 5.5
- * @param[in] buf The contents of the tensor output (a single frame. tensor/tensors). Number of buf is determined by tensorsinfo->num_tensors.
- * @param[in] size The size of the buffer. Number of size is determined by tensorsinfo->num_tensors. Note that max num_tensors is 16 (ML_TENSOR_SIZE_LIMIT).
- * @param[in] tensors_info The cardinality, dimension, and type of given tensor/tensors.
- * @param[in,out] pdata User Application's Private Data
+ * @param[in] data The contents of the tensor output (a single frame. tensor/tensors). Number of tensors is determined by data->num_tensors. Note that max num_tensors is 16 (ML_TENSOR_SIZE_LIMIT).
+ * @param[in] info The cardinality, dimension, and type of given tensor/tensors.
+ * @param[in,out] pdata User Application's Private Data.
  */
-typedef void (*ml_pipeline_sink_cb)
-(const char *buf[], const size_t size[], const ml_tensors_info_s *tensors_info, void *pdata);
+typedef void (*ml_pipeline_sink_cb) (const ml_tensors_data_s *data, const ml_tensors_info_s *info, void *pdata);
 
 /****************************************************
  ** NNStreamer Pipeline Construction (gst-parse)   **
@@ -333,17 +339,15 @@ int ml_pipeline_src_put_handle (ml_pipeline_src_h h);
 /**
  * @brief Puts an input data frame.
  * @param[in] h The source handle returned by ml_pipeline_src_get_handle().
+ * @param[in] data The input tensors, in the format of tensors info given by ml_pipeline_src_get_handle().
  * @param[in] policy The policy of buf deallocation.
- * @param[in] buf The input buffers, in the format of tensorsinfo given by ml_pipeline_gethandle()
- * @param[in] size The sizes of input buffers. This must be consistent with the given tensorsinfo, probed by ml_pipeline_src_get_handle().
- * @param[in] num_tensors The number of tensors (number of buf and number of size) for the input frame. This must be consistent with the given tensorinfo, probed by ml_pipeline_src_get_handle(). MAX is 16 (ML_TENSOR_SIZE_LIMIT).
  * @return 0 on success (buf is filled). otherwise a negative error value.
  * @retval #ML_ERROR_NONE Successful
  * @retval #ML_ERROR_INVALID_PARAMETER Given parameter is invalid.
  * @retval #ML_ERROR_STREAMS_PIPE The pipeline has inconsistent padcaps. Not negotiated?
  * @retval #ML_ERROR_TRY_AGAIN The pipeline is not ready yet.
  */
-int ml_pipeline_src_input_data (ml_pipeline_src_h h, ml_pipeline_buf_policy_e policy, char *buf[], const size_t size[], unsigned int num_tensors);
+int ml_pipeline_src_input_data (ml_pipeline_src_h h, const ml_tensors_data_s *data, ml_pipeline_buf_policy_e policy);
 
 /****************************************************
  ** NNStreamer Pipeline Switch/Valve Control       **
index 6b2627e..c026555 100644 (file)
 #include <glib.h>
 #include <gmodule.h>
 #include <gst/gst.h>
-#include "nnstreamer.h"
+#include <gst/app/gstappsrc.h>
+
 #include <tizen_error.h>
 #include <dlog.h>
+
+#include "nnstreamer.h"
 #include <nnstreamer/tensor_typedef.h>
-#include <gst/app/gstappsrc.h>
 
-#define DLOG_TAG "nnstreamer-capi-pipeline"
+#define DLOG_TAG "nnstreamer-capi"
 
 #define dlogi(...) \
     dlog_print (DLOG_INFO, DLOG_TAG, __VA_ARGS__)
index 7f6b5f8..c0715fc 100644 (file)
@@ -298,13 +298,13 @@ ml_model_close (ml_simpleshot_model_h model)
 /**
  * @brief Invoke the model with the given input data. (more info in nnstreamer-single.h)
  */
-ml_tensor_data_s *
+ml_tensors_data_s *
 ml_model_inference (ml_simpleshot_model_h model,
-    const ml_tensor_data_s * input, ml_tensor_data_s * output)
+    const ml_tensors_data_s * input, ml_tensors_data_s * output)
 {
   ml_simpleshot_model *model_h;
   ml_tensors_info_s out_info;
-  ml_tensor_data_s *result;
+  ml_tensors_data_s *result;
   GstSample *sample;
   GstBuffer *buffer;
   GstMemory *mem;
@@ -331,8 +331,8 @@ ml_model_inference (ml_simpleshot_model_h model,
     }
 
     for (i = 0; i < output->num_tensors; i++) {
-      if (!output->tensor[i] ||
-          output->size[i] !=
+      if (!output->tensors[i].tensor ||
+          output->tensors[i].size !=
           ml_util_get_tensor_size (&out_info.info[i])) {
         dloge ("Invalid output data, the size of output is different.");
         return NULL;
@@ -344,7 +344,8 @@ ml_model_inference (ml_simpleshot_model_h model,
 
   for (i = 0; i < input->num_tensors; i++) {
     mem = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
-        input->tensor[i], input->size[i], 0, input->size[i], NULL, NULL);
+        input->tensors[i].tensor, input->tensors[i].size, 0,
+        input->tensors[i].size, NULL, NULL);
     gst_buffer_append_memory (buffer, mem);
   }
 
@@ -365,7 +366,7 @@ ml_model_inference (ml_simpleshot_model_h model,
   if (output) {
     result = output;
   } else {
-    result = ml_model_allocate_tensor_data (&out_info);
+    result = ml_model_allocate_tensors_data (&out_info);
   }
 
   if (!result) {
@@ -379,7 +380,7 @@ ml_model_inference (ml_simpleshot_model_h model,
     mem = gst_buffer_peek_memory (buffer, i);
     gst_memory_map (mem, &mem_info, GST_MAP_READ);
 
-    memcpy (result->tensor[i], mem_info.data, mem_info.size);
+    memcpy (result->tensors[i].tensor, mem_info.data, mem_info.size);
 
     gst_memory_unmap (mem, &mem_info);
   }
@@ -514,7 +515,7 @@ ml_util_get_tensor_size (const ml_tensor_info_s * info)
     tensor_size = 8;
     break;
   default:
-    dloge ("The given param tensor_type is invalid.");
+    dloge ("In the given param, tensor type is invalid.");
     return 0;
   }
 
@@ -555,42 +556,42 @@ ml_model_free_tensors_info (ml_tensors_info_s * type)
  * @brief Free the tensors data pointer. (more info in nnstreamer-single.h)
  */
 void
-ml_model_free_tensor_data (ml_tensor_data_s * tensor)
+ml_model_free_tensors_data (ml_tensors_data_s * data)
 {
   gint i;
 
-  if (!tensor) {
-    dloge ("The given param tensor is invalid.");
+  if (!data) {
+    dloge ("The given param data is invalid.");
     return;
   }
 
-  for (i = 0; i < tensor->num_tensors; i++) {
-    if (tensor->tensor[i]) {
-      g_free (tensor->tensor[i]);
-      tensor->tensor[i] = NULL;
+  for (i = 0; i < data->num_tensors; i++) {
+    if (data->tensors[i].tensor) {
+      g_free (data->tensors[i].tensor);
+      data->tensors[i].tensor = NULL;
     }
 
-    tensor->size[i] = 0;
+    data->tensors[i].size = 0;
   }
 
-  tensor->num_tensors = 0;
+  data->num_tensors = 0;
 }
 
 /**
  * @brief Allocate a tensor data frame with the given tensors type. (more info in nnstreamer-single.h)
  */
-ml_tensor_data_s *
-ml_model_allocate_tensor_data (const ml_tensors_info_s * info)
+ml_tensors_data_s *
+ml_model_allocate_tensors_data (const ml_tensors_info_s * info)
 {
-  ml_tensor_data_s *data;
+  ml_tensors_data_s *data;
   gint i;
 
   if (!info) {
-    dloge ("The given param type is invalid.");
+    dloge ("The given param info is invalid.");
     return NULL;
   }
 
-  data = g_new0 (ml_tensor_data_s, 1);
+  data = g_new0 (ml_tensors_data_s, 1);
   if (!data) {
     dloge ("Failed to allocate the memory block.");
     return NULL;
@@ -598,8 +599,8 @@ ml_model_allocate_tensor_data (const ml_tensors_info_s * info)
 
   data->num_tensors = info->num_tensors;
   for (i = 0; i < data->num_tensors; i++) {
-    data->size[i] = ml_util_get_tensor_size (&info->info[i]);
-    data->tensor[i] = g_malloc0 (data->size[i]);
+    data->tensors[i].size = ml_util_get_tensor_size (&info->info[i]);
+    data->tensors[i].tensor = g_malloc0 (data->tensors[i].size);
   }
 
   return data;
index a2c6ee4..90be088 100644 (file)
@@ -115,9 +115,9 @@ get_tensors_info_from_GstTensorsInfo (GstTensorsInfo * gst_tensorsinfo,
  * @brief Handle a sink element for registered ml_pipeline_sink_cb
  */
 static void
-cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
+cb_sink_event (GstElement * e, GstBuffer * b, gpointer user_data)
 {
-  ml_pipeline_element *elem = data;
+  ml_pipeline_element *elem = user_data;
 
   /** @todo CRITICAL if the pipeline is being killed, don't proceed! */
 
@@ -126,8 +126,7 @@ cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
   guint i;
   guint num_mems;
   GList *l;
-  const char *buf[ML_TENSOR_SIZE_LIMIT];
-  size_t size[ML_TENSOR_SIZE_LIMIT];
+  ml_tensors_data_s tensors_data;
   size_t total_size = 0;
 
   num_mems = gst_buffer_n_memory (b);
@@ -138,12 +137,18 @@ cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
     return;
   }
 
+  /* set tensor data */
+  memset (&tensors_data, 0, sizeof (ml_tensors_data_s));
+
+  tensors_data.num_tensors = num_mems;
   for (i = 0; i < num_mems; i++) {
     mem[i] = gst_buffer_peek_memory (b, i);
     gst_memory_map (mem[i], &info[i], GST_MAP_READ);
-    buf[i] = (const char *) info[i].data;
-    size[i] = info[i].size;
-    total_size += size[i];
+
+    tensors_data.tensors[i].tensor = info[i].data;
+    tensors_data.tensors[i].size = info[i].size;
+
+    total_size += info[i].size;
   }
 
   g_mutex_lock (&elem->lock);
@@ -178,29 +183,25 @@ cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
 
           if (elem->tensorsinfo.num_tensors != num_mems) {
             dloge
-                ("The sink event of [%s] cannot be handled because the tensor type mismatches.",
+                ("The sink event of [%s] cannot be handled because the number of tensors mismatches.",
                 elem->name);
 
             gst_object_unref (elem->sink);
             elem->sink = NULL;
-            g_mutex_unlock (&elem->lock);
-
-            return;
+            goto error;
           }
 
           for (i = 0; i < elem->tensorsinfo.num_tensors; i++) {
             size_t sz = gst_tensor_info_get_size (&elem->tensorsinfo.info[i]);
 
-            if (sz != size[i]) {
+            if (sz != tensors_data.tensors[i].size) {
               dloge
                   ("The sink event of [%s] cannot be handled because the tensor dimension mismatches.",
                   elem->name);
 
               gst_object_unref (elem->sink);
               elem->sink = NULL;
-              g_mutex_unlock (&elem->lock);
-
-              return;
+              goto error;
             }
 
             elem->size += sz;
@@ -220,8 +221,7 @@ cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
     dloge
         ("The buffersize mismatches. All the three values must be the same: %zu, %zu, %zu",
         total_size, elem->size, gst_buffer_get_size (b));
-    g_mutex_unlock (&elem->lock);
-    return;
+    goto error;
   }
 
   /* Iterate e->handles, pass the data to them */
@@ -232,11 +232,12 @@ cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
 
     get_tensors_info_from_GstTensorsInfo (&elem->tensorsinfo, &tensors_info);
 
-    callback (buf, size, &tensors_info, sink->pdata);
+    callback (&tensors_data, &tensors_info, sink->pdata);
 
     /** @todo Measure time. Warn if it takes long. Kill if it takes too long. */
   }
 
+error:
   g_mutex_unlock (&elem->lock);
 
   for (i = 0; i < num_mems; i++) {
@@ -827,9 +828,8 @@ ml_pipeline_src_put_handle (ml_pipeline_src_h h)
  * @brief Push a data frame to a src (more info in nnstreamer.h)
  */
 int
-ml_pipeline_src_input_data (ml_pipeline_src_h h,
-    ml_pipeline_buf_policy_e policy, char *buf[], const size_t size[],
-    unsigned int num_tensors)
+ml_pipeline_src_input_data (ml_pipeline_src_h h, const ml_tensors_data_s * data,
+    ml_pipeline_buf_policy_e policy)
 {
   /** @todo NYI */
   GstBuffer *buffer;
@@ -838,9 +838,15 @@ ml_pipeline_src_input_data (ml_pipeline_src_h h,
 
   handle_init (src, src, h);
 
-  if (num_tensors < 1 || num_tensors > ML_TENSOR_SIZE_LIMIT) {
+  if (!data) {
+    dloge ("The given param data is invalid.");
+    ret = ML_ERROR_INVALID_PARAMETER;
+    goto unlock_return;
+  }
+
+  if (data->num_tensors < 1 || data->num_tensors > ML_TENSOR_SIZE_LIMIT) {
     dloge ("The tensor size if invalid. It should be 1 ~ %u; where it is %u",
-        ML_TENSOR_SIZE_LIMIT, num_tensors);
+        ML_TENSOR_SIZE_LIMIT, data->num_tensors);
     ret = ML_ERROR_INVALID_PARAMETER;
     goto unlock_return;
   }
@@ -874,10 +880,10 @@ ml_pipeline_src_input_data (ml_pipeline_src_h h,
         memcpy (&elem->tensorsinfo, &tconfig.info, sizeof (GstTensorsInfo));
         elem->size = 0;
 
-        if (elem->tensorsinfo.num_tensors != num_tensors) {
+        if (elem->tensorsinfo.num_tensors != data->num_tensors) {
           dloge
               ("The src push of [%s] cannot be handled because the number of tensors in a frame mismatches. %u != %u",
-              elem->name, elem->tensorsinfo.num_tensors, num_tensors);
+              elem->name, elem->tensorsinfo.num_tensors, data->num_tensors);
 
           gst_object_unref (elem->src);
           elem->src = NULL;
@@ -888,10 +894,10 @@ ml_pipeline_src_input_data (ml_pipeline_src_h h,
         for (i = 0; i < elem->tensorsinfo.num_tensors; i++) {
           size_t sz = gst_tensor_info_get_size (&elem->tensorsinfo.info[i]);
 
-          if (sz != size[i]) {
+          if (sz != data->tensors[i].size) {
             dloge
-                ("The sink event of [%s] cannot be handled because the tensor dimension mismatches.",
-                elem->name);
+                ("The given input tensor size (%d'th, %zu bytes) mismatches the source pad (%zu bytes)",
+                i, data->tensors[i].size, sz);
 
             gst_object_unref (elem->src);
             elem->src = NULL;
@@ -900,17 +906,6 @@ ml_pipeline_src_input_data (ml_pipeline_src_h h,
           }
 
           elem->size += sz;
-
-          if (sz != size[i]) {
-            dloge
-                ("The given input tensor size (%d'th, %zu bytes) mismatches the source pad (%zu bytes)",
-                i, size[i], sz);
-
-            gst_object_unref (elem->src);
-            elem->src = NULL;
-            ret = ML_ERROR_INVALID_PARAMETER;
-            goto unlock_return;
-          }
         }
       } else {
         gst_object_unref (elem->src);
@@ -927,12 +922,12 @@ ml_pipeline_src_input_data (ml_pipeline_src_h h,
   }
 
   /* Create buffer to be pushed from buf[] */
-  buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
-      buf[0], size[0], 0, size[0], buf[0], ml_buf_policy[policy]);
-  for (i = 1; i < num_tensors; i++) {
+  buffer = gst_buffer_new ();
+  for (i = 0; i < data->num_tensors; i++) {
     GstBuffer *addbuffer =
-        gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, buf[i], size[i],
-        0, size[i], buf[i], ml_buf_policy[policy]);
+        gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+        data->tensors[i].tensor, data->tensors[i].size, 0,
+        data->tensors[i].size, data->tensors[i].tensor, ml_buf_policy[policy]);
     buffer = gst_buffer_append (buffer, addbuffer);
 
     /** @todo Verify that gst_buffer_append lists tensors/gstmem in the correct order */