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#58eaa3c6edb7484955a5d8c32f47a60ba9501210 Lines: 91.8 % 305 280
Test Date: 2025-04-18 05:37:26 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         1152 : 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           22 : gst_tensor_split_class_init (GstTensorSplitClass * klass)
     110              : {
     111              :   GObjectClass *gobject_class;
     112              :   GstElementClass *gstelement_class;
     113              : 
     114           22 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_split_debug, "tensor_split", 0,
     115              :       "Element to split tensors stream to tensor stream");
     116              : 
     117           22 :   gobject_class = (GObjectClass *) klass;
     118           22 :   gstelement_class = (GstElementClass *) klass;
     119              : 
     120           22 :   parent_class = g_type_class_peek_parent (klass);
     121              : 
     122           22 :   gobject_class->finalize = gst_tensor_split_finalize;
     123           22 :   gobject_class->get_property = gst_tensor_split_get_property;
     124           22 :   gobject_class->set_property = gst_tensor_split_set_property;
     125              : 
     126           22 :   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           22 :   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           22 :   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           22 :   gstelement_class->change_state =
     139           22 :       GST_DEBUG_FUNCPTR (gst_tensor_split_change_state);
     140              : 
     141           22 :   gst_element_class_add_pad_template (gstelement_class,
     142              :       gst_static_pad_template_get (&sink_templ));
     143           22 :   gst_element_class_add_pad_template (gstelement_class,
     144              :       gst_static_pad_template_get (&src_templ));
     145              : 
     146           22 :   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           22 : }
     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->in_config);
     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->in_config);
     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              : 
     228           12 :       gst_event_parse_caps (event, &caps);
     229           12 :       if (!gst_tensors_config_from_caps (&split->in_config, caps, TRUE)) {
     230            0 :         GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
     231              :             ("This stream contains no valid type."), NULL);
     232              :       }
     233           12 :       break;
     234              :     }
     235           12 :     case GST_EVENT_EOS:
     236           12 :       if (!split->srcpads) {
     237            0 :         GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
     238              :             ("This stream contains no valid stremas."),
     239              :             ("Got EOS before adding any pads"));
     240            0 :         gst_event_unref (event);
     241            0 :         return FALSE;
     242              :       }
     243           12 :       break;
     244           24 :     default:
     245           24 :       break;
     246              :   }
     247              : 
     248           48 :   return gst_pad_event_default (pad, parent, event);
     249              : }
     250              : 
     251              : /**
     252              :  * @brief Checking if the source pad is created and if not, create TensorPad
     253              :  * @param split TensorSplit Object
     254              :  * @param inbuf inputbuf GstBuffer Object including GstMeta
     255              :  * @param[out] created will be updated in this function
     256              :  * @param nth source ordering
     257              :  * @return TensorPad if pad is already created, then return created pad.
     258              :  *         If not return new pad after creation.
     259              :  */
     260              : static GstTensorPad *
     261          191 : gst_tensor_split_get_tensor_pad (GstTensorSplit * split, GstBuffer * inbuf,
     262              :     gboolean * created, guint nth)
     263              : {
     264          191 :   GstElement *element = GST_ELEMENT_CAST (split);
     265          191 :   g_autofree gchar *element_name = gst_element_get_name (element);
     266              :   GSList *walk;
     267              :   GstPad *pad;
     268              :   GstTensorPad *tensorpad;
     269              :   gchar *name;
     270              :   GstEvent *event;
     271              :   gchar *stream_id;
     272              :   GstCaps *caps;
     273              :   GstTensorsConfig pad_config;
     274              :   tensor_dim *dim;
     275              :   guint i;
     276              :   UNUSED (inbuf);
     277              : 
     278          191 :   walk = split->srcpads;
     279          304 :   while (walk) {
     280          280 :     GstTensorPad *pad = (GstTensorPad *) walk->data;
     281          280 :     if (nth == pad->nth) {
     282          167 :       if (created) {
     283          167 :         *created = FALSE;
     284              :       }
     285          167 :       return pad;
     286              :     }
     287          113 :     walk = g_slist_next (walk);
     288              :   }
     289              : 
     290           24 :   tensorpad = g_new0 (GstTensorPad, 1);
     291           24 :   g_assert (tensorpad != NULL);
     292           24 :   GST_DEBUG_OBJECT (split, "creating pad: %d(%dth)", split->num_srcpads, nth);
     293              : 
     294           24 :   name = g_strdup_printf ("src_%u", split->num_srcpads);
     295           24 :   pad = gst_pad_new_from_static_template (&src_templ, name);
     296           24 :   stream_id = gst_pad_create_stream_id_printf (pad, element,
     297              :       "%s-nnssplit-%s-%08x", element_name, name, g_random_int ());
     298           24 :   g_free (name);
     299              : 
     300           24 :   tensorpad->pad = pad;
     301           24 :   tensorpad->nth = nth;
     302           24 :   tensorpad->last_ret = GST_FLOW_OK;
     303           24 :   tensorpad->last_ts = GST_CLOCK_TIME_NONE;
     304              : 
     305           24 :   split->srcpads = g_slist_append (split->srcpads, tensorpad);
     306           24 :   dim = g_array_index (split->tensorseg, tensor_dim *, split->num_srcpads);
     307              : 
     308           24 :   split->num_srcpads++;
     309              : 
     310           24 :   gst_pad_use_fixed_caps (pad);
     311           24 :   gst_pad_set_active (pad, TRUE);
     312              : 
     313           24 :   if (!split->have_group_id) {
     314              :     event =
     315           12 :         gst_pad_get_sticky_event (split->sinkpad, GST_EVENT_STREAM_START, 0);
     316           12 :     if (event) {
     317           12 :       split->have_group_id = gst_event_parse_group_id (event, &split->group_id);
     318           12 :       gst_event_unref (event);
     319            0 :     } else if (!split->have_group_id) {
     320            0 :       split->have_group_id = TRUE;
     321            0 :       split->group_id = gst_util_group_id_next ();
     322              :     }
     323              :   }
     324              : 
     325           24 :   event = gst_event_new_stream_start (stream_id);
     326           24 :   if (split->have_group_id)
     327           24 :     gst_event_set_group_id (event, split->group_id);
     328              : 
     329           24 :   gst_pad_store_sticky_event (pad, event);
     330           24 :   g_free (stream_id);
     331           24 :   gst_event_unref (event);
     332              : 
     333              :   /* tensor config to set caps */
     334           24 :   gst_tensors_config_init (&pad_config);
     335           24 :   pad_config.info.num_tensors = 1;
     336          408 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     337          384 :     pad_config.info.info[0].dimension[i] = (*dim)[i];
     338              :   }
     339           24 :   pad_config.info.info[0].type = split->in_config.info.info[0].type;
     340           24 :   pad_config.rate_n = split->in_config.rate_n;
     341           24 :   pad_config.rate_d = split->in_config.rate_d;
     342              : 
     343           24 :   caps = gst_tensor_pad_caps_from_config (pad, &pad_config);
     344              : 
     345           24 :   gst_pad_set_caps (pad, caps);
     346           24 :   gst_element_add_pad (GST_ELEMENT_CAST (split), pad);
     347              : 
     348           24 :   gst_caps_unref (caps);
     349              : 
     350           24 :   if (created) {
     351           24 :     *created = TRUE;
     352              :   }
     353              : 
     354           24 :   if (split->tensorpick != NULL) {
     355            5 :     GST_DEBUG_OBJECT (split, "TensorPick is set! : %dth tensor\n", nth);
     356            5 :     if (g_list_length (split->tensorpick) == split->num_srcpads) {
     357            2 :       gst_element_no_more_pads (GST_ELEMENT_CAST (split));
     358              :     }
     359              :   }
     360              : 
     361           24 :   return tensorpad;
     362              : }
     363              : 
     364              : /**
     365              :  * @brief Check the status among sources in split
     366              :  * @param split TensorSplit Object
     367              :  * @param TensorPad Tensorpad
     368              :  * @param ret return status of current pad
     369              :  * @return return status after check sources
     370              :  */
     371              : static GstFlowReturn
     372          191 : gst_tensor_split_combine_flows (GstTensorSplit * split,
     373              :     GstTensorPad * pad, GstFlowReturn ret)
     374              : {
     375              :   GSList *walk;
     376              :   GstTensorPad *opad;
     377              : 
     378          191 :   pad->last_ret = ret;
     379          191 :   if (ret != GST_FLOW_NOT_LINKED)
     380          147 :     goto done;
     381              : 
     382           44 :   for (walk = split->srcpads; walk; walk = g_slist_next (walk)) {
     383           44 :     opad = (GstTensorPad *) walk->data;
     384           44 :     ret = opad->last_ret;
     385           44 :     if (ret != GST_FLOW_NOT_LINKED)
     386           44 :       goto done;
     387              :   }
     388            0 : done:
     389          191 :   return ret;
     390              : }
     391              : 
     392              : /**
     393              :  * @brief Make splitted tensor
     394              :  * @param split TensorSplit object
     395              :  * @param buffer gstbuffer form src
     396              :  * @param nth orther of tensor
     397              :  * @return return GstMemory for splitted tensor
     398              :  */
     399              : static GstMemory *
     400          191 : gst_tensor_split_get_splitted (GstTensorSplit * split, GstBuffer * buffer,
     401              :     gint nth)
     402              : {
     403              :   GstMemory *mem;
     404              :   tensor_dim *dim;
     405              :   int i;
     406              :   gsize size, offset;
     407              :   GstMapInfo src_info, dest_info;
     408              : 
     409          191 :   dim = g_array_index (split->tensorseg, tensor_dim *, nth);
     410          191 :   size = gst_tensor_get_element_count (*dim) *
     411          191 :       gst_tensor_get_element_size (split->in_config.info.info[0].type);
     412              : 
     413          191 :   mem = gst_allocator_alloc (NULL, size, NULL);
     414          191 :   if (!gst_memory_map (mem, &dest_info, GST_MAP_WRITE)) {
     415            0 :     ml_logf ("Cannot map memory for destination buffer.\n");
     416            0 :     gst_memory_unref (mem);
     417          191 :     return NULL;
     418              :   }
     419          191 :   if (!gst_buffer_map (buffer, &src_info, GST_MAP_READ)) {
     420            0 :     ml_logf ("Cannot map src-memory to gst buffer at tensor-split.\n");
     421            0 :     gst_memory_unmap (mem, &dest_info);
     422            0 :     gst_memory_unref (mem);
     423            0 :     return NULL;
     424              :   }
     425              : 
     426          191 :   offset = 0;
     427          304 :   for (i = 0; i < nth; i++) {
     428          113 :     dim = g_array_index (split->tensorseg, tensor_dim *, i);
     429          113 :     offset += gst_tensor_get_element_count (*dim) *
     430          113 :         gst_tensor_get_element_size (split->in_config.info.info[0].type);
     431              :   }
     432              : 
     433          191 :   nns_memcpy (dest_info.data, src_info.data + offset, size);
     434          191 :   gst_buffer_unmap (buffer, &src_info);
     435          191 :   gst_memory_unmap (mem, &dest_info);
     436              : 
     437          191 :   return mem;
     438              : }
     439              : 
     440              : /**
     441              :  * @brief chain function for sink (gst element vmethod)
     442              :  */
     443              : static GstFlowReturn
     444           94 : gst_tensor_split_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     445              : {
     446              :   GstTensorSplit *split;
     447              :   guint num_tensors, i;
     448           94 :   GstFlowReturn res = GST_FLOW_OK;
     449              :   UNUSED (pad);
     450              : 
     451           94 :   split = GST_TENSOR_SPLIT (parent);
     452              : 
     453           94 :   num_tensors = split->num_tensors;
     454           94 :   GST_DEBUG_OBJECT (split, " Number of Tensors: %d", num_tensors);
     455              : 
     456           94 :   if (split->tensorseg == NULL) {
     457            0 :     GST_ERROR_OBJECT (split, "No rule to split incoming buffers.");
     458            0 :     return GST_FLOW_ERROR;
     459              :   }
     460              : 
     461          293 :   for (i = 0; i < num_tensors; i++) {
     462              :     GstTensorPad *srcpad;
     463              :     GstBuffer *outbuf;
     464              :     GstMemory *mem;
     465              :     gboolean created;
     466              :     GstClockTime ts;
     467              : 
     468          201 :     if (split->tensorpick != NULL) {
     469           45 :       gboolean found = FALSE;
     470              :       GList *list;
     471           90 :       for (list = split->tensorpick; list != NULL; list = list->next) {
     472           80 :         if (i == GPOINTER_TO_UINT (list->data)) {
     473           35 :           found = TRUE;
     474           35 :           break;
     475              :         }
     476              :       }
     477           45 :       if (!found)
     478           10 :         continue;
     479              :     }
     480              : 
     481          191 :     srcpad = gst_tensor_split_get_tensor_pad (split, buf, &created, i);
     482              : 
     483          191 :     outbuf = gst_buffer_new ();
     484          191 :     mem = gst_tensor_split_get_splitted (split, buf, i);
     485          191 :     gst_buffer_append_memory (outbuf, mem);
     486          191 :     ts = GST_BUFFER_TIMESTAMP (buf);
     487              : 
     488          191 :     if (created) {
     489              :       GstSegment segment;
     490           24 :       gst_segment_init (&segment, GST_FORMAT_TIME);
     491           24 :       gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
     492              :     }
     493              : 
     494          191 :     outbuf = gst_buffer_make_writable (outbuf);
     495              : 
     496              :     /* metadata from incoming buffer */
     497          191 :     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
     498              : 
     499          191 :     if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
     500          191 :       srcpad->last_ts = ts;
     501              :     } else {
     502            0 :       GST_DEBUG_OBJECT (split, "invalid timestamp %" GST_TIME_FORMAT,
     503              :           GST_TIME_ARGS (ts));
     504              :     }
     505              : 
     506          191 :     GST_DEBUG_OBJECT (split, "pushing buffer with timestamp %" GST_TIME_FORMAT,
     507              :         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
     508          191 :     res = gst_pad_push (srcpad->pad, outbuf);
     509          191 :     res = gst_tensor_split_combine_flows (split, srcpad, res);
     510          191 :     if (res != GST_FLOW_OK)
     511            2 :       break;
     512              :   }
     513              : 
     514           94 :   gst_buffer_unref (buf);
     515           94 :   return res;
     516              : }
     517              : 
     518              : /**
     519              :  * @brief change state (gst element vmethod)
     520              :  */
     521              : static GstStateChangeReturn
     522           70 : gst_tensor_split_change_state (GstElement * element, GstStateChange transition)
     523              : {
     524              :   GstTensorSplit *split;
     525              :   GstStateChangeReturn ret;
     526              : 
     527           70 :   split = GST_TENSOR_SPLIT (element);
     528              : 
     529           70 :   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
     530           70 :   if (ret == GST_STATE_CHANGE_FAILURE)
     531            0 :     return ret;
     532              : 
     533           70 :   switch (transition) {
     534           11 :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     535           11 :       break;
     536           12 :     case GST_STATE_CHANGE_PAUSED_TO_READY:
     537           12 :       split->group_id = G_MAXUINT;
     538           12 :       split->have_group_id = FALSE;
     539           12 :       gst_tensor_split_remove_src_pads (split);
     540           12 :       break;
     541           12 :     case GST_STATE_CHANGE_READY_TO_NULL:
     542           12 :       break;
     543           35 :     default:
     544           35 :       break;
     545              :   }
     546              : 
     547           70 :   return ret;
     548              : }
     549              : 
     550              : /**
     551              :  * @brief Glib Array Clear Function
     552              :  */
     553              : static void
     554           29 : _clear_tensorseg (tensor_dim ** element)
     555              : {
     556           29 :   g_free (*element);
     557           29 : }
     558              : 
     559              : /**
     560              :  * @brief Get property (gst element vmethod)
     561              :  */
     562              : static void
     563           18 : gst_tensor_split_set_property (GObject * object, guint prop_id,
     564              :     const GValue * value, GParamSpec * pspec)
     565              : {
     566              :   GstTensorSplit *split;
     567              : 
     568           18 :   split = GST_TENSOR_SPLIT (object);
     569              : 
     570           18 :   switch (prop_id) {
     571            2 :     case PROP_SILENT:
     572            2 :       split->silent = g_value_get_boolean (value);
     573            2 :       break;
     574            3 :     case PROP_TENSORPICK:
     575              :     {
     576              :       gint i;
     577              :       gint64 val;
     578            3 :       const gchar *param = g_value_get_string (value);
     579            3 :       gchar **strv = g_strsplit_set (param, ",.;/", -1);
     580            3 :       gint num = g_strv_length (strv);
     581           11 :       for (i = 0; i < num; i++) {
     582            8 :         val = g_ascii_strtoll (strv[i], NULL, 10);
     583            8 :         split->tensorpick =
     584            8 :             g_list_append (split->tensorpick, GINT_TO_POINTER (val));
     585              :       }
     586            3 :       g_strfreev (strv);
     587            3 :       break;
     588              :     }
     589           13 :     case PROP_TENSORSEG:
     590              :     {
     591              :       guint i;
     592           13 :       const gchar *param = g_value_get_string (value);
     593           13 :       gchar **strv = g_strsplit_set (param, ",.;/", -1);
     594           13 :       GArray *tensorseg = split->tensorseg;
     595              : 
     596           13 :       split->num_tensors = g_strv_length (strv);
     597           13 :       if (NULL == tensorseg) {
     598           13 :         split->tensorseg =
     599           13 :             g_array_sized_new (FALSE, FALSE, sizeof (tensor_dim *),
     600              :             split->num_tensors);
     601           13 :         g_array_set_clear_func (split->tensorseg,
     602              :             (GDestroyNotify) _clear_tensorseg);
     603              : 
     604           42 :         for (i = 0; i < split->num_tensors; i++) {
     605           29 :           tensor_dim *d = g_new0 (tensor_dim, 1);
     606           29 :           g_array_append_val (split->tensorseg, d);
     607              :         }
     608           13 :         tensorseg = split->tensorseg;
     609              :       }
     610           42 :       for (i = 0; i < split->num_tensors; i++) {
     611              :         gchar **p;
     612              :         gint num, k;
     613              :         tensor_dim *d;
     614           29 :         p = g_strsplit_set (strv[i], ":", -1);
     615           29 :         num = g_strv_length (p);
     616              : 
     617           29 :         d = g_array_index (tensorseg, tensor_dim *, i);
     618              : 
     619          130 :         for (k = 0; k < num; k++) {
     620          101 :           (*d)[k] = g_ascii_strtod (p[k], NULL);
     621              :         }
     622              : 
     623           29 :         g_strfreev (p);
     624              :       }
     625           13 :       g_strfreev (strv);
     626           13 :       break;
     627              :     }
     628            0 :     default:
     629            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     630            0 :       break;
     631              :   }
     632           18 : }
     633              : 
     634              : /**
     635              :  * @brief Get property (gst element vmethod)
     636              :  */
     637              : static void
     638            3 : gst_tensor_split_get_property (GObject * object, guint prop_id,
     639              :     GValue * value, GParamSpec * pspec)
     640              : {
     641              :   GstTensorSplit *split;
     642              : 
     643            3 :   split = GST_TENSOR_SPLIT (object);
     644              : 
     645            3 :   switch (prop_id) {
     646            1 :     case PROP_SILENT:
     647            1 :       g_value_set_boolean (value, split->silent);
     648            1 :       break;
     649            1 :     case PROP_TENSORPICK:
     650              :     {
     651              :       GList *list;
     652              :       char *p;
     653            1 :       GPtrArray *arr = g_ptr_array_new ();
     654              :       gchar **strings;
     655              : 
     656            4 :       for (list = split->tensorpick; list != NULL; list = list->next) {
     657            3 :         g_ptr_array_add (arr, g_strdup_printf ("%i",
     658            3 :                 GPOINTER_TO_INT (list->data)));
     659              :       }
     660            1 :       g_ptr_array_add (arr, NULL);
     661            1 :       strings = (gchar **) g_ptr_array_free (arr, FALSE);
     662            1 :       p = g_strjoinv (",", strings);
     663            1 :       g_strfreev (strings);
     664            1 :       g_value_take_string (value, p);
     665            1 :       break;
     666              :     }
     667            1 :     case PROP_TENSORSEG:
     668              :     {
     669            2 :       if ((split->tensorseg) && (split->tensorseg->len > 0)) {
     670            1 :         tensor_dim *dim = NULL;
     671            1 :         gchar *strv = NULL;
     672              :         guint i, j;
     673              : 
     674              : 
     675            4 :         for (i = 0; i < split->tensorseg->len; i++) {
     676            3 :           GPtrArray *arr = g_ptr_array_new ();
     677            3 :           gchar *p = NULL;
     678              :           gchar **strings;
     679              : 
     680            3 :           dim = g_array_index (split->tensorseg, tensor_dim *, i);
     681           51 :           for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++) {
     682           48 :             g_ptr_array_add (arr, g_strdup_printf ("%i", (*dim)[j]));
     683              :           }
     684            3 :           g_ptr_array_add (arr, NULL);
     685            3 :           strings = (gchar **) g_ptr_array_free (arr, FALSE);
     686            3 :           p = g_strjoinv (":", strings);
     687            3 :           g_strfreev (strings);
     688            3 :           if (i > 0) {
     689              :             /**
     690              :              * If i = 1, this is previous p.
     691              :              * Otherwise, it's previous g_strjoin result.
     692              :              */
     693            2 :             gchar *oldstrv = strv;
     694              : 
     695            2 :             strv = g_strjoin (",", strv, p, NULL);
     696            2 :             g_free (oldstrv);
     697            2 :             g_free (p);
     698              :           } else {
     699            1 :             strv = p;
     700              :           }
     701              :         }
     702              :         /* the second parameter, strv (i.e., gchar *v_string), is nullable */
     703            1 :         g_value_take_string (value, strv ? strv : g_strdup (""));
     704              :       } else {
     705            0 :         g_value_set_string (value, "");
     706              :       }
     707            1 :       break;
     708              :     }
     709            0 :     default:
     710            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     711            0 :       break;
     712              :   }
     713            3 : }
        

Generated by: LCOV version 2.0-1