Doxygen Book
gsttensor_merge.c
Go to the documentation of this file.
1 
55 #ifdef HAVE_CONFIG_H
56 #include <config.h>
57 #endif
58 
59 #include <string.h>
60 #include <gst/gst.h>
61 #include <glib.h>
62 #include <nnstreamer_util.h>
63 
64 #include "gsttensor_merge.h"
65 
66 GST_DEBUG_CATEGORY_STATIC (gst_tensor_merge_debug);
67 #define GST_CAT_DEFAULT gst_tensor_merge_debug
68 
72 #ifndef DBG
73 #define DBG (!tensor_merge->silent)
74 #endif
75 
76 enum
77 {
84 };
85 
86 static const gchar *gst_tensor_merge_mode_string[] = {
87  [GTT_LINEAR] = "linear",
88  [GTT_END] = "error",
89 };
90 
91 static const gchar *gst_tensor_merge_linear_string[] = {
92  [LINEAR_FIRST] = "0",
93  [LINEAR_SECOND] = "1",
94  [LINEAR_THIRD] = "2",
95  [LINEAR_FOURTH] = "3",
96  [LINEAR_END] = NULL,
97 };
98 
102 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_WITH_NUM ("1")
103 
108 static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
109  GST_PAD_SRC,
110  GST_PAD_ALWAYS,
111  GST_STATIC_CAPS (CAPS_STRING));
112 
113 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink_%u",
114  GST_PAD_SINK,
115  GST_PAD_REQUEST,
116  GST_STATIC_CAPS (CAPS_STRING));
117 
118 static gboolean gst_tensor_merge_src_event (GstPad * pad, GstObject * parent,
119  GstEvent * event);
120 static GstPad *gst_tensor_merge_request_new_pad (GstElement * element,
121  GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
122 static GstStateChangeReturn gst_tensor_merge_change_state (GstElement * element,
123  GstStateChange transition);
124 static gboolean gst_tensor_merge_sink_event (GstCollectPads * pads,
125  GstCollectData * data, GstEvent * event, GstTensorMerge * tensor_merge);
126 static GstFlowReturn gst_tensor_merge_collected (GstCollectPads * pads,
127  GstTensorMerge * tensor_merge);
128 
129 static void gst_tensor_merge_set_property (GObject * object, guint prop_id,
130  const GValue * value, GParamSpec * pspec);
131 static void gst_tensor_merge_get_property (GObject * object, guint prop_id,
132  GValue * value, GParamSpec * pspec);
133 static void gst_tensor_merge_finalize (GObject * object);
134 
135 #define gst_tensor_merge_parent_class parent_class
136 G_DEFINE_TYPE (GstTensorMerge, gst_tensor_merge, GST_TYPE_ELEMENT);
137 
141 static void
143 {
144  GObjectClass *gobject_class;
145  GstElementClass *gstelement_class;
146 
147  GST_DEBUG_CATEGORY_INIT (gst_tensor_merge_debug, "tensor_merge", 0,
148  "Element to merge multiple tensor stream to tensor stream");
149 
150  gobject_class = (GObjectClass *) klass;
151  gstelement_class = (GstElementClass *) klass;
152 
153  parent_class = g_type_class_peek_parent (klass);
154 
155  gobject_class->finalize = gst_tensor_merge_finalize;
156  gobject_class->get_property = gst_tensor_merge_get_property;
157  gobject_class->set_property = gst_tensor_merge_set_property;
158 
159  g_object_class_install_property (gobject_class, PROP_SILENT,
160  g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
161  TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
162 
163  g_object_class_install_property (gobject_class, PROP_MODE,
164  g_param_spec_string ("mode", "Mode",
165  "Tensor Merge mode. Currently, `linear` is available only.",
166  gst_tensor_merge_mode_string[GTT_LINEAR], G_PARAM_READWRITE));
167  g_object_class_install_property (gobject_class, PROP_OPTION,
168  g_param_spec_string ("option", "Option",
169  "Option for the tensor Merge mode.\n"
170  "\t\t\t 1) linear mode: it will become the index of the rank.\n"
171  "\t\t\t (e.g. want to merge 3:640:480 & 3:640:480 to 3:1280:480, option=1)\n"
172  "\t\t\t 2) TBU", "", G_PARAM_READWRITE));
173 
174  g_object_class_install_property (gobject_class, PROP_SYNC_MODE,
175  g_param_spec_string ("sync-mode", "Sync Mode",
176  "Time synchronization mode\n"
177  "\t\t\tSee also: https://github.com/nnstreamer/nnstreamer/blob/main/Documentation/synchronization-policies-at-mux-merge.md",
178  "", G_PARAM_READWRITE));
179 
180  g_object_class_install_property (gobject_class, PROP_SYNC_OPTION,
181  g_param_spec_string ("sync-option", "Sync Option",
182  "Option for the time synchronization mode", "", G_PARAM_READWRITE));
183 
184  gstelement_class->request_new_pad =
185  GST_DEBUG_FUNCPTR (gst_tensor_merge_request_new_pad);
186  gstelement_class->change_state =
187  GST_DEBUG_FUNCPTR (gst_tensor_merge_change_state);
188 
189  gst_element_class_add_pad_template (gstelement_class,
190  gst_static_pad_template_get (&sink_templ));
191  gst_element_class_add_pad_template (gstelement_class,
192  gst_static_pad_template_get (&src_templ));
193 
194  gst_element_class_set_details_simple (gstelement_class,
195  "TensorMerge",
196  "Muxer/Tensor",
197  "Merge multiple tensor stream to tensor stream",
198  "Jijoong Moon <jijoong.moon@samsung.com>");
199 
200 }
201 
208 static void
210 {
211  GstElementClass *klass = GST_ELEMENT_GET_CLASS (tensor_merge);
212 
213  tensor_merge->srcpad =
214  gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
215  "src"), "src");
216  gst_pad_set_event_function (tensor_merge->srcpad, gst_tensor_merge_src_event);
217 
218  gst_element_add_pad (GST_ELEMENT (tensor_merge), tensor_merge->srcpad);
219 
220  tensor_merge->collect = gst_collect_pads_new ();
221  gst_collect_pads_set_event_function (tensor_merge->collect,
222  (GstCollectPadsEventFunction)
223  GST_DEBUG_FUNCPTR (gst_tensor_merge_sink_event), tensor_merge);
224  gst_collect_pads_set_function (tensor_merge->collect,
225  (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_tensor_merge_collected),
226  tensor_merge);
227 
228  tensor_merge->silent = TRUE;
229  tensor_merge->sync.mode = SYNC_NOSYNC;
230  tensor_merge->sync.option = NULL;
231  gst_tensors_config_init (&tensor_merge->tensors_config);
232  tensor_merge->mode = GTT_LINEAR;
233  tensor_merge->loaded = FALSE;
234  tensor_merge->current_time = 0;
235  tensor_merge->need_set_time = TRUE;
236 }
237 
243 static tensor_merge_mode
244 gst_tensor_merge_get_mode (const gchar * str)
245 {
246  int i;
247  for (i = 0; i < GTT_END; i++) {
248  if (g_ascii_strcasecmp (gst_tensor_merge_mode_string[i], str) == 0)
249  return i;
250  }
251  return GTT_END;
252 }
253 
257 static void
258 gst_tensor_merge_finalize (GObject * object)
259 {
260  GstTensorMerge *tensor_merge;
261 
262  tensor_merge = GST_TENSOR_MERGE (object);
263 
264  if (tensor_merge->collect) {
265  gst_tensor_time_sync_flush (tensor_merge->collect);
266  gst_object_unref (tensor_merge->collect);
267  tensor_merge->collect = NULL;
268  }
269 
270  if (tensor_merge->option) {
271  g_free (tensor_merge->option);
272  tensor_merge->option = NULL;
273  }
274 
275  if (tensor_merge->sync.option) {
276  g_free (tensor_merge->sync.option);
277  tensor_merge->sync.option = NULL;
278  }
279 
280  G_OBJECT_CLASS (parent_class)->finalize (object);
281 }
282 
286 static GstPad *
287 gst_tensor_merge_request_new_pad (GstElement * element, GstPadTemplate * templ,
288  const gchar * req_name, const GstCaps * caps)
289 {
290  GstPad *newpad;
291  GstTensorMerge *tensor_merge;
292  GSList *walk;
293  guint length;
294  gchar *name;
295  UNUSED (req_name);
296  UNUSED (caps);
297 
298  g_return_val_if_fail (templ != NULL, NULL);
299  g_return_val_if_fail (GST_IS_TENSOR_MERGE (element), NULL);
300 
301  tensor_merge = GST_TENSOR_MERGE (element);
302  walk = tensor_merge->collect->data;
303  length = g_slist_length (walk);
304 
305  if (length >= NNS_TENSOR_SIZE_LIMIT) {
306  GST_ERROR_OBJECT (tensor_merge,
307  "supposed max number of tensors is " NNS_TENSOR_SIZE_LIMIT_STR);
308  return NULL;
309  }
310 
311  name = g_strdup_printf ("sink_%u", length);
312  newpad = gst_pad_new_from_template (templ, name);
313  g_free (name);
314 
315  if (newpad) {
316  GstTensorCollectPadData *tensormergepad;
317 
318  tensormergepad = (GstTensorCollectPadData *)
319  gst_collect_pads_add_pad (tensor_merge->collect, newpad,
320  sizeof (GstTensorCollectPadData), NULL, TRUE);
321 
322  gst_pad_set_element_private (newpad, tensormergepad);
323  gst_element_add_pad (element, newpad);
324  } else {
325  GST_WARNING_OBJECT (tensor_merge, "failed to create request pad");
326  }
327  return newpad;
328 }
329 
333 static gboolean
334 gst_tensor_merge_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
335 {
336  g_return_val_if_fail (event != NULL, FALSE);
337 
338  switch (GST_EVENT_TYPE (event)) {
339  case GST_EVENT_SEEK:
340  gst_event_unref (event);
341  return FALSE;
342  default:
343  break;
344  }
345 
346  return gst_pad_event_default (pad, parent, event);
347 }
348 
352 static gboolean
353 gst_tensor_merge_sink_event (GstCollectPads * pads, GstCollectData * data,
354  GstEvent * event, GstTensorMerge * tensor_merge)
355 {
356  g_return_val_if_fail (event != NULL, FALSE);
357 
358  switch (GST_EVENT_TYPE (event)) {
359  case GST_EVENT_FLUSH_STOP:
360  tensor_merge->need_segment = TRUE;
361  tensor_merge->need_set_time = TRUE;
362  gst_tensor_time_sync_flush (tensor_merge->collect);
363  break;
364  default:
365  break;
366  }
367 
368  return gst_collect_pads_event_default (pads, data, event, FALSE);
369 }
370 
378 static gboolean
380  const GstTensorsConfig * in_config, GstTensorsConfig * out_config)
381 {
382  GstTensorsInfo *in_info;
383  GstTensorInfo *_info;
384  gboolean ret = FALSE;
385  guint i;
386  gint j;
387  tensor_dim dim;
389 
390  gst_tensors_config_init (out_config);
391 
392  in_info = (GstTensorsInfo *) &in_config->info;
393  _info = gst_tensors_info_get_nth_info (in_info, 0);
394 
395  type = _info->type;
396  memcpy (&dim, &_info->dimension, sizeof (tensor_dim));
397 
398  for (i = 1; i < in_config->info.num_tensors; i++) {
399  _info = gst_tensors_info_get_nth_info (in_info, i);
400 
401  if (type != _info->type)
402  GST_ELEMENT_ERROR (tensor_merge, CORE, NEGOTIATION, (NULL), (NULL));
403  }
404 
405  switch (tensor_merge->mode) {
406  case GTT_LINEAR:
407  {
408  int targetIdx = tensor_merge->data_linear.direction;
409  for (i = 1; i < in_config->info.num_tensors; i++) {
410  _info = gst_tensors_info_get_nth_info (in_info, i);
411 
412  for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++) {
413  if (j == targetIdx) {
414  dim[j] += _info->dimension[j];
415  } else {
416  if (dim[j] != _info->dimension[j])
417  GST_ELEMENT_ERROR (tensor_merge, CORE, NEGOTIATION, (NULL),
418  (NULL));
419  }
420  }
421  }
422 
423  out_config->info.num_tensors = 1;
424  out_config->rate_d = in_config->rate_d;
425  out_config->rate_n = in_config->rate_n;
426 
427  _info = gst_tensors_info_get_nth_info (&out_config->info, 0);
428  _info->type = type;
429  memcpy (&_info->dimension, &dim, sizeof (tensor_dim));
430  ret = TRUE;
431  }
432  break;
433  default:
434  ret = FALSE;
435  }
436 
437  return ret;
438 }
439 
447 static gboolean
449  GstBuffer * tensors_buf, gboolean * is_eos)
450 {
451  if (tensor_merge->need_set_time) {
453  &tensor_merge->sync, &tensor_merge->current_time, tensors_buf)) {
454  /* end-of-stream */
455  *is_eos = TRUE;
456  return FALSE;
457  }
458 
459  tensor_merge->need_set_time = FALSE;
460  }
461 
463  &tensor_merge->sync, tensor_merge->current_time, tensors_buf,
464  &tensor_merge->tensors_config, is_eos);
465 }
466 
474 static GstFlowReturn
476  GstBuffer * tensors_buf, GstBuffer * tensor_buf)
477 {
478  GstFlowReturn ret = GST_FLOW_OK;
479  GstMapInfo mInfo[NNS_TENSOR_SIZE_LIMIT];
480  GstMemory *mem[NNS_TENSOR_SIZE_LIMIT];
481  GstMapInfo outInfo;
482  GstMemory *outMem;
483  uint8_t *inptr, *outptr;
484  guint num_mem = tensor_merge->tensors_config.info.num_tensors;
485  GstTensorsInfo *info;
486  GstTensorInfo *_info;
487  guint i, j, k, l;
488  size_t c, s;
489  gsize outSize = 0;
490  gsize element_size;
491  tensor_dim dim;
493 
494  info = &tensor_merge->tensors_config.info;
495  _info = gst_tensors_info_get_nth_info (info, 0);
496 
497  memcpy (&dim, &_info->dimension, sizeof (tensor_dim));
498  type = _info->type;
499  element_size = gst_tensor_get_element_size (type);
500 
501  for (i = 0; i < num_mem; i++) {
502  mem[i] = gst_tensor_buffer_get_nth_memory (tensors_buf, i);
503  if (!gst_memory_map (mem[i], &mInfo[i], GST_MAP_READ)) {
504  ml_logf ("Cannot map input memory buffers (%d)\n", i);
505  gst_memory_unref (mem[i]);
506  num_mem = i;
507  ret = GST_FLOW_ERROR;
508  goto error_ret;
509  }
510  outSize += mInfo[i].size;
511  }
512 
513  outMem = gst_allocator_alloc (NULL, outSize, NULL);
514  if (!gst_memory_map (outMem, &outInfo, GST_MAP_WRITE)) {
515  gst_memory_unref (outMem);
516  ml_logf ("Cannot map output memory buffer\n");
517  ret = GST_FLOW_ERROR;
518  goto error_ret;
519  }
520  outptr = outInfo.data;
521 
522  switch (tensor_merge->mode) {
523  case GTT_LINEAR:
524  {
525  switch (tensor_merge->data_linear.direction) {
526  case LINEAR_FIRST:
527  {
528  for (l = 0; l < dim[3]; l++) {
529  for (i = 0; i < dim[2]; i++) {
530  for (j = 0; j < dim[1]; j++) {
531  for (k = 0; k < num_mem; k++) {
532  _info = gst_tensors_info_get_nth_info (info, k);
533 
534  c = _info->dimension[0];
535  s = element_size * c;
536  inptr =
537  mInfo[k].data + (l * dim[2] * dim[1] + i * dim[1] +
538  j) * s;
539  memcpy (outptr, inptr, s);
540  outptr += s;
541  }
542  }
543  }
544  }
545  break;
546  }
547  case LINEAR_SECOND:
548  {
549  for (l = 0; l < dim[3]; l++) {
550  for (i = 0; i < dim[2]; i++) {
551  for (k = 0; k < num_mem; k++) {
552  _info = gst_tensors_info_get_nth_info (info, k);
553 
554  c = 1;
555  for (j = 0; j < LINEAR_SECOND + 1; j++)
556  c *= _info->dimension[j];
557 
558  s = element_size * c;
559 
560  inptr = mInfo[k].data + (l * dim[2] + i) * s;
561 
562  memcpy (outptr, inptr, s);
563  outptr += s;
564  }
565  }
566  }
567  break;
568  }
569  case LINEAR_THIRD:
570  {
571  for (l = 0; l < dim[3]; l++) {
572  for (k = 0; k < num_mem; k++) {
573  _info = gst_tensors_info_get_nth_info (info, k);
574 
575  c = 1;
576  for (j = 0; j < LINEAR_THIRD + 1; j++)
577  c *= _info->dimension[j];
578 
579  s = element_size * c;
580 
581  inptr = mInfo[k].data + l * s;
582 
583  memcpy (outptr, inptr, s);
584  outptr += s;
585  }
586  }
587  break;
588  }
589  case LINEAR_FOURTH:
590  {
591  for (k = 0; k < num_mem; k++) {
592  _info = gst_tensors_info_get_nth_info (info, k);
593 
594  c = 1;
595  for (j = 0; j < LINEAR_FOURTH + 1; j++)
596  c *= _info->dimension[j];
597 
598  s = element_size * c;
599 
600  inptr = mInfo[k].data;
601  memcpy (outptr, inptr, s);
602  outptr += s;
603  }
604  break;
605  }
606  default:
607  ret = GST_FLOW_ERROR;
608  }
609  break;
610  }
611  default:
612  ret = GST_FLOW_ERROR;
613  }
614 
615  gst_memory_unmap (outMem, &outInfo);
616  gst_buffer_append_memory (tensor_buf, outMem);
617  gst_buffer_copy_into (tensor_buf, tensors_buf, GST_BUFFER_COPY_TIMESTAMPS, 0,
618  -1);
619 
620 error_ret:
621  for (i = 0; i < num_mem; i++) {
622  gst_memory_unmap (mem[i], &mInfo[i]);
623  gst_memory_unref (mem[i]);
624  }
625  return ret;
626 }
627 
631 static gboolean
633 {
634  if (!tensor_merge->negotiated) {
635  GstCaps *newcaps;
636  GstTensorsConfig config;
637 
638  if (!gst_tensor_merge_get_merged_config (tensor_merge,
639  &tensor_merge->tensors_config, &config)) {
640  goto nego_error;
641  }
642 
645  newcaps = gst_tensor_pad_caps_from_config (tensor_merge->srcpad, &config);
646 
647  if (gst_pad_set_caps (tensor_merge->srcpad, newcaps)) {
648  tensor_merge->negotiated = TRUE;
649  }
650 
651  gst_caps_unref (newcaps);
652  }
653 
654 nego_error:
655  if (!tensor_merge->negotiated) {
656  GST_WARNING_OBJECT (tensor_merge, "failed to set caps");
657  GST_ELEMENT_ERROR (tensor_merge, CORE, NEGOTIATION, (NULL), (NULL));
658  }
659  return tensor_merge->negotiated;
660 }
661 
665 static void
667  GstClockTime pts, GstClockTime dts)
668 {
669  if (tensor_merge->need_segment) {
670  GstSegment segment;
671  GstClockTime time = 0;
672 
673  if (GST_CLOCK_TIME_IS_VALID (dts)) {
674  time = dts;
675  } else if (GST_CLOCK_TIME_IS_VALID (pts)) {
676  time = pts;
677  }
678 
679  gst_segment_init (&segment, GST_FORMAT_TIME);
680  segment.start = time;
681  gst_pad_push_event (tensor_merge->srcpad, gst_event_new_segment (&segment));
682  tensor_merge->need_segment = FALSE;
683  }
684 }
685 
692 static GstFlowReturn
693 gst_tensor_merge_collected (GstCollectPads * pads,
694  GstTensorMerge * tensor_merge)
695 {
696  GstFlowReturn ret = GST_FLOW_OK;
697  GstBuffer *tensors_buf, *tensor_buf;
698  gboolean isEOS = FALSE;
699 
700  GST_DEBUG_OBJECT (tensor_merge, " all pads are collected ");
701 
702  if (tensor_merge->need_stream_start) {
707  GstCollectData *data = (GstCollectData *) pads->data->data;
708  g_autofree gchar *sink_stream_id = gst_pad_get_stream_id (data->pad);
709  g_autofree gchar *element_name = gst_element_get_name (tensor_merge);
710  g_autofree gchar *pad_name = gst_pad_get_name (tensor_merge->srcpad);
711  g_autofree gchar *stream_id = g_strdup_printf ("%s-%s-nnsmerge-%s-%08x",
712  GST_STR_NULL (sink_stream_id), element_name, pad_name, g_random_int ());
713 
714  gst_pad_push_event (tensor_merge->srcpad, gst_event_new_stream_start (stream_id));
715  tensor_merge->need_stream_start = FALSE;
716  }
717 
718  if ((tensors_buf = gst_buffer_new ()) == NULL) {
719  ml_logf ("gst_buffer_new() returns NULL. Out of memory?\n");
720  return GST_FLOW_ERROR;
721  }
722 
723  if (!gst_tensor_merge_collect_buffer (tensor_merge, tensors_buf, &isEOS)) {
724  if (isEOS) {
725  gst_pad_push_event (tensor_merge->srcpad, gst_event_new_eos ());
726  ret = GST_FLOW_EOS;
727  }
728 
729  goto beach;
730  }
731 
732  if (!gst_tensor_merge_set_src_caps (tensor_merge)) {
733  ret = GST_FLOW_NOT_NEGOTIATED;
734  goto beach;
735  }
736 
738  GST_BUFFER_PTS (tensors_buf), GST_BUFFER_DTS (tensors_buf));
739 
740  if ((tensor_buf = gst_buffer_new ()) == NULL) {
741  ml_logf ("gst_buffer_new() returns NULL. Out of memory?\n");
742  ret = GST_FLOW_ERROR;
743  goto beach;
744  }
745 
746  gst_tensor_merge_generate_mem (tensor_merge, tensors_buf, tensor_buf);
747 
748  ret = gst_pad_push (tensor_merge->srcpad, tensor_buf);
749  tensor_merge->need_set_time = TRUE;
750 
751  if (ret != GST_FLOW_OK) {
752  GST_WARNING_OBJECT (tensor_merge, "pushed outbuf, result = %s",
753  gst_flow_get_name (ret));
754  }
755 beach:
756  gst_buffer_unref (tensors_buf);
757  return ret;
758 }
759 
763 static void
765 {
766  tensor_merge->need_stream_start = TRUE;
767  tensor_merge->need_segment = TRUE;
768  tensor_merge->negotiated = FALSE;
769  gst_collect_pads_start (tensor_merge->collect);
770 }
771 
775 static GstStateChangeReturn
776 gst_tensor_merge_change_state (GstElement * element, GstStateChange transition)
777 {
778  GstTensorMerge *tensor_merge;
779  GstStateChangeReturn ret;
780  tensor_merge = GST_TENSOR_MERGE (element);
781  switch (transition) {
782  case GST_STATE_CHANGE_READY_TO_PAUSED:
783  gst_tensor_merge_ready_to_paused (tensor_merge);
784  break;
785  case GST_STATE_CHANGE_PAUSED_TO_READY:
786  gst_collect_pads_stop (tensor_merge->collect);
787  break;
788  default:
789  break;
790  }
791 
792  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
793  if (ret == GST_STATE_CHANGE_FAILURE)
794  return ret;
795  switch (transition) {
796  case GST_STATE_CHANGE_PAUSED_TO_READY:
797  break;
798  default:
799  break;
800  }
801 
802  return ret;
803 }
804 
811 static gboolean
813 {
814  if (tensor_merge->mode == GTT_END || tensor_merge->option == NULL)
815  return TRUE;
816  switch (tensor_merge->mode) {
817  case GTT_LINEAR:
818  {
819  gint idx;
820 
821  idx =
823  if (idx < 0)
824  return FALSE;
825 
826  tensor_merge->data_linear.direction = (tensor_merge_linear_mode) idx;
827  tensor_merge->loaded = TRUE;
828  }
829  break;
830  default:
831  GST_ERROR_OBJECT (tensor_merge, "Cannot identify mode\n");
832  return FALSE;
833  }
834  return TRUE;
835 }
836 
840 static void
841 gst_tensor_merge_set_property (GObject * object, guint prop_id,
842  const GValue * value, GParamSpec * pspec)
843 {
844  GstTensorMerge *tensor_merge = GST_TENSOR_MERGE (object);
845  switch (prop_id) {
846  case PROP_SILENT:
847  tensor_merge->silent = g_value_get_boolean (value);
848  break;
849  case PROP_MODE:
850  tensor_merge->mode =
851  gst_tensor_merge_get_mode (g_value_get_string (value));
852  if (tensor_merge->mode == GTT_END) {
853  ml_logw ("Given mode property is not recognized: %s\n",
854  g_value_get_string (value));
855  break;
856  }
857  if (!gst_tensor_merge_set_option_data (tensor_merge)) {
858  tensor_merge->loaded = FALSE;
859  ml_logw ("Given mode property is not consistent with its options.\n");
860  }
861  break;
862  case PROP_OPTION:
863  tensor_merge->option = g_value_dup_string (value);
864  if (!gst_tensor_merge_set_option_data (tensor_merge)) {
865  tensor_merge->loaded = FALSE;
866  ml_logw ("Given option property is not consistent with its mode.\n");
867  }
868  break;
869  case PROP_SYNC_MODE:
870  tensor_merge->sync.mode =
871  gst_tensor_time_sync_get_mode (g_value_get_string (value));
872  if (tensor_merge->sync.mode == SYNC_END) {
873  tensor_merge->sync.mode = SYNC_NOSYNC;
874  }
875  silent_debug (tensor_merge, "Mode = %d(%s)\n", tensor_merge->sync.mode,
878  break;
879  case PROP_SYNC_OPTION:
880  tensor_merge->sync.option = g_value_dup_string (value);
881  silent_debug (tensor_merge, "Option = %s\n", tensor_merge->sync.option);
883  break;
884  default:
885  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
886  break;
887  }
888 }
889 
893 static void
894 gst_tensor_merge_get_property (GObject * object, guint prop_id,
895  GValue * value, GParamSpec * pspec)
896 {
897  GstTensorMerge *tensor_merge = GST_TENSOR_MERGE (object);
898  switch (prop_id) {
899  case PROP_SILENT:
900  g_value_set_boolean (value, tensor_merge->silent);
901  break;
902  case PROP_MODE:
903  g_value_set_string (value,
904  gst_tensor_merge_mode_string[tensor_merge->mode]);
905  break;
906  case PROP_OPTION:
907  g_value_set_string (value, tensor_merge->option);
908  break;
909  case PROP_SYNC_MODE:
910  g_value_set_string (value,
912  break;
913  case PROP_SYNC_OPTION:
914  g_value_set_string (value, tensor_merge->sync.option);
915  break;
916  default:
917  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
918  break;
919  }
920 }
find_key_strv
gint find_key_strv(const gchar **strv, const gchar *key)
Find the index value of the given key string array.
Definition: nnstreamer_plugin_api_util_impl.c:1586
_GstTensorMerge::data_linear
tensor_merge_linear data_linear
Definition: gsttensor_merge.h:81
PROP_SYNC_OPTION
@ PROP_SYNC_OPTION
Definition: gsttensor_merge.c:82
gst_tensor_merge_generate_mem
static GstFlowReturn gst_tensor_merge_generate_mem(GstTensorMerge *tensor_merge, GstBuffer *tensors_buf, GstBuffer *tensor_buf)
Generate Output GstMemory.
Definition: gsttensor_merge.c:475
gst_tensor_merge_get_merged_config
static gboolean gst_tensor_merge_get_merged_config(GstTensorMerge *tensor_merge, const GstTensorsConfig *in_config, GstTensorsConfig *out_config)
Generate out TensorsConfig with in TensorsConfig.
Definition: gsttensor_merge.c:379
gst_tensor_merge_init
static void gst_tensor_merge_init(GstTensorMerge *tensor_merge)
initialize the new element instantiate pads and add them to element set pad callback functions initia...
Definition: gsttensor_merge.c:209
g_assert
g_assert(sizeof(DTYPE_UNSIGNED)==sizeof(DTYPE_SIGNED))
SYNC_NOSYNC
@ SYNC_NOSYNC
Definition: tensor_common.h:64
data
svtc_1 data
Definition: gsttensor_if.c:844
GstTensorInfo
Internal data structure for tensor info.
Definition: tensor_typedef.h:261
ml_logw
#define ml_logw
Definition: nnstreamer_log.h:77
NNS_TENSOR_SIZE_LIMIT
#define NNS_TENSOR_SIZE_LIMIT
The number of tensors NNStreamer supports is 256. The max memories of gst-buffer is 16 (See NNS_TENSO...
Definition: tensor_typedef.h:42
tensor_dim
uint32_t tensor_dim[NNS_TENSOR_RANK_LIMIT]
Definition: tensor_typedef.h:247
gst_tensor_merge_linear_string
static const gchar * gst_tensor_merge_linear_string[]
Definition: gsttensor_merge.c:91
gst_tensor_time_sync_set_option_data
gboolean gst_tensor_time_sync_set_option_data(tensor_time_sync_data *sync)
Setup time sync option.
Definition: nnstreamer_plugin_api_impl.c:126
FALSE
return FALSE
Definition: gsttensor_transform.c:590
gsttensor_merge.h
GStreamer plugin to merge tensors (as a filter for other general neural network filters)
ml_logf
#define ml_logf
Definition: nnstreamer_log.h:80
GstTensorsInfo
Internal meta data exchange format for a other/tensors instance.
Definition: tensor_typedef.h:273
LINEAR_FOURTH
@ LINEAR_FOURTH
Definition: gsttensor_merge.h:56
gst_tensor_merge_set_option_data
static gboolean gst_tensor_merge_set_option_data(GstTensorMerge *tensor_merge)
Setup internal data (data_* in GstTensor_Merge)
Definition: gsttensor_merge.c:812
gst_tensor_time_sync_buffer_from_collectpad
gboolean gst_tensor_time_sync_buffer_from_collectpad(GstCollectPads *collect, tensor_time_sync_data *sync, GstClockTime current_time, GstBuffer *tensors_buf, GstTensorsConfig *configs, gboolean *is_eos)
A function call to make tensors from collected pads. It decide which buffer is going to be used accor...
Definition: nnstreamer_plugin_api_impl.c:332
gst_tensor_merge_collect_buffer
static gboolean gst_tensor_merge_collect_buffer(GstTensorMerge *tensor_merge, GstBuffer *tensors_buf, gboolean *is_eos)
Looping to generete output buffer for srcpad.
Definition: gsttensor_merge.c:448
gst_tensor_pad_caps_from_config
GstCaps * gst_tensor_pad_caps_from_config(GstPad *pad, const GstTensorsConfig *config)
Get pad caps from tensors config and caps of the peer connected to the pad.
Definition: nnstreamer_plugin_api_impl.c:1209
gst_tensor_merge_ready_to_paused
static void gst_tensor_merge_ready_to_paused(GstTensorMerge *tensor_merge)
Ready --> Pasuse State Change.
Definition: gsttensor_merge.c:764
NNS_TENSOR_SIZE_LIMIT_STR
#define NNS_TENSOR_SIZE_LIMIT_STR
Definition: tensor_typedef.h:43
gst_tensor_time_sync_get_mode_string
const gchar * gst_tensor_time_sync_get_mode_string(tensor_time_sync_mode mode)
Get the time-sync mode string.
Definition: nnstreamer_plugin_api_impl.c:115
gst_tensor_merge_mode_string
static const gchar * gst_tensor_merge_mode_string[]
Definition: gsttensor_merge.c:86
_GstTensorMerge::srcpad
GstPad * srcpad
Definition: gsttensor_merge.h:77
SYNC_END
@ SYNC_END
Definition: tensor_common.h:68
GstTensorsConfig::rate_d
int rate_d
Definition: tensor_typedef.h:288
PROP_OPTION
@ PROP_OPTION
Definition: gsttensor_merge.c:80
G_DEFINE_TYPE
G_DEFINE_TYPE(GstTensorMerge, gst_tensor_merge, GST_TYPE_ELEMENT)
sink_templ
static GstStaticPadTemplate sink_templ
Definition: gsttensor_merge.c:113
silent_debug
#define silent_debug(self,...)
Macro for debug message.
Definition: tensor_common.h:276
LINEAR_FIRST
@ LINEAR_FIRST
Definition: gsttensor_merge.h:53
g_free
g_free(self->option[(opnum) - 1])
opnum: \
tensor_type
enum _nns_tensor_type tensor_type
Possible data element types of other/tensor.
tensor_merge_linear_mode
tensor_merge_linear_mode
Definition: gsttensor_merge.h:51
_GstTensorMerge::collect
GstCollectPads * collect
Definition: gsttensor_merge.h:85
PROP_0
@ PROP_0
Definition: gsttensor_merge.c:78
_GstTensorMerge::sync
tensor_time_sync_data sync
Definition: gsttensor_merge.h:76
_GstTensorMerge::negotiated
gboolean negotiated
Definition: gsttensor_merge.h:86
_GstTensorMerge
Tensor Merge data structure.
Definition: gsttensor_merge.h:71
g_value_set_string
g_value_set_string(value, self->option[opnum - 1])
opnum: \
_GstTensorMerge::tensors_config
GstTensorsConfig tensors_config
Definition: gsttensor_merge.h:93
GstTensorsConfig::rate_n
int rate_n
Definition: tensor_typedef.h:287
_GstTensorMergeClass
GstTensorMergeClass inherits GstElementClass.
Definition: gsttensor_merge.h:99
_GstTensorMerge::mode
tensor_merge_mode mode
Definition: gsttensor_merge.h:79
LINEAR_END
@ LINEAR_END
Definition: gsttensor_merge.h:57
gst_tensor_get_element_size
gsize gst_tensor_get_element_size(tensor_type type)
Get element size of tensor type (byte per element)
Definition: nnstreamer_plugin_api_util_impl.c:1205
_GstTensorMerge::need_set_time
gboolean need_set_time
Definition: gsttensor_merge.h:92
PROP_SILENT
@ PROP_SILENT
Definition: gsttensor_merge.c:83
_GstTensorMerge::loaded
gboolean loaded
Definition: gsttensor_merge.h:84
_GstTensorMerge::need_stream_start
gboolean need_stream_start
Definition: gsttensor_merge.h:88
gst_tensor_merge_set_property
static void gst_tensor_merge_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Get property (gst element vmethod)
Definition: gsttensor_merge.c:841
CAPS_STRING
#define CAPS_STRING
Template caps string.
Definition: gsttensor_merge.c:102
_GstTensorMerge::option
gchar * option
Definition: gsttensor_merge.h:78
gst_tensor_merge_change_state
static GstStateChangeReturn gst_tensor_merge_change_state(GstElement *element, GstStateChange transition)
change state (gst element vmethod)
Definition: gsttensor_merge.c:776
_GstTensorMerge::silent
gboolean silent
Definition: gsttensor_merge.h:75
GstTensorsConfig
Internal data structure for configured tensors info (for other/tensors).
Definition: tensor_typedef.h:284
TRUE
return TRUE
Definition: gsttensor_if.c:897
UNUSED
#define UNUSED(expr)
Definition: mqttcommon.h:19
gst_tensor_merge_class_init
static void gst_tensor_merge_class_init(GstTensorMergeClass *klass)
initialize the tensor_merge's class
Definition: gsttensor_merge.c:142
GstTensorCollectPadData
Internal data structure for Collect Pad in mux / merge.
Definition: tensor_common.h:93
nnstreamer_util.h
Optional NNStreamer utility functions for sub-plugin writers and users.
gst_tensor_merge_sink_event
static gboolean gst_tensor_merge_sink_event(GstCollectPads *pads, GstCollectData *data, GstEvent *event, GstTensorMerge *tensor_merge)
sink event vmethod
Definition: gsttensor_merge.c:353
_tensor_time_sync_data::mode
tensor_time_sync_mode mode
Definition: tensor_common.h:83
PROP_MODE
@ PROP_MODE
Definition: gsttensor_merge.c:79
gst_tensors_info_get_nth_info
GstTensorInfo * gst_tensors_info_get_nth_info(GstTensorsInfo *info, guint index)
Get the pointer of nth tensor information.
Definition: nnstreamer_plugin_api_util_impl.c:296
_tensor_time_sync_data::option
gchar * option
Definition: tensor_common.h:84
gst_tensor_merge_send_segment_event
static void gst_tensor_merge_send_segment_event(GstTensorMerge *tensor_merge, GstClockTime pts, GstClockTime dts)
Send segment event if necessary.
Definition: gsttensor_merge.c:666
GST_IS_TENSOR_MERGE
#define GST_IS_TENSOR_MERGE(obj)
Definition: gsttensor_merge.h:39
src_templ
static GstStaticPadTemplate src_templ
the capabilities of the inputs and outputs. describe the real formats here.
Definition: gsttensor_merge.c:108
gst_tensor_merge_get_property
static void gst_tensor_merge_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
Get property (gst element vmethod)
Definition: gsttensor_merge.c:894
gst_tensor_merge_finalize
static void gst_tensor_merge_finalize(GObject *object)
finalize vmethod
Definition: gsttensor_merge.c:258
GST_TENSOR_MERGE
#define GST_TENSOR_MERGE(obj)
Definition: gsttensor_merge.h:36
gst_tensor_merge_collected
static GstFlowReturn gst_tensor_merge_collected(GstCollectPads *pads, GstTensorMerge *tensor_merge)
Gst Collect Pads Function which is called once collect pads done.
Definition: gsttensor_merge.c:693
gst_tensor_merge_request_new_pad
static GstPad * gst_tensor_merge_request_new_pad(GstElement *element, GstPadTemplate *templ, const gchar *name, const GstCaps *caps)
making new request pad (gst element vmethod)
Definition: gsttensor_merge.c:287
_GstTensorMerge::current_time
GstClockTime current_time
Definition: gsttensor_merge.h:91
_GstTensorMerge::need_segment
gboolean need_segment
Definition: gsttensor_merge.h:87
GstTensorsInfo::num_tensors
unsigned int num_tensors
Definition: tensor_typedef.h:275
PROP_SYNC_MODE
@ PROP_SYNC_MODE
Definition: gsttensor_merge.c:81
gst_tensor_buffer_get_nth_memory
GstMemory * gst_tensor_buffer_get_nth_memory(GstBuffer *buffer, const guint index)
Get the nth GstMemory from given buffer.
Definition: nnstreamer_plugin_api_impl.c:1586
GTT_LINEAR
@ GTT_LINEAR
Definition: gsttensor_merge.h:47
gst_tensors_config_init
void gst_tensors_config_init(GstTensorsConfig *config)
Initialize the tensors config info structure (for other/tensors)
Definition: nnstreamer_plugin_api_util_impl.c:830
_tensor_merge_linear::direction
tensor_merge_linear_mode direction
Definition: gsttensor_merge.h:65
tensor_merge_mode
tensor_merge_mode
Definition: gsttensor_merge.h:45
GstTensorInfo::type
tensor_type type
Definition: tensor_typedef.h:266
GstTensorsConfig::info
GstTensorsInfo info
Definition: tensor_typedef.h:286
gst_tensors_config_validate
gboolean gst_tensors_config_validate(const GstTensorsConfig *config)
Check the tensors are all configured (for other/tensors)
Definition: nnstreamer_plugin_api_util_impl.c:858
GTT_END
@ GTT_END
Definition: gsttensor_merge.h:48
gst_tensor_merge_get_mode
static tensor_merge_mode gst_tensor_merge_get_mode(const gchar *str)
Get the corresponding mode from the string value.
Definition: gsttensor_merge.c:244
LINEAR_SECOND
@ LINEAR_SECOND
Definition: gsttensor_merge.h:54
LINEAR_THIRD
@ LINEAR_THIRD
Definition: gsttensor_merge.h:55
gst_tensor_time_sync_get_current_time
gboolean gst_tensor_time_sync_get_current_time(GstCollectPads *collect, tensor_time_sync_data *sync, GstClockTime *current_time, GstBuffer *tensors_buf)
A function call to decide current timestamp among collected pads based on PTS. It will decide current...
Definition: nnstreamer_plugin_api_impl.c:203
GstTensorInfo::dimension
tensor_dim dimension
Definition: tensor_typedef.h:267
NNS_TENSOR_RANK_LIMIT
#define NNS_TENSOR_RANK_LIMIT
Definition: tensor_typedef.h:34
type
svtc_1 type
Definition: gsttensor_if.c:843
gst_tensor_time_sync_get_mode
tensor_time_sync_mode gst_tensor_time_sync_get_mode(const gchar *str)
Get the corresponding mode from the string value.
Definition: nnstreamer_plugin_api_impl.c:101
gst_tensor_merge_src_event
static gboolean gst_tensor_merge_src_event(GstPad *pad, GstObject *parent, GstEvent *event)
src event vmethod
Definition: gsttensor_merge.c:334
gst_tensor_time_sync_flush
void gst_tensor_time_sync_flush(GstCollectPads *collect)
A function to be called while processing a flushing event. It should clear old buffer and reset pad d...
Definition: nnstreamer_plugin_api_impl.c:263
GST_DEBUG_CATEGORY_STATIC
GST_DEBUG_CATEGORY_STATIC(gst_tensor_merge_debug)
gst_tensor_merge_set_src_caps
static gboolean gst_tensor_merge_set_src_caps(GstTensorMerge *tensor_merge)
Set src pad caps if src pad is not negotiated.
Definition: gsttensor_merge.c:632