LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/nnstreamer/elements - gsttensor_sparsedec.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 91.3 % 138 126
Test Date: 2025-03-14 05:36:58 Functions: 100.0 % 12 12

            Line data    Source code
       1              : /* SPDX-License-Identifier: LGPL-2.1-only */
       2              : /**
       3              :  * Copyright (C) 2021 Samsung Electronics Co., Ltd.
       4              :  *
       5              :  * @file        gsttensor_sparsedec.c
       6              :  * @date        27 Jul 2021
       7              :  * @brief       GStreamer element to decode sparse tensors into dense tensors
       8              :  * @see         https://github.com/nnstreamer/nnstreamer
       9              :  * @author      Yongjoo Ahn <yongjoo1.ahn@samsung.com>
      10              :  * @bug         No known bugs except for NYI items
      11              :  */
      12              : 
      13              : /**
      14              :  * SECTION:element-tensor_sparse_dec
      15              :  *
      16              :  * tensor_sparse_dec is a GStreamer element to decode incoming sparse tensor into static (dense) format.
      17              :  *
      18              :  * The input is always in the format of other/tensors,format=sparse.
      19              :  * The output is always in the format of ohter/tensors,format=static.
      20              :  *
      21              :  * Please see also tensor_sparse_enc.
      22              :  *
      23              :  * <refsect2>
      24              :  * <title>Example launch line</title>
      25              :  * |[
      26              :  * gst-launch-1.0 ... ! other/tensors,format=static ! \
      27              :  *    tensor_sparse_enc ! other/tensors,format=sparse ! \
      28              :  *    tensor_sparse_dec ! tensor_sink
      29              :  * ]|
      30              :  * </refsect2>
      31              :  */
      32              : 
      33              : #ifdef HAVE_CONFIG_H
      34              : #include <config.h>
      35              : #endif
      36              : 
      37              : #include <string.h>
      38              : #include <nnstreamer_util.h>
      39              : #include "gsttensor_sparsedec.h"
      40              : 
      41              : /**
      42              :  * @brief Macro for debug mode.
      43              :  */
      44              : #ifndef DBG
      45              : #define DBG (!self->silent)
      46              : #endif
      47              : 
      48              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_sparse_dec_debug);
      49              : #define GST_CAT_DEFAULT gst_tensor_sparse_dec_debug
      50              : 
      51              : /**
      52              :  * @brief tensor_sparse_dec properties
      53              :  */
      54              : enum
      55              : {
      56              :   PROP_0,
      57              :   PROP_SILENT
      58              : };
      59              : 
      60              : /**
      61              :  * @brief Flag to print minimized log.
      62              :  */
      63              : #define DEFAULT_SILENT TRUE
      64              : 
      65              : /**
      66              :  * @brief Template for sink pad.
      67              :  */
      68              : static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
      69              :     GST_PAD_SINK,
      70              :     GST_PAD_ALWAYS,
      71              :     GST_STATIC_CAPS (GST_TENSORS_SPARSE_CAP_DEFAULT));
      72              : 
      73              : /**
      74              :  * @brief Template for src pad.
      75              :  */
      76              : static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
      77              :     GST_PAD_SRC,
      78              :     GST_PAD_ALWAYS,
      79              :     GST_STATIC_CAPS (GST_TENSORS_CAP_DEFAULT));
      80              : 
      81              : #define gst_tensor_sparse_dec_parent_class parent_class
      82          937 : G_DEFINE_TYPE (GstTensorSparseDec, gst_tensor_sparse_dec, GST_TYPE_ELEMENT);
      83              : 
      84              : static void gst_tensor_sparse_dec_finalize (GObject * object);
      85              : static void gst_tensor_sparse_dec_set_property (GObject * object, guint prop_id,
      86              :     const GValue * value, GParamSpec * pspec);
      87              : static void gst_tensor_sparse_dec_get_property (GObject * object, guint prop_id,
      88              :     GValue * value, GParamSpec * pspec);
      89              : static GstFlowReturn
      90              : gst_tensor_sparse_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf);
      91              : static gboolean
      92              : gst_tensor_sparse_dec_sink_event (GstPad * pad, GstObject * parent,
      93              :     GstEvent * event);
      94              : static gboolean gst_tensor_sparse_dec_sink_query (GstPad * pad,
      95              :     GstObject * parent, GstQuery * query);
      96              : 
      97              : /**
      98              :  * @brief Initialize the tensor_sparse's class.
      99              :  */
     100              : static void
     101            6 : gst_tensor_sparse_dec_class_init (GstTensorSparseDecClass * klass)
     102              : {
     103              :   GObjectClass *object_class;
     104              :   GstElementClass *element_class;
     105              : 
     106            6 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_sparse_dec_debug, "tensor_sparse_dec", 0,
     107              :       "Element to decode sparse tensors");
     108              : 
     109            6 :   object_class = (GObjectClass *) klass;
     110            6 :   element_class = (GstElementClass *) klass;
     111              : 
     112            6 :   object_class->set_property = gst_tensor_sparse_dec_set_property;
     113            6 :   object_class->get_property = gst_tensor_sparse_dec_get_property;
     114            6 :   object_class->finalize = gst_tensor_sparse_dec_finalize;
     115              : 
     116              :   /**
     117              :    * GstTensorSparseDec::silent:
     118              :    *
     119              :    * The flag to enable/disable debugging messages.
     120              :    */
     121            6 :   g_object_class_install_property (object_class, PROP_SILENT,
     122              :       g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
     123              :           DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     124              : 
     125            6 :   gst_element_class_add_pad_template (element_class,
     126              :       gst_static_pad_template_get (&src_template));
     127            6 :   gst_element_class_add_pad_template (element_class,
     128              :       gst_static_pad_template_get (&sink_template));
     129              : 
     130            6 :   gst_element_class_set_static_metadata (element_class,
     131              :       "TensorSparseDec",
     132              :       "Filter/Tensor",
     133              :       "Element to decode dense tensors into sparse tensors",
     134              :       "Samsung Electronics Co., Ltd.");
     135            6 : }
     136              : 
     137              : /**
     138              :  * @brief Initialize tensor_sparse_dec element.
     139              :  */
     140              : static void
     141            6 : gst_tensor_sparse_dec_init (GstTensorSparseDec * self)
     142              : {
     143              :   /* setup sink pad */
     144            6 :   self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
     145            6 :   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
     146              : 
     147              :   /* setup src pad */
     148            6 :   self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
     149            6 :   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
     150              : 
     151              :   /* setup chain function */
     152            6 :   gst_pad_set_chain_function (self->sinkpad,
     153              :       GST_DEBUG_FUNCPTR (gst_tensor_sparse_dec_chain));
     154              : 
     155              :   /* setup event function */
     156            6 :   gst_pad_set_event_function (self->sinkpad,
     157              :       GST_DEBUG_FUNCPTR (gst_tensor_sparse_dec_sink_event));
     158              : 
     159            6 :   gst_pad_set_query_function (self->sinkpad,
     160              :       GST_DEBUG_FUNCPTR (gst_tensor_sparse_dec_sink_query));
     161              : 
     162              :   /* init properties */
     163            6 :   self->silent = DEFAULT_SILENT;
     164            6 :   gst_tensors_config_init (&self->in_config);
     165            6 :   gst_tensors_config_init (&self->out_config);
     166            6 : }
     167              : 
     168              : /**
     169              :  * @brief Function to finalize instance.
     170              :  */
     171              : static void
     172            6 : gst_tensor_sparse_dec_finalize (GObject * object)
     173              : {
     174              :   GstTensorSparseDec *self;
     175            6 :   self = GST_TENSOR_SPARSE_DEC (object);
     176              : 
     177            6 :   gst_tensors_config_free (&self->in_config);
     178            6 :   gst_tensors_config_free (&self->out_config);
     179              : 
     180            6 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     181            6 : }
     182              : 
     183              : /**
     184              :  * @brief Setter for tensor_sparse_dec properties.
     185              :  */
     186              : static void
     187            1 : gst_tensor_sparse_dec_set_property (GObject * object, guint prop_id,
     188              :     const GValue * value, GParamSpec * pspec)
     189              : {
     190              :   GstTensorSparseDec *self;
     191              : 
     192            1 :   self = GST_TENSOR_SPARSE_DEC (object);
     193              : 
     194            1 :   switch (prop_id) {
     195            1 :     case PROP_SILENT:
     196            1 :       self->silent = g_value_get_boolean (value);
     197            1 :       break;
     198            0 :     default:
     199            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     200            0 :       break;
     201              :   }
     202            1 : }
     203              : 
     204              : /**
     205              :  * @brief Getter for tensor_sparse_dec properties.
     206              :  */
     207              : static void
     208            2 : gst_tensor_sparse_dec_get_property (GObject * object, guint prop_id,
     209              :     GValue * value, GParamSpec * pspec)
     210              : {
     211              :   GstTensorSparseDec *self;
     212              : 
     213            2 :   self = GST_TENSOR_SPARSE_DEC (object);
     214              : 
     215            2 :   switch (prop_id) {
     216            2 :     case PROP_SILENT:
     217            2 :       g_value_set_boolean (value, self->silent);
     218            2 :       break;
     219            0 :     default:
     220            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     221            0 :       break;
     222              :   }
     223            2 : }
     224              : 
     225              : /**
     226              :  * @brief Get pad caps for caps negotiation.
     227              :  */
     228              : static GstCaps *
     229           16 : gst_tensor_sparse_dec_query_caps (GstTensorSparseDec * self, GstPad * pad,
     230              :     GstCaps * filter)
     231              : {
     232              :   GstCaps *caps;
     233              : 
     234           16 :   caps = gst_pad_get_current_caps (pad);
     235           16 :   if (!caps) {
     236              :     /** pad don't have current caps. use the template caps */
     237           16 :     caps = gst_pad_get_pad_template_caps (pad);
     238              :   }
     239              : 
     240           16 :   silent_debug_caps (self, caps, "caps");
     241           16 :   silent_debug_caps (self, filter, "filter");
     242              : 
     243           16 :   if (filter) {
     244              :     GstCaps *intersection;
     245              :     intersection =
     246            5 :         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
     247              : 
     248            5 :     gst_caps_unref (caps);
     249            5 :     caps = intersection;
     250              :   }
     251              : 
     252           16 :   silent_debug_caps (self, caps, "result");
     253           16 :   return caps;
     254              : }
     255              : 
     256              : /**
     257              :  * @brief This function handles sink pad query.
     258              :  */
     259              : static gboolean
     260           24 : gst_tensor_sparse_dec_sink_query (GstPad * pad, GstObject * parent,
     261              :     GstQuery * query)
     262              : {
     263              :   GstTensorSparseDec *self;
     264           24 :   self = GST_TENSOR_SPARSE_DEC (parent);
     265              : 
     266           24 :   GST_DEBUG_OBJECT (self, "Received %s query: %" GST_PTR_FORMAT,
     267              :       GST_QUERY_TYPE_NAME (query), query);
     268              : 
     269           24 :   switch (GST_QUERY_TYPE (query)) {
     270           16 :     case GST_QUERY_CAPS:
     271              :     {
     272              :       GstCaps *caps;
     273              :       GstCaps *filter;
     274              : 
     275           16 :       gst_query_parse_caps (query, &filter);
     276           16 :       caps = gst_tensor_sparse_dec_query_caps (self, pad, filter);
     277           16 :       silent_debug_caps (self, filter, "filter");
     278           16 :       silent_debug_caps (self, caps, "caps");
     279           16 :       gst_query_set_caps_result (query, caps);
     280           16 :       gst_caps_unref (caps);
     281           16 :       return TRUE;
     282              :     }
     283            5 :     case GST_QUERY_ACCEPT_CAPS:
     284              :     {
     285              :       GstCaps *caps;
     286              :       GstCaps *template_caps;
     287            5 :       gboolean res = FALSE;
     288              : 
     289            5 :       gst_query_parse_accept_caps (query, &caps);
     290            5 :       silent_debug_caps (self, caps, "caps");
     291              : 
     292            5 :       if (gst_caps_is_fixed (caps)) {
     293            5 :         template_caps = gst_pad_get_pad_template_caps (pad);
     294              : 
     295            5 :         res = gst_caps_can_intersect (template_caps, caps);
     296            5 :         gst_caps_unref (template_caps);
     297              :       }
     298              : 
     299            5 :       gst_query_set_accept_caps_result (query, res);
     300            5 :       return TRUE;
     301              :     }
     302            3 :     default:
     303            3 :       break;
     304              :   }
     305              : 
     306            3 :   return gst_pad_query_default (pad, parent, query);
     307              : }
     308              : 
     309              : /**
     310              :  * @brief This function handles sink pad event.
     311              :  */
     312              : static gboolean
     313           20 : gst_tensor_sparse_dec_sink_event (GstPad * pad, GstObject * parent,
     314              :     GstEvent * event)
     315              : {
     316              :   GstTensorSparseDec *self;
     317           20 :   self = GST_TENSOR_SPARSE_DEC (parent);
     318           20 :   g_return_val_if_fail (event != NULL, FALSE);
     319              : 
     320           20 :   switch (GST_EVENT_TYPE (event)) {
     321            5 :     case GST_EVENT_CAPS:
     322              :     {
     323              :       GstCaps *caps, *out_caps;
     324              :       GstStructure *structure;
     325              : 
     326            5 :       gst_event_parse_caps (event, &caps);
     327            5 :       silent_debug_caps (self, caps, "caps");
     328              : 
     329              :       /* set in_config */
     330            5 :       structure = gst_caps_get_structure (caps, 0);
     331            5 :       gst_tensors_config_from_structure (&self->in_config, structure);
     332              : 
     333              :       /* set out_config as srcpad's peer */
     334            5 :       gst_tensors_config_from_peer (self->srcpad, &self->out_config, NULL);
     335            5 :       self->out_config.rate_n = self->in_config.rate_n;
     336            5 :       self->out_config.rate_d = self->in_config.rate_d;
     337              : 
     338           10 :       out_caps = gst_tensor_pad_caps_from_config (self->srcpad,
     339            5 :           &self->out_config);
     340              : 
     341            5 :       silent_debug_caps (self, out_caps, "out_caps");
     342            5 :       gst_pad_set_caps (self->srcpad, out_caps);
     343            5 :       gst_caps_unref (out_caps);
     344              : 
     345            5 :       gst_event_unref (event);
     346            5 :       return TRUE;
     347              :     }
     348           15 :     default:
     349           15 :       break;
     350              :   }
     351              : 
     352           15 :   return gst_pad_event_default (pad, parent, event);
     353              : }
     354              : 
     355              : /**
     356              :  * @brief Internal function to transform the input buffer.
     357              :  */
     358              : static GstFlowReturn
     359           14 : gst_tensor_sparse_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     360              : {
     361           14 :   GstFlowReturn ret = GST_FLOW_ERROR;
     362           14 :   GstTensorSparseDec *self = GST_TENSOR_SPARSE_DEC (parent);
     363              :   GstTensorMetaInfo meta;
     364              :   GstMemory *in_mem, *out_mem;
     365              :   GstBuffer *outbuf;
     366              :   GstTensorsInfo info;
     367              :   GstTensorInfo *_info;
     368              :   guint i;
     369              : 
     370              :   UNUSED (pad);
     371              : 
     372           14 :   buf = gst_tensor_buffer_from_config (buf, &self->in_config);
     373           14 :   outbuf = gst_buffer_new ();
     374              : 
     375           14 :   gst_tensors_info_init (&info);
     376           14 :   info.num_tensors = gst_tensor_buffer_get_count (buf);
     377              : 
     378           39 :   for (i = 0; i < info.num_tensors; ++i) {
     379           25 :     in_mem = gst_tensor_buffer_get_nth_memory (buf, i);
     380           25 :     out_mem = gst_tensor_sparse_to_dense (&meta, in_mem);
     381           25 :     gst_memory_unref (in_mem);
     382              : 
     383           25 :     if (!out_mem) {
     384            0 :       nns_loge ("failed to convert to dense tensor");
     385            0 :       goto done;
     386              :     }
     387              : 
     388           25 :     _info = gst_tensors_info_get_nth_info (&info, i);
     389           25 :     gst_tensor_meta_info_convert (&meta, _info);
     390           25 :     gst_tensor_buffer_append_memory (outbuf, out_mem, _info);
     391              :   }
     392              : 
     393              :   /* check the decoded tensor with negotiated config when it's valid */
     394           14 :   if (gst_tensors_config_validate (&self->out_config)) {
     395           12 :     if (!gst_tensors_info_is_equal (&self->out_config.info, &info)) {
     396              :       /* if it's not compatible with downstream, do not send the buffer */
     397              :       /** @todo consider more error handling */
     398            0 :       gst_buffer_unref (outbuf);
     399            0 :       ret = GST_FLOW_OK;
     400            0 :       goto done;
     401              :     }
     402              :   }
     403              : 
     404           14 :   ret = gst_pad_push (self->srcpad, outbuf);
     405              : 
     406           14 : done:
     407           14 :   gst_buffer_unref (buf);
     408           14 :   if (ret != GST_FLOW_OK)
     409            0 :     gst_buffer_unref (outbuf);
     410              : 
     411           14 :   return ret;
     412              : }
        

Generated by: LCOV version 2.0-1