[common] Add API which appends a GstMemory into given GstBuffer
authorYongjoo Ahn <yongjoo1.ahn@samsung.com>
Thu, 9 Feb 2023 12:11:10 +0000 (21:11 +0900)
committerjaeyun-jung <39614140+jaeyun-jung@users.noreply.github.com>
Fri, 10 Feb 2023 10:54:40 +0000 (19:54 +0900)
- Add a function to check whether the given memory has extra tensors.
- Add an API which appends given GstMemory into given GstBuffer.
  It append the memory into the last block of buffer with given tensor
  info in extra tensor scenario.

Signed-off-by: Yongjoo Ahn <yongjoo1.ahn@samsung.com>
gst/nnstreamer/include/nnstreamer_plugin_api.h
gst/nnstreamer/nnstreamer_plugin_api_impl.c

index 130cbdc..d166613 100644 (file)
@@ -135,5 +135,23 @@ gst_tensors_extra_init (GstTensorExtraInfo * extra, GstMemory * memory);
 extern GstMemory *
 gst_tensors_get_nth_memory (GstBuffer * buffer, const GstTensorsInfo * info, const guint index);
 
+/**
+ * @brief Check if given @a mem has extra tensors.
+ * @param[in] mem GstMemory to be checked.
+ * @return TRUE if @mem has extra tensors, otherwise FALSE.
+*/
+extern gboolean
+is_extra_tensors_memory (GstMemory * mem);
+
+/**
+ * @brief Append @a memory to given @a buffer.
+ * @param[in/out] buffer GstBuffer to be appended.
+ * @param[in] memory GstMemory to append. This function will take ownership of this.
+ * @param[in] tensor_info GstTensorInfo of given @a memory.
+ * @return TRUE if successfully appended, otherwise FALSE.
+*/
+extern gboolean
+gst_tensors_extra_append_memory_to_buffer (GstBuffer * buffer, GstMemory * memory, const GstTensorInfo * tensor_info);
+
 G_END_DECLS
 #endif /* __NNS_PLUGIN_API_H__ */
index 7ebda30..20b6a76 100644 (file)
@@ -1556,3 +1556,144 @@ gst_tensors_get_nth_memory (GstBuffer * buffer, const GstTensorsInfo * info, con
 
   return res_mem;
 }
