LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/nnstreamer/elements - gsttensor_if.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#58eaa3c6edb7484955a5d8c32f47a60ba9501210 Lines: 90.8 % 523 475
Test Date: 2025-04-18 05:37:26 Functions: 100.0 % 29 29

            Line data    Source code
       1              : /* SPDX-License-Identifier: LGPL-2.1-only */
       2              : /**
       3              :  * GStreamer/NNStreamer Tensor-IF
       4              :  * Copyright (C) 2020 MyungJoo Ham <myungjoo.ham@samsung.com>
       5              :  */
       6              : /**
       7              :  * @file        gsttensor_if.c
       8              :  * @date        08 April 2020
       9              :  * @brief       GStreamer plugin to control flow based on tensor values
      10              :  * @see         https://github.com/nnstreamer/nnstreamer
      11              :  * @author      MyungJoo Ham <myungjoo.ham@samsung.com>
      12              :  * @bug         No known bugs except for NYI items
      13              :  */
      14              : 
      15              : /**
      16              :  * SECTION:element-tensor_if
      17              :  *
      18              :  * A filter that controls its src-pad based on the values (other/tensor(s))
      19              :  * of its sink-pad.
      20              :  * For example, you may skip frames if there is no object detected with
      21              :  * high confidence.
      22              :  *
      23              :  * The format of statement with tensor-if is:
      24              :  * if (Compared_Value OPERATOR Supplied_Value(s))) then THEN else ELSE
      25              :  * Compared_Value and Supplied_Value are the operands.
      26              :  * Compared_Value is a value from input tensor(s).
      27              :  * Supplied_Value is a value from tensor-if properties.
      28              :  *
      29              :  * If the given if-condition is simple enough (e.g., if a specific element
      30              :  * is between a given range in a tensor frame), it can be expressed as:
      31              :  * <refsect2>
      32              :  * <title>Example launch line with simple if condition</title>
      33              :  * gst-launch ... (some tensor stream) !
      34              :  *      tensor_if name=tif
      35              :  *        compared-value=A_VALUE compared-value-option=3:4:2:5,0
      36              :  *        operator=RANGE_INCLUSIVE
      37              :  *        supplied-value=10,100
      38              :  *        then=PASSTHROUGH
      39              :  *        else=TENSORPICK
      40              :  *        else-option=1
      41              :  *      tif.src_0 ! queue ! (tensor(s) stream for TRUE action) ...
      42              :  *      tif.src_1 ! queue ! (tensor(s) stream for FALSE action) ...
      43              :  * </refsect2>
      44              :  *
      45              :  * However, if the if-condition is complex and cannot be expressed with
      46              :  * tensor-if expressions, you may create a corresponding custom filter
      47              :  * with tensor-filter, whose output is other/tensors with an additional tensor
      48              :  * that is "1:1:1:1, uint8", which is 1 (true) or 0 (false) as the
      49              :  * first tensor of other/tensors and the input tensor/tensors.
      50              :  * Then, you can create a pipeline as follows:
      51              :  * <refsect2>
      52              :  * <title>Example launch line with complex if condition</title>
      53              :  * gst-launch ... (some tensor stream)
      54              :  *      ! tensor_filter framework=custom name=your_code.so
      55              :  *      ! tensor_if compared-value=A_VALUE
      56              :  *          compared-value-option=0:0:0:0,0 # 1st tensor's [0][0][0][0].
      57              :  *          operator=EQ
      58              :  *          supplied-value=1
      59              :  *          then=PASSTHROUGH # or whatsoever you want
      60              :  *          else=SKIP # or whatsoever you want
      61              :  *      ! tensor_demux name=d
      62              :  *        d.src_0 ! queue ! fakesink # throw away the 1/0 value.
      63              :  *        d.src_1 ! queue ! do whatever you want here...
      64              :  *        ...
      65              :  * </refsect2>
      66              :  */
      67              : #ifdef HAVE_CONFIG_H
      68              : #include <config.h>
      69              : #endif
      70              : 
      71              : #include <nnstreamer_log.h>
      72              : #include <string.h>
      73              : 
      74              : #include <nnstreamer_subplugin.h>
      75              : #include <nnstreamer_util.h>
      76              : #include "gsttensor_if.h"
      77              : 
      78              : /**
      79              :  * @brief Macro for debug mode.
      80              :  */
      81              : #ifndef DBG
      82              : #define DBG (!tensor_if->silent)
      83              : #endif
      84              : 
      85              : /**
      86              :  * @brief tensor_if properties
      87              :  */
      88              : enum
      89              : {
      90              :   PROP_0,
      91              :   PROP_SILENT,
      92              :   PROP_CV, /**< Compared Value, operand 1 (from input tensor(s)) */
      93              :   PROP_CV_OPTION, /**< Compared Value Option */
      94              :   PROP_OP, /**< Operator */
      95              :   PROP_SV, /**< Supplied Value, operand 2 (from the properties) */
      96              :   PROP_THEN, /**< Action if it is TRUE */
      97              :   PROP_THEN_OPTION, /**< Option for TRUE Action */
      98              :   PROP_ELSE, /**< Action if it is FALSE */
      99              :   PROP_ELSE_OPTION, /**< Option for FALSE Action */
     100              : };
     101              : 
     102              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_if_debug);
     103              : #define GST_CAT_DEFAULT gst_tensor_if_debug
     104              : 
     105              : #define CAPS_STRING GST_TENSOR_CAP_DEFAULT "; " GST_TENSORS_CAP_DEFAULT
     106              : /**
     107              :  * @brief The capabilities of the inputs
     108              :  */
     109              : static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     110              :     GST_PAD_SINK,
     111              :     GST_PAD_ALWAYS,
     112              :     GST_STATIC_CAPS (CAPS_STRING));
     113              : 
     114              : /**
     115              :  * @brief The capabilities of the outputs
     116              :  */
     117              : static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
     118              :     GST_PAD_SRC,
     119              :     GST_PAD_SOMETIMES,
     120              :     GST_STATIC_CAPS (CAPS_STRING));
     121              : 
     122              : #define gst_tensor_if_parent_class parent_class
     123         1197 : G_DEFINE_TYPE (GstTensorIf, gst_tensor_if, GST_TYPE_ELEMENT);
     124              : 
     125              : /* GObject vmethod implementations */
     126              : static void gst_tensor_if_set_property (GObject * object, guint prop_id,
     127              :     const GValue * value, GParamSpec * pspec);
     128              : static void gst_tensor_if_get_property (GObject * object, guint prop_id,
     129              :     GValue * value, GParamSpec * pspec);
     130              : 
     131              : static GstFlowReturn gst_tensor_if_chain (GstPad * pad, GstObject * parent,
     132              :     GstBuffer * buf);
     133              : static gboolean gst_tensor_if_event (GstPad * pad, GstObject * parent,
     134              :     GstEvent * event);
     135              : static void gst_tensor_if_dispose (GObject * object);
     136              : 
     137              : static void gst_tensor_if_install_properties (GObjectClass * gobject_class);
     138              : 
     139              : #define GST_TYPE_TENSOR_IF_CV (gst_tensor_if_cv_get_type ())
     140              : /**
     141              :  * @brief A private function to register GEnumValue array for the 'compared-value' property
     142              :  *        to a GType and return it
     143              :  */
     144              : static GType
     145           14 : gst_tensor_if_cv_get_type (void)
     146              : {
     147              :   static GType mode_type = 0;
     148              : 
     149           14 :   if (mode_type == 0) {
     150              :     static GEnumValue mode_types[] = {
     151              :       {TIFCV_A_VALUE, "A_VALUE", "Decide based on a single scalar value"},
     152              :       {TIFCV_TENSOR_AVERAGE_VALUE, "TENSOR_AVERAGE_VALUE",
     153              :           "Decide based on a average value of a specific tensor"},
     154              :       {TIFCV_CUSTOM, "CUSTOM", "Decide based on a user defined callback"},
     155              :       {0, NULL, NULL},
     156              :     };
     157           14 :     mode_type = g_enum_register_static ("tensor_if_compared_value", mode_types);
     158              :   }
     159              : 
     160           14 :   return mode_type;
     161              : }
     162              : 
     163              : #define GST_TYPE_TENSOR_IF_OP (gst_tensor_if_op_get_type ())
     164              : /**
     165              :  * @brief A private function to register GEnumValue array for the 'operator' property
     166              :  *        to a GType and return it
     167              :  */
     168              : static GType
     169           14 : gst_tensor_if_op_get_type (void)
     170              : {
     171              :   static GType mode_type = 0;
     172              : 
     173           14 :   if (mode_type == 0) {
     174              :     static GEnumValue mode_types[] = {
     175              :       {TIFOP_EQ, "EQ", "eqaual"},
     176              :       {TIFOP_NE, "NE", "not_eqaual"},
     177              :       {TIFOP_GT, "GT", "greater_than"},
     178              :       {TIFOP_GE, "GE", "greater_or_equal"},
     179              :       {TIFOP_LT, "LT", "less_than"},
     180              :       {TIFOP_LE, "LE", "less_or_equal"},
     181              :       {TIFOP_RANGE_INCLUSIVE, "RANGE_INCLUSIVE", "range inclusive"},
     182              :       {TIFOP_RANGE_EXCLUSIVE, "RANGE_EXCLUSIVE", "range exclusive"},
     183              :       {TIFOP_NOT_IN_RANGE_INCLUSIVE, "NOT_IN_RANGE_INCLUSIVE",
     184              :           "not in range inclusive"},
     185              :       {TIFOP_NOT_IN_RANGE_EXCLUSIVE, "NOT_IN_RANGE_EXCLUSIVE",
     186              :           "not in range exclusive"},
     187              :       {0, NULL, NULL},
     188              :     };
     189           14 :     mode_type = g_enum_register_static ("tensor_if_operator", mode_types);
     190              :   }
     191              : 
     192           14 :   return mode_type;
     193              : }
     194              : 
     195              : #define GST_TYPE_TENSOR_IF_ACT (gst_tensor_if_act_get_type ())
     196              : /**
     197              :  * @brief A private function to register GEnumValue array for the 'then' and 'else' properties
     198              :  *        to a GType and return it
     199              :  */
     200              : static GType
     201           28 : gst_tensor_if_act_get_type (void)
     202              : {
     203              :   static GType mode_type = 0;
     204              : 
     205           28 :   if (mode_type == 0) {
     206              :     static GEnumValue mode_types[] = {
     207              :       {TIFB_PASSTHROUGH, "PASSTHROUGH", "passthrough"},
     208              :       {TIFB_SKIP, "SKIP", "skip"},
     209              :       {TIFB_TENSORPICK, "TENSORPICK", "tensorpick"},
     210              :       {0, NULL, NULL},
     211              :     };
     212           14 :     mode_type = g_enum_register_static ("tensor_if_behavior", mode_types);
     213              :   }
     214              : 
     215           28 :   return mode_type;
     216              : }
     217              : 
     218              : /**
     219              :  * @brief initialize the tensor_if's class (GST Standard)
     220              :  */
     221              : static void
     222           14 : gst_tensor_if_class_init (GstTensorIfClass * klass)
     223              : {
     224              :   GObjectClass *gobject_class;
     225              :   GstElementClass *gstelement_class;
     226              : 
     227           14 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_if_debug, "tensor_if", 0,
     228              :       "Tensor if to control streams based on tensor(s) values");
     229              : 
     230           14 :   gobject_class = (GObjectClass *) klass;
     231           14 :   gstelement_class = (GstElementClass *) klass;
     232              : 
     233           14 :   parent_class = g_type_class_peek_parent (klass);
     234              : 
     235           14 :   gobject_class->set_property = gst_tensor_if_set_property;
     236           14 :   gobject_class->get_property = gst_tensor_if_get_property;
     237           14 :   gobject_class->dispose = gst_tensor_if_dispose;
     238              : 
     239           14 :   gst_tensor_if_install_properties (gobject_class);
     240              : 
     241           14 :   gst_element_class_set_details_simple (gstelement_class,
     242              :       "TensorIf",
     243              :       "Filter/Tensor",
     244              :       "Controls streams based on the tensor(s) values",
     245              :       "MyungJoo Ham <myungjoo.ham@samsung.com>");
     246              : 
     247           14 :   gst_element_class_add_pad_template (gstelement_class,
     248              :       gst_static_pad_template_get (&src_factory));
     249           14 :   gst_element_class_add_pad_template (gstelement_class,
     250              :       gst_static_pad_template_get (&sink_factory));
     251           14 : }
     252              : 
     253              : /**
     254              :  * @brief initialize the new element (GST Standard)
     255              :  * instantiate pads and add them to element
     256              :  * set pad callback functions
     257              :  * initialize instance structure
     258              :  */
     259              : static void
     260           17 : gst_tensor_if_init (GstTensorIf * tensor_if)
     261              : {
     262           17 :   tensor_if->silent = TRUE;
     263           17 :   gst_tensors_config_init (&tensor_if->in_config);
     264           17 :   gst_tensors_config_init (&tensor_if->out_config[0]);
     265           17 :   gst_tensors_config_init (&tensor_if->out_config[1]);
     266              : 
     267           17 :   tensor_if->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
     268           17 :   gst_element_add_pad (GST_ELEMENT_CAST (tensor_if), tensor_if->sinkpad);
     269           17 :   gst_pad_set_chain_function (tensor_if->sinkpad,
     270              :       GST_DEBUG_FUNCPTR (gst_tensor_if_chain));
     271           17 :   gst_pad_set_event_function (tensor_if->sinkpad,
     272              :       GST_DEBUG_FUNCPTR (gst_tensor_if_event));
     273              : 
     274           17 :   tensor_if->num_srcpads = 0;
     275           17 :   tensor_if->srcpads = NULL;
     276           17 :   tensor_if->cv_option = NULL;
     277           17 :   tensor_if->then_option = NULL;
     278           17 :   tensor_if->else_option = NULL;
     279           17 :   memset (tensor_if->sv, 0, sizeof (tensor_if_sv_s) * 2);
     280           17 :   memset (&tensor_if->custom, 0, sizeof (custom_cb_s));
     281           17 :   tensor_if->custom_configured = FALSE;
     282              : 
     283           17 :   g_mutex_init (&tensor_if->lock);
     284           17 : }
     285              : 
     286              : /**
     287              :  * @brief function to remove srcpad list
     288              :  */
     289              : static void
     290           13 : gst_tensor_if_remove_src_pads (GstTensorIf * tensor_if)
     291              : {
     292           28 :   while (tensor_if->srcpads != NULL) {
     293           15 :     GstTensorPad *tensor_pad = tensor_if->srcpads->data;
     294           15 :     gst_element_remove_pad (GST_ELEMENT (tensor_if), tensor_pad->pad);
     295           15 :     g_free (tensor_pad);
     296           15 :     tensor_if->srcpads =
     297           15 :         g_slist_delete_link (tensor_if->srcpads, tensor_if->srcpads);
     298              :   }
     299           13 :   tensor_if->srcpads = NULL;
     300           13 :   tensor_if->num_srcpads = 0;
     301           13 : }
     302              : 
     303              : /**
     304              :  * @brief dispose function for tensor if (gst element vmethod)
     305              :  */
     306              : static void
     307           13 : gst_tensor_if_dispose (GObject * object)
     308              : {
     309           13 :   GstTensorIf *tensor_if = GST_TENSOR_IF (object);
     310           13 :   g_mutex_clear (&tensor_if->lock);
     311              : 
     312           13 :   gst_tensor_if_remove_src_pads (tensor_if);
     313           13 :   g_list_free (tensor_if->cv_option);
     314           13 :   g_list_free (tensor_if->then_option);
     315           13 :   g_list_free (tensor_if->else_option);
     316           13 :   g_free (tensor_if->custom.name);
     317           13 :   tensor_if->custom.func = NULL;
     318           13 :   tensor_if->custom.data = NULL;
     319           13 :   tensor_if->custom_configured = FALSE;
     320              : 
     321           13 :   G_OBJECT_CLASS (parent_class)->dispose (object);
     322           13 : }
     323              : 
     324              : /**
     325              :  * @brief Convert GValue to GList according to delimiters
     326              :  */
     327              : static void
     328           36 : gst_tensor_if_set_property_glist (const GValue * value, GList ** prop_list,
     329              :     const gchar * delimiters)
     330              : {
     331              :   gint64 val;
     332           36 :   const gchar *param = g_value_get_string (value);
     333           36 :   gchar **strv = g_strsplit_set (param, delimiters, -1);
     334           36 :   gint i, num = g_strv_length (strv);
     335              : 
     336           36 :   g_list_free (*prop_list);
     337           36 :   *prop_list = NULL;
     338              : 
     339           94 :   for (i = 0; i < num; i++) {
     340           58 :     val = g_ascii_strtoll (strv[i], NULL, 10);
     341           58 :     if (errno == ERANGE) {
     342            0 :       ml_loge ("Overflow occurred during converting %s to a gint64 value",
     343              :           strv[i]);
     344              :     }
     345           58 :     *prop_list = g_list_append (*prop_list, GINT_TO_POINTER (val));
     346              :   }
     347           36 :   g_strfreev (strv);
     348           36 : }
     349              : 
     350              : /**
     351              :  * @brief Convert GValue to GList for cv option
     352              :  */
     353              : static void
     354           18 : gst_tensor_if_set_property_cv_option (const GValue * value, GList ** prop_list)
     355              : {
     356              :   gint64 val;
     357              :   gint length, i;
     358           18 :   const gchar *param = g_value_get_string (value);
     359           18 :   gchar **strv = g_strsplit_set (param, ",", -1);
     360           18 :   GValue tmp = G_VALUE_INIT;
     361              : 
     362           18 :   length = g_strv_length (strv);
     363              : 
     364           18 :   if (length > 2) {
     365            0 :     ml_loge
     366              :         ("Invalid compared value option. It should be in the form of 'IDX_DIM0: ... :INDEX_DIM_LAST,nth-tensor'(A_VALUE) or 'nth-tensor' (TENSOR_AVERAGE_VALUE)");
     367            0 :     g_strfreev (strv);
     368            0 :     return;
     369              :   }
     370              : 
     371           18 :   g_value_init (&tmp, G_TYPE_STRING);
     372           18 :   g_value_set_string (&tmp, strv[0]);
     373              : 
     374           18 :   gst_tensor_if_set_property_glist (&tmp, prop_list, ":");
     375              : 
     376              :   /* A_VALUE */
     377           18 :   if (length == 2) {
     378            8 :     length = g_list_length (*prop_list);
     379              : 
     380              :     /* append zero value for undefined dimensions */
     381          109 :     for (i = length; i < NNS_TENSOR_RANK_LIMIT; i++) {
     382          101 :       *prop_list = g_list_append (*prop_list, GINT_TO_POINTER (0));
     383              :     }
     384              : 
     385            8 :     val = g_ascii_strtoll (strv[1], NULL, 10);
     386            8 :     if (errno == ERANGE) {
     387            0 :       ml_loge ("Overflow occurred during converting %s to a gint64 value",
     388              :           strv[1]);
     389              :     }
     390            8 :     *prop_list = g_list_append (*prop_list, GINT_TO_POINTER (val));
     391              :   }
     392           18 :   g_strfreev (strv);
     393           18 :   g_value_reset (&tmp);
     394              : }
     395              : 
     396              : /**
     397              :  * @brief Convert GValue to GList according to delimiters
     398              :  */
     399              : static void
     400           19 : gst_tensor_if_set_property_supplied_value (const GValue * value,
     401              :     tensor_if_sv_s * sv, const gchar * delimiters)
     402              : {
     403              :   gint i;
     404           19 :   gboolean is_float = FALSE;
     405           19 :   const gchar *param = g_value_get_string (value);
     406           19 :   gchar **strv = g_strsplit_set (param, delimiters, -1);
     407           19 :   gint num = g_strv_length (strv);
     408              : 
     409           19 :   if (!param) {
     410            0 :     ml_loge ("Invalid supplied value. The value is NULL.");
     411            0 :     return;
     412              :   }
     413              : 
     414           19 :   if (strchr (param, '.') || strchr (param, 'E') || strchr (param, 'e')) {
     415            2 :     is_float = TRUE;
     416              :   }
     417              : 
     418           19 :   sv->num = num;
     419           40 :   for (i = 0; i < num; i++) {
     420           21 :     if (is_float) {
     421            2 :       sv->type = _NNS_FLOAT64;
     422            2 :       sv->data[i]._double = g_ascii_strtod (strv[i], NULL);
     423              :     } else {
     424           19 :       sv->type = _NNS_INT64;
     425           19 :       sv->data[i]._int64_t = g_ascii_strtoll (strv[i], NULL, 10);
     426              :     }
     427              :   }
     428           19 :   g_strfreev (strv);
     429              : }
     430              : 
     431              : /**
     432              :  * @brief Set custom compared value property
     433              :  */
     434              : static void
     435           36 : gst_tensor_if_configure_custom_prop (GstTensorIf * self)
     436              : {
     437           36 :   if (!self->custom.name)
     438           16 :     return;
     439              : 
     440           20 :   if (self->cv == TIFCV_CUSTOM) {
     441            2 :     const custom_cb_s *ptr = get_subplugin (NNS_IF_CUSTOM, self->custom.name);
     442            2 :     if (!ptr) {
     443            1 :       nns_logw ("Failed to find custom subplugin of the tensor_if");
     444            1 :       return;
     445              :     }
     446            1 :     self->custom_configured = TRUE;
     447            1 :     self->custom.func = (*ptr).func;
     448            1 :     self->custom.data = (*ptr).data;
     449              :   }
     450              : }
     451              : 
     452              : /**
     453              :  * @brief Setter for tensor_if properties.
     454              :  */
     455              : static void
     456          130 : gst_tensor_if_set_property (GObject * object, guint prop_id,
     457              :     const GValue * value, GParamSpec * pspec)
     458              : {
     459          130 :   GstTensorIf *self = GST_TENSOR_IF (object);
     460              : 
     461          130 :   switch (prop_id) {
     462           18 :     case PROP_CV:
     463           18 :       self->cv = g_value_get_enum (value);
     464           18 :       gst_tensor_if_configure_custom_prop (self);
     465           18 :       break;
     466           18 :     case PROP_CV_OPTION:
     467           18 :       g_free (self->custom.name);
     468           18 :       self->custom.name = g_value_dup_string (value);
     469           18 :       gst_tensor_if_configure_custom_prop (self);
     470           18 :       gst_tensor_if_set_property_cv_option (value, &self->cv_option);
     471           18 :       break;
     472           18 :     case PROP_OP:
     473           18 :       self->op = g_value_get_enum (value);
     474           18 :       break;
     475           19 :     case PROP_SV:
     476           19 :       gst_tensor_if_set_property_supplied_value (value, self->sv, ",");
     477           19 :       break;
     478           18 :     case PROP_THEN:
     479           18 :       self->act_then = g_value_get_enum (value);
     480           18 :       break;
     481            9 :     case PROP_THEN_OPTION:
     482            9 :       gst_tensor_if_set_property_glist (value, &self->then_option, ",");
     483            9 :       break;
     484           18 :     case PROP_ELSE:
     485           18 :       self->act_else = g_value_get_enum (value);
     486           18 :       break;
     487            9 :     case PROP_ELSE_OPTION:
     488            9 :       gst_tensor_if_set_property_glist (value, &self->else_option, ",");
     489            9 :       break;
     490            3 :     case PROP_SILENT:
     491            3 :       self->silent = g_value_get_boolean (value);
     492            3 :       break;
     493            0 :     default:
     494            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     495            0 :       break;
     496              :   }
     497          130 : }
     498              : 
     499              : /**
     500              :  * @brief Convert GList to GValue
     501              :  */
     502              : static void
     503            4 : gst_tensor_if_property_to_string (GValue * value, GList * prop_list,
     504              :     guint prop_id)
     505              : {
     506              :   GList *list;
     507              :   gchar *p;
     508              :   GPtrArray *arr;
     509              :   gchar **strings;
     510              :   guint len;
     511              : 
     512            4 :   if (prop_list == NULL) {
     513            0 :     g_value_set_string (value, "");
     514            0 :     return;
     515              :   }
     516              : 
     517            4 :   arr = g_ptr_array_new ();
     518           24 :   for (list = prop_list; list != NULL; list = list->next) {
     519           20 :     g_ptr_array_add (arr, g_strdup_printf ("%i", GPOINTER_TO_INT (list->data)));
     520              :   }
     521            4 :   g_ptr_array_add (arr, NULL);
     522              : 
     523            4 :   len = arr->len;
     524              : 
     525            5 :   if (prop_id == PROP_CV_OPTION && len % (NNS_TENSOR_RANK_LIMIT + 2) == 0) {
     526              :     gchar *dim;
     527            1 :     gchar *tensor = (gchar *) g_ptr_array_index (arr, len - 2);
     528            1 :     g_ptr_array_remove_index (arr, len - 2);
     529            1 :     strings = (gchar **) g_ptr_array_free (arr, FALSE);
     530            1 :     dim = g_strjoinv (":", strings);
     531            1 :     p = g_strjoin (",", dim, tensor, NULL);
     532            1 :     g_free (dim);
     533            1 :     g_free (tensor);
     534              :   } else {
     535            3 :     strings = (gchar **) g_ptr_array_free (arr, FALSE);
     536            3 :     p = g_strjoinv (",", strings);
     537              :   }
     538              : 
     539            4 :   g_strfreev (strings);
     540            4 :   g_value_take_string (value, p);
     541              : }
     542              : 
     543              : /**
     544              :  * @brief Convert GValue to supplied value according to delimiters
     545              :  */
     546              : static void
     547            3 : gst_tensor_if_get_property_supplied_value (GValue * value, tensor_if_sv_s * sv)
     548              : {
     549              :   guint i;
     550              :   gchar *p;
     551              :   GPtrArray *arr;
     552              :   gchar **strings;
     553              : 
     554            3 :   if (sv == NULL || sv->num == 0) {
     555            0 :     g_value_set_string (value, "");
     556            0 :     return;
     557              :   }
     558              : 
     559            3 :   arr = g_ptr_array_new ();
     560            7 :   for (i = 0; i < sv->num; i++) {
     561            4 :     if (sv->type == _NNS_FLOAT64) {
     562            1 :       g_ptr_array_add (arr, g_strdup_printf ("%lf", sv->data[i]._double));
     563              :     } else {
     564            3 :       g_ptr_array_add (arr, g_strdup_printf ("%ld",
     565            3 :               (long int) sv->data[i]._int64_t));
     566              :     }
     567              :   }
     568            3 :   g_ptr_array_add (arr, NULL);
     569            3 :   strings = (gchar **) g_ptr_array_free (arr, FALSE);
     570            3 :   p = g_strjoinv (",", strings);
     571            3 :   g_strfreev (strings);
     572            3 :   g_value_take_string (value, p);
     573              : }
     574              : 
     575              : /**
     576              :  * @brief Getter for tensor_if properties.
     577              :  */
     578              : static void
     579           19 : gst_tensor_if_get_property (GObject * object, guint prop_id,
     580              :     GValue * value, GParamSpec * pspec)
     581              : {
     582           19 :   GstTensorIf *self = GST_TENSOR_IF (object);
     583              : 
     584           19 :   switch (prop_id) {
     585            3 :     case PROP_CV:
     586            3 :       g_value_set_enum (value, self->cv);
     587            3 :       break;
     588            4 :     case PROP_CV_OPTION:
     589            4 :       if (self->cv == TIFCV_CUSTOM) {
     590            2 :         g_value_set_string (value, self->custom.name ? self->custom.name : "");
     591              :       } else {
     592            2 :         gst_tensor_if_property_to_string (value, self->cv_option, prop_id);
     593              :       }
     594            4 :       break;
     595            2 :     case PROP_OP:
     596            2 :       g_value_set_enum (value, self->op);
     597            2 :       break;
     598            3 :     case PROP_SV:
     599            3 :       gst_tensor_if_get_property_supplied_value (value, self->sv);
     600            3 :       break;
     601            2 :     case PROP_THEN:
     602            2 :       g_value_set_enum (value, self->act_then);
     603            2 :       break;
     604            1 :     case PROP_THEN_OPTION:
     605            1 :       gst_tensor_if_property_to_string (value, self->then_option, prop_id);
     606            1 :       break;
     607            2 :     case PROP_ELSE:
     608            2 :       g_value_set_enum (value, self->act_else);
     609            2 :       break;
     610            1 :     case PROP_ELSE_OPTION:
     611            1 :       gst_tensor_if_property_to_string (value, self->else_option, prop_id);
     612            1 :       break;
     613            1 :     case PROP_SILENT:
     614            1 :       g_value_set_boolean (value, self->silent);
     615            1 :       break;
     616            0 :     default:
     617            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     618            0 :       break;
     619              :   }
     620           19 : }
     621              : 
     622              : /**
     623              :  * @brief Installs all the properties for tensor_if
     624              :  * @param[in] gobject_class Glib object class whose properties will be set
     625              :  */
     626              : static void
     627           14 : gst_tensor_if_install_properties (GObjectClass * gobject_class)
     628              : {
     629           14 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     630              :       g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
     631              :           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     632              : 
     633           14 :   g_object_class_install_property (gobject_class, PROP_CV,
     634              :       g_param_spec_enum ("compared-value", "CV",
     635              :           "Compared value from input tensor(s)", GST_TYPE_TENSOR_IF_CV,
     636              :           TIFCV_A_VALUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     637              : 
     638           14 :   g_object_class_install_property (gobject_class, PROP_CV_OPTION,
     639              :       g_param_spec_string ("compared-value-option", "CV_OPTION",
     640              :           "Specify an element of the nth tensor or pick tensor ", "",
     641              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     642              : 
     643           14 :   g_object_class_install_property (gobject_class, PROP_SV,
     644              :       g_param_spec_string ("supplied-value", "SV",
     645              :           " Supplied Value by user ", "",
     646              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     647              : 
     648           14 :   g_object_class_install_property (gobject_class, PROP_OP,
     649              :       g_param_spec_enum ("operator", "OP", "Comparison Operator",
     650              :           GST_TYPE_TENSOR_IF_OP, TIFOP_EQ,
     651              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     652              : 
     653           14 :   g_object_class_install_property (gobject_class, PROP_THEN,
     654              :       g_param_spec_enum ("then", "THEN", "Action if it is TRUE",
     655              :           GST_TYPE_TENSOR_IF_ACT, TIFB_PASSTHROUGH,
     656              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     657              : 
     658           14 :   g_object_class_install_property (gobject_class, PROP_THEN_OPTION,
     659              :       g_param_spec_string ("then-option", "THEN_OPTION",
     660              :           "Pick tensor ", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     661              : 
     662           14 :   g_object_class_install_property (gobject_class, PROP_ELSE,
     663              :       g_param_spec_enum ("else", "ELSE", "Action if it is FALSE",
     664              :           GST_TYPE_TENSOR_IF_ACT, TIFB_SKIP,
     665              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     666              : 
     667           14 :   g_object_class_install_property (gobject_class, PROP_ELSE_OPTION,
     668              :       g_param_spec_string ("else-option", "ELSE_OPTION",
     669              :           "Pick tensor ", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     670           14 : }
     671              : 
     672              : /**
     673              :  * @brief event function for sink (gst element vmethod)
     674              :  */
     675              : static gboolean
     676           97 : gst_tensor_if_event (GstPad * pad, GstObject * parent, GstEvent * event)
     677              : {
     678              :   GstTensorIf *tensor_if;
     679           97 :   tensor_if = GST_TENSOR_IF (parent);
     680              : 
     681           97 :   switch (GST_EVENT_TYPE (event)) {
     682           25 :     case GST_EVENT_CAPS:
     683              :     {
     684              :       GstCaps *caps;
     685              : 
     686           25 :       gst_event_parse_caps (event, &caps);
     687           25 :       if (!gst_tensors_config_from_caps (&tensor_if->in_config, caps, TRUE)) {
     688            0 :         GST_ERROR_OBJECT (tensor_if, "Failed to parse caps.\n");
     689            0 :         gst_event_unref (event);
     690            0 :         return FALSE;
     691              :       }
     692           25 :       break;
     693              :     }
     694           72 :     default:
     695           72 :       break;
     696              :   }
     697              : 
     698           97 :   return gst_pad_event_default (pad, parent, event);
     699              : }
     700              : 
     701              : /**
     702              :  * @brief Checking if the source pad is created and if not, create TensorPad
     703              :  * @param tensor_if TensorIf Object
     704              :  * @param config Tensors Config Data
     705              :  * @param nth source ordering
     706              :  * @return TensorPad if pad is already created, then return created pad.
     707              :  *         If not return new pad after creation.
     708              :  */
     709              : static GstTensorPad *
     710           33 : gst_tensor_if_get_tensor_pad (GstTensorIf * tensor_if,
     711              :     GstTensorsConfig * config, gboolean * created, guint nth)
     712              : {
     713              :   GSList *walk;
     714              :   GstPad *pad;
     715              :   GstTensorPad *tensorpad;
     716              :   gchar *name;
     717           33 :   GstCaps *caps = NULL;
     718              : 
     719           33 :   walk = tensor_if->srcpads;
     720           41 :   while (walk) {
     721           26 :     GstTensorPad *pad = (GstTensorPad *) walk->data;
     722           26 :     if (nth == pad->nth) {
     723           18 :       if (created) {
     724           18 :         *created = FALSE;
     725              :       }
     726           18 :       return pad;
     727              :     }
     728            8 :     walk = walk->next;
     729              :   }
     730              : 
     731           15 :   tensorpad = g_new0 (GstTensorPad, 1);
     732           15 :   g_assert (tensorpad != NULL);
     733           15 :   GST_DEBUG_OBJECT (tensor_if, "creating pad: %d(%dth)",
     734              :       tensor_if->num_srcpads, nth);
     735              : 
     736           15 :   name = g_strdup_printf ("src_%d", nth);
     737           15 :   pad = gst_pad_new_from_static_template (&src_factory, name);
     738           15 :   g_free (name);
     739              : 
     740           15 :   tensorpad->pad = pad;
     741           15 :   tensorpad->nth = nth;
     742           15 :   tensorpad->last_ret = GST_FLOW_OK;
     743           15 :   tensorpad->last_ts = GST_CLOCK_TIME_NONE;
     744              : 
     745           15 :   tensor_if->srcpads = g_slist_append (tensor_if->srcpads, tensorpad);
     746           15 :   tensor_if->num_srcpads++;
     747              : 
     748           15 :   gst_pad_use_fixed_caps (pad);
     749           15 :   gst_pad_set_active (pad, TRUE);
     750           15 :   gst_element_add_pad (GST_ELEMENT_CAST (tensor_if), pad);
     751              : 
     752           15 :   caps = gst_tensor_pad_caps_from_config (pad, config);
     753              : 
     754           15 :   silent_debug_caps (tensor_if, caps, "out caps");
     755           15 :   gst_pad_set_caps (pad, caps);
     756              : 
     757           15 :   gst_caps_unref (caps);
     758              : 
     759           15 :   if (created) {
     760           15 :     *created = TRUE;
     761              :   }
     762              : 
     763           15 :   return tensorpad;
     764              : }
     765              : 
     766              : /**
     767              :  * @brief Check the status among sources in if
     768              :  * @param tensor_if TensorIf Object
     769              :  * @param TensorPad Tensorpad
     770              :  * @param ret return status of current pad
     771              :  * @return return status after check sources
     772              :  */
     773              : static GstFlowReturn
     774           33 : gst_tensor_if_combine_flows (GstTensorIf * tensor_if,
     775              :     GstTensorPad * pad, GstFlowReturn ret)
     776              : {
     777              :   GSList *walk;
     778           33 :   pad->last_ret = ret;
     779              : 
     780           33 :   if (ret != GST_FLOW_NOT_LINKED)
     781           33 :     goto done;
     782              : 
     783            0 :   for (walk = tensor_if->srcpads; walk; walk = g_slist_next (walk)) {
     784            0 :     GstTensorPad *opad = (GstTensorPad *) walk->data;
     785            0 :     ret = opad->last_ret;
     786            0 :     if (ret != GST_FLOW_NOT_LINKED)
     787            0 :       goto done;
     788              :   }
     789            0 : done:
     790           33 :   return ret;
     791              : }
     792              : 
     793              : /**
     794              :  * @brief Macro for operator function.
     795              :  */
     796              : #define operator_func(cv,t,op,sv1,sv2,ret) do { \
     797              :   switch (op) { \
     798              :     case TIFOP_EQ: ret = (cv._##t == sv1._##t) ? TRUE : FALSE; break; \
     799              :     case TIFOP_NE: ret = (cv._##t != sv1._##t) ? TRUE : FALSE; break; \
     800              :     case TIFOP_GT: ret = (cv._##t > sv1._##t) ? TRUE : FALSE; break; \
     801              :     case TIFOP_GE: ret = (cv._##t >= sv1._##t) ? TRUE : FALSE; break; \
     802              :     case TIFOP_LT: ret = (cv._##t < sv1._##t) ? TRUE : FALSE; break; \
     803              :     case TIFOP_LE: ret = (cv._##t <= sv1._##t) ? TRUE : FALSE; break; \
     804              :     case TIFOP_RANGE_INCLUSIVE: \
     805              :       ret = (sv1._##t <= cv._##t && cv._##t <= sv2._##t) ? TRUE : FALSE; break; \
     806              :     case TIFOP_RANGE_EXCLUSIVE: \
     807              :       ret = (sv1._##t < cv._##t && cv._##t < sv2._##t) ? TRUE : FALSE; break; \
     808              :     case TIFOP_NOT_IN_RANGE_INCLUSIVE: \
     809              :       ret = (cv._##t < sv1._##t && sv2._##t < cv._##t) ? TRUE : FALSE; break; \
     810              :     case TIFOP_NOT_IN_RANGE_EXCLUSIVE: \
     811              :       ret = (cv._##t <= sv1._##t && sv2._##t <= cv._##t) ? TRUE : FALSE; break; \
     812              :     default: break; \
     813              :   } \
     814              : } while (0)
     815              : 
     816              : /**
     817              :  * @brief Get comparison value
     818              :  */
     819              : static gboolean
     820           34 : gst_tensor_if_get_comparison_result (GstTensorIf * tensor_if,
     821              :     tensor_data_s * cv, gboolean * result)
     822              : {
     823           34 :   gboolean ret = FALSE;
     824              :   tensor_data_s svtc_1, svtc_2;
     825              : 
     826           34 :   svtc_1.type = tensor_if->sv->type;
     827           34 :   svtc_1.data = tensor_if->sv->data[0];
     828           34 :   gst_tensor_data_typecast (&svtc_1, cv->type);
     829              : 
     830           34 :   svtc_2.type = tensor_if->sv->type;
     831           34 :   svtc_2.data = tensor_if->sv->data[1];
     832           34 :   gst_tensor_data_typecast (&svtc_2, cv->type);
     833              : 
     834           34 :   switch (cv->type) {
     835            5 :     case _NNS_INT32:
     836            5 :       operator_func (cv->data, int32_t, tensor_if->op, svtc_1.data, svtc_2.data,
     837              :           ret);
     838            5 :       break;
     839            1 :     case _NNS_UINT32:
     840            1 :       operator_func (cv->data, uint32_t, tensor_if->op, svtc_1.data,
     841              :           svtc_2.data, ret);
     842            1 :       break;
     843            1 :     case _NNS_INT16:
     844            1 :       operator_func (cv->data, int16_t, tensor_if->op, svtc_1.data, svtc_2.data,
     845              :           ret);
     846            1 :       break;
     847            1 :     case _NNS_UINT16:
     848            1 :       operator_func (cv->data, uint16_t, tensor_if->op, svtc_1.data,
     849              :           svtc_2.data, ret);
     850            1 :       break;
     851            1 :     case _NNS_INT8:
     852            1 :       operator_func (cv->data, int8_t, tensor_if->op, svtc_1.data, svtc_2.data,
     853              :           ret);
     854            1 :       break;
     855           21 :     case _NNS_UINT8:
     856           21 :       operator_func (cv->data, uint8_t, tensor_if->op, svtc_1.data, svtc_2.data,
     857              :           ret);
     858           21 :       break;
     859            1 :     case _NNS_FLOAT64:
     860            1 :       operator_func (cv->data, double, tensor_if->op, svtc_1.data, svtc_2.data,
     861              :           ret);
     862            1 :       break;
     863            1 :     case _NNS_FLOAT32:
     864            1 :       operator_func (cv->data, float, tensor_if->op, svtc_1.data, svtc_2.data,
     865              :           ret);
     866            1 :       break;
     867            1 :     case _NNS_INT64:
     868            1 :       operator_func (cv->data, int64_t, tensor_if->op, svtc_1.data, svtc_2.data,
     869              :           ret);
     870            1 :       break;
     871            1 :     case _NNS_UINT64:
     872            1 :       operator_func (cv->data, uint64_t, tensor_if->op, svtc_1.data,
     873              :           svtc_2.data, ret);
     874            1 :       break;
     875            0 :     default:
     876            0 :       GST_ERROR_OBJECT (tensor_if, "Unknown tensor type %d", cv->type);
     877           34 :       return FALSE;
     878              :   }
     879           34 :   *result = ret;
     880           34 :   return TRUE;
     881              : }
     882              : 
     883              : /**
     884              :  * @brief Calculate average value of the nth tensor
     885              :  */
     886              : static gboolean
     887           18 : gst_tensor_if_get_tensor_average (GstTensorIf * tensor_if,
     888              :     GstBuffer * buf, tensor_data_s * cv, guint nth)
     889              : {
     890              :   GstTensorInfo *_info;
     891              :   GstMemory *in_mem;
     892              :   GstMapInfo in_info;
     893           18 :   gdouble *avg = NULL;
     894              :   tensor_type type;
     895              : 
     896           18 :   in_mem = gst_tensor_buffer_get_nth_memory (buf, nth);
     897           18 :   if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
     898            0 :     GST_WARNING_OBJECT (tensor_if, "Failed to map the input buffer.");
     899            0 :     gst_memory_unref (in_mem);
     900           18 :     return FALSE;
     901              :   }
     902              : 
     903           18 :   _info = gst_tensors_info_get_nth_info (&tensor_if->in_config.info, nth);
     904           18 :   type = _info->type;
     905              : 
     906           18 :   gst_tensor_data_raw_average (in_info.data, in_info.size, type, &avg);
     907              : 
     908           18 :   gst_memory_unmap (in_mem, &in_info);
     909           18 :   gst_memory_unref (in_mem);
     910              : 
     911           18 :   gst_tensor_data_set (cv, _NNS_FLOAT64, avg);
     912           18 :   gst_tensor_data_typecast (cv, type);
     913              : 
     914           18 :   g_free (avg);
     915           18 :   return TRUE;
     916              : }
     917              : 
     918              : /**
     919              :  * @brief Calculate compared value
     920              :  */
     921              : static gboolean
     922           38 : gst_tensor_if_calculate_cv (GstTensorIf * tensor_if, GstBuffer * buf,
     923              :     tensor_data_s * cv)
     924              : {
     925              :   GstTensorInfo *_info;
     926              : 
     927           38 :   switch (tensor_if->cv) {
     928           18 :     case TIFCV_A_VALUE:
     929              :     {
     930              :       GstMemory *in_mem;
     931              :       GstMapInfo in_info;
     932              :       GList *list;
     933           18 :       uint32_t idx = 0, nth, i, offset = 1;
     934              :       tensor_dim target;
     935              :       const uint32_t *in_dim;
     936              :       tensor_type in_type;
     937              : 
     938           18 :       if (g_list_length (tensor_if->cv_option) != NNS_TENSOR_RANK_LIMIT + 1) {
     939            1 :         GST_ERROR_OBJECT (tensor_if,
     940              :             "Please specify a proper 'compared-value-option' property, e.g., 0:1:2:3,0");
     941            2 :         return FALSE;
     942              :       }
     943          289 :       for (list = tensor_if->cv_option; list->next != NULL; list = list->next) {
     944          272 :         target[idx++] = GPOINTER_TO_INT (list->data);
     945              :       }
     946              : 
     947           17 :       nth = GPOINTER_TO_INT (list->data);
     948           17 :       if (gst_tensor_buffer_get_count (buf) <= nth) {
     949            1 :         GST_ERROR_OBJECT (tensor_if, "Index should be lower than buffer size");
     950            1 :         return FALSE;
     951              :       }
     952              : 
     953           16 :       _info = gst_tensors_info_get_nth_info (&tensor_if->in_config.info, nth);
     954           16 :       in_type = _info->type;
     955           16 :       in_dim = _info->dimension;
     956              : 
     957           16 :       in_mem = gst_tensor_buffer_get_nth_memory (buf, nth);
     958           16 :       if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
     959            0 :         GST_WARNING_OBJECT (tensor_if, "Failed to map the input buffer.");
     960            0 :         gst_memory_unref (in_mem);
     961            0 :         return FALSE;
     962              :       }
     963              : 
     964              :       /* Find data index for mem access */
     965           16 :       idx = target[0];
     966          256 :       for (i = 1; i < NNS_TENSOR_RANK_LIMIT; i++) {
     967          240 :         offset *= in_dim[i - 1];
     968          240 :         idx += (target[i]) * offset;
     969              :       }
     970              : 
     971           16 :       idx *= gst_tensor_get_element_size (in_type);
     972              : 
     973           16 :       gst_tensor_data_set (cv, in_type, in_info.data + idx);
     974           16 :       gst_memory_unmap (in_mem, &in_info);
     975           16 :       gst_memory_unref (in_mem);
     976           16 :       break;
     977              :     }
     978           20 :     case TIFCV_TENSOR_AVERAGE_VALUE:
     979              :     {
     980              :       uint32_t nth;
     981           20 :       if (g_list_length (tensor_if->cv_option) != 1) {
     982            1 :         GST_ERROR_OBJECT (tensor_if,
     983              :             "Please specify a proper 'compared-value-option' property, For TENSOR_AVERAGE_VALUE, specify only one tensor. Tensors is not supported.");
     984            1 :         return FALSE;
     985              :       }
     986           19 :       nth = GPOINTER_TO_INT (tensor_if->cv_option->data);
     987           19 :       if (gst_tensor_buffer_get_count (buf) <= nth) {
     988            1 :         GST_ERROR_OBJECT (tensor_if, "Index should be lower than buffer size");
     989            1 :         return FALSE;
     990              :       }
     991           18 :       return gst_tensor_if_get_tensor_average (tensor_if, buf, cv, nth);
     992              :     }
     993            0 :     default:
     994            0 :       GST_ERROR_OBJECT (tensor_if,
     995              :           "Compared value is not supported yet or not defined");
     996            0 :       return FALSE;
     997              :   }
     998           16 :   return TRUE;
     999              : }
    1000              : 
    1001              : /**
    1002              :  * @brief Registers a callback for tensor_if custom condition
    1003              :  * @return 0 if success. -ERRNO if error.
    1004              :  */
    1005              : int
    1006            5 : nnstreamer_if_custom_register (const gchar * name, tensor_if_custom func,
    1007              :     void *data)
    1008              : {
    1009              :   custom_cb_s *ptr;
    1010              : 
    1011            5 :   g_return_val_if_fail (name && strlen (name), -EINVAL);
    1012            4 :   g_return_val_if_fail (func, -EINVAL);
    1013              : 
    1014            3 :   if (!(ptr = g_try_new0 (custom_cb_s, 1)))
    1015            0 :     return -ENOMEM;
    1016              : 
    1017            3 :   ptr->func = func;
    1018            3 :   ptr->data = data;
    1019              : 
    1020            3 :   if (register_subplugin (NNS_IF_CUSTOM, name, ptr))
    1021            2 :     return 0;
    1022              : 
    1023            1 :   g_free (ptr);
    1024            1 :   return -EINVAL;
    1025              : }
    1026              : 
    1027              : /**
    1028              :  * @brief Unregisters a callback for tensor_if custom condition
    1029              :  * @return 0 if success. -ERRNO if error.
    1030              :  */
    1031              : int
    1032            4 : nnstreamer_if_custom_unregister (const gchar * name)
    1033              : {
    1034              :   custom_cb_s *ptr;
    1035              : 
    1036            4 :   ptr = (custom_cb_s *) get_subplugin (NNS_IF_CUSTOM, name);
    1037            4 :   if (!unregister_subplugin (NNS_IF_CUSTOM, name)) {
    1038            2 :     ml_loge ("Failed to unregister custom callback %s.", name);
    1039            2 :     return -EINVAL;
    1040              :   }
    1041            2 :   g_free (ptr);
    1042              : 
    1043            2 :   return 0;
    1044              : }
    1045              : 
    1046              : /**
    1047              :  * @brief Determining whether a given condition is true or false
    1048              :  * @param tensor_if TensorIf Object
    1049              :  * @param buf gstbuffer from sink pad
    1050              :  * @return return TRUE if no error
    1051              :  */
    1052              : static gboolean
    1053           40 : gst_tensor_if_check_condition (GstTensorIf * tensor_if, GstBuffer * buf,
    1054              :     gboolean * result)
    1055              : {
    1056           40 :   gboolean ret = FALSE;
    1057              : 
    1058           40 :   if (tensor_if->cv == TIFCV_CUSTOM) {
    1059              :     GstMemory *in_mem[NNS_TENSOR_SIZE_LIMIT];
    1060              :     GstMapInfo in_info[NNS_TENSOR_SIZE_LIMIT];
    1061              :     GstTensorMemory in_tensors[NNS_TENSOR_SIZE_LIMIT];
    1062              :     guint i, j;
    1063              : 
    1064            2 :     if (!tensor_if->custom_configured) {
    1065            0 :       nns_loge ("custom condition of the tensor_if is not configured.");
    1066            0 :       return FALSE;
    1067              :     }
    1068              : 
    1069            6 :     for (i = 0; i < tensor_if->in_config.info.num_tensors; i++) {
    1070            4 :       in_mem[i] = gst_tensor_buffer_get_nth_memory (buf, i);
    1071            4 :       if (!gst_memory_map (in_mem[i], &in_info[i], GST_MAP_READ)) {
    1072            0 :         for (j = 0; j < i; j++) {
    1073            0 :           gst_memory_unmap (in_mem[j], &in_info[j]);
    1074            0 :           gst_memory_unref (in_mem[j]);
    1075              :         }
    1076            0 :         gst_memory_unref (in_mem[i]);
    1077              : 
    1078            0 :         GST_WARNING_OBJECT (tensor_if, "Cannot map input buffer(%d)\n", i);
    1079            0 :         return FALSE;
    1080              :       }
    1081            4 :       in_tensors[i].data = in_info[i].data;
    1082            4 :       in_tensors[i].size = in_info[i].size;
    1083              :     }
    1084              : 
    1085            2 :     ret = tensor_if->custom.func (&tensor_if->in_config.info, in_tensors,
    1086              :         tensor_if->custom.data, result);
    1087              : 
    1088            6 :     for (i = 0; i < tensor_if->in_config.info.num_tensors; i++) {
    1089            4 :       gst_memory_unmap (in_mem[i], &in_info[i]);
    1090            4 :       gst_memory_unref (in_mem[i]);
    1091              :     }
    1092              :   } else {
    1093           38 :     tensor_data_s cv = {.type = _NNS_END,.data._uint8_t = 0 };
    1094           38 :     if (!gst_tensor_if_calculate_cv (tensor_if, buf, &cv)) {
    1095            4 :       GST_ERROR_OBJECT (tensor_if, " failed to calculate compared value");
    1096            4 :       return FALSE;
    1097              :     }
    1098           34 :     ret = gst_tensor_if_get_comparison_result (tensor_if, &cv, result);
    1099              :   }
    1100              : 
    1101           36 :   return ret;
    1102              : }
    1103              : 
    1104              : /**
    1105              :  * @brief chain function for sink (gst element vmethod)
    1106              :  */
    1107              : static GstFlowReturn
    1108           40 : gst_tensor_if_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
    1109              : {
    1110              :   guint num_tensors, i;
    1111           40 :   GstFlowReturn res = GST_FLOW_OK;
    1112           40 :   GstTensorIf *tensor_if = GST_TENSOR_IF (parent);
    1113           40 :   gboolean condition_result = FALSE;
    1114           40 :   tensor_if_behavior curr_act = TIFB_PASSTHROUGH;
    1115           40 :   tensor_if_srcpads which_srcpad = TIFSP_THEN_PAD;
    1116           40 :   GList *curr_act_option = NULL;
    1117              :   GstTensorsConfig *config;
    1118              :   GstTensorPad *srcpad;
    1119           40 :   GstBuffer *outbuf = NULL;
    1120           40 :   GstMemory *mem = NULL;
    1121              :   gboolean created;
    1122              :   GstClockTime ts;
    1123              :   UNUSED (pad);
    1124              : 
    1125           40 :   num_tensors = tensor_if->in_config.info.num_tensors;
    1126           40 :   GST_DEBUG_OBJECT (tensor_if, " Number of Tensors: %u", num_tensors);
    1127              :   /* supposed n memory blocks in buffer */
    1128           40 :   g_assert (gst_tensor_buffer_get_count (buf) == num_tensors);
    1129              : 
    1130           40 :   if (!gst_tensor_if_check_condition (tensor_if, buf, &condition_result)) {
    1131            4 :     GST_ERROR_OBJECT (tensor_if, " Failed to check condition");
    1132           40 :     return GST_FLOW_ERROR;
    1133              :   }
    1134              : 
    1135           36 :   if (condition_result) {
    1136           25 :     curr_act = tensor_if->act_then;
    1137           25 :     curr_act_option = tensor_if->then_option;
    1138           25 :     which_srcpad = TIFSP_THEN_PAD;
    1139              :   } else {
    1140           11 :     curr_act = tensor_if->act_else;
    1141           11 :     curr_act_option = tensor_if->else_option;
    1142           11 :     which_srcpad = TIFSP_ELSE_PAD;
    1143              :   }
    1144              : 
    1145           36 :   config = &tensor_if->out_config[which_srcpad];
    1146              : 
    1147           36 :   if (config->info.num_tensors == 0) {
    1148           20 :     config->rate_n = tensor_if->in_config.rate_n;
    1149           20 :     config->rate_d = tensor_if->in_config.rate_d;
    1150              :   }
    1151              : 
    1152           36 :   switch (curr_act) {
    1153           13 :     case TIFB_PASSTHROUGH:
    1154           13 :       if (config->info.num_tensors == 0) {
    1155            4 :         gst_tensors_info_copy (&config->info, &tensor_if->in_config.info);
    1156              :       }
    1157           13 :       outbuf = gst_buffer_ref (buf);
    1158              : 
    1159           13 :       break;
    1160           20 :     case TIFB_TENSORPICK:
    1161              :     {
    1162              :       GList *list;
    1163           20 :       gint info_idx = 0;
    1164              :       GstTensorInfo *dest, *src;
    1165              : 
    1166           20 :       outbuf = gst_buffer_new ();
    1167           40 :       for (list = curr_act_option; list != NULL; list = list->next) {
    1168           20 :         i = GPOINTER_TO_INT (list->data);
    1169           20 :         src = gst_tensors_info_get_nth_info (&tensor_if->in_config.info, i);
    1170              : 
    1171           20 :         if (config->info.num_tensors == 0) {
    1172           13 :           dest = gst_tensors_info_get_nth_info (&config->info, info_idx);
    1173           13 :           info_idx++;
    1174              : 
    1175           13 :           gst_tensor_info_copy (dest, src);
    1176              :         }
    1177              : 
    1178           20 :         mem = gst_tensor_buffer_get_nth_memory (buf, i);
    1179           20 :         gst_tensor_buffer_append_memory (outbuf, mem, src);
    1180              :       }
    1181           20 :       config->info.num_tensors = info_idx;
    1182           20 :       break;
    1183              :     }
    1184            3 :     case TIFB_SKIP:
    1185            3 :       goto done;
    1186            0 :     default:
    1187            0 :       GST_DEBUG_OBJECT (tensor_if, " Not defined behavior");
    1188            0 :       break;
    1189              :   }
    1190              : 
    1191              :   srcpad =
    1192           33 :       gst_tensor_if_get_tensor_pad (tensor_if, config, &created, which_srcpad);
    1193              : 
    1194           33 :   if (created) {
    1195              :     GstSegment segment;
    1196           15 :     gst_segment_init (&segment, GST_FORMAT_TIME);
    1197           15 :     gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
    1198              :   }
    1199              : 
    1200           33 :   outbuf = gst_buffer_make_writable (outbuf);
    1201              : 
    1202              :   /* metadata from incoming buffer */
    1203           33 :   gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
    1204              : 
    1205           33 :   ts = GST_BUFFER_TIMESTAMP (buf);
    1206           33 :   if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
    1207           24 :     srcpad->last_ts = ts;
    1208              :   } else {
    1209            9 :     GST_DEBUG_OBJECT (tensor_if, "invalid timestamp %" GST_TIME_FORMAT,
    1210              :         GST_TIME_ARGS (ts));
    1211              :   }
    1212              : 
    1213           33 :   res = gst_pad_push (srcpad->pad, outbuf);
    1214           33 :   res = gst_tensor_if_combine_flows (tensor_if, srcpad, res);
    1215              : 
    1216           36 : done:
    1217           36 :   gst_buffer_unref (buf);
    1218           36 :   return res;
    1219              : }
        

Generated by: LCOV version 2.0-1