Doxygen Book
tensor_filter.c
Go to the documentation of this file.
1 
66 #ifdef HAVE_CONFIG_H
67 #include <config.h>
68 #endif
69 
70 #include <string.h>
71 #include <nnstreamer_util.h>
72 
73 #include "tensor_filter.h"
74 
76 #define EVENT_NAME_UPDATE_MODEL "evt_update_model"
77 
78 GST_DEBUG_CATEGORY_STATIC (gst_tensor_filter_debug);
79 #define GST_CAT_DEFAULT gst_tensor_filter_debug
80 
81 #define TF_MODELNAME(prop) \
82  ((prop)->model_files ? ((prop)->model_files[0]) : "[No Model File]")
83 
87 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_MAKE ("{ static, flexible }")
88 
92 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
93  GST_PAD_SINK,
94  GST_PAD_ALWAYS,
95  GST_STATIC_CAPS (CAPS_STRING));
96 
100 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
101  GST_PAD_SRC,
102  GST_PAD_ALWAYS,
103  GST_STATIC_CAPS (CAPS_STRING));
104 
105 #define gst_tensor_filter_parent_class parent_class
106 G_DEFINE_TYPE (GstTensorFilter, gst_tensor_filter, GST_TYPE_BASE_TRANSFORM);
107 
113 #define LATENCY_REPORT_HEADROOM 0.05
114 
120 #define LATENCY_REPORT_THRESHOLD 0.25
121 
122 /* GObject vmethod implementations */
123 static void gst_tensor_filter_set_property (GObject * object, guint prop_id,
124  const GValue * value, GParamSpec * pspec);
125 static void gst_tensor_filter_get_property (GObject * object, guint prop_id,
126  GValue * value, GParamSpec * pspec);
127 static void gst_tensor_filter_finalize (GObject * object);
128 
129 /* GstBaseTransform vmethod implementations */
130 static GstFlowReturn gst_tensor_filter_transform (GstBaseTransform * trans,
131  GstBuffer * inbuf, GstBuffer * outbuf);
132 static GstCaps *gst_tensor_filter_transform_caps (GstBaseTransform * trans,
133  GstPadDirection direction, GstCaps * caps, GstCaps * filter);
134 static GstCaps *gst_tensor_filter_fixate_caps (GstBaseTransform * trans,
135  GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
136 static gboolean gst_tensor_filter_set_caps (GstBaseTransform * trans,
137  GstCaps * incaps, GstCaps * outcaps);
138 static gboolean gst_tensor_filter_query (GstBaseTransform * trans,
139  GstPadDirection direction, GstQuery * query);
140 static gboolean gst_tensor_filter_transform_size (GstBaseTransform * trans,
141  GstPadDirection direction, GstCaps * caps, gsize size,
142  GstCaps * othercaps, gsize * othersize);
143 static gboolean gst_tensor_filter_start (GstBaseTransform * trans);
144 static gboolean gst_tensor_filter_stop (GstBaseTransform * trans);
145 static gboolean gst_tensor_filter_sink_event (GstBaseTransform * trans,
146  GstEvent * event);
147 static gboolean gst_tensor_filter_src_event (GstBaseTransform * trans,
148  GstEvent * event);
149 
153 typedef struct _FilterTransformData
154 {
158  guint num_tensors;
160 
161  gboolean is_flexible;
164 
168 static void
170 {
171  GObjectClass *gobject_class;
172  GstElementClass *gstelement_class;
173  GstBaseTransformClass *trans_class;
174 
175  GST_DEBUG_CATEGORY_INIT (gst_tensor_filter_debug, "tensor_filter", 0,
176  "Tensor filter to invoke neural network model");
177 
178  trans_class = (GstBaseTransformClass *) klass;
179  gstelement_class = (GstElementClass *) trans_class;
180  gobject_class = (GObjectClass *) gstelement_class;
181 
182  gobject_class->set_property = gst_tensor_filter_set_property;
183  gobject_class->get_property = gst_tensor_filter_get_property;
184  gobject_class->finalize = gst_tensor_filter_finalize;
185 
186  gst_tensor_filter_install_properties (gobject_class);
187 
188  gst_element_class_set_details_simple (gstelement_class,
189  "TensorFilter",
190  "Filter/Tensor",
191  "Handles NN Frameworks (e.g., tensorflow) as Media Filters with other/tensor type stream",
192  "MyungJoo Ham <myungjoo.ham@samsung.com>");
193 
194  gst_element_class_add_pad_template (gstelement_class,
195  gst_static_pad_template_get (&src_factory));
196  gst_element_class_add_pad_template (gstelement_class,
197  gst_static_pad_template_get (&sink_factory));
198 
199  /* Refer: https://gstreamer.freedesktop.org/documentation/design/element-transform.html */
200  trans_class->passthrough_on_same_caps = FALSE;
201 
202  /* Processing units */
203  trans_class->transform = GST_DEBUG_FUNCPTR (gst_tensor_filter_transform);
204 
205  /* Negotiation units */
206  trans_class->transform_caps =
207  GST_DEBUG_FUNCPTR (gst_tensor_filter_transform_caps);
208  trans_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_tensor_filter_fixate_caps);
209  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_tensor_filter_set_caps);
210 
211  /* Allocation units */
212  trans_class->transform_size =
213  GST_DEBUG_FUNCPTR (gst_tensor_filter_transform_size);
214 
215  /* setup events */
216  trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_tensor_filter_sink_event);
217  trans_class->src_event = GST_DEBUG_FUNCPTR (gst_tensor_filter_src_event);
218 
219  /* start/stop to call open/close */
220  trans_class->start = GST_DEBUG_FUNCPTR (gst_tensor_filter_start);
221  trans_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_filter_stop);
222 
223  /* Queries */
224  trans_class->query = GST_DEBUG_FUNCPTR (gst_tensor_filter_query);
225 }
226 
233 static void
235 {
236  GstTensorFilterPrivate *priv = &self->priv;
237 
239  /* init qos properties */
240  self->prev_ts = GST_CLOCK_TIME_NONE;
241  self->throttling_delay = 0;
242  self->throttling_accum = 0;
243 }
244 
248 static void
249 gst_tensor_filter_finalize (GObject * object)
250 {
251  GstTensorFilter *self;
253 
254  self = GST_TENSOR_FILTER (object);
255  priv = &self->priv;
256 
257  if (priv->prop.suspend != 0) {
258  GST_OBJECT_LOCK (self);
260  priv->watchdog_h = NULL;
261  GST_OBJECT_UNLOCK (self);
262  }
263 
266 
267  G_OBJECT_CLASS (parent_class)->finalize (object);
268 }
269 
276 static gsize
278  gboolean is_input)
279 {
281  GstTensorsInfo *info;
282 
283  priv = &self->priv;
284  if (is_input)
285  info = &priv->prop.input_meta;
286  else
287  info = &priv->prop.output_meta;
288 
289  /* Internal Logic Error: out of bound */
290  if (index >= info->num_tensors) {
291  GST_ELEMENT_ERROR_BTRACE (self, STREAM, FAILED,
292  ("tensor_filter's core has inconsistent data. Please report to https://github.com/nnstreamer/nnstreamer/issues . The index argument (%u) of tensors is greater-than or equal-to the number of tensors (%u)",
293  index, info->num_tensors));
294  return 0;
295  }
296 
298 }
299 
303 static void
304 gst_tensor_filter_set_property (GObject * object, guint prop_id,
305  const GValue * value, GParamSpec * pspec)
306 {
307  GstTensorFilter *self;
309 
310  self = GST_TENSOR_FILTER (object);
311  priv = &self->priv;
312 
313  silent_debug (self, "Setting property for prop %d.\n", prop_id);
314 
315  if (prop_id == PROP_CONFIG) {
316  g_free (priv->config_path);
317  priv->config_path = g_strdup (g_value_get_string (value));
319  return;
320  }
321 
322  if (!gst_tensor_filter_common_set_property (priv, prop_id, value, pspec))
323  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324 }
325 
329 static void
330 gst_tensor_filter_get_property (GObject * object, guint prop_id,
331  GValue * value, GParamSpec * pspec)
332 {
333  GstTensorFilter *self;
335 
336  self = GST_TENSOR_FILTER (object);
337  priv = &self->priv;
338 
339  silent_debug (self, "Getting property for prop %d.\n", prop_id);
340 
341  if (prop_id == PROP_CONFIG) {
342  g_value_set_string (value, priv->config_path ? priv->config_path : "");
343  return;
344  }
345 
346  if (!gst_tensor_filter_common_get_property (priv, prop_id, value, pspec))
347  G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
348 }
349 
356 static void
358 {
359  GPtrArray *array = (GPtrArray *) data;
360  GstTensorFilter *self = (GstTensorFilter *) g_ptr_array_index (array, 0);
361  void *tensor_data = (void *) g_ptr_array_index (array, 1);
362  g_ptr_array_free (array, TRUE);
363 
364  gst_tensor_filter_destroy_notify_util (&self->priv, tensor_data);
365 }
366 
371 static GstMemory *
373  gsize size)
374 {
375  GPtrArray *data_array = g_ptr_array_new ();
376 
377  g_ptr_array_add (data_array, (gpointer) self);
378  g_ptr_array_add (data_array, (gpointer) data);
379 
380  return gst_memory_new_wrapped (0, data, size, 0, size, (gpointer) data_array,
382 }
383 
387 static void
389 {
390  priv->stat.latest_invoke_time = g_get_real_time ();
391 }
392 
396 static void
397 accumulate_latency (void *data, void *user_data)
398 {
399  gint64 *latency = data;
400  gint64 *total_latency = user_data;
401 
402  *total_latency += *latency;
403 }
404 
405 #define THRESHOLD_DROP_OLD (2000)
406 #define THRESHOLD_CACHE_OLD (1000)
407 
411 static void
413 {
414  gint64 end_time = g_get_real_time ();
415  gint64 *latency;
416  GQueue *recent_latencies = priv->stat.recent_latencies;
417 
418  /* ignore first measurements that may be off */
419  if (priv->stat.latency_ignore_count) {
420  priv->stat.latency_ignore_count--;
421  return;
422  }
423 
424  latency = g_new (gint64, 1);
425  *latency = end_time - priv->stat.latest_invoke_time;
426  priv->stat.total_invoke_latency += *latency;
427  priv->stat.total_invoke_num += 1;
428 
429  if (g_queue_get_length (recent_latencies) == GST_TF_STAT_MAX_RECENT)
430  g_free (g_queue_pop_head (recent_latencies));
431  g_queue_push_tail (recent_latencies, latency);
432 
433  /* the queue should have at least one element */
434  g_assert (g_queue_get_length (recent_latencies) != 0);
435 
436  if (priv->latency_mode > 0 || priv->latency_reporting) {
437  gint64 avg_latency = 0;
438 
439  g_queue_foreach (recent_latencies, accumulate_latency, &avg_latency);
440  avg_latency /= g_queue_get_length (recent_latencies);
441 
442  /* check integer overflow */
443  if (avg_latency <= INT32_MAX)
444  priv->prop.latency = (gint) avg_latency;
445  else
446  priv->prop.latency = -1;
447 
448  ml_logi ("[%s] Invoke took %.3f ms", TF_MODELNAME (&(priv->prop)),
449  (*latency) / 1000.0);
450  }
451 
452  if (priv->throughput_mode > 0) {
453  gint throughput_int = -1;
454 
455  if (priv->stat.total_invoke_latency != 0) {
456  gdouble throughput =
457  (gdouble) (priv->stat.total_invoke_num * G_USEC_PER_SEC * 1000) /
459 
460  /* check integer overflow */
461  if (throughput <= INT32_MAX)
462  throughput_int = (gint) throughput;
463  }
464 
465  /* note that it's a 1000x larger value than actual throughput */
466  priv->prop.throughput = throughput_int;
467 
468  ml_logi ("[%s] Throughput: %.2f FPS", TF_MODELNAME (&(priv->prop)),
469  throughput_int / 1000.0);
470  }
471 
480  /* drop cached values */
481  priv->stat.old_total_invoke_latency = 0;
482  priv->stat.old_total_invoke_num = 0;
483  } else if (priv->stat.total_invoke_num > THRESHOLD_CACHE_OLD) {
484  /* cache old values if they are not yet set */
485  if (priv->stat.old_total_invoke_num == 0) {
488  }
489  }
490 }
491 
502 static void
504 {
505  GstTensorFilterPrivate *priv = &self->priv;
506  gint64 estimated, reported;
507  gdouble deviation;
508 
509  GST_OBJECT_LOCK (self);
510  estimated = priv->prop.latency * GST_USECOND;
511  reported = priv->latency_reported;
512  GST_OBJECT_UNLOCK (self);
513 
514  if ((priv->latency_reporting) && (estimated > 0)) {
515  if (reported > 0)
516  deviation = (gdouble) ABS (estimated - reported) / reported;
517  else
518  deviation = 0;
519 
520  if ((estimated > reported) || (deviation > LATENCY_REPORT_THRESHOLD)) {
521  ml_logd
522  ("[%s] latency reported:%" G_GINT64_FORMAT " estimated:%"
523  G_GINT64_FORMAT " deviation:%.4f", TF_MODELNAME (&(priv->prop)),
524  reported, estimated, deviation);
525 
526  gst_element_post_message (GST_ELEMENT_CAST (self),
527  gst_message_new_latency (GST_OBJECT_CAST (self)));
528  }
529  }
530 }
531 
535 static gboolean
537  GstBuffer * inbuf)
538 {
539  GstTensorFilter *self;
541 
542  self = GST_TENSOR_FILTER_CAST (trans);
543  priv = &self->priv;
544 
545  GST_OBJECT_LOCK (trans);
546 
547  if (self->throttling_delay != 0) {
548  GstClockTime curr_ts = GST_BUFFER_PTS (inbuf);
549  GstClockTime prev_ts = self->prev_ts;
550 
551  self->prev_ts = curr_ts;
552 
553  if (GST_CLOCK_TIME_IS_VALID (prev_ts)) {
554  GstClockTimeDiff diff = curr_ts - prev_ts;
555  GstClockTimeDiff delay;
556 
557  self->throttling_accum += diff;
558 
559  /* check whether the average latency is longer than throttling delay */
560  delay = MAX (priv->prop.latency * 1000, self->throttling_delay);
561 
562  if (self->throttling_accum < delay) {
563  GstClockTimeDiff duration = GST_BUFFER_DURATION (inbuf); /* original */
564  gdouble avg_rate = gst_guint64_to_gdouble (duration) /
565  gst_guint64_to_gdouble (delay);
566 
571  GstPad *sinkpad = GST_BASE_TRANSFORM_SINK_PAD (&self->element);
572  GstEvent *event = gst_event_new_qos (GST_QOS_TYPE_OVERFLOW,
573  avg_rate, (self->throttling_accum - delay), curr_ts);
574 
575  gst_pad_push_event (sinkpad, event);
576 
577  GST_OBJECT_UNLOCK (trans);
578  return TRUE;
579  }
580 
581  self->throttling_accum = 0;
582  }
583  }
584 
585  GST_OBJECT_UNLOCK (trans);
586  return FALSE;
587 }
588 
592 static GstFlowReturn
593 _gst_tensor_filter_transform_validate (GstBaseTransform * trans,
594  GstBuffer * inbuf, GstBuffer * outbuf)
595 {
596  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
597  GstTensorFilterPrivate *priv = &self->priv;
599 
600  if (G_UNLIKELY (!priv->configured)) {
601  GST_ELEMENT_ERROR_BTRACE (self, STREAM, TYPE_NOT_FOUND,
602  ("The tensor_filter instance is not configured (pad caps not negotiated). Property info (framework = '%s', framework_opened = %d, model[0] = '%s', num-models = %d, custom_properties = '%s'.",
603  prop ? prop->fwname : "property info is NULL.",
604  prop ? prop->fw_opened : -1,
605  prop ? TF_MODELNAME (prop) : "property info is NULL.",
606  prop ? prop->num_models : -1,
607  prop ? prop->custom_properties : "property info is NULL."));
608  return GST_FLOW_NOT_NEGOTIATED;
609  }
610  if (G_UNLIKELY (!priv->fw)) {
616  GST_ELEMENT_ERROR_BTRACE (self, STREAM, FAILED,
617  ("Framework (filter subplugin) is not found or not configured: 'framework=%s'. Please check if the given framework name is correct and the given model path is consistent with the intended framework especially if 'framework=auto' is given. Please refer to the warning messages created when the framework property is set.",
618  priv->prop.fwname));
619  ml_logf
620  ("\nA corresponding nnstreamer extension (tensor_filter subplugin) is not installed or the framework property of tensor_filter is incorrect: [%s] is not found.\n\n",
621  prop->fwname);
622  return GST_FLOW_ERROR;
623  }
624  if (G_UNLIKELY (!priv->fw->run_without_model) &&
625  G_UNLIKELY (!(prop->model_files &&
626  prop->num_models > 0 && prop->model_files[0]))) {
627  GST_ELEMENT_ERROR_BTRACE (self, STREAM, FAILED,
628  ("For the framework='%s', its model filepath is not provided and this framework requires a model file. Thus, we cannot proceed with tensor_filter for inferences. Please provide a valid model file path.",
629  prop->fwname));
630  return GST_FLOW_ERROR;
631  }
632  if ((GST_TF_FW_V0 (priv->fw) && G_UNLIKELY (!priv->fw->invoke_NN)) ||
633  (GST_TF_FW_V1 (priv->fw) && G_UNLIKELY (!priv->fw->invoke))) {
634  GST_ELEMENT_ERROR_BTRACE (self, STREAM, FAILED,
635  ("The tensor-filter subplugin for the framework='%s' does not have its mandatory methods (or callback functions). It appears that your subplugin implementation of '%s' is not completed. There is no 'invoke_NN (v1)' or 'invoke (v2)' methods available.",
636  prop->fwname, prop->fwname));
637  return GST_FLOW_ERROR;
638  }
639 
640  silent_debug (self, "Invoking %s with %s model\n", prop->fwname,
641  GST_STR_NULL (prop->model_files[0]));
642 
643  /* skip input data when throttling delay is set */
644  if (gst_tensor_filter_check_throttling_delay (trans, inbuf))
645  return GST_BASE_TRANSFORM_FLOW_DROPPED;
646 
647  if (!outbuf) {
648  GST_ELEMENT_ERROR_BTRACE (self, STREAM, FAILED,
649  ("The output buffer for the instance of tensor-filter subplugin (%s / %s) is null. Cannot proceed.",
650  prop->fwname, TF_MODELNAME (prop)));
651  return GST_FLOW_ERROR;
652  }
653  if (gst_buffer_get_size (outbuf) != 0) {
654  GST_ELEMENT_ERROR_BTRACE (self, STREAM, FAILED,
655  ("The output buffer for the instance of tensor-filter subplugin (%s / %s) already has a content (buffer size = %zu). It should be 0.",
656  prop->fwname, TF_MODELNAME (prop), gst_buffer_get_size (outbuf)));
657  return GST_FLOW_ERROR;
658  }
659 
660  return GST_FLOW_OK;
661 }
662 
666 static void
668  guint end_index)
669 {
670  guint i;
671 
672  for (i = 0; i < end_index; i++) {
673  if (trans_data->mem[i]) {
674  gst_memory_unmap (trans_data->mem[i], &trans_data->info[i]);
675  gst_memory_unref (trans_data->mem[i]);
676  }
677  }
678 }
679 
683 static gsize
685  GstTensorsInfo * info, guint idx)
686 {
687  gsize header_size = 0;
688  GstTensorMetaInfo *_meta;
689  GstTensorInfo *_info;
690 
691  if (trans_data->is_flexible) {
692  _meta = &trans_data->meta[idx];
693  _info = gst_tensors_info_get_nth_info (info, idx);
694 
695  gst_tensor_meta_info_parse_header (_meta, trans_data->info[idx].data);
696  header_size = gst_tensor_meta_info_get_header_size (_meta);
697  gst_tensor_meta_info_convert (_meta, _info);
698  }
699 
700  return header_size;
701 }
702 
706 static FilterTransformData *
708  GstBuffer * buf)
709 {
710  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
711  GstTensorFilterPrivate *priv = &self->priv;
713  guint i;
714  gsize hsize;
715  FilterTransformData *trans_data = NULL;
716 
717  trans_data = g_new0 (FilterTransformData, 1);
718 
719  if (!trans_data) {
720  ml_loge
721  ("Failed to allocate memory for internal data of tensor filter transform input data.");
722  return NULL;
723  }
724 
725  trans_data->num_tensors = gst_tensor_buffer_get_count (buf);
726  trans_data->is_flexible =
727  gst_tensor_pad_caps_is_flexible (GST_BASE_TRANSFORM_SINK_PAD (trans));
728 
729  for (i = 0; i < trans_data->num_tensors; i++) {
730  trans_data->mem[i] = gst_tensor_buffer_get_nth_memory (buf, i);
731  if (!gst_memory_map (trans_data->mem[i], &trans_data->info[i],
732  GST_MAP_READ)) {
734  ("gst_tensor_filter_transform: For the given input buffer, tensor-filter (%s : %s) cannot map input memory from the buffer for reading. The %u-th memory chunk (%u-th tensor) has failed for memory map.\n",
735  prop->fwname, TF_MODELNAME (prop), i, i);
737  g_free (trans_data);
738  return NULL;
739  }
740 
741  hsize = _gst_tensor_filter_convert_meta (trans_data, &prop->input_meta, i);
742 
743  trans_data->tensors[i].data = trans_data->info[i].data + hsize;
744  trans_data->tensors[i].size = trans_data->info[i].size - hsize;
745  }
746 
747  return trans_data;
748 }
749 
753 static GstTensorMemory *
755  FilterTransformData * trans_data)
756 {
757  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
758  GstTensorFilterPrivate *priv = &self->priv;
760  guint i;
761  gsize expected;
762  GstTensorMemory *invoke_tensors = NULL;
763  guint invoke_num_tensors = 0;
764 
765  if (priv->combi.in_combi_defined) {
766  invoke_num_tensors = g_list_length (priv->combi.in_combi);
767  } else {
768  if (trans_data->num_tensors != prop->input_meta.num_tensors) {
770  ("gst_tensor_filter_transform: Input buffer has invalid number of memory blocks (%u), which is expected to be %u (the number of tensors). Maybe, the pad capability is not consistent with the actual input stream.\n",
771  prop->input_meta.num_tensors, prop->input_meta.num_tensors);
772  return NULL;
773  }
774  invoke_num_tensors = trans_data->num_tensors;
775  }
776 
777  invoke_tensors = g_new0 (GstTensorMemory, invoke_num_tensors);
778 
779  if (!invoke_tensors) {
780  ml_loge
781  ("Failed to allocate memory for internal data of tensor filter transform invoke tensors. The number of invoke tensors: %u",
782  invoke_num_tensors);
783  return NULL;
784  }
785 
786  /* Prepare tensors to invoke. */
787  if (priv->combi.in_combi_defined) {
788  GList *list;
789  guint info_idx = 0;
790 
791  for (list = priv->combi.in_combi; list != NULL; list = list->next) {
792  i = GPOINTER_TO_UINT (list->data);
793 
794  if (i >= trans_data->num_tensors) {
796  ("gst_tensor_filter_transform: Invalid input combination ('input-combination' property) for the tensor-filter (%s:%s). The %u'th combination's index is %u, which is out of bound (>= %u = the number of memory chunks (tensors) of incoming buffer). Because of buffer index inconsistency, it cannot continue (cannot map the memory for the input buffer).\n",
797  prop->fwname, TF_MODELNAME (prop), info_idx, i,
798  trans_data->num_tensors);
799  g_free (invoke_tensors);
800  return NULL;
801  }
802 
803  expected = gst_tensor_filter_get_tensor_size (self, info_idx, TRUE);
804  if (expected != trans_data->tensors[i].size) {
806  ("gst_tensor_filter_transform: With the given input combination ('input-combination' property) of the tensor-filter, the incoming buffer size of combination index %u (%u'th combination) is %zd, which is invalid and is expected to be %zd. Because of buffer size inconsistency, it cannot continue (cannot map the memory for the input buffer).\n",
807  i, info_idx, trans_data->tensors[i].size, expected);
808  g_free (invoke_tensors);
809  return NULL;
810  }
811 
812  invoke_tensors[info_idx++] = trans_data->tensors[i];
813  }
814  } else {
815  for (i = 0; i < prop->input_meta.num_tensors; i++) {
816  expected = gst_tensor_filter_get_tensor_size (self, i, TRUE);
817  if (expected != trans_data->tensors[i].size) {
819  ("gst_tensor_filter_transform: Input buffer size (%u'th memory chunk: %zd) is invalid, which is expected to be %zd, which is the frame size of the corresponding tensor. Maybe, the pad capability is not consistent with the actual input stream; if the size is supposed to change dynamically and the given neural network, framework, and the subpluigins can handle it, please consider using format=flexible.\n",
820  i, trans_data->tensors[i].size, expected);
821  g_free (invoke_tensors);
822  return NULL;
823  }
824 
825  invoke_tensors[i] = trans_data->tensors[i];
826  }
827  }
828 
829  return invoke_tensors;
830 }
831 
835 static FilterTransformData *
837 {
838  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
839  GstTensorFilterPrivate *priv = &self->priv;
841  FilterTransformData *trans_data = NULL;
842 
843  trans_data = g_new0 (FilterTransformData, 1);
844 
845  if (!trans_data) {
846  ml_loge
847  ("Failed to allocate memory for internal data of tensor filter transform output data.");
848  return NULL;
849  }
850 
851  trans_data->num_tensors = prop->output_meta.num_tensors;
853  trans_data->is_flexible =
854  gst_tensor_pad_caps_is_flexible (GST_BASE_TRANSFORM_SRC_PAD (trans));
855 
856  if (prop->invoke_dynamic && !trans_data->is_flexible) {
857  ml_loge
858  ("Dynamic Invoke of tensor filter is activated but the output of tensor filter is static tensors. Currently, only flexible tensors is supported as output of dynamic invoke. If you don't want to dynamic invoke, remove the invoke-dynamic option of tensor filter.");
859  g_free (trans_data);
860  return NULL;
861  }
862 
863  return trans_data;
864 }
865 
869 static GstFlowReturn
871  FilterTransformData * trans_data)
872 {
873  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
874  GstTensorFilterPrivate *priv = &self->priv;
876  GstTensorInfo *_info;
877  guint i;
878  gsize hsize;
879 
880  for (i = 0; i < prop->output_meta.num_tensors; i++) {
881  trans_data->tensors[i].data = NULL;
882  trans_data->tensors[i].size =
884 
885  hsize = 0;
886  if (trans_data->is_flexible && !prop->invoke_dynamic) {
887  _info = gst_tensors_info_get_nth_info (&prop->output_meta, i);
888  if (!gst_tensor_info_convert_to_meta (_info, &trans_data->meta[i])) {
890  ("gst_tensor_filter_transform: The configured output tensor information is invalid, at %u'th output tensor\n",
891  i);
892  return GST_FLOW_ERROR;
893  }
894  hsize = gst_tensor_meta_info_get_header_size (&trans_data->meta[i]);
895  }
896 
897  /* allocate memory if allocate_in_invoke is FALSE */
898  if (!trans_data->allocate_in_invoke) {
899  trans_data->mem[i] =
900  gst_allocator_alloc (NULL, trans_data->tensors[i].size + hsize, NULL);
901  if (!trans_data->mem[i]) {
903  ("gst_tensor_filter_transform: cannot allocate memory for the output buffer (%u'th memory chunk for %u'th tensor), which requires %zd bytes. gst_allocate_alloc has returned Null. Out of memory?",
904  i, i, trans_data->tensors[i].size + hsize);
905  return GST_FLOW_ERROR;
906  }
907  if (!gst_memory_map (trans_data->mem[i], &trans_data->info[i],
908  GST_MAP_WRITE)) {
910  ("gst_tensor_filter_transform: For the given output buffer, allocated by gst_tensor_filter_transform, it cannot map output memory buffer for the %u'th memory chunk (%u'th output tensor) for write.\n",
911  i, i);
912  return GST_FLOW_ERROR;
913  }
914 
915  trans_data->tensors[i].data = trans_data->info[i].data + hsize;
916 
917  /* append header */
918  if (trans_data->is_flexible) {
920  (&trans_data->meta[i], trans_data->info[i].data)) {
922  ("gst_tensor_meta_info_update_header() has failed to update header for flexible format: invalid metadata or buffer for header is not available. This looks like an internal error of nnstreamer/tensor_filter. Please report to github.com/nnstreamer/nnstreamer/issues. %u'th output buffer has failed to update its header.\n",
923  i);
924  return GST_FLOW_ERROR;
925  }
926  }
927  }
928  }
929  return GST_FLOW_OK;
930 }
931 
935 static GstFlowReturn
937  FilterTransformData * in_trans_data, FilterTransformData * out_trans_data,
938  gint invoke_res)
939 {
940  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
941  GstTensorFilterPrivate *priv = &self->priv;
943  guint i;
944 
945  for (i = 0; i < in_trans_data->num_tensors; i++) {
946  gst_memory_unmap (in_trans_data->mem[i], &in_trans_data->info[i]);
947  if (invoke_res != 0)
948  gst_memory_unref (in_trans_data->mem[i]);
949  }
950 
951  if (!out_trans_data->allocate_in_invoke) {
952  for (i = 0; i < prop->output_meta.num_tensors; i++) {
953  gst_memory_unmap (out_trans_data->mem[i], &out_trans_data->info[i]);
954  if (invoke_res != 0)
955  gst_memory_unref (out_trans_data->mem[i]);
956  }
957  }
958 
959  if (invoke_res < 0) {
961  ("Calling invoke function (inference instance) of the tensor-filter subplugin (%s for %s) has failed with error code (%d).\n",
962  prop->fwname, TF_MODELNAME (prop), invoke_res);
963  return GST_FLOW_ERROR;
964  } else if (invoke_res > 0) {
965  /* drop this buffer */
966  return GST_BASE_TRANSFORM_FLOW_DROPPED;
967  }
968 
969  return GST_FLOW_OK;
970 }
971 
975 static void
977  FilterTransformData * in_trans_data, FilterTransformData * out_trans_data,
978  GstBuffer * outbuf)
979 {
980  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
981  GstTensorFilterPrivate *priv = &self->priv;
983  GstMemory *mem;
984  guint i;
985  GList *list;
986  GstTensorInfo *_info;
987  gsize hsize;
988 
989  /* If output combination is defined, append input tensors first */
990  if (priv->combi.out_combi_i_defined) {
991  for (list = priv->combi.out_combi_i; list != NULL; list = list->next) {
992  i = GPOINTER_TO_UINT (list->data);
993 
994  if (!in_trans_data->is_flexible && out_trans_data->is_flexible) {
995  /* append header */
996  _info = gst_tensors_info_get_nth_info (&priv->in_config.info, i);
997  gst_tensor_info_convert_to_meta (_info, &in_trans_data->meta[i]);
998  mem =
999  gst_tensor_meta_info_append_header (&in_trans_data->meta[i],
1000  in_trans_data->mem[i]);
1001  } else if (in_trans_data->is_flexible && !out_trans_data->is_flexible) {
1002  /* remove header */
1003  hsize = gst_tensor_meta_info_get_header_size (&in_trans_data->meta[i]);
1004  mem = gst_memory_share (in_trans_data->mem[i], hsize, -1);
1005  } else {
1006  mem = gst_memory_ref (in_trans_data->mem[i]);
1007  }
1008 
1009  gst_buffer_append_memory (outbuf, mem);
1010  }
1011  }
1012 
1013  for (i = 0; i < in_trans_data->num_tensors; i++) {
1014  if (in_trans_data->mem[i]) {
1015  gst_memory_unref (in_trans_data->mem[i]);
1016  }
1017  }
1018 
1019  for (i = 0; i < prop->output_meta.num_tensors; i++) {
1020  if (priv->combi.out_combi_o_defined) {
1021  gboolean out_combi = FALSE;
1022 
1023  for (list = priv->combi.out_combi_o; list != NULL; list = list->next) {
1024  if (i == GPOINTER_TO_UINT (list->data)) {
1025  out_combi = TRUE;
1026  break;
1027  }
1028  }
1029  if (!out_combi) {
1030  /* release memory block if output tensor is not in the combi list */
1031  if (out_trans_data->allocate_in_invoke) {
1033  out_trans_data->tensors[i].data);
1034  } else {
1035  gst_memory_unref (out_trans_data->mem[i]);
1036  }
1037 
1038  continue;
1039  }
1040  }
1041 
1042  if (prop->invoke_dynamic) {
1043  GstTensorMetaInfo meta;
1044  GstMemory *flex_mem;
1045 
1046  /* Convert to flexible tensors */
1047  _info = gst_tensors_info_get_nth_info (&prop->output_meta, i);
1048  gst_tensor_info_convert_to_meta (_info, &meta);
1049  meta.media_type = _NNS_TENSOR;
1051 
1052  flex_mem = gst_memory_new_wrapped (0,
1053  out_trans_data->tensors[i].data, out_trans_data->tensors[i].size, 0,
1054  out_trans_data->tensors[i].size, out_trans_data->tensors[i].data,
1055  g_free);
1056 
1057  out_trans_data->mem[i] =
1058  gst_tensor_meta_info_append_header (&meta, flex_mem);
1059  gst_memory_unref (flex_mem);
1060  } else if (out_trans_data->allocate_in_invoke) {
1061  /* prepare memory block if successfully done */
1062  out_trans_data->mem[i] = mem = gst_tensor_filter_get_wrapped_mem (self,
1063  out_trans_data->tensors[i].data, out_trans_data->tensors[i].size);
1064 
1065  if (out_trans_data->is_flexible) {
1066  /* prepare new memory block with meta */
1067  out_trans_data->mem[i] =
1068  gst_tensor_meta_info_append_header (&out_trans_data->meta[i], mem);
1069  gst_memory_unref (mem);
1070  }
1071  }
1072 
1073  /* append the memory block to outbuf */
1074  gst_tensor_buffer_append_memory (outbuf, out_trans_data->mem[i],
1075  gst_tensors_info_get_nth_info (&prop->output_meta, i));
1076  }
1077 }
1078 
1082 static gboolean
1084 {
1086 
1087  ml_logd ("Suspend watchdog triggered. Unload the NN framework.");
1089 
1090  return FALSE;
1091 }
1092 
1096 static GstFlowReturn
1097 gst_tensor_filter_transform (GstBaseTransform * trans,
1098  GstBuffer * inbuf, GstBuffer * outbuf)
1099 {
1100  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
1101  GstTensorFilterPrivate *priv = &self->priv;
1102  gint invoke_res = -1;
1103  gboolean need_profiling;
1104  GstFlowReturn retval = GST_FLOW_OK;
1105  FilterTransformData *in_trans_data = NULL;
1106  FilterTransformData *out_trans_data = NULL;
1107  GstTensorMemory *invoke_tensors = NULL;
1108 
1110  if (priv->prop.suspend != 0) {
1111  GST_OBJECT_LOCK (self);
1113  GST_OBJECT_UNLOCK (self);
1115  }
1116 
1117  /* 0. Check all properties. */
1118  retval = _gst_tensor_filter_transform_validate (trans, inbuf, outbuf);
1119  if (retval != GST_FLOW_OK)
1120  return retval;
1121 
1122  in_trans_data =
1124  if (!in_trans_data) {
1125  return GST_FLOW_ERROR;
1126  }
1127 
1128  invoke_tensors =
1129  _gst_tensor_filter_transform_get_invoke_tensors (trans, in_trans_data);
1130  if (!invoke_tensors) {
1131  goto mem_map_error;
1132  }
1133 
1134  out_trans_data = _gst_tensor_filter_transform_get_output_data (trans);
1135  if (!out_trans_data) {
1136  goto mem_map_error;
1137  }
1138 
1139  retval =
1141  out_trans_data);
1142  if (retval != GST_FLOW_OK) {
1143  goto mem_map_error;
1144  }
1145 
1146  need_profiling = (priv->latency_mode > 0 || priv->throughput_mode > 0 ||
1147  priv->latency_reporting);
1148  if (need_profiling)
1149  prepare_statistics (priv);
1150 
1151  GST_TF_FW_INVOKE_COMPAT (priv, invoke_res, invoke_tensors,
1152  out_trans_data->tensors);
1153  if (need_profiling) {
1154  record_statistics (priv);
1155  track_latency (self);
1156  }
1157 
1158  retval =
1160  out_trans_data, invoke_res);
1161  if (retval != GST_FLOW_OK) {
1162  goto done;
1163  }
1164 
1165  _gst_tensor_filter_transform_update_outbuf (trans, in_trans_data,
1166  out_trans_data, outbuf);
1167 
1168  goto done;
1169 
1170 mem_map_error:
1171  retval = GST_FLOW_ERROR;
1172  if (in_trans_data) {
1174  in_trans_data->num_tensors);
1175  }
1176 
1177  if (out_trans_data && !out_trans_data->allocate_in_invoke) {
1179  out_trans_data->num_tensors);
1180  }
1181 
1182 done:
1184  if (retval == GST_FLOW_OK && priv->prop.suspend != 0) {
1185  GST_OBJECT_LOCK (self);
1188  ml_logw ("Failed to feed watchdog. Suspend mode is not working.");
1189  }
1190  GST_OBJECT_UNLOCK (self);
1191  }
1192 
1193  g_free (in_trans_data);
1194  g_free (out_trans_data);
1195  g_free (invoke_tensors);
1196 
1197  return retval;
1198 }
1199 
1206 static gboolean
1208  const GstCaps * incaps)
1209 {
1210  GstTensorFilterPrivate *priv;
1212  GstStructure *structure;
1213  GstTensorsConfig in_config, out_config;
1214  GstTensorsInfo in_info, out_info;
1215  gboolean flexible;
1216 
1217  g_return_val_if_fail (incaps != NULL, FALSE);
1218  priv = &self->priv;
1219  prop = &priv->prop;
1220  gst_tensors_config_init (&in_config);
1221  gst_tensors_config_init (&out_config);
1222  gst_tensors_info_init (&in_info);
1223  gst_tensors_info_init (&out_info);
1224 
1231  gst_tensor_filter_load_tensor_info (&self->priv);
1232 
1233  structure = gst_caps_get_structure (incaps, 0);
1234  if (G_UNLIKELY (!structure)) {
1235  gchar *capstr = gst_caps_to_string (incaps);
1236  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1237  ("%s:%u The input stream padcap is not appropriate. Cannot get structured information from the given padcap: '%s' (gst_caps_get_structure() has returned NULL.). Please check if the caps you've given is correct especially if you have applied caps-filter in front of tensor-filter (%s:%s).",
1238  __func__, __LINE__, capstr, GST_STR_NULL (prop->fwname),
1239  TF_MODELNAME (prop)));
1240  g_free (capstr);
1241  goto done;
1242  }
1243  if (G_UNLIKELY (!gst_tensors_config_from_structure (&in_config, structure))) {
1244  gchar *capstr = gst_caps_to_string (incaps);
1245  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1246  ("%s:%u The input stream padcap is not appropriate. It is not a valid tensor stream (other/tensors) or a tensor stream with a few required entries missing. For example, dimesion and type are missing for a static tensor (format=static or other/tensor (single tensor)). The given padcap is '%s' for tensor-filter (%s:%s).",
1247  __func__, __LINE__, capstr, GST_STR_NULL (prop->fwname),
1248  TF_MODELNAME (prop)));
1249  g_free (capstr);
1250  goto done;
1251  }
1252 
1257  if (!gst_tensors_config_validate (&in_config)) {
1258  gchar *capstr = gst_caps_to_string (incaps);
1259  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1260  ("%s:%u The input stream padcaps cannot be validated. It is not a valid tensor stream for tensor_filter element. Input stream type for tensor_filter (%s:%s) is %s. tensor-filter could get config from the input padcap; however, it cannot be validated: framerate or format is not valid. Try a static tensor stream with a valid (0/1 is also valid!) framerate.",
1261  __func__, __LINE__, GST_STR_NULL (prop->fwname),
1262  TF_MODELNAME (prop), capstr));
1263  g_free (capstr);
1264  goto done;
1265  }
1266 
1267  if (!gst_tensor_filter_common_get_combined_in_info (priv, &in_config.info,
1268  &in_info)) {
1269  gchar *capstr = gst_caps_to_string (incaps);
1270  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1271  ("%s:%u Failed to configure combined input info for tensor-filter (%s:%s). The given padcap is '%s'. User has specified input combination (refer to the previous error log), which shuffles the order of tensors, which is not compatible with the given model. Please check the padcap, input combination, and tensor/dimension requirement of your neural network model.",
1272  __func__, __LINE__, GST_STR_NULL (prop->fwname),
1273  TF_MODELNAME (prop), capstr));
1274  g_free (capstr);
1275  goto done;
1276  }
1277 
1278  /* flexible tensor case, we cannot get the exact info from caps. */
1279  flexible = gst_tensors_config_is_flexible (&in_config);
1280 
1282  if (prop->input_meta.num_tensors > 0) {
1283  if (flexible) {
1288  GST_INFO_OBJECT (self, "The input tensor is flexible.");
1289  } else if (!gst_tensors_info_is_equal (&in_info, &prop->input_meta)) {
1290  gchar *capstr = gst_caps_to_string (incaps);
1291  gchar *compare =
1292  gst_tensorsinfo_compare_to_string (&in_info, &prop->input_meta);
1293  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1294  ("%s:%u The input tensor of tensor_filter (%s:%s) is not compatible with the configured input information. Please check tensor-filter properties if you have given input dimensions explicitly; or the model properties if you have not given them. Check the input stream caps and related caps-filters, too. The given gstcap is %s, which is not compatible: %s",
1295  __func__, __LINE__, GST_STR_NULL (prop->fwname),
1296  TF_MODELNAME (prop), capstr, compare));
1297  g_free (compare);
1298  g_free (capstr);
1299  goto done;
1300  }
1301  } else {
1302  if (flexible) {
1303  gchar *capstr = gst_caps_to_string (incaps);
1311  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1312  ("%s:%u The input tensor of tensor_filter (%s:%s) is flexible (gstcap: '%s'), which requires either explicit type/dimension tensor-filter property values or static input dimension models. The current version of tensor-filter does not support flexible tensors for dynamic-input models without explicit input dimension declaration. Declare type/dimension/tensors with tensor-filter properties, or apply caps-filter in front of tensor-filter, or use static tensor streams.",
1313  __func__, __LINE__, GST_STR_NULL (prop->fwname),
1314  TF_MODELNAME (prop), capstr));
1315  g_free (capstr);
1316  goto done;
1317  } else {
1318  gst_tensors_info_copy (&prop->input_meta, &in_info);
1319  }
1320  }
1321 
1322  prop->input_configured = TRUE;
1323 
1325  if (!prop->output_configured) {
1326  if (gst_tensor_filter_common_get_out_info (priv, &prop->input_meta,
1327  &out_info)) {
1329  if (prop->output_meta.num_tensors > 0) {
1330  if (!gst_tensors_info_is_equal (&out_info, &prop->output_meta)) {
1331  gchar *cmpstr = gst_tensorsinfo_compare_to_string (&out_info,
1332  &prop->output_meta);
1333  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1334  ("%s:%u The output tensor is not compatible with the configured tensor information. The configuration is usually set by tensor-filter properties declared by users or the given neural network itself. The following two tensor metadata are not compatible: %s.\n",
1335  __func__, __LINE__, cmpstr));
1336  g_free (cmpstr);
1337  gst_tensors_info_free (&out_info);
1338  goto done;
1339  }
1340  } else {
1341  gst_tensors_info_copy (&prop->output_meta, &out_info);
1342  }
1343 
1344  prop->output_configured = TRUE;
1345  }
1346 
1347  if (!prop->output_configured) {
1348  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1349  ("%s:%u Failed to get output tensor info: not enough related information to configure output.\n",
1350  __func__, __LINE__));
1351  goto done;
1352  }
1353  }
1354 
1361  out_config.rate_n = in_config.rate_n;
1362  out_config.rate_d = in_config.rate_d;
1363 
1365  &prop->output_meta, &out_config.info)) {
1366  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1367  ("%s:%u Failed to configure combined output info: please refer to the error message of gst_tensor_filter_common_get_combined_out_info(). ",
1368  __func__, __LINE__));
1369  goto done;
1370  }
1371 
1372  if (priv->configured) {
1374  if (!priv->prop.invoke_dynamic) {
1375  g_assert (gst_tensors_config_is_equal (&priv->in_config, &in_config));
1376  g_assert (gst_tensors_config_is_equal (&priv->out_config, &out_config));
1377  }
1378  } else {
1379  gst_tensors_config_copy (&priv->in_config, &in_config);
1380  gst_tensors_config_copy (&priv->out_config, &out_config);
1381 
1382  priv->configured = TRUE;
1383  }
1384 
1385 done:
1386  gst_tensors_config_free (&in_config);
1387  gst_tensors_config_free (&out_config);
1388  gst_tensors_info_free (&in_info);
1389  gst_tensors_info_free (&out_info);
1390 
1391  return priv->configured;
1392 }
1393 
1404 static GstCaps *
1405 gst_tensor_filter_transform_caps (GstBaseTransform * trans,
1406  GstPadDirection direction, GstCaps * caps, GstCaps * filter)
1407 {
1408  GstTensorFilter *self;
1409  GstTensorFilterPrivate *priv;
1411  GstTensorsConfig in_config, out_config;
1412  GstPad *pad;
1413  GstCaps *result;
1414  GstStructure *structure;
1415  gboolean configured = FALSE;
1416 
1417  self = GST_TENSOR_FILTER_CAST (trans);
1418  priv = &self->priv;
1419  prop = &priv->prop;
1420 
1421  /* Not ready */
1422  if (priv->fw == NULL)
1423  return NULL;
1424 
1425  gst_tensors_config_init (&in_config);
1426  gst_tensors_config_init (&out_config);
1427 
1428  silent_debug_caps (self, caps, "from");
1429  silent_debug_caps (self, filter, "filter");
1430 
1431  if (direction == GST_PAD_SINK)
1432  pad = GST_BASE_TRANSFORM_SRC_PAD (trans);
1433  else
1434  pad = GST_BASE_TRANSFORM_SINK_PAD (trans);
1435 
1444  gst_tensor_filter_load_tensor_info (&self->priv);
1445 
1446  structure = gst_caps_get_structure (caps, 0);
1447  gst_tensors_config_from_structure (&in_config, structure);
1448 
1449  /* set framerate from input config */
1450  out_config.rate_n = in_config.rate_n;
1451  out_config.rate_d = in_config.rate_d;
1452 
1453  if (direction == GST_PAD_SINK) {
1454  GstTensorsInfo out_info;
1455 
1456  gst_tensors_info_init (&out_info);
1457 
1458  /* caps: sink pad. get src pad info */
1459  if (prop->output_configured) {
1460  /* caps with sub-plugin's tensor info */
1461  gst_tensors_info_copy (&out_info, &prop->output_meta);
1462  configured = TRUE;
1463  } else {
1464  /* check in-tensor info to call setInputDimension */
1465  configured = gst_tensor_filter_common_get_out_info (priv,
1466  &in_config.info, &out_info);
1467  }
1468 
1469  /* If output combination option is given, reconfigure tensor info */
1470  if (configured)
1472  &in_config.info, &out_info, &out_config.info);
1473 
1474  gst_tensors_info_free (&out_info);
1475  } else {
1476  /* caps: src pad. get sink pad info */
1477  if (prop->input_configured && !priv->combi.in_combi_defined) {
1478  /* caps with sub-plugin's tensor info */
1479  gst_tensors_info_copy (&out_config.info, &prop->input_meta);
1480  configured = TRUE;
1481  }
1482  }
1483 
1484  if (configured) {
1485  /* output info may be configured */
1486  result = gst_tensor_pad_possible_caps_from_config (pad, &out_config);
1487 
1488  /* Update dimension for src pad caps. */
1489  if (direction == GST_PAD_SINK) {
1490  GstCaps *peer = gst_pad_peer_query_caps (pad, NULL);
1491 
1492  if (peer) {
1493  if (!gst_caps_is_any (peer))
1495  gst_caps_unref (peer);
1496  }
1497  }
1498  } else {
1499  /* we don't know the exact tensor info yet */
1500  result = gst_caps_from_string (CAPS_STRING);
1501  }
1502 
1503  if (filter && gst_caps_get_size (filter) > 0) {
1504  GstCaps *intersection;
1505 
1511  intersection =
1512  gst_caps_intersect_full (result, filter, GST_CAPS_INTERSECT_FIRST);
1513 
1514  gst_caps_unref (result);
1515  result = intersection;
1516  }
1517 
1518  silent_debug_caps (self, result, "to");
1519  gst_tensors_config_free (&in_config);
1520  gst_tensors_config_free (&out_config);
1521  return result;
1522 }
1523 
1527 static GstCaps *
1528 gst_tensor_filter_fixate_caps (GstBaseTransform * trans,
1529  GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
1530 {
1531  GstTensorFilter *self;
1532  GstTensorFilterPrivate *priv;
1533  GstCaps *result;
1534  self = GST_TENSOR_FILTER_CAST (trans);
1535  priv = &self->priv;
1536 
1537  silent_debug (self, "fixate_caps, direction = %d\n", direction);
1538  silent_debug_caps (self, caps, "caps");
1539  silent_debug_caps (self, othercaps, "othercaps");
1540 
1542  if (priv->fw == NULL) {
1543  gst_caps_unref (othercaps);
1544  return NULL;
1545  }
1546 
1550  result = gst_tensor_filter_transform_caps (trans, direction, caps, othercaps);
1551  gst_caps_unref (othercaps);
1552  result = gst_caps_make_writable (result);
1553  result = gst_caps_fixate (result);
1554 
1555  silent_debug_caps (self, result, "result");
1556  return result;
1557 }
1558 
1562 static gboolean
1563 gst_tensor_filter_set_caps (GstBaseTransform * trans,
1564  GstCaps * incaps, GstCaps * outcaps)
1565 {
1566  GstTensorFilter *self;
1567  GstTensorFilterPrivate *priv;
1568  GstStructure *structure;
1569  GstTensorsConfig config;
1570 
1571  self = GST_TENSOR_FILTER_CAST (trans);
1572  priv = &self->priv;
1573 
1574  silent_debug_caps (self, incaps, "incaps");
1575  silent_debug_caps (self, outcaps, "outcaps");
1576 
1577  if (!gst_tensor_filter_configure_tensor (self, incaps)) {
1578  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1579  ("Failed to configure tensor. Please refer to the error log of gst_tensor_filter_configure_tensor ()."));
1580  return FALSE;
1581  }
1582 
1583  if (!gst_tensors_config_validate (&priv->in_config)) {
1584  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1585  ("Failed to validate input tensor configuration. Please refer to the error log of gst_tensors_config_validate(): %s",
1586  GST_STR_NULL (_nnstreamer_error ())));
1587  return FALSE;
1588  }
1589 
1590  if (!priv->prop.invoke_dynamic &&
1592  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1593  ("Failed to validate output tensor configuration. Please refer to the error log of gst_tensors_config_validate(): %s",
1594  GST_STR_NULL (_nnstreamer_error ())));
1595  return FALSE;
1596  }
1597 
1599  structure = gst_caps_get_structure (outcaps, 0);
1600  gst_tensors_config_from_structure (&config, structure);
1601  if (gst_tensors_config_is_flexible (&config)) {
1602  GST_INFO_OBJECT (self, "Output tensor is flexible.");
1603  } else if (!gst_tensors_config_is_equal (&priv->out_config, &config)) {
1605  gchar *compare = gst_tensorsinfo_compare_to_string (&priv->out_config.info,
1606  &config.info);
1607  GST_ELEMENT_ERROR_BTRACE (self, STREAM, WRONG_TYPE,
1608  ("Set-caps failed. Invalid output config (padcaps) for tensor-filter (%s:%s): its format is static, but not equal to the internal configuration: %s\nThis might be an internal error. Please report to https://github.com/nnstreamer/nnstreamer/issues .",
1609  GST_STR_NULL (prop->fwname), TF_MODELNAME (prop), compare));
1610  g_free (compare);
1611  return FALSE;
1612  }
1613 
1614  gst_tensors_config_free (&config);
1615 
1616  return TRUE;
1617 }
1618 
1622 static gboolean
1623 gst_tensor_filter_query (GstBaseTransform * trans,
1624  GstPadDirection direction, GstQuery * query)
1625 {
1626  GstTensorFilter *self;
1627  GstTensorFilterPrivate *priv;
1628  gboolean res = FALSE;
1629 
1630  UNUSED (direction);
1631  self = GST_TENSOR_FILTER_CAST (trans);
1632  priv = &self->priv;
1633 
1634  switch (GST_QUERY_TYPE (query)) {
1635  case GST_QUERY_LATENCY:
1636  {
1637  GstClockTime min, max;
1638  gboolean live;
1639  gint estimated;
1640  gdouble latency;
1641 
1642  GST_OBJECT_LOCK (self);
1643  estimated = (gint) priv->prop.latency;
1644  GST_OBJECT_UNLOCK (self);
1645 
1646  if ((priv->latency_reporting) && (estimated > 0)) {
1647  if ((res = gst_pad_peer_query (GST_BASE_TRANSFORM (self)->sinkpad,
1648  query))) {
1649  gst_query_parse_latency (query, &live, &min, &max);
1650 
1651  GST_DEBUG_OBJECT (self, "Peer latency: min %"
1652  GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1653  GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1654 
1655  latency = (gdouble) estimated *GST_USECOND *
1657  priv->latency_reported = (gint64) latency;
1658 
1659  min += (gint64) latency;
1660  if (max != GST_CLOCK_TIME_NONE)
1661  max += (gint64) latency;
1662 
1663  GST_DEBUG_OBJECT (self, "Calculated total latency : min %"
1664  GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1665  GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1666 
1667  gst_query_set_latency (query, live, min, max);
1668  }
1669  }
1670  if (!res) {
1671  res =
1672  GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
1673  query);
1674  }
1675  break;
1676  }
1677  default:
1678  res =
1679  GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
1680  query);
1681  break;
1682  }
1683 
1684  return res;
1685 }
1686 
1693 static gboolean
1694 gst_tensor_filter_transform_size (GstBaseTransform * trans,
1695  GstPadDirection direction, GstCaps * caps, gsize size,
1696  GstCaps * othercaps, gsize * othersize)
1697 {
1698  GstTensorFilter *self;
1699  GstTensorFilterPrivate *priv;
1700  UNUSED (direction);
1701  UNUSED (caps);
1702  UNUSED (size);
1703  UNUSED (othercaps);
1704  self = GST_TENSOR_FILTER_CAST (trans);
1705  priv = &self->priv;
1707  g_assert (priv->configured);
1712  *othersize = 0;
1713  return TRUE;
1714 }
1715 
1722 static gboolean
1723 gst_tensor_filter_sink_event (GstBaseTransform * trans, GstEvent * event)
1724 {
1725  GstTensorFilter *self;
1726  GstTensorFilterPrivate *priv;
1727  self = GST_TENSOR_FILTER_CAST (trans);
1728  priv = &self->priv;
1729  switch (GST_EVENT_TYPE (event)) {
1730  case GST_EVENT_CUSTOM_DOWNSTREAM:
1731  {
1732  const GstStructure *structure = gst_event_get_structure (event);
1733  int ret = -1;
1734  if (structure == NULL ||
1735  !gst_structure_has_name (structure, EVENT_NAME_UPDATE_MODEL))
1736  break;
1737  if (priv->is_updatable) {
1738  const GValue *value =
1739  gst_structure_get_value (structure, "model_files");
1740  if (value != NULL) {
1741  g_object_set (self, "model", value, NULL);
1742  ret = 0;
1743  }
1744  }
1745 
1746  gst_event_unref (event);
1747  return (ret == 0);
1748  }
1749  default:
1750  break;
1751  }
1752 
1754  return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
1755 }
1756 
1763 static gboolean
1764 gst_tensor_filter_src_event (GstBaseTransform * trans, GstEvent * event)
1765 {
1766  GstTensorFilter *self = GST_TENSOR_FILTER_CAST (trans);
1767  switch (GST_EVENT_TYPE (event)) {
1768  case GST_EVENT_QOS:
1769  {
1770  GstQOSType type;
1771  GstClockTimeDiff diff;
1772  gst_event_parse_qos (event, &type, NULL, &diff, NULL);
1773  if (type == GST_QOS_TYPE_THROTTLE && diff > 0) {
1774  GST_OBJECT_LOCK (trans);
1775  if (self->throttling_delay != 0)
1776  /* set to more tight framerate */
1777  self->throttling_delay = MIN (self->throttling_delay, diff);
1778  else
1779  self->throttling_delay = diff;
1780  GST_OBJECT_UNLOCK (trans);
1781  gst_event_unref (event);
1782  /* enable the average latency profiling */
1783  g_object_set (self, "latency", 1, NULL);
1784  return TRUE;
1785  }
1786  }
1787  /* fall-through */
1788  default:
1789  break;
1790  }
1791 
1793  return GST_BASE_TRANSFORM_CLASS (parent_class)->src_event (trans, event);
1794 }
1795 
1801 static gboolean
1802 gst_tensor_filter_start (GstBaseTransform * trans)
1803 {
1804  GstTensorFilter *self;
1805  GstTensorFilterPrivate *priv;
1806  self = GST_TENSOR_FILTER_CAST (trans);
1807  priv = &self->priv;
1808  /* If it is not configured properly, don't allow to start! */
1809  if (priv->fw == NULL)
1810  return FALSE;
1812 
1813  if (priv->prop.suspend != 0) {
1814  GST_OBJECT_LOCK (self);
1815  if (!nnstreamer_watchdog_create (&priv->watchdog_h)) {
1816  ml_logw ("Failed to create watchdog. Suspend mode is not working.");
1817  GST_OBJECT_UNLOCK (self);
1818  return priv->prop.fw_opened;
1819  }
1822  ml_logw ("Failed to feed watchdog. Suspend mode is not working.");
1823  }
1824  GST_OBJECT_UNLOCK (self);
1825  }
1826 
1827  return priv->prop.fw_opened;
1828 }
1829 
1835 static gboolean
1836 gst_tensor_filter_stop (GstBaseTransform * trans)
1837 {
1838  GstTensorFilter *self;
1839  GstTensorFilterPrivate *priv;
1840  self = GST_TENSOR_FILTER_CAST (trans);
1841  priv = &self->priv;
1842 
1843  if (priv->prop.suspend != 0) {
1844  GST_OBJECT_LOCK (self);
1846  priv->watchdog_h = NULL;
1847  GST_OBJECT_UNLOCK (self);
1848  }
1850 
1851  return TRUE;
1852 }
gst_tensor_filter_finalize
static void gst_tensor_filter_finalize(GObject *object)
Function to finalize instance.
Definition: tensor_filter.c:249
sink_factory
static GstStaticPadTemplate sink_factory
The capabilities of the inputs.
Definition: tensor_filter.c:92
_GstTensorFilterFramework::run_without_model
int run_without_model
Definition: nnstreamer_plugin_api_filter.h:287
_GstTensorFilterFramework::invoke
int(* invoke)(const GstTensorFilterFramework *self, GstTensorFilterProperties *prop, void *private_data, const GstTensorMemory *input, GstTensorMemory *output)
Definition: nnstreamer_plugin_api_filter.h:395
_GstTensorFilterStatistics::latest_invoke_time
gint64 latest_invoke_time
Definition: tensor_filter_common.h:123
_GstTensorFilterFramework::invoke_NN
int(* invoke_NN)(const GstTensorFilterProperties *prop, void **private_data, const GstTensorMemory *input, GstTensorMemory *output)
Definition: nnstreamer_plugin_api_filter.h:292
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_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
g_assert
g_assert(sizeof(DTYPE_UNSIGNED)==sizeof(DTYPE_SIGNED))
_GstTensorFilterPrivate::latency_reported
gint64 latency_reported
Definition: tensor_filter_common.h:171
data
svtc_1 data
Definition: gsttensor_if.c:844
GstTensorInfo
Internal data structure for tensor info.
Definition: tensor_typedef.h:261
ml_logw
#define ml_logw
Definition: nnstreamer_log.h:77
gst_tensor_filter_common_open_fw
void gst_tensor_filter_common_open_fw(GstTensorFilterPrivate *priv)
Open NN framework.
Definition: tensor_filter_common.c:2491
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
THRESHOLD_DROP_OLD
#define THRESHOLD_DROP_OLD
Definition: tensor_filter.c:405
_GstTensorFilterPrivate::out_config
GstTensorsConfig out_config
Definition: tensor_filter_common.h:166
gst_tensor_filter_common_unload_fw
void gst_tensor_filter_common_unload_fw(GstTensorFilterPrivate *priv)
Unload NN framework.
Definition: tensor_filter_common.c:2545
FALSE
return FALSE
Definition: gsttensor_transform.c:590
result
case tensor_data_s gboolean * result
Definition: gsttensor_if.c:839
nnstreamer_watchdog_release
void nnstreamer_watchdog_release(nns_watchdog_h watchdog_h)
Release watchdog source. Recommended using watchdog handle with proper lock (e.g.,...
Definition: nnstreamer_watchdog.c:157
_gst_tensor_filter_release_mem_until_idx
static void _gst_tensor_filter_release_mem_until_idx(FilterTransformData *trans_data, guint end_index)
Internal function to release mem and unmap info with index.
Definition: tensor_filter.c:667
_GstTensorFilterPrivate::throughput_mode
gint throughput_mode
Definition: tensor_filter_common.h:169
ml_logf
#define ml_logf
Definition: nnstreamer_log.h:80
GstTensorMemory::data
void * data
Definition: tensor_typedef.h:254
accumulate_latency
static void accumulate_latency(void *data, void *user_data)
Helper function to accumulate latencies.
Definition: tensor_filter.c:397
_GstTensorFilterPrivate::latency_reporting
gboolean latency_reporting
Definition: tensor_filter_common.h:170
GST_ELEMENT_ERROR_BTRACE
#define GST_ELEMENT_ERROR_BTRACE(s, errtype, errcode, mesg)
Definition: nnstreamer_log.h:94
gst_tensor_filter_common_set_property
gboolean gst_tensor_filter_common_set_property(GstTensorFilterPrivate *priv, guint prop_id, const GValue *value, GParamSpec *pspec)
Set the properties for tensor_filter.
Definition: tensor_filter_common.c:1967
GST_TF_FW_V0
#define GST_TF_FW_V0(fw)
Definition: tensor_filter_common.h:47
GstTensorsInfo
Internal meta data exchange format for a other/tensors instance.
Definition: tensor_typedef.h:273
gst_tensor_meta_info_update_header
gboolean gst_tensor_meta_info_update_header(GstTensorMetaInfo *meta, gpointer header)
Update header from tensor meta.
Definition: nnstreamer_plugin_api_util_impl.c:1505
GST_TF_FW_INVOKE_COMPAT
#define GST_TF_FW_INVOKE_COMPAT(priv, ret, in, out)
Definition: tensor_filter_common.h:69
ml_loge_stacktrace
#define ml_loge_stacktrace(...)
Definition: nnstreamer_log.h:119
_gst_tensor_filter_convert_meta
static gsize _gst_tensor_filter_convert_meta(FilterTransformData *trans_data, GstTensorsInfo *info, guint idx)
Internal function to convert tensor meta and get header size of flexible tensor.
Definition: tensor_filter.c:684
gst_tensor_filter_common_get_combined_out_info
gboolean gst_tensor_filter_common_get_combined_out_info(GstTensorFilterPrivate *priv, const GstTensorsInfo *in, const GstTensorsInfo *out, GstTensorsInfo *combined)
Configure output tensor info with combi option.
Definition: tensor_filter_common.c:2315
prop
GstTensorSrcIIOChannelProperties * prop
DTYPE_UNSIGNED ( .
Definition: gsttensor_srciio.c:110
_GstTensorFilterPrivate::stat
GstTensorFilterStatistics stat
Definition: tensor_filter_common.h:157
_GstTensorFilterProperties::fw_opened
int fw_opened
Definition: nnstreamer_plugin_api_filter.h:115
gst_tensor_filter_stop
static gboolean gst_tensor_filter_stop(GstBaseTransform *trans)
Called when the element stops processing. optional vmethod of BaseTransform.
Definition: tensor_filter.c:1836
gst_tensor_filter_init
static void gst_tensor_filter_init(GstTensorFilter *self)
initialize the new element instantiate pads and add them to element set pad callback functions initia...
Definition: tensor_filter.c:234
_gst_tensor_filter_transform_check_invoke_result
static GstFlowReturn _gst_tensor_filter_transform_check_invoke_result(GstBaseTransform *trans, FilterTransformData *in_trans_data, FilterTransformData *out_trans_data, gint invoke_res)
Internal function to check the invoke result.
Definition: tensor_filter.c:936
_GstTensorFilterPrivate::config_path
gchar * config_path
Definition: tensor_filter_common.h:164
gst_tensor_caps_update_dimension
void gst_tensor_caps_update_dimension(GstCaps *caps, GstCaps *filter)
Update caps dimension for negotiation.
Definition: nnstreamer_plugin_api_impl.c:1093
gst_tensors_info_init
void gst_tensors_info_init(GstTensorsInfo *info)
Initialize the tensors info structure.
Definition: nnstreamer_plugin_api_util_impl.c:325
_GstTensorFilterProperties::suspend
uint32_t suspend
Definition: nnstreamer_plugin_api_filter.h:139
THRESHOLD_CACHE_OLD
#define THRESHOLD_CACHE_OLD
Definition: tensor_filter.c:406
TF_MODELNAME
#define TF_MODELNAME(prop)
Definition: tensor_filter.c:81
GstTensorMetaInfo
Data structure to describe a tensor data. This represents the basic information of a memory block for...
Definition: tensor_typedef.h:310
GstTensorMemory
The unit of each data tensors. It will be used as an input/output tensor of other/tensors.
Definition: tensor_typedef.h:252
tensor_filter.h
GStreamer plugin to use general neural network frameworks as filters.
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
_GstTensorFilterPrivate::in_config
GstTensorsConfig in_config
Definition: tensor_filter_common.h:165
_GstTensorFilterPrivate::watchdog_h
nns_watchdog_h watchdog_h
Definition: tensor_filter_common.h:174
_gst_tensor_filter_transform_get_all_input_data
static FilterTransformData * _gst_tensor_filter_transform_get_all_input_data(GstBaseTransform *trans, GstBuffer *buf)
Internal function to get input tensors.
Definition: tensor_filter.c:707
_GstTensorFilter
Internal data structure for tensor_filter instances.
Definition: tensor_filter.h:61
_GstTensorFilterStatistics::latency_ignore_count
guint latency_ignore_count
Definition: tensor_filter_common.h:125
LATENCY_REPORT_THRESHOLD
#define LATENCY_REPORT_THRESHOLD
Threshold deciding when tracking latency estimate that current value is sufficiently lower than repor...
Definition: tensor_filter.c:120
gst_tensor_filter_transform
static GstFlowReturn gst_tensor_filter_transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
non-ip transform. required vmethod of GstBaseTransform.
Definition: tensor_filter.c:1097
_gst_tensor_filter_transform_validate
static GstFlowReturn _gst_tensor_filter_transform_validate(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
Check input parameters for gst_tensor_filter_transform ();.
Definition: tensor_filter.c:593
_FilterTransformData::meta
GstTensorMetaInfo meta[NNS_TENSOR_SIZE_LIMIT]
Definition: tensor_filter.c:157
_NNS_TENSOR
@ _NNS_TENSOR
Definition: tensor_typedef.h:186
GST_DEBUG_CATEGORY_STATIC
GST_DEBUG_CATEGORY_STATIC(gst_tensor_filter_debug)
_GstTensorFilterStatistics::recent_latencies
void * recent_latencies
Definition: tensor_filter_common.h:124
_FilterTransformData
Internal data structure for tensor_filter transform data.
Definition: tensor_filter.c:153
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
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
g_free
g_free(self->option[(opnum) - 1])
opnum: \
src_factory
static GstStaticPadTemplate src_factory
The capabilities of the outputs.
Definition: tensor_filter.c:100
ml_logf_stacktrace
#define ml_logf_stacktrace(...)
Definition: nnstreamer_log.h:102
_GstTensorFilterStatistics::old_total_invoke_num
gint64 old_total_invoke_num
Definition: tensor_filter_common.h:121
gst_tensor_filter_query
static gboolean gst_tensor_filter_query(GstBaseTransform *trans, GstPadDirection direction, GstQuery *query)
query handling, optional vmethod of GstBaseTransform.
Definition: tensor_filter.c:1623
track_latency
static void track_latency(GstTensorFilter *self)
Track estimated latency and notify pipeline when it changes. Latency estimates may be a bit jittery....
Definition: tensor_filter.c:503
gst_tensor_filter_common_free_property
void gst_tensor_filter_common_free_property(GstTensorFilterPrivate *priv)
Free the properties for tensor-filter.
Definition: tensor_filter_common.c:1065
g_value_set_string
g_value_set_string(value, self->option[opnum - 1])
opnum: \
gst_tensor_filter_fixate_caps
static GstCaps * gst_tensor_filter_fixate_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *othercaps)
fixate caps. required vmethod of GstBaseTransform.
Definition: tensor_filter.c:1528
nnstreamer_watchdog_feed
gboolean nnstreamer_watchdog_feed(nns_watchdog_h watchdog_h, GSourceFunc func, guint interval, void *user_data)
Set watchdog timeout. Recommended using watchdog handle with proper lock (e.g., GST_OBJECT_LOCK())
Definition: nnstreamer_watchdog.c:171
gst_tensor_meta_info_parse_header
gboolean gst_tensor_meta_info_parse_header(GstTensorMetaInfo *meta, gpointer header)
Parse header and fill the tensor meta.
Definition: nnstreamer_plugin_api_util_impl.c:1527
FilterTransformData
struct _FilterTransformData FilterTransformData
Internal data structure for tensor_filter transform data.
GstTensorsConfig::rate_n
int rate_n
Definition: tensor_typedef.h:287
_NNS_TENSOR_FORMAT_FLEXIBLE
@ _NNS_TENSOR_FORMAT_FLEXIBLE
Definition: tensor_typedef.h:196
_nnstreamer_error
const char * _nnstreamer_error(void)
return the last internal error string and clean it.
Definition: nnstreamer_log.c:81
LATENCY_REPORT_HEADROOM
#define LATENCY_REPORT_HEADROOM
Headroom (extra duration) added to actual latency estimate reported to LATENCY query,...
Definition: tensor_filter.c:113
_GstTensorFilterCombination::out_combi_i_defined
gboolean out_combi_i_defined
Definition: tensor_filter_common.h:137
gst_tensor_filter_common_get_out_info
gboolean gst_tensor_filter_common_get_out_info(GstTensorFilterPrivate *priv, GstTensorsInfo *in, GstTensorsInfo *out)
Get output tensor info from NN model with given input info.
Definition: tensor_filter_common.c:2374
gst_tensors_config_copy
void gst_tensors_config_copy(GstTensorsConfig *dest, const GstTensorsConfig *src)
Copy tensors config.
Definition: nnstreamer_plugin_api_util_impl.c:904
_gst_tensor_filter_transform_get_output_data
static FilterTransformData * _gst_tensor_filter_transform_get_output_data(GstBaseTransform *trans)
Internal function to get output tensors.
Definition: tensor_filter.c:836
GstTensorMemory::size
size_t size
Definition: tensor_typedef.h:255
gst_tensor_filter_transform_caps
static GstCaps * gst_tensor_filter_transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter)
configure tensor-srcpad cap from "proposed" cap.
Definition: tensor_filter.c:1405
prepare_statistics
static void prepare_statistics(GstTensorFilterPrivate *priv)
Prepare statistics for performance profiling (e.g, latency, throughput)
Definition: tensor_filter.c:388
_GstTensorFilterCombination::out_combi_i
GList * out_combi_i
Definition: tensor_filter_common.h:134
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_tensor_filter_transform_prepare_output_tensors
static GstFlowReturn _gst_tensor_filter_transform_prepare_output_tensors(GstBaseTransform *trans, FilterTransformData *trans_data)
Internal function to get output tensors.
Definition: tensor_filter.c:870
_GstTensorFilterStatistics::old_total_invoke_latency
gint64 old_total_invoke_latency
Definition: tensor_filter_common.h:122
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_tensor_filter_set_property
static void gst_tensor_filter_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
Setter for tensor_filter properties.
Definition: tensor_filter.c:304
gst_tensor_filter_destroy_notify_util
void gst_tensor_filter_destroy_notify_util(GstTensorFilterPrivate *priv, void *data)
Free the data allocated for tensor filter output.
Definition: tensor_filter_common.c:786
gst_tensor_filter_install_properties
void gst_tensor_filter_install_properties(GObjectClass *gobject_class)
Installs all the properties for tensor_filter.
Definition: tensor_filter_common.c:888
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
gst_tensor_filter_sink_event
static gboolean gst_tensor_filter_sink_event(GstBaseTransform *trans, GstEvent *event)
Event handler for sink pad of tensor filter.
Definition: tensor_filter.c:1723
gst_tensor_filter_get_wrapped_mem
static GstMemory * gst_tensor_filter_get_wrapped_mem(GstTensorFilter *self, gpointer data, gsize size)
Allocate new memory block from given data.
Definition: tensor_filter.c:372
GstTensorsConfig
Internal data structure for configured tensors info (for other/tensors).
Definition: tensor_typedef.h:284
ml_logi
#define ml_logi
Definition: nnstreamer_log.h:76
silent_debug_caps
#define silent_debug_caps(self, caps, msg)
Macro for capability debug message.
Definition: tensor_common.h:285
ml_loge
#define ml_loge
Definition: nnstreamer_log.h:78
gst_tensorsinfo_compare_to_string
gchar * gst_tensorsinfo_compare_to_string(const GstTensorsInfo *info1, const GstTensorsInfo *info2)
Printout the comparison results of two tensors as a string.
Definition: tensor_filter_common.c:811
gst_tensor_filter_check_throttling_delay
static gboolean gst_tensor_filter_check_throttling_delay(GstBaseTransform *trans, GstBuffer *inbuf)
Check throttling delay and send qos overflow event to upstream elements.
Definition: tensor_filter.c:536
nnstreamer_watchdog_destroy
void nnstreamer_watchdog_destroy(nns_watchdog_h watchdog_h)
Destroy watchdog source. Recommended using watchdog handle with proper lock (e.g.,...
Definition: nnstreamer_watchdog.c:133
TRUE
return TRUE
Definition: gsttensor_if.c:897
UNUSED
#define UNUSED(expr)
Definition: mqttcommon.h:19
_GstTensorFilterPrivate
Structure definition for common tensor-filter properties.
Definition: tensor_filter_common.h:152
gst_tensor_filter_common_get_combined_in_info
gboolean gst_tensor_filter_common_get_combined_in_info(GstTensorFilterPrivate *priv, const GstTensorsInfo *in, GstTensorsInfo *combined)
Configure input tensor info with combi option.
Definition: tensor_filter_common.c:2270
gst_tensor_filter_watchdog_trigger
static gboolean gst_tensor_filter_watchdog_trigger(gpointer ptr)
Called when there is no input within suspend time specified by the user.
Definition: tensor_filter.c:1083
nnstreamer_util.h
Optional NNStreamer utility functions for sub-plugin writers and users.
_FilterTransformData::info
GstMapInfo info[NNS_TENSOR_SIZE_LIMIT]
Definition: tensor_filter.c:156
gst_tensor_pad_possible_caps_from_config
GstCaps * gst_tensor_pad_possible_caps_from_config(GstPad *pad, const GstTensorsConfig *config)
Get all possible caps from tensors config. Unlike gst_tensor_pad_caps_from_config(),...
Definition: nnstreamer_plugin_api_impl.c:1286
_GstTensorFilterCombination::in_combi
GList * in_combi
Definition: tensor_filter_common.h:133
CAPS_STRING
#define CAPS_STRING
Default caps string for both sink and source pad.
Definition: tensor_filter.c:87
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
_GstTensorFilterPrivate::fw
const GstTensorFilterFramework * fw
Definition: tensor_filter_common.h:158
_GstTensorFilterProperties::fwname
const char * fwname
Definition: nnstreamer_plugin_api_filter.h:114
nnstreamer_watchdog_create
gboolean nnstreamer_watchdog_create(nns_watchdog_h *watchdog_h)
Create nnstreamer watchdog. Recommended using watchdog handle with proper lock (e....
Definition: nnstreamer_watchdog.c:72
_FilterTransformData::mem
GstMemory * mem[NNS_TENSOR_SIZE_LIMIT]
Definition: tensor_filter.c:155
_GstTensorFilterProperties
GstTensorFilter's properties for NN framework (internal data structure)
Definition: nnstreamer_plugin_api_filter.h:112
_GstTensorFilterPrivate::is_updatable
gboolean is_updatable
Definition: tensor_filter_common.h:163
_GstTensorFilterCombination::in_combi_defined
gboolean in_combi_defined
Definition: tensor_filter_common.h:136
_GstTensorFilterProperties::output_meta
GstTensorsInfo output_meta
Definition: nnstreamer_plugin_api_filter.h:125
_GstTensorFilterStatistics::total_invoke_latency
gint64 total_invoke_latency
Definition: tensor_filter_common.h:120
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
_GstTensorFilterProperties::input_meta
GstTensorsInfo input_meta
Definition: nnstreamer_plugin_api_filter.h:120
_gst_tensor_filter_transform_get_invoke_tensors
static GstTensorMemory * _gst_tensor_filter_transform_get_invoke_tensors(GstBaseTransform *trans, FilterTransformData *trans_data)
Internal function to get invoke tensors.
Definition: tensor_filter.c:754
_GstTensorFilterPrivate::configured
gboolean configured
Definition: tensor_filter_common.h:162
_gst_tensor_filter_transform_update_outbuf
static void _gst_tensor_filter_transform_update_outbuf(GstBaseTransform *trans, FilterTransformData *in_trans_data, FilterTransformData *out_trans_data, GstBuffer *outbuf)
Internal function to make output buffer.
Definition: tensor_filter.c:976
PROP_CONFIG
@ PROP_CONFIG
Definition: gsttensor_decoder.c:78
_GstTensorFilterCombination::out_combi_o
GList * out_combi_o
Definition: tensor_filter_common.h:135
gst_tensor_filter_common_get_property
gboolean gst_tensor_filter_common_get_property(GstTensorFilterPrivate *priv, guint prop_id, GValue *value, GParamSpec *pspec)
Get the properties for tensor_filter.
Definition: tensor_filter_common.c:2102
gst_tensor_filter_load_tensor_info
void gst_tensor_filter_load_tensor_info(GstTensorFilterPrivate *priv)
Load tensor info from NN model. (both input and output tensor)
Definition: tensor_filter_common.c:2409
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_FILTER_CAST
#define GST_TENSOR_FILTER_CAST(obj)
Definition: tensor_filter.h:53
_FilterTransformData::num_tensors
guint num_tensors
Definition: tensor_filter.c:158
gst_tensor_filter_get_property
static void gst_tensor_filter_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
Getter for tensor_filter properties.
Definition: tensor_filter.c:330
EVENT_NAME_UPDATE_MODEL
#define EVENT_NAME_UPDATE_MODEL
Definition: tensor_filter.c:76
_FilterTransformData::allocate_in_invoke
gboolean allocate_in_invoke
Definition: tensor_filter.c:162
gst_tensor_filter_transform_size
static gboolean gst_tensor_filter_transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, gsize size, GstCaps *othercaps, gsize *othersize)
Tell the framework the required size of buffer based on the info of the other side pad....
Definition: tensor_filter.c:1694
gst_tensor_filter_destroy_notify
static void gst_tensor_filter_destroy_notify(void *data)
Free the data allocated for tensor transform.
Definition: tensor_filter.c:357
gst_tensor_filter_allocate_in_invoke
gboolean gst_tensor_filter_allocate_in_invoke(GstTensorFilterPrivate *priv)
check if the allocate_in_invoke is valid for the framework
Definition: tensor_filter_common.c:757
record_statistics
static void record_statistics(GstTensorFilterPrivate *priv)
Record statistics for performance profiling (e.g, latency, throughput)
Definition: tensor_filter.c:412
GstTensorMetaInfo::format
uint32_t format
Definition: tensor_typedef.h:316
GstTensorsInfo::num_tensors
unsigned int num_tensors
Definition: tensor_typedef.h:275
gst_tensor_parse_config_file
void gst_tensor_parse_config_file(const gchar *config_path, const GObject *object)
Parses a configuration file and sets the corresponding properties on a GObject.
Definition: nnstreamer_plugin_api_impl.c:1902
_GstTensorFilterProperties::throughput
int throughput
Definition: nnstreamer_plugin_api_filter.h:136
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
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
ml_logd
#define ml_logd
Definition: nnstreamer_log.h:79
gst_tensor_filter_common_init_property
void gst_tensor_filter_common_init_property(GstTensorFilterPrivate *priv)
Initialize the properties for tensor-filter.
Definition: tensor_filter_common.c:1041
_GstTensorFilterPrivate::combi
GstTensorFilterCombination combi
Definition: tensor_filter_common.h:173
GST_TENSOR_FILTER
#define GST_TENSOR_FILTER(obj)
Definition: tensor_filter.h:45
_GstTensorFilterPrivate::prop
GstTensorFilterProperties prop
Definition: tensor_filter_common.h:155
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
_GstTensorFilterProperties::latency
int latency
Definition: nnstreamer_plugin_api_filter.h:135
GstTensorsConfig::info
GstTensorsInfo info
Definition: tensor_typedef.h:286
gst_tensor_filter_class_init
static void gst_tensor_filter_class_init(GstTensorFilterClass *klass)
initialize the tensor_filter's class
Definition: tensor_filter.c:169
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
GST_TF_STAT_MAX_RECENT
#define GST_TF_STAT_MAX_RECENT
Definition: tensor_filter_common.h:78
gst_tensor_filter_start
static gboolean gst_tensor_filter_start(GstBaseTransform *trans)
Called when the element starts processing. optional vmethod of BaseTransform.
Definition: tensor_filter.c:1802
_GstTensorFilterClass
GstTensorFilterClass inherits GstBaseTransformClass.
Definition: tensor_filter.h:79
gst_tensor_filter_get_tensor_size
static gsize gst_tensor_filter_get_tensor_size(GstTensorFilter *self, guint index, gboolean is_input)
Calculate tensor buffer size.
Definition: tensor_filter.c:277
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
_GstTensorFilterCombination::out_combi_o_defined
gboolean out_combi_o_defined
Definition: tensor_filter_common.h:138
gst_tensor_filter_common_close_fw
void gst_tensor_filter_common_close_fw(GstTensorFilterPrivate *priv)
Close NN framework.
Definition: tensor_filter_common.c:2560
gst_tensors_config_from_structure
gboolean gst_tensors_config_from_structure(GstTensorsConfig *config, const GstStructure *structure)
Parse structure and set tensors config (for other/tensors)
Definition: nnstreamer_plugin_api_impl.c:1413
gst_tensor_filter_set_caps
static gboolean gst_tensor_filter_set_caps(GstBaseTransform *trans, GstCaps *incaps, GstCaps *outcaps)
set caps. required vmethod of GstBaseTransform.
Definition: tensor_filter.c:1563
type
svtc_1 type
Definition: gsttensor_if.c:843
_FilterTransformData::tensors
GstTensorMemory tensors[NNS_TENSOR_SIZE_LIMIT]
Definition: tensor_filter.c:159
_GstTensorFilterPrivate::latency_mode
gint latency_mode
Definition: tensor_filter_common.h:168
gst_tensor_filter_src_event
static gboolean gst_tensor_filter_src_event(GstBaseTransform *trans, GstEvent *event)
Event handler for src pad of tensor filter.
Definition: tensor_filter.c:1764
GST_TF_FW_V1
#define GST_TF_FW_V1(fw)
Definition: tensor_filter_common.h:48
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
_GstTensorFilterStatistics::total_invoke_num
gint64 total_invoke_num
Definition: tensor_filter_common.h:119
_GstTensorFilterProperties::invoke_dynamic
int invoke_dynamic
Definition: nnstreamer_plugin_api_filter.h:137
G_DEFINE_TYPE
G_DEFINE_TYPE(GstTensorFilter, gst_tensor_filter, GST_TYPE_BASE_TRANSFORM)
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
gst_tensor_filter_configure_tensor
static gboolean gst_tensor_filter_configure_tensor(GstTensorFilter *self, const GstCaps *incaps)
Configure input and output tensor info from incaps.
Definition: tensor_filter.c:1207
_FilterTransformData::is_flexible
gboolean is_flexible
Definition: tensor_filter.c:161