+
+/**
+ * @brief Check if given @a mem has extra tensors.
+ * @param[in] mem GstMemory to be checked.
+ * @return TRUE if @mem has extra tensors, otherwise FALSE.
+*/
+gboolean
+is_extra_tensors_memory (GstMemory * mem)
+{
+  GstMapInfo map;
+  GstTensorExtraInfo *extra_info;
+
+  g_return_val_if_fail (mem != NULL, FALSE);
+
+  if (!gst_memory_map (mem, &map, GST_MAP_READ)) {
+    nns_loge ("Failed to map extra memory");
+    return FALSE;
+  }
+
+  extra_info = (GstTensorExtraInfo *) map.data;
+  g_return_val_if_fail (extra_info != NULL, FALSE);
+
+  /* check header (extra info) of the memory */
+  /* check magic */
+  if (extra_info->magic != NNS_TENSOR_EXTRA_MAGIC) {
+    gst_memory_unmap (mem, &map);
+    return FALSE;
+  }
+
+  gst_memory_unmap (mem, &map);
+  return TRUE;
+}
+
+/**
+ * @brief Append @a memory to given @a buffer.
+ * @param[in/out] buffer GstBuffer to be appended.
+ * @param[in] memory GstMemory to append. This function will take ownership of this.
+ * @param[in] tensor_info GstTensorInfo of given @a memory.
+ * @return TRUE if successfully appended, otherwise FALSE.
+*/
+gboolean
+gst_tensors_extra_append_memory_to_buffer (GstBuffer * buffer, GstMemory * memory, const GstTensorInfo * tensor_info)
+{
+  guint num_mems, offset, i;
+
+  GstMemory *new_memory, *last_memory;
+  gsize new_mem_size;
+
+  GstMapInfo new_memory_map, last_memory_map, incoming_memory_map;
+  GstTensorExtraInfo *new_memory_extra_info;
+
+  if (!GST_IS_BUFFER (buffer)) {
+    nns_loge ("Failed to append memory, given buffer is invalid.");
+    return FALSE;
+  }
+
+  if (!memory) {
+    nns_loge ("Failed to append memory, given memory is NULL.");
+    return FALSE;
+  }
+
+  num_mems = gst_buffer_n_memory (buffer);
+
+  /* trivial call to gst_buffer_append_memory */
+  if (num_mems < NNS_TENSOR_SIZE_LIMIT) {
+    gst_buffer_append_memory (buffer, memory);
+    return TRUE;
+  }
+
+  /* given buffer has NNS_TENSOR_SIZE_LIMIT memory blocks */
+  last_memory = gst_buffer_peek_memory (buffer, num_mems - 1);
+  if (!last_memory) {
+    nns_loge ("Failed to get last memory");
+    return FALSE;
+  }
+
+  new_mem_size = gst_memory_get_sizes (last_memory, NULL, NULL);
+
+  /* if the memory does not have proper header, append it */
+  if (!is_extra_tensors_memory (last_memory)) {
+    new_mem_size += sizeof (GstTensorExtraInfo);
+  }
+
+  new_mem_size += gst_memory_get_sizes (memory, NULL, NULL);
+
+  new_memory = gst_allocator_alloc (NULL, new_mem_size, NULL);
+  if (!new_memory) {
+    nns_loge ("Failed to allocate memory for extra tensors.");
+    return FALSE;
+  }
+
+  if (!gst_memory_map (new_memory, &new_memory_map, GST_MAP_WRITE)) {
+    nns_loge ("Failed to map extra memory");
+    gst_memory_unref (new_memory);
+    return FALSE;
+  }
+
+  /* copy last_memory into new_memory */
+  if (!gst_memory_map (last_memory, &last_memory_map, GST_MAP_READ)) {
+    nns_loge ("Failed to map last memory");
+    gst_memory_unref (new_memory);
+    return FALSE;
+  }
+
+  /* if the last_memory does not have proper header, append it */
+  if (!is_extra_tensors_memory (last_memory)) {
+    GstTensorExtraInfo *extra_info = (GstTensorExtraInfo *) new_memory_map.data;
+    gst_tensors_extra_init (extra_info, last_memory);
+    extra_info->reserved = gst_memory_get_sizes (last_memory, NULL, NULL);
+    offset = sizeof (GstTensorExtraInfo);
+  } else {
+    offset = 0;
+  }
+
+  memcpy (new_memory_map.data + offset, last_memory_map.data, last_memory_map.size);
+
+  /* copy incoming_memory into new_memory*/
+  if (!gst_memory_map (memory, &incoming_memory_map, GST_MAP_READ)) {
+    nns_loge ("Failed to map incoming memory");
+    gst_memory_unref (new_memory);
+    return FALSE;
+  }
+
+  new_memory_extra_info = (GstTensorExtraInfo *) new_memory_map.data;
+  new_memory_extra_info->num_extra_tensors += 1;
+
+  for (i = 0; i < new_memory_extra_info->num_extra_tensors; ++i) {
+    gst_tensor_info_copy (&new_memory_extra_info->infos[i], tensor_info);
+  }
+
+  memcpy (new_memory_map.data + offset + last_memory_map.size, incoming_memory_map.data, incoming_memory_map.size);
+
+  gst_memory_unmap (new_memory, &new_memory_map);
+  gst_memory_unmap (memory, &incoming_memory_map);
+  gst_memory_unmap (last_memory, &last_memory_map);
+
+  gst_memory_unref (memory);
+  gst_buffer_replace_memory (buffer, num_mems - 1, new_memory);
+
+  return TRUE;
+}