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;
/**
* @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
* 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
{
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);
}
/** parse the read data */
- map_data_float = (gfloat *) map.data;
raw_data = raw_data_base;
/**
* 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;
}
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 */
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,
{
iio_dev_dir_struct *dev0;
GstElement *src_iio_pipeline;
+ GstElement *src_iio;
GstStateChangeReturn status;
GstState state;
gchar *parse_launch;
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 */
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);
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 */