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#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 90.8 % 523 475
Test Date: 2025-03-14 05:36:58 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         1167 : 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            4 : gst_tensor_if_cv_get_type (void)
     146              : {
     147              :   static GType mode_type = 0;
     148              : 
     149            4 :   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            4 :     mode_type = g_enum_register_static ("tensor_if_compared_value", mode_types);
     158              :   }
     159              : 
     160            4 :   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            4 : gst_tensor_if_op_get_type (void)
     170              : {
     171              :   static GType mode_type = 0;
     172              : 
     173            4 :   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            4 :     mode_type = g_enum_register_static ("tensor_if_operator", mode_types);
     190              :   }
     191              : 
     192            4 :   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            8 : gst_tensor_if_act_get_type (void)
     202              : {
     203              :   static GType mode_type = 0;
     204              : 
     205            8 :   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            4 :     mode_type = g_enum_register_static ("tensor_if_behavior", mode_types);
     213              :   }
     214              : 
     215            8 :   return mode_type;
     216              : }
     217              : 
     218              : /**
     219              :  * @brief initialize the tensor_if's class (GST Standard)
     220              :  */
     221              : static void
     222            4 : gst_tensor_if_class_init (GstTensorIfClass * klass)
     223              : {
     224              :   GObjectClass *gobject_class;
     225              :   GstElementClass *gstelement_class;
     226              : 
     227            4 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_if_debug, "tensor_if", 0,
     228              :       "Tensor if to control streams based on tensor(s) values");
     229              : 
     230            4 :   gobject_class = (GObjectClass *) klass;
     231            4 :   gstelement_class = (GstElementClass *) klass;
     232              : 
     233            4 :   parent_class = g_type_class_peek_parent (klass);
     234              : 
     235            4 :   gobject_class->set_property = gst_tensor_if_set_property;
     236            4 :   gobject_class->get_property = gst_tensor_if_get_property;
     237            4 :   gobject_class->dispose = gst_tensor_if_dispose;
     238              : 
     239            4 :   gst_tensor_if_install_properties (gobject_class);
     240              : 
     241            4 :   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            4 :   gst_element_class_add_pad_template (gstelement_class,
     248              :       gst_static_pad_template_get (&src_factory));
     249            4 :   gst_element_class_add_pad_template (gstelement_class,
     250              :       gst_static_pad_template_get (&sink_factory));
     251            4 : }
     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            4 : gst_tensor_if_install_properties (GObjectClass * gobject_class)
     628              : {
     629            4 :   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            4 :   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            4 :   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            4 :   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            4 :   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            4 :   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            4 :   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            4 :   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            4 :   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            4 : }
     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           25 :       gst_event_parse_caps (event, &caps);
     686           25 :       if (!gst_tensors_config_from_cap (&tensor_if->in_config, caps)) {
     687            0 :         GST_ERROR_OBJECT (tensor_if, "Failed to parse caps.\n");
     688            0 :         gst_event_unref (event);
     689            0 :         return FALSE;
     690              :       }
     691           25 :       break;
     692              :     }
     693           72 :     default:
     694           72 :       break;
     695              :   }
     696              : 
     697           97 :   return gst_pad_event_default (pad, parent, event);
     698              : }
     699              : 
     700              : /**
     701              :  * @brief Checking if the source pad is created and if not, create TensorPad
     702              :  * @param tensor_if TensorIf Object
     703              :  * @param config Tensors Config Data
     704              :  * @param nth source ordering
     705              :  * @return TensorPad if pad is already created, then return created pad.
     706              :  *         If not return new pad after creation.
     707              :  */
     708              : static GstTensorPad *
     709           33 : gst_tensor_if_get_tensor_pad (GstTensorIf * tensor_if,
     710              :     GstTensorsConfig * config, gboolean * created, guint nth)
     711              : {
     712              :   GSList *walk;
     713              :   GstPad *pad;
     714              :   GstTensorPad *tensorpad;
     715              :   gchar *name;
     716           33 :   GstCaps *caps = NULL;
     717              : 
     718           33 :   walk = tensor_if->srcpads;
     719           41 :   while (walk) {
     720           26 :     GstTensorPad *pad = (GstTensorPad *) walk->data;
     721           26 :     if (nth == pad->nth) {
     722           18 :       if (created) {
     723           18 :         *created = FALSE;
     724              :       }
     725           18 :       return pad;
     726              :     }
     727            8 :     walk = walk->next;
     728              :   }
     729              : 
     730           15 :   tensorpad = g_new0 (GstTensorPad, 1);
     731           15 :   g_assert (tensorpad != NULL);
     732           15 :   GST_DEBUG_OBJECT (tensor_if, "creating pad: %d(%dth)",
     733              :       tensor_if->num_srcpads, nth);
     734              : 
     735           15 :   name = g_strdup_printf ("src_%d", nth);
     736           15 :   pad = gst_pad_new_from_static_template (&src_factory, name);
     737           15 :   g_free (name);
     738              : 
     739           15 :   tensorpad->pad = pad;
     740           15 :   tensorpad->nth = nth;
     741           15 :   tensorpad->last_ret = GST_FLOW_OK;
     742           15 :   tensorpad->last_ts = GST_CLOCK_TIME_NONE;
     743              : 
     744           15 :   tensor_if->srcpads = g_slist_append (tensor_if->srcpads, tensorpad);
     745           15 :   tensor_if->num_srcpads++;
     746              : 
     747           15 :   gst_pad_use_fixed_caps (pad);
     748           15 :   gst_pad_set_active (pad, TRUE);
     749           15 :   gst_element_add_pad (GST_ELEMENT_CAST (tensor_if), pad);
     750              : 
     751           15 :   caps = gst_tensor_pad_caps_from_config (pad, config);
     752              : 
     753           15 :   silent_debug_caps (tensor_if, caps, "out caps");
     754           15 :   gst_pad_set_caps (pad, caps);
     755              : 
     756           15 :   gst_caps_unref (caps);
     757              : 
     758           15 :   if (created) {
     759           15 :     *created = TRUE;
     760              :   }
     761              : 
     762           15 :   return tensorpad;
     763              : }
     764              : 
     765              : /**
     766              :  * @brief Check the status among sources in if
     767              :  * @param tensor_if TensorIf Object
     768              :  * @param TensorPad Tensorpad
     769              :  * @param ret return status of current pad
     770              :  * @return return status after check sources
     771              :  */
     772              : static GstFlowReturn
     773           33 : gst_tensor_if_combine_flows (GstTensorIf * tensor_if,
     774              :     GstTensorPad * pad, GstFlowReturn ret)
     775              : {
     776              :   GSList *walk;
     777           33 :   pad->last_ret = ret;
     778              : 
     779           33 :   if (ret != GST_FLOW_NOT_LINKED)
     780           33 :     goto done;
     781              : 
     782            0 :   for (walk = tensor_if->srcpads; walk; walk = g_slist_next (walk)) {
     783            0 :     GstTensorPad *opad = (GstTensorPad *) walk->data;
     784            0 :     ret = opad->last_ret;
     785            0 :     if (ret != GST_FLOW_NOT_LINKED)
     786            0 :       goto done;
     787              :   }
     788            0 : done:
     789           33 :   return ret;
     790              : }
     791              : 
     792              : /**
     793              :  * @brief Macro for operator function.
     794              :  */
     795              : #define operator_func(cv,t,op,sv1,sv2,ret) do { \
     796              :   switch (op) { \
     797              :     case TIFOP_EQ: ret = (cv._##t == sv1._##t) ? TRUE : FALSE; break; \
     798              :     case TIFOP_NE: ret = (cv._##t != sv1._##t) ? TRUE : FALSE; break; \
     799              :     case TIFOP_GT: ret = (cv._##t > sv1._##t) ? TRUE : FALSE; break; \
     800              :     case TIFOP_GE: ret = (cv._##t >= sv1._##t) ? TRUE : FALSE; break; \
     801              :     case TIFOP_LT: ret = (cv._##t < sv1._##t) ? TRUE : FALSE; break; \
     802              :     case TIFOP_LE: ret = (cv._##t <= sv1._##t) ? TRUE : FALSE; break; \
     803              :     case TIFOP_RANGE_INCLUSIVE: \
     804              :       ret = (sv1._##t <= cv._##t && cv._##t <= sv2._##t) ? TRUE : FALSE; break; \
     805              :     case TIFOP_RANGE_EXCLUSIVE: \
     806              :       ret = (sv1._##t < cv._##t && cv._##t < sv2._##t) ? TRUE : FALSE; break; \
     807              :     case TIFOP_NOT_IN_RANGE_INCLUSIVE: \
     808              :       ret = (cv._##t < sv1._##t && sv2._##t < cv._##t) ? TRUE : FALSE; break; \
     809              :     case TIFOP_NOT_IN_RANGE_EXCLUSIVE: \
     810              :       ret = (cv._##t <= sv1._##t && sv2._##t <= cv._##t) ? TRUE : FALSE; break; \
     811              :     default: break; \
     812              :   } \
     813              : } while (0)
     814              : 
     815              : /**
     816              :  * @brief Get comparison value
     817              :  */
     818              : static gboolean
     819           34 : gst_tensor_if_get_comparison_result (GstTensorIf * tensor_if,
     820              :     tensor_data_s * cv, gboolean * result)
     821              : {
     822           34 :   gboolean ret = FALSE;
     823              :   tensor_data_s svtc_1, svtc_2;
     824              : 
     825           34 :   svtc_1.type = tensor_if->sv->type;
     826           34 :   svtc_1.data = tensor_if->sv->data[0];
     827           34 :   gst_tensor_data_typecast (&svtc_1, cv->type);
     828              : 
     829           34 :   svtc_2.type = tensor_if->sv->type;
     830           34 :   svtc_2.data = tensor_if->sv->data[1];
     831           34 :   gst_tensor_data_typecast (&svtc_2, cv->type);
     832              : 
     833           34 :   switch (cv->type) {
     834            5 :     case _NNS_INT32:
     835            5 :       operator_func (cv->data, int32_t, tensor_if->op, svtc_1.data, svtc_2.data,
     836              :           ret);
     837            5 :       break;
     838            1 :     case _NNS_UINT32:
     839            1 :       operator_func (cv->data, uint32_t, tensor_if->op, svtc_1.data,
     840              :           svtc_2.data, ret);
     841            1 :       break;
     842            1 :     case _NNS_INT16:
     843            1 :       operator_func (cv->data, int16_t, tensor_if->op, svtc_1.data, svtc_2.data,
     844              :           ret);
     845            1 :       break;
     846            1 :     case _NNS_UINT16:
     847            1 :       operator_func (cv->data, uint16_t, tensor_if->op, svtc_1.data,
     848              :           svtc_2.data, ret);
     849            1 :       break;
     850            1 :     case _NNS_INT8:
     851            1 :       operator_func (cv->data, int8_t, tensor_if->op, svtc_1.data, svtc_2.data,
     852              :           ret);
     853            1 :       break;
     854           21 :     case _NNS_UINT8:
     855           21 :       operator_func (cv->data, uint8_t, tensor_if->op, svtc_1.data, svtc_2.data,
     856              :           ret);
     857           21 :       break;
     858            1 :     case _NNS_FLOAT64:
     859            1 :       operator_func (cv->data, double, tensor_if->op, svtc_1.data, svtc_2.data,
     860              :           ret);
     861            1 :       break;
     862            1 :     case _NNS_FLOAT32:
     863            1 :       operator_func (cv->data, float, tensor_if->op, svtc_1.data, svtc_2.data,
     864              :           ret);
     865            1 :       break;
     866            1 :     case _NNS_INT64:
     867            1 :       operator_func (cv->data, int64_t, tensor_if->op, svtc_1.data, svtc_2.data,
     868              :           ret);
     869            1 :       break;
     870            1 :     case _NNS_UINT64:
     871            1 :       operator_func (cv->data, uint64_t, tensor_if->op, svtc_1.data,
     872              :           svtc_2.data, ret);
     873            1 :       break;
     874            0 :     default:
     875            0 :       GST_ERROR_OBJECT (tensor_if, "Unknown tensor type %d", cv->type);
     876           34 :       return FALSE;
     877              :   }
     878           34 :   *result = ret;
     879           34 :   return TRUE;
     880              : }
     881              : 
     882              : /**
     883              :  * @brief Calculate average value of the nth tensor
     884              :  */
     885              : static gboolean
     886           18 : gst_tensor_if_get_tensor_average (GstTensorIf * tensor_if,
     887              :     GstBuffer * buf, tensor_data_s * cv, guint nth)
     888              : {
     889              :   GstTensorInfo *_info;
     890              :   GstMemory *in_mem;
     891              :   GstMapInfo in_info;
     892           18 :   gdouble *avg = NULL;
     893              :   tensor_type type;
     894              : 
     895           18 :   in_mem = gst_tensor_buffer_get_nth_memory (buf, nth);
     896           18 :   if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
     897            0 :     GST_WARNING_OBJECT (tensor_if, "Failed to map the input buffer.");
     898            0 :     gst_memory_unref (in_mem);
     899           18 :     return FALSE;
     900              :   }
     901              : 
     902           18 :   _info = gst_tensors_info_get_nth_info (&tensor_if->in_config.info, nth);
     903           18 :   type = _info->type;
     904              : 
     905           18 :   gst_tensor_data_raw_average (in_info.data, in_info.size, type, &avg);
     906              : 
     907           18 :   gst_memory_unmap (in_mem, &in_info);
     908           18 :   gst_memory_unref (in_mem);
     909              : 
     910           18 :   gst_tensor_data_set (cv, _NNS_FLOAT64, avg);
     911           18 :   gst_tensor_data_typecast (cv, type);
     912              : 
     913           18 :   g_free (avg);
     914           18 :   return TRUE;
     915              : }
     916              : 
     917              : /**
     918              :  * @brief Calculate compared value
     919              :  */
     920              : static gboolean
     921           38 : gst_tensor_if_calculate_cv (GstTensorIf * tensor_if, GstBuffer * buf,
     922              :     tensor_data_s * cv)
     923              : {
     924              :   GstTensorInfo *_info;
     925              : 
     926           38 :   switch (tensor_if->cv) {
     927           18 :     case TIFCV_A_VALUE:
     928              :     {
     929              :       GstMemory *in_mem;
     930              :       GstMapInfo in_info;
     931              :       GList *list;
     932           18 :       uint32_t idx = 0, nth, i, offset = 1;
     933              :       tensor_dim target;
     934              :       const uint32_t *in_dim;
     935              :       tensor_type in_type;
     936              : 
     937           18 :       if (g_list_length (tensor_if->cv_option) != NNS_TENSOR_RANK_LIMIT + 1) {
     938            1 :         GST_ERROR_OBJECT (tensor_if,
     939              :             "Please specify a proper 'compared-value-option' property, e.g., 0:1:2:3,0");
     940            2 :         return FALSE;
     941              :       }
     942          289 :       for (list = tensor_if->cv_option; list->next != NULL; list = list->next) {
     943          272 :         target[idx++] = GPOINTER_TO_INT (list->data);
     944              :       }
     945              : 
     946           17 :       nth = GPOINTER_TO_INT (list->data);
     947           17 :       if (gst_tensor_buffer_get_count (buf) <= nth) {
     948            1 :         GST_ERROR_OBJECT (tensor_if, "Index should be lower than buffer size");
     949            1 :         return FALSE;
     950              :       }
     951              : 
     952           16 :       _info = gst_tensors_info_get_nth_info (&tensor_if->in_config.info, nth);
     953           16 :       in_type = _info->type;
     954           16 :       in_dim = _info->dimension;
     955              : 
     956           16 :       in_mem = gst_tensor_buffer_get_nth_memory (buf, nth);
     957           16 :       if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
     958            0 :         GST_WARNING_OBJECT (tensor_if, "Failed to map the input buffer.");
     959            0 :         gst_memory_unref (in_mem);
     960            0 :         return FALSE;
     961              :       }
     962              : 
     963              :       /* Find data index for mem access */
     964           16 :       idx = target[0];
     965          256 :       for (i = 1; i < NNS_TENSOR_RANK_LIMIT; i++) {
     966          240 :         offset *= in_dim[i - 1];
     967          240 :         idx += (target[i]) * offset;
     968              :       }
     969              : 
     970           16 :       idx *= gst_tensor_get_element_size (in_type);
     971              : 
     972           16 :       gst_tensor_data_set (cv, in_type, in_info.data + idx);
     973           16 :       gst_memory_unmap (in_mem, &in_info);
     974           16 :       gst_memory_unref (in_mem);
     975           16 :       break;
     976              :     }
     977           20 :     case TIFCV_TENSOR_AVERAGE_VALUE:
     978              :     {
     979              :       uint32_t nth;
     980           20 :       if (g_list_length (tensor_if->cv_option) != 1) {
     981            1 :         GST_ERROR_OBJECT (tensor_if,
     982              :             "Please specify a proper 'compared-value-option' property, For TENSOR_AVERAGE_VALUE, specify only one tensor. Tensors is not supported.");
     983            1 :         return FALSE;
     984              :       }
     985           19 :       nth = GPOINTER_TO_INT (tensor_if->cv_option->data);
     986           19 :       if (gst_tensor_buffer_get_count (buf) <= nth) {
     987            1 :         GST_ERROR_OBJECT (tensor_if, "Index should be lower than buffer size");
     988            1 :         return FALSE;
     989              :       }
     990           18 :       return gst_tensor_if_get_tensor_average (tensor_if, buf, cv, nth);
     991              :     }
     992            0 :     default:
     993            0 :       GST_ERROR_OBJECT (tensor_if,
     994              :           "Compared value is not supported yet or not defined");
     995            0 :       return FALSE;
     996              :   }
     997           16 :   return TRUE;
     998              : }
     999              : 
    1000              : /**
    1001              :  * @brief Registers a callback for tensor_if custom condition
    1002              :  * @return 0 if success. -ERRNO if error.
    1003              :  */
    1004              : int
    1005            5 : nnstreamer_if_custom_register (const gchar * name, tensor_if_custom func,
    1006              :     void *data)
    1007              : {
    1008              :   custom_cb_s *ptr;
    1009              : 
    1010            5 :   g_return_val_if_fail (name && strlen (name), -EINVAL);
    1011            4 :   g_return_val_if_fail (func, -EINVAL);
    1012              : 
    1013            3 :   if (!(ptr = g_try_new0 (custom_cb_s, 1)))
    1014            0 :     return -ENOMEM;
    1015              : 
    1016            3 :   ptr->func = func;
    1017            3 :   ptr->data = data;
    1018              : 
    1019            3 :   if (register_subplugin (NNS_IF_CUSTOM, name, ptr))
    1020            2 :     return 0;
    1021              : 
    1022            1 :   g_free (ptr);
    1023            1 :   return -EINVAL;
    1024              : }
    1025              : 
    1026              : /**
    1027              :  * @brief Unregisters a callback for tensor_if custom condition
    1028              :  * @return 0 if success. -ERRNO if error.
    1029              :  */
    1030              : int
    1031            4 : nnstreamer_if_custom_unregister (const gchar * name)
    1032              : {
    1033              :   custom_cb_s *ptr;
    1034              : 
    1035            4 :   ptr = (custom_cb_s *) get_subplugin (NNS_IF_CUSTOM, name);
    1036            4 :   if (!unregister_subplugin (NNS_IF_CUSTOM, name)) {
    1037            2 :     ml_loge ("Failed to unregister custom callback %s.", name);
    1038            2 :     return -EINVAL;
    1039              :   }
    1040            2 :   g_free (ptr);
    1041              : 
    1042            2 :   return 0;
    1043              : }
    1044              : 
    1045              : /**
    1046              :  * @brief Determining whether a given condition is true or false
    1047              :  * @param tensor_if TensorIf Object
    1048              :  * @param buf gstbuffer from sink pad
    1049              :  * @return return TRUE if no error
    1050              :  */
    1051              : static gboolean
    1052           40 : gst_tensor_if_check_condition (GstTensorIf * tensor_if, GstBuffer * buf,
    1053              :     gboolean * result)
    1054              : {
    1055           40 :   gboolean ret = FALSE;
    1056              : 
    1057           40 :   if (tensor_if->cv == TIFCV_CUSTOM) {
    1058              :     GstMemory *in_mem[NNS_TENSOR_SIZE_LIMIT];
    1059              :     GstMapInfo in_info[NNS_TENSOR_SIZE_LIMIT];
    1060              :     GstTensorMemory in_tensors[NNS_TENSOR_SIZE_LIMIT];
    1061              :     guint i, j;
    1062              : 
    1063            2 :     if (!tensor_if->custom_configured) {
    1064            0 :       nns_loge ("custom condition of the tensor_if is not configured.");
    1065            0 :       return FALSE;
    1066              :     }
    1067              : 
    1068            6 :     for (i = 0; i < tensor_if->in_config.info.num_tensors; i++) {
    1069            4 :       in_mem[i] = gst_tensor_buffer_get_nth_memory (buf, i);
    1070            4 :       if (!gst_memory_map (in_mem[i], &in_info[i], GST_MAP_READ)) {
    1071            0 :         for (j = 0; j < i; j++) {
    1072            0 :           gst_memory_unmap (in_mem[j], &in_info[j]);
    1073            0 :           gst_memory_unref (in_mem[j]);
    1074              :         }
    1075            0 :         gst_memory_unref (in_mem[i]);
    1076              : 
    1077            0 :         GST_WARNING_OBJECT (tensor_if, "Cannot map input buffer(%d)\n", i);
    1078            0 :         return FALSE;
    1079              :       }
    1080            4 :       in_tensors[i].data = in_info[i].data;
    1081            4 :       in_tensors[i].size = in_info[i].size;
    1082              :     }
    1083              : 
    1084            2 :     ret = tensor_if->custom.func (&tensor_if->in_config.info, in_tensors,
    1085              :         tensor_if->custom.data, result);
    1086              : 
    1087            6 :     for (i = 0; i < tensor_if->in_config.info.num_tensors; i++) {
    1088            4 :       gst_memory_unmap (in_mem[i], &in_info[i]);
    1089            4 :       gst_memory_unref (in_mem[i]);
    1090              :     }
    1091              :   } else {
    1092           38 :     tensor_data_s cv = {.type = _NNS_END,.data._uint8_t = 0 };
    1093           38 :     if (!gst_tensor_if_calculate_cv (tensor_if, buf, &cv)) {
    1094            4 :       GST_ERROR_OBJECT (tensor_if, " failed to calculate compared value");
    1095            4 :       return FALSE;
    1096              :     }
    1097           34 :     ret = gst_tensor_if_get_comparison_result (tensor_if, &cv, result);
    1098              :   }
    1099              : 
    1100           36 :   return ret;
    1101              : }
    1102              : 
    1103              : /**
    1104              :  * @brief chain function for sink (gst element vmethod)
    1105              :  */
    1106              : static GstFlowReturn
    1107           40 : gst_tensor_if_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
    1108              : {
    1109              :   guint num_tensors, i;
    1110           40 :   GstFlowReturn res = GST_FLOW_OK;
    1111           40 :   GstTensorIf *tensor_if = GST_TENSOR_IF (parent);
    1112           40 :   gboolean condition_result = FALSE;
    1113           40 :   tensor_if_behavior curr_act = TIFB_PASSTHROUGH;
    1114           40 :   tensor_if_srcpads which_srcpad = TIFSP_THEN_PAD;
    1115           40 :   GList *curr_act_option = NULL;
    1116              :   GstTensorsConfig *config;
    1117              :   GstTensorPad *srcpad;
    1118           40 :   GstBuffer *outbuf = NULL;
    1119           40 :   GstMemory *mem = NULL;
    1120              :   gboolean created;
    1121              :   GstClockTime ts;
    1122              :   UNUSED (pad);
    1123              : 
    1124           40 :   num_tensors = tensor_if->in_config.info.num_tensors;
    1125           40 :   GST_DEBUG_OBJECT (tensor_if, " Number of Tensors: %u", num_tensors);
    1126              :   /* supposed n memory blocks in buffer */
    1127           40 :   g_assert (gst_tensor_buffer_get_count (buf) == num_tensors);
    1128              : 
    1129           40 :   if (!gst_tensor_if_check_condition (tensor_if, buf, &condition_result)) {
    1130            4 :     GST_ERROR_OBJECT (tensor_if, " Failed to check condition");
    1131           40 :     return GST_FLOW_ERROR;
    1132              :   }
    1133              : 
    1134           36 :   if (condition_result) {
    1135           25 :     curr_act = tensor_if->act_then;
    1136           25 :     curr_act_option = tensor_if->then_option;
    1137           25 :     which_srcpad = TIFSP_THEN_PAD;
    1138              :   } else {
    1139           11 :     curr_act = tensor_if->act_else;
    1140           11 :     curr_act_option = tensor_if->else_option;
    1141           11 :     which_srcpad = TIFSP_ELSE_PAD;
    1142              :   }
    1143              : 
    1144           36 :   config = &tensor_if->out_config[which_srcpad];
    1145              : 
    1146           36 :   if (config->info.num_tensors == 0) {
    1147           20 :     config->rate_n = tensor_if->in_config.rate_n;
    1148           20 :     config->rate_d = tensor_if->in_config.rate_d;
    1149              :   }
    1150              : 
    1151           36 :   switch (curr_act) {
    1152           13 :     case TIFB_PASSTHROUGH:
    1153           13 :       if (config->info.num_tensors == 0) {
    1154            4 :         gst_tensors_info_copy (&config->info, &tensor_if->in_config.info);
    1155              :       }
    1156           13 :       outbuf = gst_buffer_ref (buf);
    1157              : 
    1158           13 :       break;
    1159           20 :     case TIFB_TENSORPICK:
    1160              :     {
    1161              :       GList *list;
    1162           20 :       gint info_idx = 0;
    1163              :       GstTensorInfo *dest, *src;
    1164              : 
    1165           20 :       outbuf = gst_buffer_new ();
    1166           40 :       for (list = curr_act_option; list != NULL; list = list->next) {
    1167           20 :         i = GPOINTER_TO_INT (list->data);
    1168           20 :         src = gst_tensors_info_get_nth_info (&tensor_if->in_config.info, i);
    1169              : 
    1170           20 :         if (config->info.num_tensors == 0) {
    1171           13 :           dest = gst_tensors_info_get_nth_info (&config->info, info_idx);
    1172           13 :           info_idx++;
    1173              : 
    1174           13 :           gst_tensor_info_copy (dest, src);
    1175              :         }
    1176              : 
    1177           20 :         mem = gst_tensor_buffer_get_nth_memory (buf, i);
    1178           20 :         gst_tensor_buffer_append_memory (outbuf, mem, src);
    1179              :       }
    1180           20 :       config->info.num_tensors = info_idx;
    1181           20 :       break;
    1182              :     }
    1183            3 :     case TIFB_SKIP:
    1184            3 :       goto done;
    1185            0 :     default:
    1186            0 :       GST_DEBUG_OBJECT (tensor_if, " Not defined behavior");
    1187            0 :       break;
    1188              :   }
    1189              : 
    1190              :   srcpad =
    1191           33 :       gst_tensor_if_get_tensor_pad (tensor_if, config, &created, which_srcpad);
    1192              : 
    1193           33 :   if (created) {
    1194              :     GstSegment segment;
    1195           15 :     gst_segment_init (&segment, GST_FORMAT_TIME);
    1196           15 :     gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
    1197              :   }
    1198              : 
    1199           33 :   outbuf = gst_buffer_make_writable (outbuf);
    1200              : 
    1201              :   /* metadata from incoming buffer */
    1202           33 :   gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
    1203              : 
    1204           33 :   ts = GST_BUFFER_TIMESTAMP (buf);
    1205           33 :   if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
    1206           24 :     srcpad->last_ts = ts;
    1207              :   } else {
    1208            9 :     GST_DEBUG_OBJECT (tensor_if, "invalid timestamp %" GST_TIME_FORMAT,
    1209              :         GST_TIME_ARGS (ts));
    1210              :   }
    1211              : 
    1212           33 :   res = gst_pad_push (srcpad->pad, outbuf);
    1213           33 :   res = gst_tensor_if_combine_flows (tensor_if, srcpad, res);
    1214              : 
    1215           36 : done:
    1216           36 :   gst_buffer_unref (buf);
    1217           36 :   return res;
    1218              : }
        

Generated by: LCOV version 2.0-1