Doxygen Book
gsttensor_converter.c
Go to the documentation of this file.
1 
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46 
47 #include <string.h>
48 #include "gsttensor_converter.h"
49 #include "tensor_meta.h"
50 
51 #ifdef NO_VIDEO
53 #else
55 #endif
56 
57 #ifdef NO_AUDIO
59 #else
61 #endif
62 #include <nnstreamer_log.h>
63 #include <nnstreamer_subplugin.h>
64 #include <nnstreamer_util.h>
65 
69 #define TEXT_CAPS_STR "text/x-raw, format = (string) utf8"
70 
71 #define append_text_caps_template(caps) \
72  gst_caps_append (caps, gst_caps_from_string (TEXT_CAPS_STR))
73 
77 #define OCTET_CAPS_STR "application/octet-stream"
78 
79 #define append_octet_caps_template(caps) \
80  gst_caps_append (caps, gst_caps_from_string (OCTET_CAPS_STR))
81 
85 #define append_flex_tensor_caps_template(caps) \
86  gst_caps_append (caps, gst_caps_from_string (GST_TENSORS_FLEX_CAP_DEFAULT))
87 
91 #ifndef DBG
92 #define DBG (!self->silent)
93 #endif
94 
95 #define silent_debug_timestamp(self, buf) do { \
96  if (DBG) { \
97  GST_DEBUG_OBJECT (self, "pts = %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (buf))); \
98  GST_DEBUG_OBJECT (self, "dts = %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DTS (buf))); \
99  GST_DEBUG_OBJECT (self, "duration = %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); \
100  } \
101 } while (0)
102 
103 GST_DEBUG_CATEGORY_STATIC (gst_tensor_converter_debug);
104 #define GST_CAT_DEFAULT gst_tensor_converter_debug
105 
106 #define STRING_CUSTOM_MODE(self) \
107  (((self)->mode == _CONVERTER_MODE_CUSTOM_CODE) ? \
108  "custom_code (function)" : \
109  (((self)->mode == _CONVERTER_MODE_CUSTOM_SCRIPT) ? \
110  "custom_script (py)" : \
111  "unknown custom mode (internal error!)"))
112 
117 enum
118 {
127 };
128 
132 #define DEFAULT_SET_TIMESTAMP TRUE
133 
137 #define DEFAULT_SILENT TRUE
138 
142 #define DEFAULT_FRAMES_PER_TENSOR 1
143 
144 #define gst_tensor_converter_parent_class parent_class
145 G_DEFINE_TYPE (GstTensorConverter, gst_tensor_converter, GST_TYPE_ELEMENT);
146 
147 static void gst_tensor_converter_finalize (GObject * object);
148 static void gst_tensor_converter_set_property (GObject * object,
149  guint prop_id, const GValue * value, GParamSpec * pspec);
150 static void gst_tensor_converter_get_property (GObject * object,
151  guint prop_id, GValue * value, GParamSpec * pspec);
152 
153 static gboolean gst_tensor_converter_sink_event (GstPad * pad,
154  GstObject * parent, GstEvent * event);
155 static gboolean gst_tensor_converter_sink_query (GstPad * pad,
156  GstObject * parent, GstQuery * query);
157 static gboolean gst_tensor_converter_src_query (GstPad * pad,
158  GstObject * parent, GstQuery * query);
159 static GstFlowReturn gst_tensor_converter_chain (GstPad * pad,
160  GstObject * parent, GstBuffer * buf);
161 static GstStateChangeReturn
162 gst_tensor_converter_change_state (GstElement * element,
163  GstStateChange transition);
164 
167  GstPad * pad, GstCaps * filter);
169  const GstCaps * caps);
171 static const NNStreamerExternalConverter *findExternalConverter (const char
172  *media_type_name);
173 
177 static void
179 {
180  GObjectClass *object_class;
181  GstElementClass *element_class;
182  GstPadTemplate *pad_template;
183  GstCaps *pad_caps;
184  gchar **str_array;
185  guint total, i;
186  const NNStreamerExternalConverter *ex;
187 
188  GST_DEBUG_CATEGORY_INIT (gst_tensor_converter_debug, "tensor_converter", 0,
189  "Element to convert media stream to tensor stream");
190 
191  object_class = (GObjectClass *) klass;
192  element_class = (GstElementClass *) klass;
193 
194  /* GObjectClass vmethods */
195  object_class->set_property = gst_tensor_converter_set_property;
196  object_class->get_property = gst_tensor_converter_get_property;
197  object_class->finalize = gst_tensor_converter_finalize;
198 
207  g_object_class_install_property (object_class, PROP_INPUT_DIMENSION,
208  g_param_spec_string ("input-dim", "Input tensor dimension",
209  "Input tensor dimension from inner array", "",
210  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
211 
220  g_object_class_install_property (object_class, PROP_INPUT_TYPE,
221  g_param_spec_string ("input-type", "Input tensor type",
222  "Type of each element of the input tensor", "",
223  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
224 
231  g_object_class_install_property (object_class, PROP_FRAMES_PER_TENSOR,
232  g_param_spec_uint ("frames-per-tensor", "Frames per tensor",
233  "The number of frames in output tensor", 1, G_MAXUINT,
235  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
236 
242  g_object_class_install_property (object_class, PROP_SET_TIMESTAMP,
243  g_param_spec_boolean ("set-timestamp", "Set timestamp",
244  "The flag to set timestamp when received a buffer with invalid timestamp",
245  DEFAULT_SET_TIMESTAMP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
246 
252  g_object_class_install_property (object_class, PROP_SUBPLUGINS,
253  g_param_spec_string ("sub-plugins", "Sub-plugins",
254  "Registrable sub-plugins list", "",
255  G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
256 
262  g_object_class_install_property (object_class, PROP_SILENT,
263  g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
264  DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
265 
271  g_object_class_install_property (object_class, PROP_MODE,
272  g_param_spec_string ("mode", "Mode",
273  "Converter mode. e.g., mode=custom-code:<registered callback name>. For detail, refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter",
274  "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
275 
276  /* set src pad template */
277  pad_caps =
278  gst_caps_from_string (GST_TENSOR_CAP_DEFAULT ";"
279  GST_TENSORS_CAP_MAKE ("{ static, flexible }"));
280 
281  pad_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
282  pad_caps);
283  gst_element_class_add_pad_template (element_class, pad_template);
284 
285  gst_caps_unref (pad_caps);
286 
287  /* set sink pad template */
288  pad_caps = gst_caps_new_empty ();
289 
290  /* append caps string for all media types */
291  append_video_caps_template (pad_caps);
292  append_audio_caps_template (pad_caps);
293  append_text_caps_template (pad_caps);
294  append_octet_caps_template (pad_caps);
296 
297  /* append sub-plugin template caps */
299  if (str_array) {
300  total = g_strv_length (str_array);
301 
302  for (i = 0; i < total; i++) {
303  ex = nnstreamer_converter_find (str_array[i]);
304  if (ex && ex->query_caps)
305  gst_caps_append (pad_caps, ex->query_caps (NULL));
306  }
307 
308  g_strfreev (str_array);
309  }
310 
311  pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
312  pad_caps);
313  gst_element_class_add_pad_template (element_class, pad_template);
314 
315  gst_caps_unref (pad_caps);
316 
317  gst_element_class_set_static_metadata (element_class,
318  "TensorConverter",
319  "Converter/Tensor",
320  "Converts an audio, video, text, or arbitrary stream to a tensor stream of C-Array for neural network framework filters",
321  "MyungJoo Ham <myungjoo.ham@samsung.com>");
322 
323  /* GstElementClass vmethods */
324  element_class->change_state = gst_tensor_converter_change_state;
325 }
326 
330 static void
332 {
334  self->sinkpad =
335  gst_pad_new_from_template (gst_element_class_get_pad_template
336  (GST_ELEMENT_GET_CLASS (self), "sink"), "sink");
337  gst_pad_set_event_function (self->sinkpad,
338  GST_DEBUG_FUNCPTR (gst_tensor_converter_sink_event));
339  gst_pad_set_query_function (self->sinkpad,
340  GST_DEBUG_FUNCPTR (gst_tensor_converter_sink_query));
341  gst_pad_set_chain_function (self->sinkpad,
342  GST_DEBUG_FUNCPTR (gst_tensor_converter_chain));
343  GST_PAD_SET_PROXY_CAPS (self->sinkpad);
344  gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
345 
347  self->srcpad =
348  gst_pad_new_from_template (gst_element_class_get_pad_template
349  (GST_ELEMENT_GET_CLASS (self), "src"), "src");
350  gst_pad_set_query_function (self->srcpad,
351  GST_DEBUG_FUNCPTR (gst_tensor_converter_src_query));
352  GST_PAD_SET_PROXY_CAPS (self->srcpad);
353  gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
354 
356  self->silent = DEFAULT_SILENT;
357  self->set_timestamp = DEFAULT_SET_TIMESTAMP;
358  self->frames_per_tensor = DEFAULT_FRAMES_PER_TENSOR;
359  self->in_media_type = _NNS_MEDIA_INVALID;
360  self->frame_size = 0;
361  self->remove_padding = FALSE;
362  self->externalConverter = NULL;
363  self->priv_data = NULL;
364  self->mode = _CONVERTER_MODE_NONE;
365  self->mode_option = NULL;
366  self->custom.func = NULL;
367  self->custom.data = NULL;
368  self->do_not_append_header = FALSE;
369  gst_tensors_info_init (&self->tensors_info);
370  gst_tensors_config_init (&self->tensors_config);
371  self->tensors_configured = FALSE;
372 
373  self->adapter_table = gst_tensor_aggregation_init ();
375 }
376 
380 static void
382 {
383  GstTensorConverter *self;
384 
385  self = GST_TENSOR_CONVERTER (object);
386 
388 
389  gst_tensors_config_free (&self->tensors_config);
390  gst_tensors_info_free (&self->tensors_info);
391  g_hash_table_destroy (self->adapter_table);
392 
393  g_free (self->mode_option);
394  g_free (self->ext_fw);
395  self->custom.func = NULL;
396  self->custom.data = NULL;
397  if (self->externalConverter && self->externalConverter->close)
398  self->externalConverter->close (&self->priv_data);
399  G_OBJECT_CLASS (parent_class)->finalize (object);
400 }
401 
405 static void
406 gst_tensor_converter_set_property (GObject * object, guint prop_id,
407  const GValue * value, GParamSpec * pspec)
408 {
409  GstTensorConverter *self;
410  GstTensorsInfo *info;
411  GstTensorInfo *_info;
412  guint i, j, num;
413  const gchar *value_str;
414 
415  self = GST_TENSOR_CONVERTER (object);
416  info = &self->tensors_info;
417 
418  switch (prop_id) {
420  value_str = g_value_get_string (value);
421  num = gst_tensors_info_parse_dimensions_string (info, value_str);
422 
423  if (num == 0) {
424  GST_WARNING ("%s is invalid dimension string.", value_str);
425  } else if (info->num_tensors > 0 && info->num_tensors != num) {
426  GST_WARNING ("%s, the number of tensor is %u.", value_str, num);
427  }
428 
429  /* prevent invalid value, init dimensions. */
430  for (i = num; i < NNS_TENSOR_SIZE_LIMIT; ++i) {
431  _info = gst_tensors_info_get_nth_info (info, i);
432 
433  for (j = 0; j < NNS_TENSOR_RANK_LIMIT; ++j)
434  _info->dimension[j] = 0;
435  }
436 
437  info->num_tensors = num;
438  break;
439  case PROP_INPUT_TYPE:
440  value_str = g_value_get_string (value);
441  num = gst_tensors_info_parse_types_string (info, value_str);
442 
443  if (num == 0) {
444  GST_WARNING ("%s is invalid type string.", value_str);
445  } else if (info->num_tensors > 0 && info->num_tensors != num) {
446  GST_WARNING ("%s, the number of tensor is %u.", value_str, num);
447  }
448 
449  /* prevent invalid value, init types. */
450  for (i = num; i < NNS_TENSOR_SIZE_LIMIT; ++i) {
451  _info = gst_tensors_info_get_nth_info (info, i);
452  _info->type = _NNS_END;
453  }
454 
455  info->num_tensors = num;
456  break;
458  self->frames_per_tensor = g_value_get_uint (value);
459  silent_debug (self, "Set frames in output = %d", self->frames_per_tensor);
460  break;
461  case PROP_SET_TIMESTAMP:
462  self->set_timestamp = g_value_get_boolean (value);
463  silent_debug (self, "Set timestamp = %d", self->set_timestamp);
464  break;
465  case PROP_SILENT:
466  self->silent = g_value_get_boolean (value);
467  silent_debug (self, "Set silent = %d", self->silent);
468  break;
469  case PROP_MODE:
470  {
471  const gchar *param = g_value_get_string (value);
472  const converter_custom_cb_s *ptr = NULL;
473  gchar **strv = g_strsplit_set (param, ":", -1);
474  self->custom.func = NULL;
475 
476  if (g_strv_length (strv) < 2) {
477  nns_logw
478  ("Tensor converter mode option is incorrect. Please specify mode option as <MODE>:<MODE_OPTION>. Refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter for detail.");
479  g_strfreev (strv);
480  break;
481  }
482 
483  self->mode_option = g_strdup (strv[1]);
484  if (g_ascii_strcasecmp (strv[0], "custom-code") == 0) {
485  self->mode = _CONVERTER_MODE_CUSTOM_CODE;
486  ptr = get_subplugin (NNS_CUSTOM_CONVERTER, self->mode_option);
487  if (!ptr) {
488  nns_logw
489  ("Failed to find custom subplugin of the tensor_converter. The custom-code for tensor_converter, \"%s\" is not registered by nnstreamer_converter_custom_register() function. Refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter for detail.",
490  strv[1]);
491  return;
492  }
493  self->custom.func = ptr->func;
494  self->custom.data = ptr->data;
495  } else if (g_ascii_strcasecmp (strv[0], "custom-script") == 0) {
496  self->mode = _CONVERTER_MODE_CUSTOM_SCRIPT;
498  self->ext_fw = g_strdup ("python3");
499  }
500  g_strfreev (strv);
501 
502  break;
503  }
504  default:
505  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
506  break;
507  }
508 }
509 
513 static void
514 gst_tensor_converter_get_property (GObject * object, guint prop_id,
515  GValue * value, GParamSpec * pspec)
516 {
517  GstTensorConverter *self;
518  GstTensorsInfo *info;
519 
520  self = GST_TENSOR_CONVERTER (object);
521  info = &self->tensors_info;
522 
523  switch (prop_id) {
525  if (info->num_tensors > 0) {
526  g_value_take_string (value,
528  } else {
529  g_value_set_string (value, "");
530  }
531  break;
532  case PROP_INPUT_TYPE:
533  if (info->num_tensors > 0) {
534  g_value_take_string (value, gst_tensors_info_get_types_string (info));
535  } else {
536  g_value_set_string (value, "");
537  }
538  break;
540  g_value_set_uint (value, self->frames_per_tensor);
541  break;
542  case PROP_SET_TIMESTAMP:
543  g_value_set_boolean (value, self->set_timestamp);
544  break;
545  case PROP_SUBPLUGINS:
546  {
547  gchar **str_array = get_all_subplugins (NNS_SUBPLUGIN_CONVERTER);
548 
549  if (str_array) {
550  g_value_take_string (value, g_strjoinv (",", str_array));
551  g_strfreev (str_array);
552  } else {
553  g_value_set_string (value, "");
554  }
555  break;
556  }
557  case PROP_SILENT:
558  g_value_set_boolean (value, self->silent);
559  break;
560  case PROP_MODE:
561  {
562  gchar *mode_str = NULL;
563  if (self->mode_option == NULL)
564  mode_str = g_strdup ("");
565  else {
566  if (self->mode == _CONVERTER_MODE_CUSTOM_CODE)
567  mode_str =
568  g_strdup_printf ("%s:%s", "custom-code", self->mode_option);
569  else if (self->mode == _CONVERTER_MODE_CUSTOM_SCRIPT)
570  mode_str =
571  g_strdup_printf ("%s:%s", "custom-script", self->mode_option);
572  }
573  g_value_take_string (value, mode_str);
574  break;
575  }
576  default:
577  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
578  break;
579  }
580 }
581 
585 static gboolean
586 gst_tensor_converter_sink_event (GstPad * pad, GstObject * parent,
587  GstEvent * event)
588 {
589  GstTensorConverter *self;
590 
591  self = GST_TENSOR_CONVERTER (parent);
592 
593  GST_DEBUG_OBJECT (self, "Received %s event: %" GST_PTR_FORMAT,
594  GST_EVENT_TYPE_NAME (event), event);
595 
596  switch (GST_EVENT_TYPE (event)) {
597  case GST_EVENT_CAPS:
598  {
599  GstCaps *in_caps;
600 
601  gst_event_parse_caps (event, &in_caps);
602  silent_debug_caps (self, in_caps, "in-caps");
603 
604  if (gst_tensor_converter_parse_caps (self, in_caps)) {
606  gst_event_unref (event);
607  return TRUE;
608  } else {
609  gst_event_unref (event);
610  return FALSE;
611  }
612  break;
613  }
614  case GST_EVENT_FLUSH_STOP:
616  break;
617  case GST_EVENT_SEGMENT:
618  {
619  GstSegment seg;
620 
621  gst_event_copy_segment (event, &seg);
622  silent_debug (self, "received seg %s", gst_format_get_name (seg.format));
623 
624  self->segment = seg;
625  self->have_segment = TRUE;
626 
627  if (seg.format == GST_FORMAT_TIME) {
628  return gst_pad_push_event (self->srcpad, event);
629  }
630 
631  if (seg.format == GST_FORMAT_BYTES) {
632  /* handle seg event in chain function */
633  self->need_segment = TRUE;
634  gst_event_unref (event);
635  return TRUE;
636  }
637 
638  GST_ERROR_OBJECT (self, "Unsupported format = %s\n",
639  gst_format_get_name (seg.format));
640  gst_event_unref (event);
641  return FALSE;
642  }
643  default:
644  break;
645  }
646 
647  return gst_pad_event_default (pad, parent, event);
648 }
649 
653 static gboolean
654 gst_tensor_converter_sink_query (GstPad * pad, GstObject * parent,
655  GstQuery * query)
656 {
657  GstTensorConverter *self;
658 
659  self = GST_TENSOR_CONVERTER (parent);
660  GST_DEBUG_OBJECT (self, "Received %s query: %" GST_PTR_FORMAT,
661  GST_QUERY_TYPE_NAME (query), query);
662 
663  switch (GST_QUERY_TYPE (query)) {
664  case GST_QUERY_CAPS:
665  {
666  GstCaps *caps;
667  GstCaps *filter;
668 
669  gst_query_parse_caps (query, &filter);
670  caps = gst_tensor_converter_query_caps (self, pad, filter);
671 
672  gst_query_set_caps_result (query, caps);
673  gst_caps_unref (caps);
674  return TRUE;
675  }
676  case GST_QUERY_ACCEPT_CAPS:
677  {
678  GstCaps *caps;
679  GstCaps *template_caps;
680  gboolean res = FALSE;
681 
682  gst_query_parse_accept_caps (query, &caps);
683  silent_debug_caps (self, caps, "accept-caps");
684 
685  if (gst_caps_is_fixed (caps)) {
686  template_caps = gst_pad_get_pad_template_caps (pad);
687 
688  res = gst_caps_can_intersect (template_caps, caps);
689  gst_caps_unref (template_caps);
690  }
691 
692  gst_query_set_accept_caps_result (query, res);
693  return TRUE;
694  }
695  default:
696  break;
697  }
698 
699  return gst_pad_query_default (pad, parent, query);
700 }
701 
705 static GstAdapter *
707 {
708  GstMetaQuery *meta;
709  guint32 key = 0;
710 
711  meta = gst_buffer_get_meta_query (buf);
712  if (meta)
713  key = meta->client_id;
714 
715  return gst_tensor_aggregation_get_adapter (self->adapter_table, key);
716 }
717 
721 static gboolean
722 gst_tensor_converter_src_query (GstPad * pad, GstObject * parent,
723  GstQuery * query)
724 {
725  GstTensorConverter *self;
726 
727  self = GST_TENSOR_CONVERTER (parent);
728 
729  GST_DEBUG_OBJECT (self, "Received %s query: %" GST_PTR_FORMAT,
730  GST_QUERY_TYPE_NAME (query), query);
731 
732  switch (GST_QUERY_TYPE (query)) {
733  case GST_QUERY_CAPS:
734  {
735  GstCaps *caps;
736  GstCaps *filter;
737 
738  gst_query_parse_caps (query, &filter);
739  caps = gst_tensor_converter_query_caps (self, pad, filter);
740 
741  gst_query_set_caps_result (query, caps);
742  gst_caps_unref (caps);
743  return TRUE;
744  }
745  default:
746  break;
747  }
748 
749  return gst_pad_query_default (pad, parent, query);
750 }
751 
753 static void
755  gsize frame_size)
756 {
757  if (self->need_segment) {
758  GstTensorsConfig *config;
759  GstSegment seg;
760  guint64 start;
761  gboolean have_framerate;
762 
763  config = &self->tensors_config;
764  have_framerate = (config->rate_n > 0 && config->rate_d > 0);
765 
767  g_assert (self->have_segment);
768  start = self->segment.start;
769 
770  gst_segment_init (&seg, GST_FORMAT_TIME);
771 
772  if (have_framerate && start > 0) {
773  start = gst_util_uint64_scale_int (start * config->rate_d, GST_SECOND,
774  frame_size * config->rate_n);
775  seg.start = seg.time = start;
776  }
777 
778  self->segment = seg;
779  self->need_segment = FALSE;
780 
781  gst_pad_push_event (self->srcpad, gst_event_new_segment (&seg));
782  }
783 }
784 
786 static void
788  GstBuffer * inbuf, guint frames_in)
789 {
790  if (self->set_timestamp) {
791  GstTensorsConfig *config;
792  GstClockTime pts, duration;
793  gboolean have_framerate;
794 
795  config = &self->tensors_config;
796  have_framerate = (config->rate_n > 0 && config->rate_d > 0);
797 
798  /* set duration */
799  duration = GST_BUFFER_DURATION (inbuf);
800 
801  if (!GST_CLOCK_TIME_IS_VALID (duration)) {
802  if (have_framerate) {
803  duration =
804  gst_util_uint64_scale_int ((guint64) frames_in * config->rate_d,
805  GST_SECOND, config->rate_n);
806 
807  GST_BUFFER_DURATION (inbuf) = duration;
808  }
809  }
810 
811  /* set timestamp if buffer has invalid timestamp */
812  pts = GST_BUFFER_TIMESTAMP (inbuf);
813 
814  if (!GST_CLOCK_TIME_IS_VALID (pts)) {
815  pts = self->segment.start;
816 
817  if (have_framerate) {
818  if (GST_CLOCK_TIME_IS_VALID (self->old_timestamp)) {
819  pts = self->old_timestamp + duration;
820  }
821  } else {
822  GstClock *clock;
823 
824  clock = gst_element_get_clock (GST_ELEMENT (self));
825 
826  if (clock) {
827  GstClockTime now, base;
828 
829  base = gst_element_get_base_time (GST_ELEMENT (self));
830  now = gst_clock_get_time (clock);
831 
832  pts = (base < now) ? (now - base) : 0;
833  gst_object_unref (clock);
834  }
835  }
836 
837  GST_BUFFER_TIMESTAMP (inbuf) = pts;
838  }
839  }
840 
841  /* update old timestamp */
842  self->old_timestamp = GST_BUFFER_TIMESTAMP (inbuf);
843 }
844 
846 static GstBuffer *
848 {
849  GstBuffer *buffer = buf;
850  GstTensorsInfo *info = &self->tensors_config.info;
851  gboolean multi = (info->num_tensors > 1);
852 
853  /* configure multi tensors */
854  if (multi || gst_buffer_n_memory (buf) > 1) {
855  GstTensorInfo *_info;
856  GstMemory *mem, *new_mem;
857  gsize offset, size;
858  guint i;
859 
860  g_assert (self->frames_per_tensor == 1);
861 
862  offset = 0;
863  buffer = gst_buffer_new ();
864  mem = gst_buffer_get_all_memory (buf);
865 
866  if (multi) {
867  for (i = 0; i < info->num_tensors; ++i) {
868  _info = gst_tensors_info_get_nth_info (info, i);
869 
870  size = gst_tensor_info_get_size (_info);
871  new_mem = gst_memory_share (mem, offset, size);
872  offset += size;
873 
874  gst_tensor_buffer_append_memory (buffer, new_mem, _info);
875  }
876 
877  gst_memory_unref (mem);
878  } else {
879  _info = gst_tensors_info_get_nth_info (info, 0);
880  gst_tensor_buffer_append_memory (buffer, mem, _info);
881  }
882 
883  /* copy timestamps */
884  gst_buffer_copy_into (buffer, buf, GST_BUFFER_COPY_METADATA, 0, -1);
885  gst_buffer_unref (buf);
886  }
887 
888  return buffer;
889 }
890 
892 static GstBuffer *
894  GstBuffer * buf)
895 {
896  GstBuffer *buffer;
897  GstMemory *mem, *new_mem;
898  GstTensorsInfo *info;
899  GstTensorInfo *_info;
900  GstTensorMetaInfo meta;
901  guint i;
902 
903  info = &self->tensors_config.info;
904  buffer = gst_buffer_new ();
905 
906  for (i = 0; i < info->num_tensors; i++) {
907  _info = gst_tensors_info_get_nth_info (info, i);
908  gst_tensor_info_convert_to_meta (_info, &meta);
909 
910  /* set media type */
911  switch (self->in_media_type) {
912  case _NNS_VIDEO:
913  case _NNS_AUDIO:
914  case _NNS_TEXT:
915  case _NNS_OCTET:
916  meta.media_type = self->in_media_type;
917  break;
918  default:
919  /* default output type is tensor */
920  meta.media_type = _NNS_TENSOR;
921  break;
922  }
923 
924  mem = gst_tensor_buffer_get_nth_memory (buf, i);
925  new_mem = gst_tensor_meta_info_append_header (&meta, mem);
926  gst_memory_unref (mem);
927 
928  gst_tensor_buffer_append_memory (buffer, new_mem, _info);
929  }
930 
931  gst_buffer_copy_into (buffer, buf, GST_BUFFER_COPY_METADATA, 0, -1);
932  gst_buffer_unref (buf);
933  return buffer;
934 }
935 
937 static GstFlowReturn
939 {
940  GstBuffer *buffer = buf;
941 
942  if (self->in_media_type == _NNS_OCTET) {
943  /* configure multi tensors */
944  buffer = _gst_tensor_converter_chain_octet (self, buffer);
945  }
946 
947  /* if output is flexible, add header. */
948  if (!self->do_not_append_header
949  && gst_tensor_pad_caps_is_flexible (self->srcpad)) {
950  buffer = _gst_tensor_converter_chain_flex_tensor (self, buffer);
951  }
952 
953  silent_debug_timestamp (self, buffer);
954  return gst_pad_push (self->srcpad, buffer);
955 }
956 
958 static GstFlowReturn
960  GstBuffer * inbuf, guint frames_in, guint frames_out, gsize frame_size)
961 {
962  GstAdapter *adapter;
963  GstTensorsConfig *config;
964  GstFlowReturn ret = GST_FLOW_OK;
965  GstClockTime pts, dts, duration;
966  gsize avail, out_size;
967  gboolean have_framerate;
968 
969  config = &self->tensors_config;
970  adapter = gst_tensor_converter_get_adapter (self, inbuf);
971  g_assert (adapter != NULL);
972 
973  have_framerate = (config->rate_n > 0 && config->rate_d > 0);
974 
975  duration = GST_BUFFER_DURATION (inbuf);
976  if (GST_CLOCK_TIME_IS_VALID (duration)) {
978  duration = gst_util_uint64_scale_int (duration, frames_out, frames_in);
979  }
980 
981  gst_adapter_push (adapter, inbuf);
982 
983  out_size = frames_out * frame_size;
984  while ((avail = gst_adapter_available (adapter)) >= out_size &&
985  ret == GST_FLOW_OK) {
986  GstBuffer *outbuf;
987  guint64 pts_dist, dts_dist;
988 
989  pts = gst_adapter_prev_pts (adapter, &pts_dist);
990  dts = gst_adapter_prev_dts (adapter, &dts_dist);
991 
996  if (frames_in > 1 && have_framerate) {
997  if (GST_CLOCK_TIME_IS_VALID (pts)) {
998  pts +=
999  gst_util_uint64_scale_int (pts_dist * config->rate_d, GST_SECOND,
1000  config->rate_n * frame_size);
1001  }
1002 
1003  if (GST_CLOCK_TIME_IS_VALID (dts)) {
1004  dts +=
1005  gst_util_uint64_scale_int (dts_dist * config->rate_d, GST_SECOND,
1006  config->rate_n * frame_size);
1007  }
1008  }
1009 
1010  outbuf = gst_adapter_take_buffer (adapter, out_size);
1011  outbuf = gst_buffer_make_writable (outbuf);
1012 
1014  GST_BUFFER_PTS (outbuf) = pts;
1015  GST_BUFFER_DTS (outbuf) = dts;
1016  GST_BUFFER_DURATION (outbuf) = duration;
1017 
1018  ret = _gst_tensor_converter_chain_push (self, outbuf);
1019  }
1020 
1021  return ret;
1022 }
1023 
1027 static GstFlowReturn
1028 gst_tensor_converter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1029 {
1030  GstTensorConverter *self;
1031  GstTensorsConfig *config;
1032  GstTensorsConfig new_config;
1033  GstTensorInfo *_info;
1034  GstBuffer *inbuf;
1035  gsize buf_size, frame_size;
1036  guint frames_in, frames_out;
1037  UNUSED (pad);
1038 
1039  buf_size = gst_buffer_get_size (buf);
1040  g_return_val_if_fail (buf_size > 0, GST_FLOW_ERROR);
1041 
1042  self = GST_TENSOR_CONVERTER (parent);
1043 
1045  g_assert (self->tensors_configured);
1046  config = &self->tensors_config;
1047  gst_tensors_config_init (&new_config);
1048 
1049  frames_out = self->frames_per_tensor;
1050  inbuf = buf;
1051 
1056  frame_size = self->frame_size;
1057  frames_in = 1;
1058 
1059  switch (self->in_media_type) {
1060  case _NNS_VIDEO:
1061  {
1062  guint color, width, height;
1063  gsize type;
1064 
1065  color = config->info.info[0].dimension[0];
1066  width = config->info.info[0].dimension[1];
1067  height = config->info.info[0].dimension[2];
1069 
1071  frame_size = type * color * width * height;
1072 
1074  g_assert ((buf_size / self->frame_size) == 1);
1075 
1076  if (self->remove_padding) {
1077  GstMapInfo src_info, dest_info;
1078  guint d0, d1;
1079  unsigned int src_idx = 0, dest_idx = 0;
1080  size_t size, offset;
1081 
1082  if (!gst_buffer_map (buf, &src_info, GST_MAP_READ)) {
1083  ml_logf
1084  ("tensor_converter: Cannot map src buffer at tensor_converter/video. The incoming buffer (GstBuffer) for the sinkpad of tensor_converter cannot be mapped for reading.\n");
1085  goto error;
1086  }
1087 
1088  inbuf = gst_buffer_new_and_alloc (frame_size);
1089  gst_buffer_memset (inbuf, 0, 0, frame_size);
1090  if (!gst_buffer_map (inbuf, &dest_info, GST_MAP_WRITE)) {
1091  ml_logf
1092  ("tensor_converter: Cannot map dest buffer at tensor_converter/video. The outgoing buffer (GstBuffer) for the srcpad of tensor_converter cannot be mapped for writing.\n");
1093  gst_buffer_unmap (buf, &src_info);
1094  gst_buffer_unref (inbuf); /* the new buffer is wasted. */
1095  goto error;
1096  }
1097 
1101  size = offset = type * color * width;
1102 
1103  g_assert (offset % 4);
1104  if (offset % 4) {
1105  offset += 4 - (offset % 4);
1106  }
1107 
1108  for (d0 = 0; d0 < frames_in; d0++) {
1109  for (d1 = 0; d1 < height; d1++) {
1110  memcpy (dest_info.data + dest_idx, src_info.data + src_idx, size);
1111  dest_idx += size;
1112  src_idx += offset;
1113  }
1114  }
1115 
1116  gst_buffer_unmap (buf, &src_info);
1117  gst_buffer_unmap (inbuf, &dest_info);
1118 
1120  gst_buffer_copy_into (inbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1121  }
1122  break;
1123  }
1124  case _NNS_AUDIO:
1125  /* number of bytes for one frame */
1126  frames_in = buf_size / frame_size;
1127  break;
1128  case _NNS_TEXT:
1129  if (buf_size != frame_size) {
1130  GstMapInfo src_info, dest_info;
1131  gsize block_size = MIN (buf_size, frame_size);
1132 
1133  if (!gst_buffer_map (buf, &src_info, GST_MAP_READ)) {
1134  ml_logf
1135  ("tensor_converter: Cannot map src buffer at tensor_converter/text. The incoming buffer (GstBuffer) for the sinkpad of tensor_converter cannot be mapped for reading.\n");
1136  goto error;
1137  }
1138 
1139  inbuf = gst_buffer_new_and_alloc (frame_size);
1140  gst_buffer_memset (inbuf, 0, 0, frame_size);
1141  if (!gst_buffer_map (inbuf, &dest_info, GST_MAP_WRITE)) {
1142  ml_logf
1143  ("tensor_converter: Cannot map dest buffer at tensor_converter/text. The outgoing buffer (GstBuffer) for the srcpad of tensor_converter cannot be mapped for writing.\n");
1144  gst_buffer_unmap (buf, &src_info);
1145  gst_buffer_unref (inbuf); /* the new buffer is wasted. */
1146  goto error;
1147  }
1148 
1149  memcpy (dest_info.data, src_info.data, block_size);
1150 
1151  gst_buffer_unmap (buf, &src_info);
1152  gst_buffer_unmap (inbuf, &dest_info);
1153 
1155  gst_buffer_copy_into (inbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1156  }
1157  break;
1158  case _NNS_OCTET:
1159  if (gst_tensors_config_is_flexible (config)) {
1160  /* update dimension with buffer size */
1161  config->info.info[0].dimension[0] = buf_size;
1162  frame_size = buf_size;
1163  } else {
1164  /* get frame size from the properties */
1165  g_assert ((buf_size % frame_size) == 0);
1166  frames_in = buf_size / frame_size;
1167  }
1168  break;
1169  case _NNS_TENSOR:
1170  {
1171  GstTensorMetaInfo meta;
1172  GstTensorsConfig tmp;
1173  GstMemory *mem, *new_mem;
1174  gsize s1, s2, hsize;
1175  guint n;
1176 
1177  gst_tensors_config_init (&tmp);
1178  tmp.rate_n = config->rate_n;
1179  tmp.rate_d = config->rate_d;
1180 
1182  buf = gst_tensor_buffer_from_config (buf, &tmp);
1183 
1184  /* type and dimension from buffer */
1187 
1188  /* compare data size and append memory */
1189  inbuf = gst_buffer_new ();
1190 
1191  for (n = 0; n < tmp.info.num_tensors; n++) {
1192  _info = gst_tensors_info_get_nth_info (&tmp.info, n);
1193  mem = gst_tensor_buffer_get_nth_memory (buf, n);
1194  s1 = gst_memory_get_sizes (mem, NULL, NULL);
1195 
1196  /* flex-tensor has header in each mem block */
1197  gst_tensor_meta_info_parse_memory (&meta, mem);
1198  gst_tensor_meta_info_convert (&meta, _info);
1199  hsize = gst_tensor_meta_info_get_header_size (&meta);
1200  s1 -= hsize;
1201 
1202  s2 = gst_tensor_info_get_size (_info);
1203 
1208  if (s1 != s2) {
1209  nns_loge
1210  ("Cannot process an incoming buffer frame for tensor_converter (chain function). It appears that it is trying to convert other/tensors,format=flexible to other/tensors,format=static. Incoming buffer has invalid data size %zd, expected size is %zd (%u/%u).",
1211  s1, s2, (n + 1), tmp.info.num_tensors);
1212  gst_memory_unref (mem);
1213  gst_buffer_unref (inbuf);
1214  goto error;
1215  }
1216 
1217  new_mem = gst_memory_share (mem, hsize, s1);
1218  gst_memory_unref (mem);
1219  gst_tensor_buffer_append_memory (inbuf, new_mem, _info);
1220  }
1221 
1222  gst_buffer_copy_into (inbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1223 
1224  if (!gst_tensors_config_is_equal (config, &tmp)) {
1225  if (gst_tensors_info_validate (&self->tensors_info)) {
1226  nns_loge
1227  ("Incoming buffer does not match with given tensors info. It appears that it is trying to convert other/tensors,format=flexible to other/tensors,format=static. The converted output appears not compatible with the given configuration.");
1228  gst_buffer_unref (inbuf);
1229  goto error;
1230  }
1231 
1232  /* update caps with new configuration */
1233  *config = tmp;
1235  }
1236  break;
1237  }
1238  case _NNS_MEDIA_ANY:
1239  {
1240  if (self->mode == _CONVERTER_MODE_CUSTOM_CODE) {
1241  if (self->custom.func == NULL) {
1242  nns_loge
1243  ("Tensor converter is in custom/code mode (mode=custom-code:${funcname}), where a user code as a callback function is required. However, the required information to configure the tensor converter is not given or incorrectly given. For detail, please refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter. The given ${funcname} is \"%s\", which is an invalid/unregistered name.",
1244  self->mode_option);
1245  goto error;
1246  }
1247  inbuf = self->custom.func (buf, self->custom.data, &new_config);
1248 
1249  if (inbuf == NULL) {
1250  nns_loge
1251  ("Failed to convert input streams to tensors: the converted result of the incoming buffer is NULL. The converter is custom-func with %s function, which is available and loaded, but has returned NULL buffer after the conversion.",
1252  self->mode_option);
1253  goto error;
1254  }
1255  } else if (self->externalConverter && self->externalConverter->convert) {
1256  inbuf =
1257  self->externalConverter->convert (buf, &new_config,
1258  self->priv_data);
1259 
1260  if (inbuf == NULL) {
1261  nns_loge
1262  ("Failed to convert input streams to tensors: the converted result of the incoming buffer is NULL. The converter is using external tensor_converter subplugin (%s), which is available and loaded, but has returned NULL buffer after the conversion.",
1263  self->externalConverter->name);
1264  goto error;
1265  }
1266  } else if (self->mode == _CONVERTER_MODE_CUSTOM_SCRIPT) {
1267  /* self->externalConverter->converter should've been available! */
1268  GST_ERROR_OBJECT (self,
1269  "Tensor converter is in custom/script mode (mode=custom-script:${scriptpath}), where a path to a script file is required. However, it is not properly configured. The given ${scriptpath} is \"%s\".",
1270  self->mode_option);
1271  goto error;
1272  } else {
1274  GST_ERROR_OBJECT (self,
1275  "Tensor converter has an undefined behavior with type _NNS_MEDIA_ANY. It should've been custom-code or custom-script mode or a corresponding external converter should've been registered (tensor_converter subplugin). However, nothing is available for the given input stream.");
1276  goto error;
1277  }
1278  self->do_not_append_header =
1279  (new_config.info.format == _NNS_TENSOR_FORMAT_FLEXIBLE);
1280 
1281  frames_in = 1;
1282  frame_size = gst_buffer_get_size (inbuf);
1283 
1284  if (!gst_tensors_config_is_equal (config, &new_config)) {
1285  gst_tensors_config_free (config);
1286  *config = new_config;
1287 
1289  } else {
1290  gst_tensors_config_free (&new_config);
1291  }
1292 
1293  break;
1294  }
1295  case _NNS_MEDIA_INVALID:
1296  GST_ERROR_OBJECT (self,
1297  "The incoming tensor to be converted has no type defined (INVALID). This is an internal unknown error. Please report the case to https://github.com/nnstreamer/issues with the pipeline description reproducing the error.");
1298  goto error;
1299  break;
1300  default:
1301  GST_ERROR_OBJECT (self,
1302  "The incoming tensor to be converted has unknown type (type value not recognized: %d). This is an internal unknown error. Please report the case to https://github.com/nnstreamer/issues with the pipeline description reproducing the error.",
1303  self->in_media_type);
1304  goto error;
1305  }
1306 
1307  if (inbuf != buf)
1308  gst_buffer_unref (buf);
1309 
1312  _gst_tensor_converter_chain_segment (self, frame_size);
1313 
1315  _gst_tensor_converter_chain_timestamp (self, inbuf, frames_in);
1316 
1317  if (frames_in == frames_out) {
1319  return _gst_tensor_converter_chain_push (self, inbuf);
1320  }
1321 
1322  /* push multiple buffers */
1323  return _gst_tensor_converter_chain_chunk (self, inbuf, frames_in,
1324  frames_out, frame_size);
1325 
1326 error:
1327  gst_buffer_unref (buf);
1328  gst_tensors_config_free (&new_config);
1329  return GST_FLOW_ERROR;
1330 }
1331 
1335 static GstStateChangeReturn
1337  GstStateChange transition)
1338 {
1339  GstTensorConverter *self;
1340  GstStateChangeReturn ret;
1341 
1342  self = GST_TENSOR_CONVERTER (element);
1343 
1344  switch (transition) {
1345  case GST_STATE_CHANGE_READY_TO_PAUSED:
1347  break;
1348  default:
1349  break;
1350  }
1351 
1352  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1353 
1354  switch (transition) {
1355  case GST_STATE_CHANGE_PAUSED_TO_READY:
1357  break;
1358  default:
1359  break;
1360  }
1361 
1362  return ret;
1363 }
1364 
1368 static void
1370 {
1371  /* remove all buffers from adapter */
1372  gst_tensor_aggregation_clear_all (self->adapter_table);
1373 
1374  self->have_segment = FALSE;
1375  self->need_segment = FALSE;
1376  gst_segment_init (&self->segment, GST_FORMAT_TIME);
1377 
1378  self->old_timestamp = GST_CLOCK_TIME_NONE;
1379 }
1380 
1384 static void
1386 {
1387  GValue item = G_VALUE_INIT;
1388  gchar *str;
1389  va_list args;
1390 
1391  g_value_init (list, GST_TYPE_LIST);
1392 
1393  va_start (args, list);
1394  while ((str = va_arg (args, gchar *))) {
1395  g_value_init (&item, G_TYPE_STRING);
1396  g_value_set_string (&item, str);
1397 
1398  gst_value_list_append_value (list, &item);
1399  g_value_unset (&item);
1400  }
1401  va_end (args);
1402 }
1403 
1408 static gboolean
1410 {
1415  switch (format) {
1417  case GST_VIDEO_FORMAT_RGB:
1418  case GST_VIDEO_FORMAT_BGR:
1419  case GST_VIDEO_FORMAT_I420:
1420 #if GST_CHECK_VERSION(1, 20, 0)
1421  case GST_VIDEO_FORMAT_RGBP:
1422  case GST_VIDEO_FORMAT_BGRP:
1423 #endif
1424  if (width % 4) {
1425  return TRUE;
1426  }
1427  break;
1428  default:
1429  break;
1430  }
1431 
1432  return FALSE;
1433 }
1434 
1443 static gboolean
1445  const GstCaps * caps, GstTensorsConfig * config)
1446 {
1452  GstVideoInfo vinfo;
1453  GstVideoFormat format;
1454  gint width, height, views;
1455  guint i;
1456 
1457  g_return_val_if_fail (config != NULL, FALSE);
1458 
1459  gst_tensors_config_init (config);
1460 
1461  gst_video_info_init (&vinfo);
1462  if (!gst_video_info_from_caps (&vinfo, caps)) {
1463  char *capstr = gst_caps_to_string (caps);
1464  GST_ERROR_OBJECT (self,
1465  "Failed to get video info from caps; gst_video_info_from_caps (&info, \"%s\") has returned FALSE, which means the given caps cannot be parsed as a video.",
1466  capstr);
1467  g_free (capstr);
1468  return FALSE;
1469  }
1470 
1471  format = GST_VIDEO_INFO_FORMAT (&vinfo);
1472  width = GST_VIDEO_INFO_WIDTH (&vinfo);
1473  height = GST_VIDEO_INFO_HEIGHT (&vinfo);
1474  views = GST_VIDEO_INFO_VIEWS (&vinfo);
1475 
1476  if (views > 1) {
1477  GST_WARNING_OBJECT (self,
1478  "Incoming video caps should have 'views=(int)1 but has views=(int)%d - ignoring all but view #0. \n",
1479  views);
1480  }
1481 
1482  config->info.num_tensors = 1;
1483 
1484  /* [color-space][width][height][frames] */
1485  switch (format) {
1487  config->info.info[0].type = _NNS_UINT8;
1488  config->info.info[0].dimension[0] = 1;
1489  config->info.info[0].dimension[1] = width;
1490  config->info.info[0].dimension[2] = height;
1491  break;
1494  config->info.info[0].type = _NNS_UINT16;
1495  config->info.info[0].dimension[0] = 1;
1496  config->info.info[0].dimension[1] = width;
1497  config->info.info[0].dimension[2] = height;
1498  break;
1499  case GST_VIDEO_FORMAT_RGB:
1500  case GST_VIDEO_FORMAT_BGR:
1501  config->info.info[0].type = _NNS_UINT8;
1502  config->info.info[0].dimension[0] = 3;
1503  config->info.info[0].dimension[1] = width;
1504  config->info.info[0].dimension[2] = height;
1505  break;
1506  case GST_VIDEO_FORMAT_RGBx:
1507  case GST_VIDEO_FORMAT_BGRx:
1508  case GST_VIDEO_FORMAT_xRGB:
1509  case GST_VIDEO_FORMAT_xBGR:
1510  case GST_VIDEO_FORMAT_RGBA:
1511  case GST_VIDEO_FORMAT_BGRA:
1512  case GST_VIDEO_FORMAT_ARGB:
1513  case GST_VIDEO_FORMAT_ABGR:
1514  config->info.info[0].type = _NNS_UINT8;
1515  config->info.info[0].dimension[0] = 4;
1516  config->info.info[0].dimension[1] = width;
1517  config->info.info[0].dimension[2] = height;
1518  break;
1519 #if GST_CHECK_VERSION(1, 20, 0)
1520  case GST_VIDEO_FORMAT_RGBP:
1521  case GST_VIDEO_FORMAT_BGRP:
1522  config->info.info[0].type = _NNS_UINT8;
1523  config->info.info[0].dimension[0] = width;
1524  config->info.info[0].dimension[1] = height;
1525  config->info.info[0].dimension[2] = 3;
1526  break;
1527 #endif
1528  default:
1529  GST_WARNING_OBJECT (self,
1530  "The given video caps with format \"%s\" is not supported. Please use " NNS_VIDEO_FORMAT,
1531  GST_STR_NULL (gst_video_format_to_string (format)));
1532  break;
1533  }
1534 
1535  /* Supposed 1 frame in tensor, change dimension[3] if tensor contains N frames. */
1536  config->info.info[0].dimension[3] = 1;
1537  for (i = 4; i < NNS_TENSOR_RANK_LIMIT; i++)
1538  config->info.info[0].dimension[i] = 0;
1539 
1540  config->rate_n = GST_VIDEO_INFO_FPS_N (&vinfo);
1541  config->rate_d = GST_VIDEO_INFO_FPS_D (&vinfo);
1542 
1547  if (gst_tensor_converter_video_stride (format, width)) {
1548  self->remove_padding = TRUE;
1549  silent_debug (self, "Set flag to remove padding, width = %d", width);
1550 
1551 #if GST_CHECK_VERSION(1, 20, 0)
1552  if (format == GST_VIDEO_FORMAT_RGBP || format == GST_VIDEO_FORMAT_BGRP) {
1553  if (self->remove_padding) {
1554  GST_ERROR_OBJECT (self,
1555  "Padding removal is not supported for RGBP and BGRP formats. Please use width as multiple of 4. Given width: %d",
1556  width);
1557  return FALSE;
1558  }
1559  }
1560 #endif
1561 
1563  GST_WARNING_OBJECT (self,
1564  "\nYOUR STREAM CONFIGURATION INCURS PERFORMANCE DETERIORATION!\n"
1565  "Please use 4 x n as image width for inputs; the width of your input is %d.\n",
1566  width);
1567  }
1568 
1569  self->frame_size = GST_VIDEO_INFO_SIZE (&vinfo);
1570  return (config->info.info[0].type != _NNS_END);
1571 }
1572 
1581 static gboolean
1583  const GstCaps * caps, GstTensorsConfig * config)
1584 {
1590  GstAudioInfo ainfo;
1591  GstAudioFormat format;
1592  gint channels;
1593  guint i;
1594 
1595  g_return_val_if_fail (config != NULL, FALSE);
1596 
1597  gst_tensors_config_init (config);
1598 
1599  gst_audio_info_init (&ainfo);
1600  if (!gst_audio_info_from_caps (&ainfo, caps)) {
1601  char *capstr = gst_caps_to_string (caps);
1602  GST_ERROR_OBJECT (self,
1603  "Failed to get audio info from caps; gst_audio_info_from_caps(&info, \"%s\") has returned FALSE.\n",
1604  capstr);
1605  g_free (capstr);
1606  return FALSE;
1607  }
1608 
1609  format = GST_AUDIO_INFO_FORMAT (&ainfo);
1610  channels = GST_AUDIO_INFO_CHANNELS (&ainfo);
1611 
1612  config->info.num_tensors = 1;
1613 
1614  /* [channels][frames] */
1615  switch (format) {
1616  case GST_AUDIO_FORMAT_S8:
1617  config->info.info[0].type = _NNS_INT8;
1618  break;
1619  case GST_AUDIO_FORMAT_U8:
1620  config->info.info[0].type = _NNS_UINT8;
1621  break;
1622  case GST_AUDIO_FORMAT_S16:
1623  config->info.info[0].type = _NNS_INT16;
1624  break;
1625  case GST_AUDIO_FORMAT_U16:
1626  config->info.info[0].type = _NNS_UINT16;
1627  break;
1628  case GST_AUDIO_FORMAT_S32:
1629  config->info.info[0].type = _NNS_INT32;
1630  break;
1631  case GST_AUDIO_FORMAT_U32:
1632  config->info.info[0].type = _NNS_UINT32;
1633  break;
1634  case GST_AUDIO_FORMAT_F32:
1635  config->info.info[0].type = _NNS_FLOAT32;
1636  break;
1637  case GST_AUDIO_FORMAT_F64:
1638  config->info.info[0].type = _NNS_FLOAT64;
1639  break;
1640  default:
1641  GST_WARNING_OBJECT (self,
1642  "Audio format \"%s\" is not supported. Please use S8, U8, S16, U16, S32, U32, F32, or F64.\n",
1643  GST_STR_NULL (gst_audio_format_to_string (format)));
1644  break;
1645  }
1646 
1647  config->info.info[0].dimension[0] = channels;
1648 
1649  /* Supposed 1 frame in tensor, change dimension[1] if tensor contains N frames. */
1650  config->info.info[0].dimension[1] = 1;
1651  for (i = 2; i < NNS_TENSOR_RANK_LIMIT; i++)
1652  config->info.info[0].dimension[i] = 0;
1653 
1654  config->rate_n = GST_AUDIO_INFO_RATE (&ainfo);
1655  config->rate_d = 1;
1656 
1657  self->frame_size = GST_AUDIO_INFO_BPF (&ainfo);
1658  return (config->info.info[0].type != _NNS_END);
1659 }
1660 
1669 static gboolean
1671  GstTensorsConfig * config, const GstStructure * structure)
1672 {
1677  const gchar *format_string;
1678  guint i, text_size;
1679 
1680  g_return_val_if_fail (config != NULL, FALSE);
1681  g_return_val_if_fail (structure != NULL, FALSE);
1682 
1683  gst_tensors_config_init (config);
1684 
1685  /* get fixed size of text string from property */
1686  text_size = self->tensors_info.info[0].dimension[0];
1687  if (text_size == 0) {
1688  GST_ERROR_OBJECT (self,
1689  "Failed to get tensor info, need to update string size.");
1690 
1691  ml_loge
1692  ("tensor_converter: Please set the property input-dim to convert stream manually for text streams unlike video streams. For example, input-dim=30 to handle up to 30 bytes of string per frame.");
1693  return FALSE;
1694  }
1695 
1696  format_string = gst_structure_get_string (structure, "format");
1697  if (format_string) {
1698  if (g_ascii_strcasecmp (format_string, "utf8") == 0) {
1699  config->info.info[0].type = _NNS_UINT8;
1700  } else {
1701  GST_WARNING_OBJECT (self,
1702  "For text streams, only utf8 streams are supported; format = \"%s\" is not supported.\n",
1703  format_string);
1704  return FALSE;
1705  }
1706  }
1707 
1708  config->info.num_tensors = 1;
1709 
1710  /* [size][frames] */
1711  /* Fixed size of string, we cannot get the size from caps. */
1712  config->info.info[0].dimension[0] = text_size;
1713 
1714  /* Supposed 1 frame in tensor, change dimension[1] if tensor contains N frames. */
1715  config->info.info[0].dimension[1] = 1;
1716  for (i = 2; i < NNS_TENSOR_RANK_LIMIT; i++)
1717  config->info.info[0].dimension[i] = 0;
1718 
1719  if (gst_structure_has_field (structure, "framerate")) {
1720  gst_structure_get_fraction (structure, "framerate", &config->rate_n,
1721  &config->rate_d);
1722  } else {
1723  /* cannot get the framerate for text type */
1724  config->rate_n = 0;
1725  config->rate_d = 1;
1726  }
1727 
1728  self->frame_size = gst_tensor_info_get_size (&config->info.info[0]);
1729  return (config->info.info[0].type != _NNS_END);
1730 }
1731 
1740 static gboolean
1742  GstTensorsConfig * config, const GstStructure * structure)
1743 {
1744  GstTensorsInfo *info = &self->tensors_info;
1745  GstTensorsConfig peer;
1746  gboolean flexible, configured;
1747  guint i;
1748 
1749  g_return_val_if_fail (config != NULL, FALSE);
1750  g_return_val_if_fail (structure != NULL, FALSE);
1751 
1752  gst_tensors_config_init (config);
1753  flexible = configured = FALSE;
1754 
1755  /* get possible tensors info from peer if no property is given */
1756  if (!gst_tensors_info_validate (info)) {
1757  if (gst_tensors_config_from_peer (self->srcpad, &peer, NULL)) {
1758  flexible = gst_tensors_config_is_flexible (&peer);
1759  configured = gst_tensors_info_validate (&peer.info);
1760 
1761  if (configured)
1762  info = &peer.info;
1763  }
1764 
1765  if (!flexible && !configured) {
1766  GST_ERROR_OBJECT (self,
1767  "Failed to get tensor info, need to update dimension and type.");
1768 
1769  ml_loge
1770  ("tensor_converter: Please set the properties input-dim and input-type to convert application/stream to non-flexible other/tensors. Use other/tensors,format=flexible if you want flexible dimensions. For static (non-flexible) tensors, you may, for example, use input-dim=30,input-type=uint8 to handle 30 bytes of bin data as a single frame.");
1771  return FALSE;
1772  }
1773  }
1774 
1775  if (self->frames_per_tensor > 1) {
1779  if (info->num_tensors > 1) {
1780  ml_loge
1781  ("tensor_converter: Cannot configure multiple tensors (num_tensors = %u) from an application/octet stream with frames_per_tensor (= %u)> 1. Please set the property frames-per-tensor 1 to convert stream to multiple-tensors (num_tensors > 1).",
1782  info->num_tensors, self->frames_per_tensor);
1783  return FALSE;
1784  }
1785  if (flexible) {
1786  ml_loge
1787  ("tensor_converter: Cannot configure flexible tensors from an application/octet stream with frames_per_tensor (%u) > 1. Please set the property frames-per-tensor 1 to convert stream to flexible tensors.",
1788  self->frames_per_tensor);
1789  return FALSE;
1790  }
1791  }
1792 
1793  if (gst_structure_has_field (structure, "framerate")) {
1794  gst_structure_get_fraction (structure, "framerate", &config->rate_n,
1795  &config->rate_d);
1796  } else {
1797  /* cannot get the framerate */
1798  config->rate_n = 0;
1799  config->rate_d = 1;
1800  }
1801 
1809  if (flexible) {
1811 
1812  config->info.num_tensors = 1;
1813  config->info.info[0].type = _NNS_UINT8;
1814  config->info.info[0].dimension[0] = 1;
1815  for (i = 1; i < NNS_TENSOR_RANK_LIMIT; i++)
1816  config->info.info[0].dimension[i] = 0;
1817  } else {
1818  gst_tensors_info_copy (&config->info, info);
1819  self->frame_size = gst_tensors_info_get_size (&config->info, -1);
1820  }
1821 
1822  return TRUE;
1823 }
1824 
1833 static gboolean
1835  GstTensorsConfig * config, const GstStructure * structure)
1836 {
1837  GstTensorsInfo *info = &self->tensors_info;
1838  guint i;
1839 
1840  g_return_val_if_fail (config != NULL, FALSE);
1841  g_return_val_if_fail (structure != NULL, FALSE);
1842 
1843  gst_tensors_config_init (config);
1844 
1845  if (self->frames_per_tensor > 1) {
1846  ml_loge
1847  ("tensor_converter: Cannot configure multiple tensors. Please set the property frames-per-tensor (%u != 1) 1 to convert stream into tensor stream with num_tensor > 1.",
1848  self->frames_per_tensor);
1849  return FALSE;
1850  }
1851 
1852  /* update tensor info from properties */
1853  if (gst_tensors_info_validate (info)) {
1854  gst_tensors_info_copy (&config->info, info);
1855  self->frame_size = gst_tensors_info_get_size (&config->info, -1);
1856  } else {
1862  config->info.num_tensors = 1;
1863  config->info.info[0].type = _NNS_UINT8;
1864  config->info.info[0].dimension[0] = 1;
1865  for (i = 1; i < NNS_TENSOR_RANK_LIMIT; i++)
1866  config->info.info[0].dimension[i] = 0;
1867  }
1868 
1869  if (gst_structure_has_field (structure, "framerate")) {
1870  gst_structure_get_fraction (structure, "framerate", &config->rate_n,
1871  &config->rate_d);
1872  } else {
1873  /* cannot get the framerate */
1874  config->rate_n = 0;
1875  config->rate_d = 1;
1876  }
1877 
1878  return TRUE;
1879 }
1880 
1888 static gboolean
1890  GstTensorsConfig * config, const GstCaps * caps)
1891 {
1892  GstStructure *structure;
1893  const gchar *mimetype;
1894  gboolean is_fixed = FALSE;
1895 
1896  g_return_val_if_fail (config != NULL, FALSE);
1897  g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
1898 
1899  gst_tensors_config_from_peer (self->srcpad, config, &is_fixed);
1900 
1901  structure = gst_caps_get_structure (caps, 0);
1902  mimetype = gst_structure_get_name (structure);
1903 
1904  if (self->mode == _CONVERTER_MODE_CUSTOM_CODE) {
1905  if (!is_fixed) {
1906  gst_tensors_config_init (config);
1907  /* All tensor info should be updated later in chain function. */
1908  config->info.num_tensors = 1;
1909  config->info.info[0].type = _NNS_UINT8;
1910  gst_tensor_parse_dimension ("1:1:1:1", config->info.info[0].dimension);
1911 
1912  if (gst_structure_has_field (structure, "framerate")) {
1913  gst_structure_get_fraction (structure, "framerate", &config->rate_n,
1914  &config->rate_d);
1915  } else {
1916  /* cannot get the framerate */
1917  config->rate_n = 0;
1918  config->rate_d = 1;
1919  }
1920  }
1921  } else if (!self->externalConverter) {
1922  const NNStreamerExternalConverter *ex;
1923  if (self->mode == _CONVERTER_MODE_CUSTOM_SCRIPT) {
1924  mimetype = self->ext_fw;
1925  }
1926  if (!(ex = findExternalConverter (mimetype))) {
1927  ml_loge
1928  ("tensor_converter: Failed to get external converter for %s. Cannot find a corresponding external converter for the given type. The custom converter mode is %s with \"%s\"",
1929  mimetype, STRING_CUSTOM_MODE (self), self->mode_option);
1930  return FALSE;
1931  }
1932 
1933  if (!is_fixed) {
1934  if (!ex->get_out_config) {
1935  ml_loge
1936  ("tensor_converter: Failed to get tensors info from %s (%s:%s). Its corresponding external converter is found. but its mandatory callback, get_out_config is not available.",
1937  mimetype, STRING_CUSTOM_MODE (self), self->mode_option);
1938  return FALSE;
1939  }
1940  if (!ex->get_out_config (caps, config)) {
1941  char *capstr = gst_caps_to_string (caps);
1942  ml_loge
1943  ("tensor_converter: Failed to get tensors info from %s (%s:%s). Its corresponding external converter is found. but its mandatory callback, get_out_config(\"%s\", config) has returned FALSE (cannot get config from the caps).",
1944  mimetype, STRING_CUSTOM_MODE (self), self->mode_option, capstr);
1945  g_free (capstr);
1946  return FALSE;
1947  }
1948  }
1949 
1950  self->externalConverter = ex;
1951  if (self->mode == _CONVERTER_MODE_CUSTOM_SCRIPT) {
1952  int ret = 0;
1953  if (self->externalConverter->open &&
1954  (ret = self->externalConverter->open (self->mode_option,
1955  &self->priv_data)) < 0) {
1956  ml_loge
1957  ("tensor_converter: Failed to open tensor converter custom subplugin: custom-script mode with \"%s\" for \"%s\" (%s) has 'open' callback; however, it has returned %d error.\n",
1958  self->mode_option, mimetype, self->externalConverter->name, ret);
1959  self->externalConverter = NULL;
1960  return FALSE;
1961  }
1962  }
1963  }
1964 
1965  return TRUE;
1966 }
1967 
1971 static GstCaps *
1973 {
1974  GstCaps *media_caps = NULL;
1975  GstTensorsConfig config;
1976 
1977  /* get possible caps from downstream element */
1978  if (gst_tensors_config_from_peer (self->srcpad, &config, NULL)) {
1979  GstStructure *st;
1980  guint i, caps_len;
1981  media_type type;
1982 
1983  /* convert peer caps to possible media caps */
1984  media_caps = gst_pad_get_pad_template_caps (self->sinkpad);
1985  media_caps = gst_caps_make_writable (media_caps);
1986 
1987  caps_len = gst_caps_get_size (media_caps);
1988 
1989  for (i = 0; i < caps_len; ++i) {
1990  st = gst_caps_get_structure (media_caps, i);
1992 
1993  switch (type) {
1994  case _NNS_VIDEO:
1995  /* video caps from tensor info */
1996  if (is_video_supported (self)) {
1997  GValue supported_formats = G_VALUE_INIT;
1998  gint colorspace, width, height;
1999 
2000  colorspace = config.info.info[0].dimension[0];
2001  width = config.info.info[0].dimension[1];
2002  height = config.info.info[0].dimension[2];
2003 
2004  switch (colorspace) {
2005  case 1:
2006  gst_tensor_converter_get_format_list (&supported_formats,
2007  "GRAY8", "GRAY16_BE", "GRAY16_LE", NULL);
2008  break;
2009  case 3:
2010  gst_tensor_converter_get_format_list (&supported_formats,
2011  "RGB", "BGR", NULL);
2012  break;
2013  case 4:
2014  gst_tensor_converter_get_format_list (&supported_formats,
2015  "RGBx", "BGRx", "xRGB", "xBGR", "RGBA", "BGRA", "ARGB",
2016  "ABGR", NULL);
2017  break;
2018  default:
2019  /* unsupported format, set default video formats */
2020  break;
2021  }
2022 
2023  if (G_VALUE_TYPE (&supported_formats) == GST_TYPE_LIST &&
2024  gst_value_list_get_size (&supported_formats) > 0) {
2025  gst_structure_set_value (st, "format", &supported_formats);
2026  }
2027  g_value_unset (&supported_formats);
2028 
2029  if (width > 0) {
2030  gst_structure_set (st, "width", G_TYPE_INT, width, NULL);
2031  }
2032 
2033  if (height > 0) {
2034  gst_structure_set (st, "height", G_TYPE_INT, height, NULL);
2035  }
2036 
2037  if (config.rate_n >= 0 && config.rate_d > 0) {
2038  gst_structure_set (st, "framerate", GST_TYPE_FRACTION,
2039  config.rate_n, config.rate_d, NULL);
2040  }
2041 
2042  /* add new structure for NCHW formats */
2043 #if GST_CHECK_VERSION(1, 20, 0)
2044  width = config.info.info[0].dimension[0];
2045  height = config.info.info[0].dimension[1];
2046  colorspace = config.info.info[0].dimension[2];
2047 
2048  if (colorspace == 3) {
2049  GValue nchw_format = G_VALUE_INIT;
2050  GstStructure *nchw_st = gst_structure_copy (st);
2051 
2053  "RGBP", "BGRP", NULL);
2054 
2055  if (G_VALUE_TYPE (&nchw_format) == GST_TYPE_LIST &&
2056  gst_value_list_get_size (&nchw_format) > 0) {
2057  gst_structure_set_value (nchw_st, "format", &nchw_format);
2058  }
2059  g_value_unset (&nchw_format);
2060 
2061  if (width > 0) {
2062  gst_structure_set (nchw_st, "width", G_TYPE_INT, width, NULL);
2063  }
2064 
2065  if (height > 0) {
2066  gst_structure_set (nchw_st, "height", G_TYPE_INT, height, NULL);
2067  }
2068  gst_caps_append_structure (media_caps, nchw_st);
2069  }
2070 #endif
2071  }
2072  break;
2073  case _NNS_AUDIO:
2074  /* audio caps from tensor info */
2075  if (is_audio_supported (self)
2076  && config.info.info[0].type != _NNS_END) {
2077  gint ch, rate;
2078  GstAudioFormat aformat;
2079 
2080  switch (config.info.info[0].type) {
2081  case _NNS_INT8:
2082  aformat = GST_AUDIO_FORMAT_S8;
2083  break;
2084  case _NNS_UINT8:
2085  aformat = GST_AUDIO_FORMAT_U8;
2086  break;
2087  case _NNS_INT16:
2088  aformat = GST_AUDIO_FORMAT_S16;
2089  break;
2090  case _NNS_UINT16:
2091  aformat = GST_AUDIO_FORMAT_U16;
2092  break;
2093  case _NNS_INT32:
2094  aformat = GST_AUDIO_FORMAT_S32;
2095  break;
2096  case _NNS_UINT32:
2097  aformat = GST_AUDIO_FORMAT_U32;
2098  break;
2099  case _NNS_FLOAT16:
2100  aformat = GST_AUDIO_FORMAT_UNKNOWN;
2101  ml_loge
2102  ("tensor_converter: Audio stream cannot be converted to float16 stream directly because GStreamer's standard audio streams do not support float16. Try Float32 or Float64 instead and 'transform' it to Float16 later.\n");
2103  break;
2104  case _NNS_FLOAT32:
2105  aformat = GST_AUDIO_FORMAT_F32;
2106  break;
2107  case _NNS_FLOAT64:
2108  aformat = GST_AUDIO_FORMAT_F64;
2109  break;
2110  default:
2111  /* unsupported format */
2112  aformat = GST_AUDIO_FORMAT_UNKNOWN;
2113  break;
2114  }
2115 
2116  if (aformat != GST_AUDIO_FORMAT_UNKNOWN) {
2117  gst_structure_set (st, "format", G_TYPE_STRING,
2118  gst_audio_format_to_string (aformat), NULL);
2119 
2120  if ((ch = config.info.info[0].dimension[0]) > 0) {
2121  gst_structure_set (st, "channels", G_TYPE_INT, ch, NULL);
2122  }
2123 
2124  if ((rate = config.rate_n) > 0) {
2125  gst_structure_set (st, "rate", G_TYPE_INT, rate, NULL);
2126  }
2127  }
2128  }
2129  break;
2130  default:
2131  /* do nothing for text and octet stream */
2132  break;
2133  }
2134  }
2135  }
2136 
2137  return media_caps;
2138 }
2139 
2143 static GstCaps *
2145  GstCaps * filter)
2146 {
2147  GstCaps *caps;
2148 
2149  caps = gst_pad_get_current_caps (pad);
2150  if (!caps) {
2151  caps = gst_pad_get_pad_template_caps (pad);
2152  }
2153 
2154  if (pad == self->sinkpad) {
2155  GstCaps *media_caps;
2156 
2158  if (media_caps) {
2159  /* intersect with pad caps */
2160  GstCaps *tmp = gst_caps_intersect_full (media_caps, caps,
2161  GST_CAPS_INTERSECT_FIRST);
2162  gst_caps_unref (caps);
2163  caps = tmp;
2164 
2165  gst_caps_unref (media_caps);
2166  }
2167  }
2168 
2169  silent_debug_caps (self, caps, "caps");
2170  silent_debug_caps (self, filter, "filter");
2171 
2172  if (filter) {
2173  GstCaps *intersection;
2174 
2175  intersection =
2176  gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
2177 
2178  gst_caps_unref (caps);
2179  caps = intersection;
2180  }
2181 
2182  silent_debug_caps (self, caps, "result");
2183  return caps;
2184 }
2185 
2189 static gboolean
2191  const GstCaps * caps)
2192 {
2193  GstStructure *structure;
2194  GstTensorsConfig config;
2195  media_type in_type;
2196  gint frames_dim = -1;
2198  g_return_val_if_fail (caps != NULL, FALSE);
2199  g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
2200 
2201  structure = gst_caps_get_structure (caps, 0);
2202  if (self->mode != _CONVERTER_MODE_NONE) {
2203  in_type = _NNS_MEDIA_ANY;
2204  } else {
2205  in_type = gst_structure_get_media_type (structure);
2206  }
2207 
2208  switch (in_type) {
2209  case _NNS_VIDEO:
2210  if (is_video_supported (self)) {
2211  if (!gst_tensor_converter_parse_video (self, caps, &config)) {
2212  char *capstr = gst_caps_to_string (caps);
2213  GST_ERROR_OBJECT (self,
2214  "Failed to configure tensor from gst cap \"%s\" for video streams.",
2215  capstr);
2216  g_free (capstr);
2217  return FALSE;
2218  }
2219 
2220  frames_dim = 3;
2221  } else {
2222  ml_loge
2223  ("tensor_converter: This binary does not support video type. Please build NNStreamer with -Dvideo-support=enabled (default). You have configured -Dvideo-support=disabled when you build this binary.\n");
2224  return FALSE;
2225  }
2226  break;
2227  case _NNS_AUDIO:
2228  if (is_audio_supported (self)) {
2229  if (!gst_tensor_converter_parse_audio (self, caps, &config)) {
2230  char *capstr = gst_caps_to_string (caps);
2231  GST_ERROR_OBJECT (self,
2232  "Failed to configure tensor from gst cap \"%s\" for audio streams.",
2233  capstr);
2234  g_free (capstr);
2235  return FALSE;
2236  }
2237 
2238  frames_dim = 1;
2239  } else {
2240  ml_loge
2241  ("tensor_converter: This binary does not support audio type. Please build NNStreamer with -Daudio-support=enabled (default). You have configured -Daudio-support=disabled when you build this binary.\n");
2242  return FALSE;
2243  }
2244  break;
2245  case _NNS_TEXT:
2246  if (!gst_tensor_converter_parse_text (self, &config, structure)) {
2247  char *capstr = gst_caps_to_string (caps);
2248  GST_ERROR_OBJECT (self,
2249  "Failed to configure tensor from gst cap \"%s\" for text streams.",
2250  capstr);
2251  g_free (capstr);
2252  return FALSE;
2253  }
2254 
2255  frames_dim = 1;
2256  break;
2257  case _NNS_OCTET:
2258  if (!gst_tensor_converter_parse_octet (self, &config, structure)) {
2259  char *capstr = gst_caps_to_string (caps);
2260  GST_ERROR_OBJECT (self,
2261  "Failed to configure tensors from gst cap \"%s\" for octet streams.",
2262  capstr);
2263  g_free (capstr);
2264  return FALSE;
2265  }
2266  break;
2267  case _NNS_TENSOR:
2268  /* flexible tensor to static tensor stream */
2269  if (!gst_tensor_converter_parse_tensor (self, &config, structure)) {
2270  char *capstr = gst_caps_to_string (caps);
2271  GST_ERROR_OBJECT (self,
2272  "Failed to configure tensor from flexible tensor (%s); trying to convert to static tensor.",
2273  capstr);
2274  g_free (capstr);
2275  return FALSE;
2276  }
2277  break;
2278  default:
2279  if (!gst_tensor_converter_parse_custom (self, &config, caps)) {
2280  char *capstr = gst_caps_to_string (caps);
2281  GST_ERROR_OBJECT (self,
2282  "Failed to configure tensors with custom mode from streams of gst cap (%s) with custom converter subplugins.",
2283  capstr);
2284  g_free (capstr);
2285  return FALSE;
2286  }
2287  in_type = _NNS_MEDIA_ANY;
2288  break;
2289  }
2290 
2292  if (frames_dim >= 0) {
2293  config.info.info[0].dimension[frames_dim] = self->frames_per_tensor;
2294  }
2295 
2296  if (!gst_tensors_config_validate (&config)) {
2298  char *capstr = gst_caps_to_string (caps);
2299  char *cfgstr = gst_tensors_config_to_string (&config);
2300  GST_ERROR_OBJECT (self,
2301  "Failed to configure tensors info with gst cap (%s). Cannot validate tensor configuration acquired from the given gst cap. The resulting invalid tensor config is: %s\n",
2302  capstr, cfgstr);
2303  g_free (capstr);
2304  g_free (cfgstr);
2305  return FALSE;
2306  }
2307 
2308  if (gst_tensors_info_validate (&self->tensors_info)) {
2310  if (!gst_tensors_info_is_equal (&self->tensors_info, &config.info)) {
2311  gchar *str1 = gst_tensors_info_to_string (&self->tensors_info);
2312  gchar *str2 = gst_tensors_info_to_string (&config.info);
2313  GST_ERROR_OBJECT (self,
2314  "Failed, mismatched tensor info. The two tensor configuration should match: \"configured by properties and tensor output\": %s and \"configured by input stream\": %s\n",
2315  str1, str2);
2316  g_free (str1);
2317  g_free (str2);
2318  return FALSE;
2319  }
2320  }
2321 
2322  self->in_media_type = in_type;
2323  self->tensors_configured = TRUE;
2324  self->tensors_config = config;
2325 
2326  return TRUE;
2327 }
2328 
2332 static void
2334 {
2335  GstTensorsConfig *config;
2336  GstCaps *curr_caps, *out_caps;
2337 
2338  config = &self->tensors_config;
2339  out_caps = gst_tensor_pad_caps_from_config (self->srcpad, config);
2340 
2341  /* Update src pad caps if it is different. */
2342  curr_caps = gst_pad_get_current_caps (self->srcpad);
2343  if (curr_caps == NULL || !gst_caps_is_equal (curr_caps, out_caps)) {
2344  silent_debug_caps (self, out_caps, "set out-caps");
2345  gst_pad_set_caps (self->srcpad, out_caps);
2346  }
2347 
2348  if (curr_caps)
2349  gst_caps_unref (curr_caps);
2350 
2351  gst_caps_unref (out_caps);
2352 }
2353 
2360 nnstreamer_converter_find (const char *name)
2361 {
2362  return get_subplugin (NNS_SUBPLUGIN_CONVERTER, name);
2363 }
2364 
2368 static gboolean
2370 {
2371  if (!converter || !converter->name) {
2372  /* invalid name */
2373  return FALSE;
2374  }
2375 
2376  if (!converter->query_caps || !converter->get_out_config
2377  || !converter->convert) {
2378  /* invalid methods in converter sub-plugin */
2379  return FALSE;
2380  }
2381 
2382  return TRUE;
2383 }
2384 
2388 int
2390 {
2391  g_return_val_if_fail (nnstreamer_converter_validate (ex), FALSE);
2393 }
2394 
2398 void
2400 {
2402 }
2403 
2407 static const NNStreamerExternalConverter *
2409 {
2410  gchar **str_array;
2411  guint total, i, j, caps_size;
2412  GstCaps *caps;
2413  const gchar *caps_name;
2414  const NNStreamerExternalConverter *ex;
2415 
2417  if (str_array) {
2418  total = g_strv_length (str_array);
2419 
2420  for (i = 0; i < total; i++) {
2421  ex = nnstreamer_converter_find (str_array[i]);
2422 
2423  if (g_strcmp0 (media_type, str_array[i]) == 0) {
2424  /* found matched media type */
2425  g_strfreev (str_array);
2426  return ex;
2427  }
2428 
2429  if (ex && ex->query_caps) {
2430  caps = ex->query_caps (NULL);
2431  caps_size = gst_caps_get_size (caps);
2432 
2433  for (j = 0; j < caps_size; j++) {
2434  caps_name = gst_structure_get_name (gst_caps_get_structure (caps, j));
2435  if (g_strcmp0 (media_type, caps_name) == 0) {
2436  /* found matched media type */
2437  gst_caps_unref (caps);
2438  g_strfreev (str_array);
2439  return ex;
2440  }
2441  }
2442 
2443  gst_caps_unref (caps);
2444  }
2445  }
2446 
2447  g_strfreev (str_array);
2448  }
2449 
2450  return NULL;
2451 }
2452 
2456 void
2458  const char *prop, ...)
2459 {
2460  va_list varargs;
2461 
2462  va_start (varargs, prop);
2464  varargs);
2465  va_end (varargs);
2466 }
2467 
2472 int
2474  tensor_converter_custom func, void *data)
2475 {
2476  converter_custom_cb_s *ptr;
2477 
2478  g_return_val_if_fail (name && strlen (name), -EINVAL);
2479  g_return_val_if_fail (func, -EINVAL);
2480 
2481  ptr = g_new0 (converter_custom_cb_s, 1);
2482  ptr->func = func;
2483  ptr->data = data;
2484 
2485  if (register_subplugin (NNS_CUSTOM_CONVERTER, name, ptr))
2486  return 0;
2487 
2488  g_free (ptr);
2489  ml_loge
2490  ("tensor_converter: cannot register a converter subplugin, \"%s\" function. register_subplugin () has failed to register \"%s\".",
2491  name, name);
2492  return -EINVAL;
2493 }
2494 
2499 int
2501 {
2502  converter_custom_cb_s *ptr;
2503 
2506  ml_loge ("tensor_converter: Failed to unregister custom callback %s.",
2507  name);
2508  return -EINVAL;
2509  }
2510  g_free (ptr);
2511 
2512  return 0;
2513 }
gst_video_info_init
#define gst_video_info_init(i)
Definition: gsttensor_converter_media_no_video.h:46
gst_tensors_config_is_flexible
#define gst_tensors_config_is_flexible(c)
Macro to check stream format (flexible tensors for caps negotiation)
Definition: nnstreamer_plugin_api_util.h:279
GST_TENSOR_CAP_DEFAULT
#define GST_TENSOR_CAP_DEFAULT
Default static capability for other/tensor.
Definition: tensor_typedef.h:78
gst_tensors_config_is_equal
gboolean gst_tensors_config_is_equal(const GstTensorsConfig *c1, const GstTensorsConfig *c2)
Compare tensor config info (for other/tensors)
Definition: nnstreamer_plugin_api_util_impl.c:881
NNS_VIDEO_FORMAT
#define NNS_VIDEO_FORMAT
Caps string for supported video format.
Definition: gsttensor_converter_media_info_video.h:31
gst_tensor_buffer_from_config
GstBuffer * gst_tensor_buffer_from_config(GstBuffer *in, GstTensorsConfig *config)
Configure gst-buffer with tensors information. NNStreamer handles single memory chunk as single tenso...
Definition: nnstreamer_plugin_api_impl.c:535
GST_VIDEO_FORMAT_xRGB
@ GST_VIDEO_FORMAT_xRGB
Definition: gsttensor_converter_media_no_video.h:35
g_assert
g_assert(sizeof(DTYPE_UNSIGNED)==sizeof(DTYPE_SIGNED))
gst_tensor_aggregation_get_adapter
GstAdapter * gst_tensor_aggregation_get_adapter(GHashTable *table, const guint32 key)
Gets adapter from hash table.
Definition: nnstreamer_plugin_api_impl.c:790
GstAudioInfo
#define GstAudioInfo
Definition: gsttensor_converter_media_no_audio.h:26
GST_VIDEO_FORMAT_RGBx
@ GST_VIDEO_FORMAT_RGBx
Definition: gsttensor_converter_media_no_video.h:33
data
svtc_1 data
Definition: gsttensor_if.c:844
GstTensorInfo
Internal data structure for tensor info.
Definition: tensor_typedef.h:261
gst_tensor_converter_class_init
static void gst_tensor_converter_class_init(GstTensorConverterClass *klass)
Initialize the tensor_converter's class.
Definition: gsttensor_converter.c:178
silent_debug_timestamp
#define silent_debug_timestamp(self, buf)
Definition: gsttensor_converter.c:95
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
_gst_tensor_converter_chain_push
static GstFlowReturn _gst_tensor_converter_chain_push(GstTensorConverter *self, GstBuffer *buf)
Chain function's private routine to push buffer into src pad.
Definition: gsttensor_converter.c:938
GST_VIDEO_FORMAT_BGRx
@ GST_VIDEO_FORMAT_BGRx
Definition: gsttensor_converter_media_no_video.h:34
FALSE
return FALSE
Definition: gsttensor_transform.c:590
nnstreamer_subplugin.h
Subplugin Manager for NNStreamer.
_CONVERTER_MODE_CUSTOM_SCRIPT
@ _CONVERTER_MODE_CUSTOM_SCRIPT
Definition: gsttensor_converter.h:69
converter_custom_cb_s::data
void * data
Definition: gsttensor_converter.h:60
ml_logf
#define ml_logf
Definition: nnstreamer_log.h:80
gsttensor_converter_media_no_audio.h
Define collection of media type and functions to parse media info for audio if there is no audio supp...
GstTensorsInfo
Internal meta data exchange format for a other/tensors instance.
Definition: tensor_typedef.h:273
gst_tensor_converter_parse_caps
static gboolean gst_tensor_converter_parse_caps(GstTensorConverter *self, const GstCaps *caps)
Parse caps and set tensors info.
Definition: gsttensor_converter.c:2190
gst_tensor_converter_get_possible_media_caps
static GstCaps * gst_tensor_converter_get_possible_media_caps(GstTensorConverter *self)
Get possible media-caps from downstream element.
Definition: gsttensor_converter.c:1972
_NNS_FLOAT16
@ _NNS_FLOAT16
Definition: tensor_typedef.h:150
_NNS_VIDEO
@ _NNS_VIDEO
Definition: tensor_typedef.h:182
gst_tensors_config_from_peer
gboolean gst_tensors_config_from_peer(GstPad *pad, GstTensorsConfig *config, gboolean *is_fixed)
Parse caps from peer pad and set tensors config.
Definition: nnstreamer_plugin_api_impl.c:1041
GST_VIDEO_FORMAT_ABGR
@ GST_VIDEO_FORMAT_ABGR
Definition: gsttensor_converter_media_no_video.h:40
prop
GstTensorSrcIIOChannelProperties * prop
DTYPE_UNSIGNED ( .
Definition: gsttensor_srciio.c:110
PROP_INPUT_TYPE
@ PROP_INPUT_TYPE
Definition: gsttensor_converter.c:121
gsttensor_converter_media_info_video.h
Define collection of media type and functions to parse media info for video support.
DEFAULT_SET_TIMESTAMP
#define DEFAULT_SET_TIMESTAMP
Flag to set timestamp when received a buffer with invalid timestamp.
Definition: gsttensor_converter.c:132
_NNS_OCTET
@ _NNS_OCTET
Definition: tensor_typedef.h:185
GST_VIDEO_FORMAT_GRAY8
@ GST_VIDEO_FORMAT_GRAY8
Definition: gsttensor_converter_media_no_video.h:30
GST_AUDIO_FORMAT_F64
@ GST_AUDIO_FORMAT_F64
Definition: gsttensor_converter_media_no_audio.h:37
gst_tensors_info_validate
gboolean gst_tensors_info_validate(const GstTensorsInfo *info)
Check the tensors info is valid.
Definition: nnstreamer_plugin_api_util_impl.c:404
nnstreamer_converter_set_custom_property_desc
void nnstreamer_converter_set_custom_property_desc(const char *name, const char *prop,...)
set custom property description for tensor converter sub-plugin
Definition: gsttensor_converter.c:2457
subplugin_set_custom_property_desc
void subplugin_set_custom_property_desc(subpluginType type, const char *name, const gchar *prop, va_list varargs)
common interface to set custom property description of a sub-plugin.
Definition: nnstreamer_subplugin.c:329
_NNS_UINT16
@ _NNS_UINT16
Definition: tensor_typedef.h:143
gst_tensor_converter_get_format_list
static void gst_tensor_converter_get_format_list(GValue *list,...)
Get supported format list.
Definition: gsttensor_converter.c:1385
nnstreamer_log.h
Internal log util for NNStreamer plugins and native APIs.
GST_VIDEO_FORMAT_I420
@ GST_VIDEO_FORMAT_I420
Definition: gsttensor_converter_media_no_video.h:41
GstMetaQuery::client_id
query_client_id_t client_id
Definition: tensor_meta.h:30
nnstreamer_converter_custom_register
int nnstreamer_converter_custom_register(const gchar *name, tensor_converter_custom func, void *data)
Registers a callback for tensor_converter custom condition.
Definition: gsttensor_converter.c:2473
gst_tensor_converter_sink_event
static gboolean gst_tensor_converter_sink_event(GstPad *pad, GstObject *parent, GstEvent *event)
This function handles sink event.
Definition: gsttensor_converter.c:586
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_tensors_info_init
void gst_tensors_info_init(GstTensorsInfo *info)
Initialize the tensors info structure.
Definition: nnstreamer_plugin_api_util_impl.c:325
gst_tensor_converter_init
static void gst_tensor_converter_init(GstTensorConverter *self)
Initialize tensor_converter element.
Definition: gsttensor_converter.c:331
GstTensorMetaInfo
Data structure to describe a tensor data. This represents the basic information of a memory block for...
Definition: tensor_typedef.h:310
append_text_caps_template
#define append_text_caps_template(caps)
Definition: gsttensor_converter.c:71
NNS_CUSTOM_CONVERTER
@ NNS_CUSTOM_CONVERTER
Definition: nnstreamer_subplugin.h:46
GstTensorsConfig::rate_d
int rate_d
Definition: tensor_typedef.h:288
gst_tensors_info_free
void gst_tensors_info_free(GstTensorsInfo *info)
Free allocated data in tensors info structure.
Definition: nnstreamer_plugin_api_util_impl.c:347
GstMetaQuery
GstMetaQuery meta structure.
Definition: tensor_meta.h:26
gst_tensor_parse_dimension
guint gst_tensor_parse_dimension(const gchar *dimstr, tensor_dim dim)
Parse tensor dimension parameter string.
Definition: nnstreamer_plugin_api_util_impl.c:1040
tensor_meta.h
Internal tensor meta header for nnstreamer.
gst_tensor_converter_parse_octet
static gboolean gst_tensor_converter_parse_octet(GstTensorConverter *self, GstTensorsConfig *config, const GstStructure *structure)
Set the tensors configs structure from octet stream (internal static function)
Definition: gsttensor_converter.c:1741
_NNS_TENSOR
@ _NNS_TENSOR
Definition: tensor_typedef.h:186
gst_tensors_info_get_types_string
gchar * gst_tensors_info_get_types_string(const GstTensorsInfo *info)
Get the string of types in tensors info.
Definition: nnstreamer_plugin_api_util_impl.c:714
gst_tensor_converter_reset
static void gst_tensor_converter_reset(GstTensorConverter *self)
Clear and reset data.
Definition: gsttensor_converter.c:1369
gst_tensor_converter_change_state
static GstStateChangeReturn gst_tensor_converter_change_state(GstElement *element, GstStateChange transition)
Called to perform state change.
Definition: gsttensor_converter.c:1336
gst_tensors_info_to_string
gchar * gst_tensors_info_to_string(const GstTensorsInfo *info)
GstTensorsInfo represented as a string. Caller should free it.
Definition: nnstreamer_plugin_api_util_impl.c:783
gst_tensor_converter_chain
static GstFlowReturn gst_tensor_converter_chain(GstPad *pad, GstObject *parent, GstBuffer *buf)
Chain function, this function does the actual processing.
Definition: gsttensor_converter.c:1028
GST_AUDIO_INFO_RATE
#define GST_AUDIO_INFO_RATE(...)
Definition: gsttensor_converter_media_no_audio.h:46
silent_debug
#define silent_debug(self,...)
Macro for debug message.
Definition: tensor_common.h:276
GstTensorMetaInfo::media_type
uint32_t media_type
Definition: tensor_typedef.h:317
gst_tensor_pad_caps_is_flexible
#define gst_tensor_pad_caps_is_flexible(p)
Macro to check current pad caps is flexible tensor.
Definition: tensor_common.h:231
append_flex_tensor_caps_template
#define append_flex_tensor_caps_template(caps)
Macro to append template caps for flexible tensor.
Definition: gsttensor_converter.c:85
gst_audio_info_init
#define gst_audio_info_init(i)
Definition: gsttensor_converter_media_no_audio.h:40
_NNStreamerExternalConverter::name
const char * name
Definition: nnstreamer_plugin_api_converter.h:45
gst_tensor_meta_info_append_header
GstMemory * gst_tensor_meta_info_append_header(GstTensorMetaInfo *meta, GstMemory *mem)
Append header to memory.
Definition: nnstreamer_plugin_api_impl.c:1544
PROP_FRAMES_PER_TENSOR
@ PROP_FRAMES_PER_TENSOR
Definition: gsttensor_converter.c:122
NNS_SUBPLUGIN_CONVERTER
@ NNS_SUBPLUGIN_CONVERTER
Definition: nnstreamer_subplugin.h:44
_CONVERTER_MODE_NONE
@ _CONVERTER_MODE_NONE
Definition: gsttensor_converter.h:67
GST_TENSOR_CONVERTER
#define GST_TENSOR_CONVERTER(obj)
Definition: gsttensor_converter.h:46
GST_AUDIO_FORMAT_U32
@ GST_AUDIO_FORMAT_U32
Definition: gsttensor_converter_media_no_audio.h:35
g_free
g_free(self->option[(opnum) - 1])
opnum: \
G_DEFINE_TYPE
G_DEFINE_TYPE(GstTensorConverter, gst_tensor_converter, GST_TYPE_ELEMENT)
GST_VIDEO_FORMAT_RGB
@ GST_VIDEO_FORMAT_RGB
Definition: gsttensor_converter_media_no_video.h:31
g_value_set_string
g_value_set_string(value, self->option[opnum - 1])
opnum: \
gst_tensor_converter_finalize
static void gst_tensor_converter_finalize(GObject *object)
Function to finalize instance.
Definition: gsttensor_converter.c:381
_gst_tensor_converter_chain_flex_tensor
static GstBuffer * _gst_tensor_converter_chain_flex_tensor(GstTensorConverter *self, GstBuffer *buf)
Chain function's private routine to process flex tensor.
Definition: gsttensor_converter.c:893
GST_AUDIO_FORMAT_S16
@ GST_AUDIO_FORMAT_S16
Definition: gsttensor_converter_media_no_audio.h:32
GstTensorsConfig::rate_n
int rate_n
Definition: tensor_typedef.h:287
_NNS_END
@ _NNS_END
Definition: tensor_typedef.h:152
_NNS_TENSOR_FORMAT_FLEXIBLE
@ _NNS_TENSOR_FORMAT_FLEXIBLE
Definition: tensor_typedef.h:196
DEFAULT_FRAMES_PER_TENSOR
#define DEFAULT_FRAMES_PER_TENSOR
Frames in output tensor.
Definition: gsttensor_converter.c:142
gst_audio_info_from_caps
#define gst_audio_info_from_caps(...)
Definition: gsttensor_converter_media_no_audio.h:41
append_video_caps_template
#define append_video_caps_template(caps)
Definition: gsttensor_converter_media_info_video.h:38
GstTensorsInfo::info
GstTensorInfo info[NNS_TENSOR_MEMORY_MAX]
Definition: tensor_typedef.h:276
gst_tensor_converter_sink_query
static gboolean gst_tensor_converter_sink_query(GstPad *pad, GstObject *parent, GstQuery *query)
This function handles sink pad query.
Definition: gsttensor_converter.c:654
gst_video_info_from_caps
#define gst_video_info_from_caps(...)
Definition: gsttensor_converter_media_no_video.h:47
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
GST_VIDEO_FORMAT_BGR
@ GST_VIDEO_FORMAT_BGR
Definition: gsttensor_converter_media_no_video.h:32
gst_structure_get_media_type
media_type gst_structure_get_media_type(const GstStructure *structure)
Get media type from structure.
Definition: nnstreamer_plugin_api_impl.c:1001
_NNS_FLOAT32
@ _NNS_FLOAT32
Definition: tensor_typedef.h:147
gst_tensors_config_free
void gst_tensors_config_free(GstTensorsConfig *config)
Free allocated data in tensors config structure.
Definition: nnstreamer_plugin_api_util_impl.c:845
gst_buffer_get_meta_query
#define gst_buffer_get_meta_query(b)
Definition: tensor_meta.h:44
register_subplugin
gboolean register_subplugin(subpluginType type, const char *name, const void *data)
Public function defined in the header.
Definition: nnstreamer_subplugin.c:225
GST_VIDEO_INFO_FORMAT
#define GST_VIDEO_INFO_FORMAT(...)
Definition: gsttensor_converter_media_no_video.h:50
GstVideoFormat
GstVideoFormat
Definition: gsttensor_converter_media_no_video.h:28
_NNS_TENSOR_FORMAT_STATIC
@ _NNS_TENSOR_FORMAT_STATIC
Definition: tensor_typedef.h:195
GST_VIDEO_FORMAT_BGRA
@ GST_VIDEO_FORMAT_BGRA
Definition: gsttensor_converter_media_no_video.h:38
gst_tensor_info_convert_to_meta
gboolean gst_tensor_info_convert_to_meta(GstTensorInfo *info, GstTensorMetaInfo *meta)
Convert GstTensorInfo structure to GstTensorMetaInfo.
Definition: nnstreamer_plugin_api_util_impl.c:260
GST_AUDIO_INFO_CHANNELS
#define GST_AUDIO_INFO_CHANNELS(...)
Definition: gsttensor_converter_media_no_audio.h:45
GST_VIDEO_INFO_HEIGHT
#define GST_VIDEO_INFO_HEIGHT(...)
Definition: gsttensor_converter_media_no_video.h:52
GST_VIDEO_FORMAT_GRAY16_LE
@ GST_VIDEO_FORMAT_GRAY16_LE
Definition: gsttensor_converter_media_no_video.h:43
gst_tensor_converter_parse_tensor
static gboolean gst_tensor_converter_parse_tensor(GstTensorConverter *self, GstTensorsConfig *config, const GstStructure *structure)
Set the tensors configs structure from fliex tensor stream (internal static function)
Definition: gsttensor_converter.c:1834
_NNStreamerExternalConverter::convert
GstBuffer *(* convert)(GstBuffer *in_buf, GstTensorsConfig *config, void *priv_data)
Definition: nnstreamer_plugin_api_converter.h:48
gst_tensor_meta_info_convert
gboolean gst_tensor_meta_info_convert(GstTensorMetaInfo *meta, GstTensorInfo *info)
Convert GstTensorMetaInfo structure to GstTensorInfo.
Definition: nnstreamer_plugin_api_util_impl.c:1562
registerExternalConverter
int registerExternalConverter(NNStreamerExternalConverter *ex)
Converter's external subplugins should call this at init.
Definition: gsttensor_converter.c:2389
GstVideoInfo
#define GstVideoInfo
Definition: gsttensor_converter_media_no_video.h:26
_NNS_TEXT
@ _NNS_TEXT
Definition: tensor_typedef.h:184
GstTensorsConfig
Internal data structure for configured tensors info (for other/tensors).
Definition: tensor_typedef.h:284
PROP_SET_TIMESTAMP
@ PROP_SET_TIMESTAMP
Definition: gsttensor_converter.c:123
gst_tensors_config_to_string
gchar * gst_tensors_config_to_string(const GstTensorsConfig *config)
Tensor config represented as a string. Caller should free it.
Definition: nnstreamer_plugin_api_util_impl.c:920
get_all_subplugins
gchar ** get_all_subplugins(subpluginType type)
Public function defined in the header.
Definition: nnstreamer_subplugin.c:176
GST_VIDEO_INFO_FPS_D
#define GST_VIDEO_INFO_FPS_D(...)
Definition: gsttensor_converter_media_no_video.h:55
gst_tensor_converter_parse_video
static gboolean gst_tensor_converter_parse_video(GstTensorConverter *self, const GstCaps *caps, GstTensorsConfig *config)
Set the tensors config structure from video info (internal static function)
Definition: gsttensor_converter.c:1444
silent_debug_caps
#define silent_debug_caps(self, caps, msg)
Macro for capability debug message.
Definition: tensor_common.h:285
GST_AUDIO_INFO_BPF
#define GST_AUDIO_INFO_BPF(...)
Definition: gsttensor_converter_media_no_audio.h:47
is_video_supported
#define is_video_supported(...)
Definition: gsttensor_converter_media_info_video.h:41
ml_loge
#define ml_loge
Definition: nnstreamer_log.h:78
GST_AUDIO_FORMAT_UNKNOWN
@ GST_AUDIO_FORMAT_UNKNOWN
Definition: gsttensor_converter_media_no_audio.h:29
_gst_tensor_converter_chain_octet
static GstBuffer * _gst_tensor_converter_chain_octet(GstTensorConverter *self, GstBuffer *buf)
Chain function's private routine to process octet stream.
Definition: gsttensor_converter.c:847
_NNS_INT32
@ _NNS_INT32
Definition: tensor_typedef.h:140
TRUE
return TRUE
Definition: gsttensor_if.c:897
UNUSED
#define UNUSED(expr)
Definition: mqttcommon.h:19
gst_tensor_aggregation_init
GHashTable * gst_tensor_aggregation_init(void)
Gets new hash table for tensor aggregation.
Definition: nnstreamer_plugin_api_impl.c:737
nns_loge
#define nns_loge
Definition: nnstreamer_log.h:142
_GstTensorConverterClass
GstTensorConverterClass data structure.
Definition: gsttensor_converter.h:115
nnstreamer_util.h
Optional NNStreamer utility functions for sub-plugin writers and users.
is_audio_supported
#define is_audio_supported(...)
Definition: gsttensor_converter_media_info_audio.h:35
gst_tensor_info_get_size
gsize gst_tensor_info_get_size(const GstTensorInfo *info)
Get data size of single tensor.
Definition: nnstreamer_plugin_api_util_impl.c:156
PROP_SILENT
@ PROP_SILENT
Definition: gsttensor_converter.c:125
_gst_tensor_converter_chain_chunk
static GstFlowReturn _gst_tensor_converter_chain_chunk(GstTensorConverter *self, GstBuffer *inbuf, guint frames_in, guint frames_out, gsize frame_size)
Chain function's private routine to push multiple buffers.
Definition: gsttensor_converter.c:959
_gst_tensor_converter_chain_segment
static void _gst_tensor_converter_chain_segment(GstTensorConverter *self, gsize frame_size)
Chain function's private routine.
Definition: gsttensor_converter.c:754
GST_AUDIO_FORMAT_F32
@ GST_AUDIO_FORMAT_F32
Definition: gsttensor_converter_media_no_audio.h:36
_NNStreamerExternalConverter::get_out_config
gboolean(* get_out_config)(const GstCaps *in_caps, GstTensorsConfig *config)
Definition: nnstreamer_plugin_api_converter.h:58
append_audio_caps_template
#define append_audio_caps_template(caps)
Definition: gsttensor_converter_media_info_audio.h:32
_CONVERTER_MODE_CUSTOM_CODE
@ _CONVERTER_MODE_CUSTOM_CODE
Definition: gsttensor_converter.h:68
gst_audio_format_to_string
#define gst_audio_format_to_string(...)
Definition: gsttensor_converter_media_no_audio.h:42
_GstTensorConverter
Internal data structure for tensor_converter instances.
Definition: gsttensor_converter.h:75
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
media_type
enum _nns_media_type media_type
Float16 compiler extension support.
GST_TENSORS_CAP_MAKE
#define GST_TENSORS_CAP_MAKE(fmt)
Caps string for the caps template of tensor stream. format should be a string that describes the data...
Definition: tensor_typedef.h:97
GST_DEBUG_CATEGORY_STATIC
GST_DEBUG_CATEGORY_STATIC(gst_tensor_converter_debug)
nnstreamer_converter_find
const NNStreamerExternalConverter * nnstreamer_converter_find(const char *name)
Find converter sub-plugin with the name.
Definition: gsttensor_converter.c:2360
gst_tensors_info_get_size
gsize gst_tensors_info_get_size(const GstTensorsInfo *info, gint index)
Get data size of single tensor.
Definition: nnstreamer_plugin_api_util_impl.c:376
_NNS_MEDIA_INVALID
@ _NNS_MEDIA_INVALID
Definition: tensor_typedef.h:181
gst_video_format_to_string
#define gst_video_format_to_string(...)
Definition: gsttensor_converter_media_no_video.h:48
gst_tensor_converter_parse_text
static gboolean gst_tensor_converter_parse_text(GstTensorConverter *self, GstTensorsConfig *config, const GstStructure *structure)
Set the tensors config structure from text info (internal static function)
Definition: gsttensor_converter.c:1670
_NNS_AUDIO
@ _NNS_AUDIO
Definition: tensor_typedef.h:183
GST_VIDEO_FORMAT_RGBA
@ GST_VIDEO_FORMAT_RGBA
Definition: gsttensor_converter_media_no_video.h:37
GST_AUDIO_FORMAT_U16
@ GST_AUDIO_FORMAT_U16
Definition: gsttensor_converter_media_no_audio.h:33
_NNS_INT16
@ _NNS_INT16
Definition: tensor_typedef.h:142
gst_tensors_info_is_equal
gboolean gst_tensors_info_is_equal(const GstTensorsInfo *i1, const GstTensorsInfo *i2)
Compare tensors info.
Definition: nnstreamer_plugin_api_util_impl.c:454
gst_tensor_converter_src_query
static gboolean gst_tensor_converter_src_query(GstPad *pad, GstObject *parent, GstQuery *query)
This function handles src pad query.
Definition: gsttensor_converter.c:722
GST_AUDIO_FORMAT_S32
@ GST_AUDIO_FORMAT_S32
Definition: gsttensor_converter_media_no_audio.h:34
GST_VIDEO_INFO_FPS_N
#define GST_VIDEO_INFO_FPS_N(...)
Definition: gsttensor_converter_media_no_video.h:54
append_octet_caps_template
#define append_octet_caps_template(caps)
Definition: gsttensor_converter.c:79
nns_logw
#define nns_logw
Definition: nnstreamer_log.h:141
GST_AUDIO_FORMAT_U8
@ GST_AUDIO_FORMAT_U8
Definition: gsttensor_converter_media_no_audio.h:31
GST_VIDEO_INFO_SIZE
#define GST_VIDEO_INFO_SIZE(...)
Definition: gsttensor_converter_media_no_video.h:53
gst_tensor_converter_update_caps
static void gst_tensor_converter_update_caps(GstTensorConverter *self)
Update src pad caps from tensors config.
Definition: gsttensor_converter.c:2333
GstTensorsInfo::num_tensors
unsigned int num_tensors
Definition: tensor_typedef.h:275
_NNS_FLOAT64
@ _NNS_FLOAT64
Definition: tensor_typedef.h:146
gst_tensor_aggregation_clear_all
void gst_tensor_aggregation_clear_all(GHashTable *table)
Clears buffers from all adapters in hash table.
Definition: nnstreamer_plugin_api_impl.c:778
gst_tensor_converter_video_stride
static gboolean gst_tensor_converter_video_stride(GstVideoFormat format, gint width)
Determine if we need zero-padding.
Definition: gsttensor_converter.c:1409
gsttensor_converter.h
GStreamer plugin to convert media types to tensors (as a filter for other general neural network filt...
findExternalConverter
static const NNStreamerExternalConverter * findExternalConverter(const char *media_type_name)
Internal static function to find registered subplugins.
Definition: gsttensor_converter.c:2408
PROP_0
@ PROP_0
Definition: gsttensor_converter.c:119
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
PROP_SUBPLUGINS
@ PROP_SUBPLUGINS
Definition: gsttensor_converter.c:124
tensor_converter_custom
G_BEGIN_DECLS typedef GstBuffer *(* tensor_converter_custom)(GstBuffer *in_buf, void *data, GstTensorsConfig *config)
Convert to tensors as customized operation.
Definition: tensor_converter_custom.h:31
_gst_tensor_converter_chain_timestamp
static void _gst_tensor_converter_chain_timestamp(GstTensorConverter *self, GstBuffer *inbuf, guint frames_in)
Chain function's private routine.
Definition: gsttensor_converter.c:787
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
GstAudioFormat
GstAudioFormat
Definition: gsttensor_converter_media_no_audio.h:28
_NNStreamerExternalConverter::query_caps
GstCaps *(* query_caps)(const GstTensorsConfig *config)
Definition: nnstreamer_plugin_api_converter.h:68
gsttensor_converter_media_no_video.h
Define collection of media type and functions to parse media info for video if there is no video supp...
GST_VIDEO_FORMAT_xBGR
@ GST_VIDEO_FORMAT_xBGR
Definition: gsttensor_converter_media_no_video.h:36
gst_tensor_buffer_get_count
guint gst_tensor_buffer_get_count(GstBuffer *buffer)
Get the number of tensors in the buffer.
Definition: nnstreamer_plugin_api_impl.c:1813
unregisterExternalConverter
void unregisterExternalConverter(const char *name)
Converter's external subplugins should call this at exit.
Definition: gsttensor_converter.c:2399
gsttensor_converter_media_info_audio.h
Define collection of media type and functions to parse media info for audio support.
converter_custom_cb_s::func
tensor_converter_custom func
Definition: gsttensor_converter.h:59
GstTensorInfo::type
tensor_type type
Definition: tensor_typedef.h:266
GstTensorsConfig::info
GstTensorsInfo info
Definition: tensor_typedef.h:286
gst_tensors_info_parse_dimensions_string
guint gst_tensors_info_parse_dimensions_string(GstTensorsInfo *info, const gchar *dim_string)
Parse the string of dimensions.
Definition: nnstreamer_plugin_api_util_impl.c:532
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
_NNS_UINT32
@ _NNS_UINT32
Definition: tensor_typedef.h:141
gst_tensor_meta_info_parse_memory
gboolean gst_tensor_meta_info_parse_memory(GstTensorMetaInfo *meta, GstMemory *mem)
Parse memory and fill the tensor meta.
Definition: nnstreamer_plugin_api_impl.c:1509
STRING_CUSTOM_MODE
#define STRING_CUSTOM_MODE(self)
Definition: gsttensor_converter.c:106
_NNS_INT8
@ _NNS_INT8
Definition: tensor_typedef.h:144
gst_tensors_info_get_dimensions_string
gchar * gst_tensors_info_get_dimensions_string(const GstTensorsInfo *info)
Get the string of dimensions in tensors info.
Definition: nnstreamer_plugin_api_util_impl.c:661
GST_AUDIO_INFO_FORMAT
#define GST_AUDIO_INFO_FORMAT(...)
Definition: gsttensor_converter_media_no_audio.h:44
gst_tensors_info_copy
void gst_tensors_info_copy(GstTensorsInfo *dest, const GstTensorsInfo *src)
Copy tensor info.
Definition: nnstreamer_plugin_api_util_impl.c:502
GST_VIDEO_FORMAT_ARGB
@ GST_VIDEO_FORMAT_ARGB
Definition: gsttensor_converter_media_no_video.h:39
GstTensorInfo::dimension
tensor_dim dimension
Definition: tensor_typedef.h:267
gst_tensor_converter_get_adapter
static GstAdapter * gst_tensor_converter_get_adapter(GstTensorConverter *self, GstBuffer *buf)
Internal function to get adapter.
Definition: gsttensor_converter.c:706
gst_tensor_converter_query_caps
static GstCaps * gst_tensor_converter_query_caps(GstTensorConverter *self, GstPad *pad, GstCaps *filter)
Get pad caps for caps negotiation.
Definition: gsttensor_converter.c:2144
_NNS_UINT8
@ _NNS_UINT8
Definition: tensor_typedef.h:145
nnstreamer_converter_validate
static gboolean nnstreamer_converter_validate(const NNStreamerExternalConverter *converter)
Validate converter sub-plugin's data.
Definition: gsttensor_converter.c:2369
NNS_TENSOR_RANK_LIMIT
#define NNS_TENSOR_RANK_LIMIT
Definition: tensor_typedef.h:34
gst_tensor_converter_parse_audio
static gboolean gst_tensor_converter_parse_audio(GstTensorConverter *self, const GstCaps *caps, GstTensorsConfig *config)
Set the tensors config structure from audio info (internal static function)
Definition: gsttensor_converter.c:1582
type
svtc_1 type
Definition: gsttensor_if.c:843
nnstreamer_converter_custom_unregister
int nnstreamer_converter_custom_unregister(const gchar *name)
Unregisters a callback for tensor_converter custom condition.
Definition: gsttensor_converter.c:2500
GST_VIDEO_INFO_WIDTH
#define GST_VIDEO_INFO_WIDTH(...)
Definition: gsttensor_converter_media_no_video.h:51
gst_tensor_converter_parse_custom
static gboolean gst_tensor_converter_parse_custom(GstTensorConverter *self, GstTensorsConfig *config, const GstCaps *caps)
Set the tensors config structure from caps (internal static function for custom mode)
Definition: gsttensor_converter.c:1889
gst_tensors_info_parse_types_string
guint gst_tensors_info_parse_types_string(GstTensorsInfo *info, const gchar *type_string)
Parse the string of types.
Definition: nnstreamer_plugin_api_util_impl.c:572
if
if(!gst_tensordec_process_plugin_options(self,(opnum) - 1)) GST_ERROR_OBJECT(self
gst_tensor_buffer_append_memory
gboolean gst_tensor_buffer_append_memory(GstBuffer *buffer, GstMemory *memory, const GstTensorInfo *info)
Append memory to given buffer.
Definition: nnstreamer_plugin_api_impl.c:1666
gst_tensor_converter_get_property
static void gst_tensor_converter_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
Getter for tensor_converter properties.
Definition: gsttensor_converter.c:514
GstTensorsInfo::format
tensor_format format
Definition: tensor_typedef.h:278
DEFAULT_SILENT
#define DEFAULT_SILENT
Flag to print minimized log.
Definition: gsttensor_converter.c:137
PROP_MODE
@ PROP_MODE
Definition: gsttensor_converter.c:126
get_subplugin
const void * get_subplugin(subpluginType type, const char *name)
Public function defined in the header.
Definition: nnstreamer_subplugin.c:141
unregister_subplugin
gboolean unregister_subplugin(subpluginType type, const char *name)
Public function defined in the header.
Definition: nnstreamer_subplugin.c:289
_NNS_MEDIA_ANY
@ _NNS_MEDIA_ANY
Definition: tensor_typedef.h:187
gst_tensor_meta_info_get_header_size
gsize gst_tensor_meta_info_get_header_size(GstTensorMetaInfo *meta)
Get the header size to handle a tensor meta.
Definition: nnstreamer_plugin_api_util_impl.c:1456
PROP_INPUT_DIMENSION
@ PROP_INPUT_DIMENSION
Definition: gsttensor_converter.c:120
converter_custom_cb_s
Definition: gsttensor_converter.h:57
gst_tensor_converter_set_property
static void gst_tensor_converter_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Setter for tensor_converter properties.
Definition: gsttensor_converter.c:406
GST_VIDEO_FORMAT_GRAY16_BE
@ GST_VIDEO_FORMAT_GRAY16_BE
Definition: gsttensor_converter_media_no_video.h:42
_NNStreamerExternalConverter
Converter's subplugin implementation.
Definition: nnstreamer_plugin_api_converter.h:41
GST_AUDIO_FORMAT_S8
@ GST_AUDIO_FORMAT_S8
Definition: gsttensor_converter_media_no_audio.h:30