[IIO] Added support for other/tensors
authorParichay Kapoor <pk.kapoor@samsung.com>
Wed, 17 Apr 2019 03:13:54 +0000 (12:13 +0900)
committerwooksong <wook16.song@samsung.com>
Wed, 24 Apr 2019 12:52:22 +0000 (21:52 +0900)
Added support for other/tensors when merging of channels
with corresponding test cases

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
gst/nnstreamer/tensor_source/tensor_src_iio.c
tests/nnstreamer_source/unittest_src_iio.cpp

index 1dc684e..c77f27e 100644 (file)
@@ -2224,18 +2224,25 @@ gst_tensor_src_iio_create (GstBaseSrc * src, guint64 offset,
   GstBuffer *buf;
   GstMemory *mem;
   guint buffer_size;
+  gint idx = 0;
 
   self = GST_TENSOR_SRC_IIO_CAST (src);
+  buf = gst_buffer_new ();
   buffer_size = gst_tensor_info_get_size (&self->tensors_config->info.info[0]);
 
-  mem = gst_allocator_alloc (NULL, buffer_size, NULL);
-  if (mem == NULL) {
-    GST_ERROR_OBJECT (self, "Error allocating memory for buffer.");
-    return GST_FLOW_ERROR;
-  }
+  for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
+    /** all the data, if unermged should be of the same size*/
+    g_assert (buffer_size ==
+        gst_tensor_info_get_size (&self->tensors_config->info.info[idx]));
 
-  buf = gst_buffer_new ();
-  gst_buffer_append_memory (buf, mem);
+    mem = gst_allocator_alloc (NULL, buffer_size, NULL);
+    if (mem == NULL) {
+      GST_ERROR_OBJECT (self, "Error allocating memory for buffer.");
+      goto error_buffer_unref;
+    }
+
+    gst_buffer_append_memory (buf, mem);
+  }
 
   if (gst_tensor_src_iio_fill (src, offset, buffer_size, buf) != GST_FLOW_OK) {
     goto error_buffer_unref;
@@ -2251,7 +2258,7 @@ error_buffer_unref:
 
 /**
  * @brief process the scanned data from IIO device
- * @param[in] channels List of the all enabled channels
+ * @param[in] prop Properties of one of the enabled channels
  * @param[in] data Data read from the IIO device
  * @param[in/out] buffer_map Gst buffer map to write data to
  * @returns FALSE if fail, else TRUE
@@ -2259,97 +2266,89 @@ error_buffer_unref:
  * assumes each data starting point is byte aligned
  */
 static gboolean
-gst_tensor_src_iio_process_scanned_data (GList * channels, gchar * data,
-    gfloat * buffer_map)
+gst_tensor_src_iio_process_scanned_data (GstTensorSrcIIOChannelProperties *
+    prop, gchar * data, gfloat * buffer_map)
 {
-  GList *list;
-  GstTensorSrcIIOChannelProperties *prop;
   guint64 storage_mask;
-  guint channel_idx;
-
-  for (list = channels, channel_idx = 0; list != NULL;
-      list = list->next, channel_idx += 1) {
-    prop = list->data;
-    switch (prop->storage_bytes) {
-      case 1:
-      {
-        guint8 value = *(guint8 *) (data + prop->location);
+  switch (prop->storage_bytes) {
+    case 1:
+    {
+      guint8 value = *(guint8 *) (data + prop->location);
         /** right shift the extra storage bits */
-        value >>= (8 - prop->storage_bits);
-        buffer_map[channel_idx] =
-            gst_tensor_src_iio_process_scanned_data_from_guint8 (prop, value);
-        break;
-      }
-      case 2:
-      {
-        guint16 value = *(guint16 *) (data + prop->location);
-        if (prop->big_endian) {
-          value = GUINT16_FROM_BE (value);
+      value >>= (8 - prop->storage_bits);
+      *buffer_map =
+          gst_tensor_src_iio_process_scanned_data_from_guint8 (prop, value);
+      break;
+    }
+    case 2:
+    {
+      guint16 value = *(guint16 *) (data + prop->location);
+      if (prop->big_endian) {
+        value = GUINT16_FROM_BE (value);
           /** right shift the extra storage bits for big endian */
-          value >>= (16 - prop->storage_bits);
-        } else {
-          value = GUINT16_FROM_LE (value);
+        value >>= (16 - prop->storage_bits);
+      } else {
+        value = GUINT16_FROM_LE (value);
           /** mask out the extra storage bits for little endian */
-          storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
-          value &= storage_mask;
-        }
-        buffer_map[channel_idx] =
-            gst_tensor_src_iio_process_scanned_data_from_guint16 (prop, value);
-        break;
+        storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
+        value &= storage_mask;
       }
-      case 3:
+      *buffer_map =
+          gst_tensor_src_iio_process_scanned_data_from_guint16 (prop, value);
+      break;
+    }
+    case 3:
       /** follow through */
-      case 4:
-      {
-        guint32 value = *(guint32 *) (data + prop->location);
-        if (prop->big_endian) {
-          value = GUINT32_FROM_BE (value);
+    case 4:
+    {
+      guint32 value = *(guint32 *) (data + prop->location);
+      if (prop->big_endian) {
+        value = GUINT32_FROM_BE (value);
           /** right shift the extra storage bits for big endian */
-          value >>= (32 - prop->storage_bits);
-        } else {
-          value = GUINT32_FROM_LE (value);
+        value >>= (32 - prop->storage_bits);
+      } else {
+        value = GUINT32_FROM_LE (value);
           /** mask out the extra storage bits for little endian */
-          storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
-          value &= storage_mask;
-        }
-        buffer_map[channel_idx] =
-            gst_tensor_src_iio_process_scanned_data_from_guint32 (prop, value);
-        break;
+        storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
+        value &= storage_mask;
       }
-      case 5:
+      *buffer_map =
+          gst_tensor_src_iio_process_scanned_data_from_guint32 (prop, value);
+      break;
+    }
+    case 5:
       /** follow through */
-      case 6:
+    case 6:
       /** follow through */
-      case 7:
+    case 7:
       /** follow through */
-      case 8:
-      {
-        guint64 value = *(guint64 *) (data + prop->location);
-        if (prop->big_endian) {
-          value = GUINT64_FROM_BE (value);
+    case 8:
+    {
+      guint64 value = *(guint64 *) (data + prop->location);
+      if (prop->big_endian) {
+        value = GUINT64_FROM_BE (value);
           /** right shift the extra storage bits for big endian */
-          value >>= (64 - prop->storage_bits);
-        } else {
-          value = GUINT64_FROM_LE (value);
+        value >>= (64 - prop->storage_bits);
+      } else {
+        value = GUINT64_FROM_LE (value);
           /** mask out the extra storage bits for little endian */
-          storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
-          value &= storage_mask;
-        }
-        buffer_map[channel_idx] =
-            gst_tensor_src_iio_process_scanned_data_from_guint64 (prop, value);
-        break;
+        storage_mask = G_MAXUINT64 >> (64 - prop->storage_bits);
+        value &= storage_mask;
       }
-      default:
-        GST_ERROR ("Storage bytes for channel %s out of bounds", prop->name);
-        return FALSE;
+      *buffer_map =
+          gst_tensor_src_iio_process_scanned_data_from_guint64 (prop, value);
+      break;
     }
+    default:
+      GST_ERROR ("Storage bytes for channel %s out of bounds", prop->name);
+      return FALSE;
   }
   return TRUE;
 }
 
 /**
  * @brief fill the buffer with data
- * @note ignore offset as there is no header
+ * @note ignore offset,size as there is pull mode
  * @note buffer timestamp is already handled by gstreamer with gst clock
  */
 static GstFlowReturn
@@ -2358,26 +2357,32 @@ gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset,
 {
   GstTensorSrcIIO *self;
   gint status, bytes_to_read;
-  guint idx;
+  guint idx, ch_idx, num_mapped;
   gchar *raw_data_base, *raw_data;
   gfloat *map_data_float;
-  GstMemory *mem;
-  GstMapInfo map;
+  GstMemory *mem[NNS_TENSOR_SIZE_LIMIT];
+  GstMapInfo map[NNS_TENSOR_SIZE_LIMIT];
   guint64 time_to_end, cur_time;
   guint64 safe_multiply;
+  GList *channels;
 
   self = GST_TENSOR_SRC_IIO (src);
 
   /** Only supporting tensors made of 1 tensor for now */
-  g_assert (self->tensors_config->info.num_tensors == 1);
-  g_assert (size ==
-      gst_tensor_info_get_size (&self->tensors_config->info.info[0]));
   g_assert (gst_buffer_n_memory (buffer) ==
       self->tensors_config->info.num_tensors);
 
   /** get writable buffer */
-  mem = gst_buffer_peek_memory (buffer, 0);
-  g_assert (gst_memory_map (mem, &map, GST_MAP_WRITE));
+  for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
+    mem[idx] = gst_buffer_peek_memory (buffer, idx);
+    if (!gst_memory_map (mem[idx], &map[idx], GST_MAP_WRITE)) {
+      for (ch_idx = 0; ch_idx < num_mapped; ch_idx++) {
+        gst_memory_unmap (mem[ch_idx], &map[ch_idx]);
+      }
+      return GST_FLOW_ERROR;
+    }
+    num_mapped = idx + 1;
+  }
   /** memory to data from file */
   bytes_to_read = self->scan_size * self->buffer_capacity;
   raw_data_base = g_malloc (bytes_to_read);
@@ -2433,7 +2438,6 @@ gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset,
   }
 
   /** parse the read data */
-  map_data_float = (gfloat *) map.data;
   raw_data = raw_data_base;
 
   /**
@@ -2441,24 +2445,40 @@ gst_tensor_src_iio_fill (GstBaseSrc * src, guint64 offset,
    * a 1 dimension data. 2nd dimension comes from buffer capacity.
    */
   for (idx = 0; idx < self->buffer_capacity; idx++) {
-    map_data_float = ((gfloat *) map.data) + idx * self->num_channels_enabled;
-    if (!gst_tensor_src_iio_process_scanned_data (self->channels, raw_data,
-            map_data_float)) {
-      GST_ERROR_OBJECT (self, "Error while processing scanned data.");
-      goto error_data_free;
+    for (channels = self->channels, ch_idx = 0;
+        ch_idx < self->num_channels_enabled;
+        ch_idx++, channels = channels->next) {
+      if (self->tensors_config->info.num_tensors == 1) {
+        /** for other/tensor, only 1 map exist as there is only 1 mem */
+        map_data_float =
+            ((gfloat *) map[0].data) + idx * self->num_channels_enabled +
+            ch_idx;
+      } else {
+        /** for other/tensors, multiple maps exist as there are multiple mem */
+        map_data_float = ((gfloat *) map[ch_idx].data) + idx;
+      }
+      if (!gst_tensor_src_iio_process_scanned_data (channels->data, raw_data,
+              map_data_float)) {
+        GST_ERROR_OBJECT (self, "Error while processing scanned data.");
+        goto error_data_free;
+      }
     }
     raw_data += self->scan_size;
   }
 
   /** wrap up the buffer */
   g_free (raw_data_base);
-  gst_memory_unmap (mem, &map);
+  for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
+    gst_memory_unmap (mem[idx], &map[idx]);
+  }
 
   return GST_FLOW_OK;
 
 error_data_free:
   g_free (raw_data_base);
-  gst_memory_unmap (mem, &map);
+  for (idx = 0; idx < self->tensors_config->info.num_tensors; idx++) {
+    gst_memory_unmap (mem[idx], &map[idx]);
+  }
 
   return GST_FLOW_ERROR;
 }
index bd43abb..9278d18 100644 (file)
@@ -1225,6 +1225,10 @@ TEST (test_tensor_src_iio, data_verify_trigger)
   EXPECT_EQ (config.info.dimension[2], 1);
   EXPECT_EQ (config.info.dimension[3], 1);
 
+  gst_object_unref (src_iio);
+  gst_object_unref (src_pad);
+  gst_caps_unref (caps);
+
   /** let a few frames transfer */
   for (int idx = 0; idx < NUM_FRAMES; idx++) {
     /** wait for filter to process the frame and multifilesink to write it */
@@ -1347,6 +1351,10 @@ TEST (test_tensor_src_iio, data_verify_custom_channels)
   EXPECT_EQ (config.info.dimension[2], 1);
   EXPECT_EQ (config.info.dimension[3], 1);
 
+  gst_object_unref (src_iio);
+  gst_object_unref (src_pad);
+  gst_caps_unref (caps);
+
   /** verify paused state has been maintained */
   status =
       gst_element_get_state (src_iio_pipeline, &state, NULL,
@@ -1381,6 +1389,7 @@ TEST (test_tensor_src_iio, data_verify_freq_generic_type)
 {
   iio_dev_dir_struct *dev0;
   GstElement *src_iio_pipeline;
+  GstElement *src_iio;
   GstStateChangeReturn status;
   GstState state;
   gchar *parse_launch;
@@ -1394,10 +1403,15 @@ TEST (test_tensor_src_iio, data_verify_freq_generic_type)
   gchar *expect_val_char, *actual_val_char;
   struct stat stat_buf;
   gint stat_ret;
+  GstCaps *caps;
+  GstPad *src_pad;
+  GstStructure *structure;
+  GstTensorsConfig config;
+  gint num_scan_elements;
+
   data_value = DATA;
   data_bits = 16;
   gint samp_freq_idx = 1;
-  gint num_scan_elements;
   gchar *ret_string = NULL;
   const gchar *buffer_length_char = "3";
   /** Make device */
@@ -1410,7 +1424,7 @@ TEST (test_tensor_src_iio, data_verify_freq_generic_type)
   parse_launch =
       g_strdup_printf
       ("%s device-number=%d trigger-number=%d silent=FALSE frequency=%d "
-      "name=my-src-iio ! multifilesink location=%s",
+      "merge-channels-data=False name=my-src-iio ! multifilesink location=%s",
       ELEMENT_NAME, 0, 0, samp_freq, dev0->log_file);
   src_iio_pipeline = gst_parse_launch (parse_launch, NULL);
 
@@ -1434,6 +1448,40 @@ TEST (test_tensor_src_iio, data_verify_freq_generic_type)
   EXPECT_EQ (status, GST_STATE_CHANGE_SUCCESS);
   EXPECT_EQ (state, GST_STATE_PLAYING);
 
+  /** get and verify the caps */
+  src_iio = gst_bin_get_by_name (GST_BIN (src_iio_pipeline), "my-src-iio");
+  ASSERT_NE (src_iio, nullptr);
+  src_pad = gst_element_get_static_pad (src_iio, "src");
+  ASSERT_NE (src_pad, nullptr);
+  caps = gst_pad_get_current_caps (src_pad);
+  ASSERT_NE (caps, nullptr);
+  structure = gst_caps_get_structure (caps, 0);
+  ASSERT_NE (structure, nullptr);
+
+  /** Default has merge channels enabled */
+  EXPECT_STREQ (gst_structure_get_name (structure), "other/tensors");
+  EXPECT_EQ (gst_tensors_config_from_structure (&config, structure), TRUE);
+  EXPECT_EQ (config.rate_n, samp_freq);
+  EXPECT_EQ (config.rate_d, 1);
+  EXPECT_EQ (config.info.num_tensors, num_scan_elements);
+  for (int idx = 0; idx < num_scan_elements; idx++) {
+    EXPECT_EQ (config.info.info[idx].type, _NNS_FLOAT32);
+    EXPECT_EQ (config.info.info[idx].dimension[0], 1);
+    EXPECT_EQ (config.info.info[idx].dimension[1], 1);
+    EXPECT_EQ (config.info.info[idx].dimension[2], 1);
+    EXPECT_EQ (config.info.info[idx].dimension[3], 1);
+  }
+  for (int idx = num_scan_elements; idx < NNS_TENSOR_SIZE_LIMIT; idx++) {
+    EXPECT_EQ (config.info.info[idx].dimension[0], 0);
+    EXPECT_EQ (config.info.info[idx].dimension[1], 0);
+    EXPECT_EQ (config.info.info[idx].dimension[2], 0);
+    EXPECT_EQ (config.info.info[idx].dimension[3], 0);
+  }
+
+  gst_object_unref (src_iio);
+  gst_object_unref (src_pad);
+  gst_caps_unref (caps);
+
   /** let a few frames transfer */
   for (int idx = 0; idx < NUM_FRAMES; idx++) {
     /** wait for filter to process the frame and multifilesink to write it */