LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/nnstreamer/elements - gsttensor_split.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 91.8 % 305 280
Test Date: 2025-03-14 05:36:58 Functions: 100.0 % 16 16

            Line data    Source code
       1              : /**
       2              :  * GStreamer
       3              :  * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
       4              :  * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
       5              :  * Copyright (C) 2018 Jijoong Moon <jijoong.moon@samsung.com>
       6              :  *
       7              :  * This library is free software; you can redistribute it and/or
       8              :  * modify it under the terms of the GNU Library General Public
       9              :  * License as published by the Free Software Foundation;
      10              :  * version 2.1 of the License.
      11              :  *
      12              :  * This library is distributed in the hope that it will be useful,
      13              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              :  * Library General Public License for more details.
      16              :  *
      17              :  */
      18              : /**
      19              :  * @file        gsttensor_split.c
      20              :  * @date        27 Aug 2018
      21              :  * @brief       GStreamer plugin to split tensor (as a filter for other general neural network filters)
      22              :  * @see         https://github.com/nnstreamer/nnstreamer
      23              :  * @author      Jijoong Moon <jijoong.moon@samsung.com>
      24              :  * @bug         No known bugs except for NYI items
      25              :  *
      26              :  */
      27              : 
      28              : /**
      29              :  * SECTION:element-tensor_split
      30              :  *
      31              :  * A Deuxer that split tensors stream to tensor stream for NN frameworks.
      32              :  * The outputs are always in the format of other/tensor.
      33              :  *
      34              :  * <refsect2>
      35              :  * <title>Example launch line</title>
      36              :  * |[
      37              :  * gst-launch -v -m filesrc location=testcase_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter
      38              :  * ! tensor_split name=split tensorseg=2:100:100,1:100:100 split.src_0 ! queue ! filesink location=src0.log
      39              :  * split.src_1 ! queue ! filesink location=src1.log
      40              :  * ]|
      41              :  *
      42              :  * </refsect2>
      43              :  *
      44              :  */
      45              : 
      46              : 
      47              : #ifdef HAVE_CONFIG_H
      48              : #include <config.h>
      49              : #endif
      50              : 
      51              : #include <string.h>
      52              : #include <gst/gst.h>
      53              : #include <glib.h>
      54              : 
      55              : #include "gsttensor_split.h"
      56              : #include <tensor_common.h>
      57              : #include <nnstreamer_util.h>
      58              : 
      59              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_split_debug);
      60              : #define GST_CAT_DEFAULT gst_tensor_split_debug
      61              : 
      62              : enum
      63              : {
      64              :   PROP_0,
      65              :   PROP_SILENT,
      66              :   PROP_TENSORPICK,
      67              :   PROP_TENSORSEG
      68              : };
      69              : 
      70              : /**
      71              :  * @brief Template caps string.
      72              :  */
      73              : #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_WITH_NUM ("1")
      74              : 
      75              : /**
      76              :  * @brief the capabilities of the inputs and outputs.
      77              :  * describe the real formats here.
      78              :  */
      79              : static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src_%u",
      80              :     GST_PAD_SRC,
      81              :     GST_PAD_SOMETIMES,
      82              :     GST_STATIC_CAPS (CAPS_STRING));
      83              : 
      84              : static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
      85              :     GST_PAD_SINK,
      86              :     GST_PAD_ALWAYS,
      87              :     GST_STATIC_CAPS (CAPS_STRING));
      88              : 
      89              : static GstFlowReturn gst_tensor_split_chain (GstPad * pad, GstObject * parent,
      90              :     GstBuffer * buf);
      91              : static gboolean gst_tensor_split_event (GstPad * pad, GstObject * parent,
      92              :     GstEvent * event);
      93              : static GstStateChangeReturn gst_tensor_split_change_state (GstElement * element,
      94              :     GstStateChange transition);
      95              : static void gst_tensor_split_set_property (GObject * object, guint prop_id,
      96              :     const GValue * value, GParamSpec * pspec);
      97              : static void gst_tensor_split_get_property (GObject * object, guint prop_id,
      98              :     GValue * value, GParamSpec * pspec);
      99              : static void gst_tensor_split_finalize (GObject * object);
     100              : 
     101              : #define gst_tensor_split_parent_class parent_class
     102         1122 : G_DEFINE_TYPE (GstTensorSplit, gst_tensor_split, GST_TYPE_ELEMENT);
     103              : 
     104              : 
     105              : /**
     106              :  * @brief initialize the tensor_split's class
     107              :  */
     108              : static void
     109           12 : gst_tensor_split_class_init (GstTensorSplitClass * klass)
     110              : {
     111              :   GObjectClass *gobject_class;
     112              :   GstElementClass *gstelement_class;
     113              : 
     114           12 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_split_debug, "tensor_split", 0,
     115              :       "Element to split tensors stream to tensor stream");
     116              : 
     117           12 :   gobject_class = (GObjectClass *) klass;
     118           12 :   gstelement_class = (GstElementClass *) klass;
     119              : 
     120           12 :   parent_class = g_type_class_peek_parent (klass);
     121              : 
     122           12 :   gobject_class->finalize = gst_tensor_split_finalize;
     123           12 :   gobject_class->get_property = gst_tensor_split_get_property;
     124           12 :   gobject_class->set_property = gst_tensor_split_set_property;
     125              : 
     126           12 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     127              :       g_param_spec_boolean ("silent", "Silent",
     128              :           "Do not produce verbose output ?", TRUE, G_PARAM_READWRITE));
     129              : 
     130           12 :   g_object_class_install_property (gobject_class, PROP_TENSORPICK,
     131              :       g_param_spec_string ("tensorpick", "TensorPick",
     132              :           "Choose nth tensor among tensors ?", "", G_PARAM_READWRITE));
     133              : 
     134           12 :   g_object_class_install_property (gobject_class, PROP_TENSORSEG,
     135              :       g_param_spec_string ("tensorseg", "TensorSeg",
     136              :           "How to split tensor ?", "", G_PARAM_READWRITE));
     137              : 
     138           12 :   gstelement_class->change_state =
     139           12 :       GST_DEBUG_FUNCPTR (gst_tensor_split_change_state);
     140              : 
     141           12 :   gst_element_class_add_pad_template (gstelement_class,
     142              :       gst_static_pad_template_get (&sink_templ));
     143           12 :   gst_element_class_add_pad_template (gstelement_class,
     144              :       gst_static_pad_template_get (&src_templ));
     145              : 
     146           12 :   gst_element_class_set_details_simple (gstelement_class,
     147              :       "TensorSplit",
     148              :       "Demuxer/Tensor",
     149              :       "Split tensor stream to other/tensor stream",
     150              :       "Jijoong Moon <jijoong.moon@samsung.com>");
     151           12 : }
     152              : 
     153              : /**
     154              :  * @brief initialize the new element
     155              :  * instantiate pads and add them to element
     156              :  * set pad callback functions
     157              :  * initialize instance structure
     158              :  */
     159              : static void
     160           13 : gst_tensor_split_init (GstTensorSplit * split)
     161              : {
     162           13 :   split->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
     163           13 :   gst_element_add_pad (GST_ELEMENT_CAST (split), split->sinkpad);
     164           13 :   gst_pad_set_chain_function (split->sinkpad,
     165              :       GST_DEBUG_FUNCPTR (gst_tensor_split_chain));
     166           13 :   gst_pad_set_event_function (split->sinkpad,
     167              :       GST_DEBUG_FUNCPTR (gst_tensor_split_event));
     168              : 
     169           13 :   split->num_tensors = 0;
     170           13 :   split->num_srcpads = 0;
     171           13 :   split->silent = TRUE;
     172           13 :   split->tensorpick = NULL;
     173           13 :   split->tensorseg = NULL;
     174           13 :   split->have_group_id = FALSE;
     175           13 :   split->group_id = G_MAXUINT;
     176           13 :   split->srcpads = NULL;
     177           13 :   gst_tensors_config_init (&split->sink_tensor_conf);
     178           13 : }
     179              : 
     180              : /**
     181              :  * @brief function to remove srcpad list
     182              :  */
     183              : static void
     184           25 : gst_tensor_split_remove_src_pads (GstTensorSplit * split)
     185              : {
     186           49 :   while (split->srcpads != NULL) {
     187           24 :     GstTensorPad *tensor_pad = split->srcpads->data;
     188           24 :     gst_element_remove_pad (GST_ELEMENT (split), tensor_pad->pad);
     189           24 :     g_free (tensor_pad);
     190           24 :     split->srcpads = g_slist_delete_link (split->srcpads, split->srcpads);
     191              :   }
     192           25 :   split->srcpads = NULL;
     193           25 :   split->num_tensors = 0;
     194           25 :   split->num_srcpads = 0;
     195           25 :   gst_tensors_config_free (&split->sink_tensor_conf);
     196           25 : }
     197              : 
     198              : /**
     199              :  * @brief finalize function for tensor split (gst element vmethod)
     200              :  */
     201              : static void
     202           13 : gst_tensor_split_finalize (GObject * object)
     203              : {
     204              :   GstTensorSplit *split;
     205              : 
     206           13 :   split = GST_TENSOR_SPLIT (object);
     207           13 :   gst_tensor_split_remove_src_pads (split);
     208           13 :   g_list_free (split->tensorpick);
     209           13 :   g_array_free (split->tensorseg, TRUE);
     210           13 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     211           13 : }
     212              : 
     213              : /**
     214              :  * @brief event function for sink (gst element vmethod)
     215              :  */
     216              : static gboolean
     217           48 : gst_tensor_split_event (GstPad * pad, GstObject * parent, GstEvent * event)
     218              : {
     219              :   GstTensorSplit *split;
     220              : 
     221           48 :   split = GST_TENSOR_SPLIT (parent);
     222              : 
     223           48 :   switch (GST_EVENT_TYPE (event)) {
     224           12 :     case GST_EVENT_CAPS:
     225              :     {
     226              :       GstCaps *caps;
     227           12 :       gst_event_parse_caps (event, &caps);
     228           12 :       if (!gst_tensors_config_from_cap (&split->sink_tensor_conf, caps)) {
     229            0 :         GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
     230              :             ("This stream contains no valid type."), NULL);
     231              :       }
     232           12 :       break;
     233              :     }
     234           12 :     case GST_EVENT_EOS:
     235           12 :       if (!split->srcpads) {
     236            0 :         GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
     237              :             ("This stream contains no valid stremas."),
     238              :             ("Got EOS before adding any pads"));
     239            0 :         gst_event_unref (event);
     240            0 :         return FALSE;
     241              :       }
     242           12 :       break;
     243           24 :     default:
     244           24 :       break;
     245              :   }
     246              : 
     247           48 :   return gst_pad_event_default (pad, parent, event);
     248              : }
     249              : 
     250              : /**
     251              :  * @brief Checking if the source pad is created and if not, create TensorPad
     252              :  * @param split TensorSplit Object
     253              :  * @param inbuf inputbuf GstBuffer Object including GstMeta
     254              :  * @param[out] created will be updated in this function
     255              :  * @param nth source ordering
     256              :  * @return TensorPad if pad is already created, then return created pad.
     257              :  *         If not return new pad after creation.
     258              :  */
     259              : static GstTensorPad *
     260          191 : gst_tensor_split_get_tensor_pad (GstTensorSplit * split, GstBuffer * inbuf,
     261              :     gboolean * created, guint nth)
     262              : {
     263          191 :   GstElement *element = GST_ELEMENT_CAST (split);
     264          191 :   g_autofree gchar *element_name = gst_element_get_name (element);
     265              :   GSList *walk;
     266              :   GstPad *pad;
     267              :   GstTensorPad *tensorpad;
     268              :   gchar *name;
     269              :   GstEvent *event;
     270              :   gchar *stream_id;
     271              :   GstCaps *caps;
     272              :   GstTensorsConfig pad_config;
     273              :   tensor_dim *dim;
     274              :   guint i;
     275              :   UNUSED (inbuf);
     276              : 
     277          191 :   walk = split->srcpads;
     278          304 :   while (walk) {
     279          280 :     GstTensorPad *pad = (GstTensorPad *) walk->data;
     280          280 :     if (nth == pad->nth) {
     281          167 :       if (created) {
     282          167 :         *created = FALSE;
     283              :       }
     284          167 :       return pad;
     285              :     }
     286          113 :     walk = g_slist_next (walk);
     287              :   }
     288              : 
     289           24 :   tensorpad = g_new0 (GstTensorPad, 1);
     290           24 :   g_assert (tensorpad != NULL);
     291           24 :   GST_DEBUG_OBJECT (split, "creating pad: %d(%dth)", split->num_srcpads, nth);
     292              : 
     293           24 :   name = g_strdup_printf ("src_%u", split->num_srcpads);
     294           24 :   pad = gst_pad_new_from_static_template (&src_templ, name);
     295           24 :   stream_id = gst_pad_create_stream_id_printf (pad, element,
     296              :       "%s-nnssplit-%s-%08x", element_name, name, g_random_int ());
     297           24 :   g_free (name);
     298              : 
     299           24 :   tensorpad->pad = pad;
     300           24 :   tensorpad->nth = nth;
     301           24 :   tensorpad->last_ret = GST_FLOW_OK;
     302           24 :   tensorpad->last_ts = GST_CLOCK_TIME_NONE;
     303              : 
     304           24 :   split->srcpads = g_slist_append (split->srcpads, tensorpad);
     305           24 :   dim = g_array_index (split->tensorseg, tensor_dim *, split->num_srcpads);
     306              : 
     307           24 :   split->num_srcpads++;
     308              : 
     309           24 :   gst_pad_use_fixed_caps (pad);
     310           24 :   gst_pad_set_active (pad, TRUE);
     311              : 
     312           24 :   if (!split->have_group_id) {
     313              :     event =
     314           12 :         gst_pad_get_sticky_event (split->sinkpad, GST_EVENT_STREAM_START, 0);
     315           12 :     if (event) {
     316           12 :       split->have_group_id = gst_event_parse_group_id (event, &split->group_id);
     317           12 :       gst_event_unref (event);
     318            0 :     } else if (!split->have_group_id) {
     319            0 :       split->have_group_id = TRUE;
     320            0 :       split->group_id = gst_util_group_id_next ();
     321              :     }
     322              :   }
     323              : 
     324           24 :   event = gst_event_new_stream_start (stream_id);
     325           24 :   if (split->have_group_id)
     326           24 :     gst_event_set_group_id (event, split->group_id);
     327              : 
     328           24 :   gst_pad_store_sticky_event (pad, event);
     329           24 :   g_free (stream_id);
     330           24 :   gst_event_unref (event);
     331              : 
     332              :   /* tensor config to set caps */
     333           24 :   gst_tensors_config_init (&pad_config);
     334           24 :   pad_config.info.num_tensors = 1;
     335          408 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     336          384 :     pad_config.info.info[0].dimension[i] = (*dim)[i];
     337              :   }
     338           24 :   pad_config.info.info[0].type = split->sink_tensor_conf.info.info[0].type;
     339           24 :   pad_config.rate_n = split->sink_tensor_conf.rate_n;
     340           24 :   pad_config.rate_d = split->sink_tensor_conf.rate_d;
     341              : 
     342           24 :   caps = gst_tensor_pad_caps_from_config (pad, &pad_config);
     343              : 
     344           24 :   gst_pad_set_caps (pad, caps);
     345           24 :   gst_element_add_pad (GST_ELEMENT_CAST (split), pad);
     346              : 
     347           24 :   gst_caps_unref (caps);
     348              : 
     349           24 :   if (created) {
     350           24 :     *created = TRUE;
     351              :   }
     352              : 
     353           24 :   if (split->tensorpick != NULL) {
     354            5 :     GST_DEBUG_OBJECT (split, "TensorPick is set! : %dth tensor\n", nth);
     355            5 :     if (g_list_length (split->tensorpick) == split->num_srcpads) {
     356            2 :       gst_element_no_more_pads (GST_ELEMENT_CAST (split));
     357              :     }
     358              :   }
     359              : 
     360           24 :   return tensorpad;
     361              : }
     362              : 
     363              : /**
     364              :  * @brief Check the status among sources in split
     365              :  * @param split TensorSplit Object
     366              :  * @param TensorPad Tensorpad
     367              :  * @param ret return status of current pad
     368              :  * @return return status after check sources
     369              :  */
     370              : static GstFlowReturn
     371          191 : gst_tensor_split_combine_flows (GstTensorSplit * split,
     372              :     GstTensorPad * pad, GstFlowReturn ret)
     373              : {
     374              :   GSList *walk;
     375              :   GstTensorPad *opad;
     376              : 
     377          191 :   pad->last_ret = ret;
     378          191 :   if (ret != GST_FLOW_NOT_LINKED)
     379          147 :     goto done;
     380              : 
     381           44 :   for (walk = split->srcpads; walk; walk = g_slist_next (walk)) {
     382           44 :     opad = (GstTensorPad *) walk->data;
     383           44 :     ret = opad->last_ret;
     384           44 :     if (ret != GST_FLOW_NOT_LINKED)
     385           44 :       goto done;
     386              :   }
     387            0 : done:
     388          191 :   return ret;
     389              : }
     390              : 
     391              : /**
     392              :  * @brief Make splitted tensor
     393              :  * @param split TensorSplit object
     394              :  * @param buffer gstbuffer form src
     395              :  * @param nth orther of tensor
     396              :  * @return return GstMemory for splitted tensor
     397              :  */
     398              : static GstMemory *
     399          191 : gst_tensor_split_get_splitted (GstTensorSplit * split, GstBuffer * buffer,
     400              :     gint nth)
     401              : {
     402              :   GstMemory *mem;
     403              :   tensor_dim *dim;
     404              :   int i;
     405              :   gsize size, offset;
     406              :   GstMapInfo src_info, dest_info;
     407              : 
     408          191 :   dim = g_array_index (split->tensorseg, tensor_dim *, nth);
     409          191 :   size = gst_tensor_get_element_count (*dim) *
     410          191 :       gst_tensor_get_element_size (split->sink_tensor_conf.info.info[0].type);
     411              : 
     412          191 :   mem = gst_allocator_alloc (NULL, size, NULL);
     413          191 :   if (!gst_memory_map (mem, &dest_info, GST_MAP_WRITE)) {
     414            0 :     ml_logf ("Cannot map memory for destination buffer.\n");
     415            0 :     gst_memory_unref (mem);
     416          191 :     return NULL;
     417              :   }
     418          191 :   if (!gst_buffer_map (buffer, &src_info, GST_MAP_READ)) {
     419            0 :     ml_logf ("Cannot map src-memory to gst buffer at tensor-split.\n");
     420            0 :     gst_memory_unmap (mem, &dest_info);
     421            0 :     gst_memory_unref (mem);
     422            0 :     return NULL;
     423              :   }
     424              : 
     425          191 :   offset = 0;
     426          304 :   for (i = 0; i < nth; i++) {
     427          113 :     dim = g_array_index (split->tensorseg, tensor_dim *, i);
     428          113 :     offset += gst_tensor_get_element_count (*dim) *
     429          113 :         gst_tensor_get_element_size (split->sink_tensor_conf.info.info[0].type);
     430              :   }
     431              : 
     432          191 :   nns_memcpy (dest_info.data, src_info.data + offset, size);
     433          191 :   gst_buffer_unmap (buffer, &src_info);
     434          191 :   gst_memory_unmap (mem, &dest_info);
     435              : 
     436          191 :   return mem;
     437              : }
     438              : 
     439              : /**
     440              :  * @brief chain function for sink (gst element vmethod)
     441              :  */
     442              : static GstFlowReturn
     443           94 : gst_tensor_split_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     444              : {
     445              :   GstTensorSplit *split;
     446              :   guint num_tensors, i;
     447           94 :   GstFlowReturn res = GST_FLOW_OK;
     448              :   UNUSED (pad);
     449              : 
     450           94 :   split = GST_TENSOR_SPLIT (parent);
     451              : 
     452           94 :   num_tensors = split->num_tensors;
     453           94 :   GST_DEBUG_OBJECT (split, " Number of Tensors: %d", num_tensors);
     454              : 
     455           94 :   if (split->tensorseg == NULL) {
     456            0 :     GST_ERROR_OBJECT (split, "No rule to split incoming buffers.");
     457            0 :     return GST_FLOW_ERROR;
     458              :   }
     459              : 
     460          293 :   for (i = 0; i < num_tensors; i++) {
     461              :     GstTensorPad *srcpad;
     462              :     GstBuffer *outbuf;
     463              :     GstMemory *mem;
     464              :     gboolean created;
     465              :     GstClockTime ts;
     466              : 
     467          201 :     if (split->tensorpick != NULL) {
     468           45 :       gboolean found = FALSE;
     469              :       GList *list;
     470           90 :       for (list = split->tensorpick; list != NULL; list = list->next) {
     471           80 :         if (i == GPOINTER_TO_UINT (list->data)) {
     472           35 :           found = TRUE;
     473           35 :           break;
     474              :         }
     475              :       }
     476           45 :       if (!found)
     477           10 :         continue;
     478              :     }
     479              : 
     480          191 :     srcpad = gst_tensor_split_get_tensor_pad (split, buf, &created, i);
     481              : 
     482          191 :     outbuf = gst_buffer_new ();
     483          191 :     mem = gst_tensor_split_get_splitted (split, buf, i);
     484          191 :     gst_buffer_append_memory (outbuf, mem);
     485          191 :     ts = GST_BUFFER_TIMESTAMP (buf);
     486              : 
     487          191 :     if (created) {
     488              :       GstSegment segment;
     489           24 :       gst_segment_init (&segment, GST_FORMAT_TIME);
     490           24 :       gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
     491              :     }
     492              : 
     493          191 :     outbuf = gst_buffer_make_writable (outbuf);
     494              : 
     495              :     /* metadata from incoming buffer */
     496          191 :     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
     497              : 
     498          191 :     if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
     499          191 :       srcpad->last_ts = ts;
     500              :     } else {
     501            0 :       GST_DEBUG_OBJECT (split, "invalid timestamp %" GST_TIME_FORMAT,
     502              :           GST_TIME_ARGS (ts));
     503              :     }
     504              : 
     505          191 :     GST_DEBUG_OBJECT (split, "pushing buffer with timestamp %" GST_TIME_FORMAT,
     506              :         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
     507          191 :     res = gst_pad_push (srcpad->pad, outbuf);
     508          191 :     res = gst_tensor_split_combine_flows (split, srcpad, res);
     509          191 :     if (res != GST_FLOW_OK)
     510            2 :       break;
     511              :   }
     512              : 
     513           94 :   gst_buffer_unref (buf);
     514           94 :   return res;
     515              : }
     516              : 
     517              : /**
     518              :  * @brief change state (gst element vmethod)
     519              :  */
     520              : static GstStateChangeReturn
     521           70 : gst_tensor_split_change_state (GstElement * element, GstStateChange transition)
     522              : {
     523              :   GstTensorSplit *split;
     524              :   GstStateChangeReturn ret;
     525              : 
     526           70 :   split = GST_TENSOR_SPLIT (element);
     527              : 
     528           70 :   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
     529           70 :   if (ret == GST_STATE_CHANGE_FAILURE)
     530            0 :     return ret;
     531              : 
     532           70 :   switch (transition) {
     533           11 :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     534           11 :       break;
     535           12 :     case GST_STATE_CHANGE_PAUSED_TO_READY:
     536           12 :       split->group_id = G_MAXUINT;
     537           12 :       split->have_group_id = FALSE;
     538           12 :       gst_tensor_split_remove_src_pads (split);
     539           12 :       break;
     540           12 :     case GST_STATE_CHANGE_READY_TO_NULL:
     541           12 :       break;
     542           35 :     default:
     543           35 :       break;
     544              :   }
     545              : 
     546           70 :   return ret;
     547              : }
     548              : 
     549              : /**
     550              :  * @brief Glib Array Clear Function
     551              :  */
     552              : static void
     553           29 : _clear_tensorseg (tensor_dim ** element)
     554              : {
     555           29 :   g_free (*element);
     556           29 : }
     557              : 
     558              : /**
     559              :  * @brief Get property (gst element vmethod)
     560              :  */
     561              : static void
     562           18 : gst_tensor_split_set_property (GObject * object, guint prop_id,
     563              :     const GValue * value, GParamSpec * pspec)
     564              : {
     565              :   GstTensorSplit *split;
     566              : 
     567           18 :   split = GST_TENSOR_SPLIT (object);
     568              : 
     569           18 :   switch (prop_id) {
     570            2 :     case PROP_SILENT:
     571            2 :       split->silent = g_value_get_boolean (value);
     572            2 :       break;
     573            3 :     case PROP_TENSORPICK:
     574              :     {
     575              :       gint i;
     576              :       gint64 val;
     577            3 :       const gchar *param = g_value_get_string (value);
     578            3 :       gchar **strv = g_strsplit_set (param, ",.;/", -1);
     579            3 :       gint num = g_strv_length (strv);
     580           11 :       for (i = 0; i < num; i++) {
     581            8 :         val = g_ascii_strtoll (strv[i], NULL, 10);
     582            8 :         split->tensorpick =
     583            8 :             g_list_append (split->tensorpick, GINT_TO_POINTER (val));
     584              :       }
     585            3 :       g_strfreev (strv);
     586            3 :       break;
     587              :     }
     588           13 :     case PROP_TENSORSEG:
     589              :     {
     590              :       guint i;
     591           13 :       const gchar *param = g_value_get_string (value);
     592           13 :       gchar **strv = g_strsplit_set (param, ",.;/", -1);
     593           13 :       GArray *tensorseg = split->tensorseg;
     594              : 
     595           13 :       split->num_tensors = g_strv_length (strv);
     596           13 :       if (NULL == tensorseg) {
     597           13 :         split->tensorseg =
     598           13 :             g_array_sized_new (FALSE, FALSE, sizeof (tensor_dim *),
     599              :             split->num_tensors);
     600           13 :         g_array_set_clear_func (split->tensorseg,
     601              :             (GDestroyNotify) _clear_tensorseg);
     602              : 
     603           42 :         for (i = 0; i < split->num_tensors; i++) {
     604           29 :           tensor_dim *d = g_new0 (tensor_dim, 1);
     605           29 :           g_array_append_val (split->tensorseg, d);
     606              :         }
     607           13 :         tensorseg = split->tensorseg;
     608              :       }
     609           42 :       for (i = 0; i < split->num_tensors; i++) {
     610              :         gchar **p;
     611              :         gint num, k;
     612              :         tensor_dim *d;
     613           29 :         p = g_strsplit_set (strv[i], ":", -1);
     614           29 :         num = g_strv_length (p);
     615              : 
     616           29 :         d = g_array_index (tensorseg, tensor_dim *, i);
     617              : 
     618          130 :         for (k = 0; k < num; k++) {
     619          101 :           (*d)[k] = g_ascii_strtod (p[k], NULL);
     620              :         }
     621              : 
     622           29 :         g_strfreev (p);
     623              :       }
     624           13 :       g_strfreev (strv);
     625           13 :       break;
     626              :     }
     627            0 :     default:
     628            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     629            0 :       break;
     630              :   }
     631           18 : }
     632              : 
     633              : /**
     634              :  * @brief Get property (gst element vmethod)
     635              :  */
     636              : static void
     637            3 : gst_tensor_split_get_property (GObject * object, guint prop_id,
     638              :     GValue * value, GParamSpec * pspec)
     639              : {
     640              :   GstTensorSplit *split;
     641              : 
     642            3 :   split = GST_TENSOR_SPLIT (object);
     643              : 
     644            3 :   switch (prop_id) {
     645            1 :     case PROP_SILENT:
     646            1 :       g_value_set_boolean (value, split->silent);
     647            1 :       break;
     648            1 :     case PROP_TENSORPICK:
     649              :     {
     650              :       GList *list;
     651              :       char *p;
     652            1 :       GPtrArray *arr = g_ptr_array_new ();
     653              :       gchar **strings;
     654              : 
     655            4 :       for (list = split->tensorpick; list != NULL; list = list->next) {
     656            3 :         g_ptr_array_add (arr, g_strdup_printf ("%i",
     657            3 :                 GPOINTER_TO_INT (list->data)));
     658              :       }
     659            1 :       g_ptr_array_add (arr, NULL);
     660            1 :       strings = (gchar **) g_ptr_array_free (arr, FALSE);
     661            1 :       p = g_strjoinv (",", strings);
     662            1 :       g_strfreev (strings);
     663            1 :       g_value_take_string (value, p);
     664            1 :       break;
     665              :     }
     666            1 :     case PROP_TENSORSEG:
     667              :     {
     668            2 :       if ((split->tensorseg) && (split->tensorseg->len > 0)) {
     669            1 :         tensor_dim *dim = NULL;
     670            1 :         gchar *strv = NULL;
     671              :         guint i, j;
     672              : 
     673              : 
     674            4 :         for (i = 0; i < split->tensorseg->len; i++) {
     675            3 :           GPtrArray *arr = g_ptr_array_new ();
     676            3 :           gchar *p = NULL;
     677              :           gchar **strings;
     678              : 
     679            3 :           dim = g_array_index (split->tensorseg, tensor_dim *, i);
     680           51 :           for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++) {
     681           48 :             g_ptr_array_add (arr, g_strdup_printf ("%i", (*dim)[j]));
     682              :           }
     683            3 :           g_ptr_array_add (arr, NULL);
     684            3 :           strings = (gchar **) g_ptr_array_free (arr, FALSE);
     685            3 :           p = g_strjoinv (":", strings);
     686            3 :           g_strfreev (strings);
     687            3 :           if (i > 0) {
     688              :             /**
     689              :              * If i = 1, this is previous p.
     690              :              * Otherwise, it's previous g_strjoin result.
     691              :              */
     692            2 :             gchar *oldstrv = strv;
     693              : 
     694            2 :             strv = g_strjoin (",", strv, p, NULL);
     695            2 :             g_free (oldstrv);
     696            2 :             g_free (p);
     697              :           } else {
     698            1 :             strv = p;
     699              :           }
     700              :         }
     701              :         /* the second parameter, strv (i.e., gchar *v_string), is nullable */
     702            1 :         g_value_take_string (value, strv ? strv : g_strdup (""));
     703              :       } else {
     704            0 :         g_value_set_string (value, "");
     705              :       }
     706            1 :       break;
     707              :     }
     708            0 :     default:
     709            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     710            0 :       break;
     711              :   }
     712            3 : }
        

Generated by: LCOV version 2.0-1