LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/nnstreamer/elements - gsttensor_demux.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 90.7 % 269 244
Test Date: 2025-03-14 05:36:58 Functions: 100.0 % 15 15

            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_demux.c
      20              :  * @date        03 July 2018
      21              :  * @brief       GStreamer plugin to demux tensors (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_demux
      30              :  *
      31              :  * A Demuxer that demux tensors stream to tensor(s) stream for NN frameworks.
      32              :  * The output is always in the format of other/tensor or other/tensors.
      33              :  *
      34              :  * <refsect2>
      35              :  * <title>Example launch line</title>
      36              :  * |[
      37              :  * gst-launch-1.0 tensor_mux name=mux ! tensor_demux name=demux \
      38              :  * filesrc location=testcase01_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1  ! tensor_converter ! mux.sink_0 \
      39              :  * filesrc location=testcase01_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1  ! tensor_converter ! mux.sink_1 \
      40              :  * filesrc location=testcase01_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1  ! tensor_converter ! mux.sink_2 \
      41              :  * demux.src_0 ! queue ! filesink location=demux00.log \
      42              :  * demux.src_1 ! queue ! filesink location=demux01.log \
      43              :  * demux.src_2 ! queue ! filesink location=demux02.log
      44              :  * ]|
      45              :  *
      46              :  * |[
      47              :  * gst-launch-1.0 tensor_mux name=mux ! tensor_demux name=demux tensorpick=0,1:2,2+0 \
      48              :  * ... (tensor 0) ! mux.sink_0 \
      49              :  * ... (tensor 1) ! mux.sink_1 \
      50              :  * ... (tensor 2) ! mux.sink_2 \
      51              :  * demux.src_0 ! (tensor 0) ...
      52              :  * demux.src_1 ! (tensor 1,2) ...
      53              :  * demux.src_2 ! (tensor 2,0) ...
      54              :  * ]|
      55              :  *
      56              :  * </refsect2>
      57              :  *
      58              :  */
      59              : 
      60              : 
      61              : #ifdef HAVE_CONFIG_H
      62              : #include <config.h>
      63              : #endif
      64              : 
      65              : #include <string.h>
      66              : #include <gst/gst.h>
      67              : #include <glib.h>
      68              : #include <nnstreamer_util.h>
      69              : 
      70              : #include "gsttensor_demux.h"
      71              : 
      72              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_demux_debug);
      73              : #define GST_CAT_DEFAULT gst_tensor_demux_debug
      74              : 
      75              : /**
      76              :  * @brief Default caps string for sink pad.
      77              :  */
      78              : #define CAPS_STRING_SINK GST_TENSORS_CAP_MAKE ("{ static, flexible }")
      79              : 
      80              : /**
      81              :  * @brief Default caps string for src pad.
      82              :  */
      83              : #define CAPS_STRING_SRC GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_MAKE ("{ static, flexible }")
      84              : 
      85              : enum
      86              : {
      87              :   PROP_0,
      88              :   PROP_SILENT,
      89              :   PROP_TENSORPICK
      90              : };
      91              : 
      92              : /**
      93              :  * @brief the capabilities of the inputs and outputs.
      94              :  * describe the real formats here.
      95              :  */
      96              : static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src_%u",
      97              :     GST_PAD_SRC,
      98              :     GST_PAD_SOMETIMES,
      99              :     GST_STATIC_CAPS (CAPS_STRING_SRC)
     100              :     );
     101              : 
     102              : static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
     103              :     GST_PAD_SINK,
     104              :     GST_PAD_ALWAYS,
     105              :     GST_STATIC_CAPS (CAPS_STRING_SINK)
     106              :     );
     107              : 
     108              : static GstFlowReturn gst_tensor_demux_chain (GstPad * pad, GstObject * parent,
     109              :     GstBuffer * buf);
     110              : static gboolean gst_tensor_demux_event (GstPad * pad, GstObject * parent,
     111              :     GstEvent * event);
     112              : static GstStateChangeReturn gst_tensor_demux_change_state (GstElement * element,
     113              :     GstStateChange transition);
     114              : static void gst_tensor_demux_set_property (GObject * object, guint prop_id,
     115              :     const GValue * value, GParamSpec * pspec);
     116              : static void gst_tensor_demux_get_property (GObject * object, guint prop_id,
     117              :     GValue * value, GParamSpec * pspec);
     118              : static void gst_tensor_demux_dispose (GObject * object);
     119              : #define gst_tensor_demux_parent_class parent_class
     120         1403 : G_DEFINE_TYPE (GstTensorDemux, gst_tensor_demux, GST_TYPE_ELEMENT);
     121              : 
     122              : 
     123              : /**
     124              :  * @brief initialize the tensor_demux's class
     125              :  */
     126              : static void
     127           24 : gst_tensor_demux_class_init (GstTensorDemuxClass * klass)
     128              : {
     129              :   GObjectClass *gobject_class;
     130              :   GstElementClass *gstelement_class;
     131              : 
     132           24 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_demux_debug, "tensor_demux", 0,
     133              :       "Element to demux tensors to tensor stream");
     134              : 
     135           24 :   gobject_class = (GObjectClass *) klass;
     136           24 :   gstelement_class = (GstElementClass *) klass;
     137              : 
     138           24 :   parent_class = g_type_class_peek_parent (klass);
     139              : 
     140           24 :   gobject_class->dispose = gst_tensor_demux_dispose;
     141           24 :   gobject_class->get_property = gst_tensor_demux_get_property;
     142           24 :   gobject_class->set_property = gst_tensor_demux_set_property;
     143              : 
     144           24 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     145              :       g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
     146              :           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     147              : 
     148           24 :   g_object_class_install_property (gobject_class, PROP_TENSORPICK,
     149              :       g_param_spec_string ("tensorpick", "TensorPick",
     150              :           "Choose nth tensor among tensors ?", "",
     151              :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     152              : 
     153           24 :   gstelement_class->change_state =
     154           24 :       GST_DEBUG_FUNCPTR (gst_tensor_demux_change_state);
     155              : 
     156           24 :   gst_element_class_add_pad_template (gstelement_class,
     157              :       gst_static_pad_template_get (&sink_templ));
     158           24 :   gst_element_class_add_pad_template (gstelement_class,
     159              :       gst_static_pad_template_get (&src_templ));
     160              : 
     161           24 :   gst_element_class_set_details_simple (gstelement_class,
     162              :       "TensorDemux",
     163              :       "Demuxer/Tensor",
     164              :       "Demux tensors stream to other/tensor stream",
     165              :       "Jijoong Moon <jijoong.moon@samsung.com>");
     166           24 : }
     167              : 
     168              : /**
     169              :  * @brief initialize the new element
     170              :  * instantiate pads and add them to element
     171              :  * set pad callback functions
     172              :  * initialize instance structure
     173              :  */
     174              : static void
     175           33 : gst_tensor_demux_init (GstTensorDemux * tensor_demux)
     176              : {
     177           33 :   tensor_demux->sinkpad =
     178           33 :       gst_pad_new_from_static_template (&sink_templ, "sink");
     179           33 :   gst_element_add_pad (GST_ELEMENT_CAST (tensor_demux), tensor_demux->sinkpad);
     180           33 :   gst_pad_set_chain_function (tensor_demux->sinkpad,
     181              :       GST_DEBUG_FUNCPTR (gst_tensor_demux_chain));
     182           33 :   gst_pad_set_event_function (tensor_demux->sinkpad,
     183              :       GST_DEBUG_FUNCPTR (gst_tensor_demux_event));
     184              : 
     185           33 :   tensor_demux->num_srcpads = 0;
     186           33 :   tensor_demux->silent = TRUE;
     187           33 :   tensor_demux->tensorpick = NULL;
     188           33 :   tensor_demux->have_group_id = FALSE;
     189           33 :   tensor_demux->group_id = G_MAXUINT;
     190           33 :   tensor_demux->srcpads = NULL;
     191              : 
     192           33 :   gst_tensors_config_init (&tensor_demux->tensors_config);
     193           33 : }
     194              : 
     195              : /**
     196              :  * @brief function to remove srcpad list
     197              :  */
     198              : static void
     199           63 : gst_tensor_demux_remove_src_pads (GstTensorDemux * tensor_demux)
     200              : {
     201          149 :   while (tensor_demux->srcpads != NULL) {
     202           86 :     GstTensorPad *tensor_pad = tensor_demux->srcpads->data;
     203           86 :     gst_element_remove_pad (GST_ELEMENT (tensor_demux), tensor_pad->pad);
     204           86 :     g_free (tensor_pad);
     205           86 :     tensor_demux->srcpads =
     206           86 :         g_slist_delete_link (tensor_demux->srcpads, tensor_demux->srcpads);
     207              :   }
     208           63 :   tensor_demux->srcpads = NULL;
     209           63 :   tensor_demux->num_srcpads = 0;
     210              : 
     211           63 :   gst_tensors_config_free (&tensor_demux->tensors_config);
     212           63 :   gst_tensors_config_init (&tensor_demux->tensors_config);
     213           63 : }
     214              : 
     215              : /**
     216              :  * @brief dispose function for tensor demux (gst element vmethod)
     217              :  */
     218              : static void
     219           32 : gst_tensor_demux_dispose (GObject * object)
     220              : {
     221           32 :   GstTensorDemux *tensor_demux = GST_TENSOR_DEMUX (object);
     222              : 
     223           32 :   gst_tensor_demux_remove_src_pads (tensor_demux);
     224           32 :   g_list_free_full (tensor_demux->tensorpick, g_free);
     225           32 :   G_OBJECT_CLASS (parent_class)->dispose (object);
     226           32 : }
     227              : 
     228              : /**
     229              :  * @brief event function for sink (gst element vmethod)
     230              :  */
     231              : static gboolean
     232          128 : gst_tensor_demux_event (GstPad * pad, GstObject * parent, GstEvent * event)
     233              : {
     234              :   GstTensorDemux *tensor_demux;
     235          128 :   tensor_demux = GST_TENSOR_DEMUX (parent);
     236              : 
     237          128 :   switch (GST_EVENT_TYPE (event)) {
     238           31 :     case GST_EVENT_CAPS:
     239              :     {
     240              :       GstCaps *caps;
     241           31 :       gst_event_parse_caps (event, &caps);
     242           31 :       gst_tensors_config_from_cap (&tensor_demux->tensors_config, caps);
     243           31 :       break;
     244              :     }
     245           31 :     case GST_EVENT_EOS:
     246           31 :       if (!tensor_demux->srcpads) {
     247            1 :         GST_ELEMENT_ERROR (tensor_demux, STREAM, WRONG_TYPE,
     248              :             ("This stream contains no valid stremas."),
     249              :             ("Got EOS before adding any pads"));
     250            1 :         gst_event_unref (event);
     251            1 :         return FALSE;
     252              :       }
     253           30 :       break;
     254           66 :     default:
     255           66 :       break;
     256              :   }
     257              : 
     258          127 :   return gst_pad_event_default (pad, parent, event);
     259              : }
     260              : 
     261              : /**
     262              :  * @brief Get tensor config info from configured tensors
     263              :  * @param tensor_demux "this" pointer
     264              :  * @param config tensor config to be filled
     265              :  * @param nth source ordering
     266              :  * @param total number of tensors
     267              :  * @return TRUE if successfully configured
     268              :  */
     269              : static gboolean
     270           86 : gst_tensor_demux_get_tensor_config (GstTensorDemux * tensor_demux,
     271              :     GstTensorsConfig * config, const guint nth, const guint total)
     272              : {
     273           86 :   gst_tensors_config_init (config);
     274              : 
     275           86 :   if (tensor_demux->tensorpick != NULL) {
     276              :     gchar *selected_tensor;
     277              :     gchar **strv;
     278              :     guint i, num, idx;
     279              : 
     280           15 :     g_assert (g_list_length (tensor_demux->tensorpick) >= nth);
     281              : 
     282           15 :     selected_tensor = (gchar *) g_list_nth_data (tensor_demux->tensorpick, nth);
     283           15 :     strv = g_strsplit_set (selected_tensor, ":+", -1);
     284           15 :     num = g_strv_length (strv);
     285              : 
     286           32 :     for (i = 0; i < num; i++) {
     287           17 :       idx = (guint) g_ascii_strtoll (strv[i], NULL, 10);
     288              : 
     289              :       /* Internal error, handle invalid index. */
     290           17 :       if (idx >= total) {
     291            0 :         g_strfreev (strv);
     292            0 :         return FALSE;
     293              :       }
     294              : 
     295           17 :       gst_tensor_info_copy (gst_tensors_info_get_nth_info (&config->info, i),
     296           17 :           gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
     297              :               idx));
     298              :     }
     299              : 
     300           15 :     config->info.num_tensors = num;
     301           15 :     g_strfreev (strv);
     302              :   } else {
     303              :     /* Internal error, handle invalid index. */
     304           71 :     if (nth >= total)
     305            0 :       return FALSE;
     306              : 
     307           71 :     config->info.num_tensors = 1;
     308           71 :     gst_tensor_info_copy (&config->info.info[0],
     309           71 :         gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
     310              :             nth));
     311              :   }
     312              : 
     313           86 :   config->info.format = tensor_demux->tensors_config.info.format;
     314           86 :   config->rate_n = tensor_demux->tensors_config.rate_n;
     315           86 :   config->rate_d = tensor_demux->tensors_config.rate_d;
     316           86 :   return TRUE;
     317              : }
     318              : 
     319              : /**
     320              :  * @brief Checking if the source pad is created and if not, create TensorPad
     321              :  * @param tensor_demux TensorDemux Object
     322              :  * @param[out] created will be updated in this function
     323              :  * @param nth source ordering
     324              :  * @param total number of tensors
     325              :  * @return TensorPad if pad is already created, then return created pad.
     326              :  *         If not return new pad after creation.
     327              :  */
     328              : static GstTensorPad *
     329          429 : gst_tensor_demux_get_tensor_pad (GstTensorDemux * tensor_demux,
     330              :     gboolean * created, const guint nth, const guint total)
     331              : {
     332          429 :   GstElement *element = GST_ELEMENT_CAST (tensor_demux);
     333          429 :   g_autofree gchar *element_name = gst_element_get_name (element);
     334              :   GSList *walk;
     335              :   GstPad *pad;
     336              :   GstTensorPad *tensorpad;
     337              :   gchar *name;
     338              :   GstEvent *event;
     339              :   gchar *stream_id;
     340          429 :   GstCaps *caps = NULL;
     341              :   GstTensorsConfig config;
     342              : 
     343          429 :   walk = tensor_demux->srcpads;
     344         1642 :   while (walk) {
     345         1556 :     GstTensorPad *pad = (GstTensorPad *) walk->data;
     346         1556 :     if (nth == pad->nth) {
     347          343 :       if (created) {
     348          343 :         *created = FALSE;
     349              :       }
     350          343 :       return pad;
     351              :     }
     352         1213 :     walk = walk->next;
     353              :   }
     354              : 
     355           86 :   tensorpad = g_new0 (GstTensorPad, 1);
     356           86 :   g_assert (tensorpad != NULL);
     357           86 :   GST_DEBUG_OBJECT (tensor_demux, "creating pad: %d(%dth)",
     358              :       tensor_demux->num_srcpads, nth);
     359              : 
     360           86 :   name = g_strdup_printf ("src_%u", tensor_demux->num_srcpads);
     361           86 :   pad = gst_pad_new_from_static_template (&src_templ, name);
     362           86 :   stream_id = gst_pad_create_stream_id_printf (pad, element,
     363              :       "%s-nnsdemux-%s-%08x", element_name, name, g_random_int ());
     364           86 :   g_free (name);
     365              : 
     366           86 :   tensorpad->pad = pad;
     367           86 :   tensorpad->nth = nth;
     368           86 :   tensorpad->last_ret = GST_FLOW_OK;
     369           86 :   tensorpad->last_ts = GST_CLOCK_TIME_NONE;
     370              : 
     371           86 :   tensor_demux->srcpads = g_slist_append (tensor_demux->srcpads, tensorpad);
     372           86 :   tensor_demux->num_srcpads++;
     373              : 
     374           86 :   gst_pad_use_fixed_caps (pad);
     375           86 :   gst_pad_set_active (pad, TRUE);
     376           86 :   gst_element_add_pad (GST_ELEMENT_CAST (tensor_demux), pad);
     377              : 
     378           86 :   if (!tensor_demux->have_group_id) {
     379              :     event =
     380           86 :         gst_pad_get_sticky_event (tensor_demux->sinkpad, GST_EVENT_STREAM_START,
     381              :         0);
     382           86 :     if (event) {
     383           86 :       tensor_demux->have_group_id =
     384           86 :           gst_event_parse_group_id (event, &tensor_demux->group_id);
     385           86 :       gst_event_unref (event);
     386            0 :     } else if (!tensor_demux->have_group_id) {
     387            0 :       tensor_demux->have_group_id = TRUE;
     388            0 :       tensor_demux->group_id = gst_util_group_id_next ();
     389              :     }
     390              :   }
     391              : 
     392           86 :   event = gst_event_new_stream_start (stream_id);
     393           86 :   if (tensor_demux->have_group_id)
     394            0 :     gst_event_set_group_id (event, tensor_demux->group_id);
     395              : 
     396           86 :   gst_pad_store_sticky_event (pad, event);
     397           86 :   g_free (stream_id);
     398           86 :   gst_event_unref (event);
     399              : 
     400              :   /* configure nth pad caps */
     401           86 :   if (gst_tensor_demux_get_tensor_config (tensor_demux, &config, nth, total)) {
     402           86 :     caps = gst_tensor_pad_caps_from_config (pad, &config);
     403              : 
     404           86 :     gst_pad_set_caps (pad, caps);
     405           86 :     gst_caps_unref (caps);
     406              :   } else {
     407            0 :     GST_WARNING_OBJECT (tensor_demux, "Unable to set pad caps");
     408              :   }
     409              : 
     410           86 :   if (created) {
     411           86 :     *created = TRUE;
     412              :   }
     413              : 
     414           86 :   if (tensor_demux->tensorpick != NULL) {
     415           15 :     GST_DEBUG_OBJECT (tensor_demux, "TensorPick is set! : %dth tensor\n", nth);
     416           15 :     if (g_list_length (tensor_demux->tensorpick) == tensor_demux->num_srcpads) {
     417            9 :       gst_element_no_more_pads (GST_ELEMENT_CAST (tensor_demux));
     418              :     }
     419              :   }
     420              : 
     421           86 :   gst_tensors_config_free (&config);
     422           86 :   return tensorpad;
     423              : }
     424              : 
     425              : /**
     426              :  * @brief Check the status among sources in demux
     427              :  * @param tensor_demux TensorDemux Object
     428              :  * @param TensorPad Tensorpad
     429              :  * @param ret return status of current pad
     430              :  * @return return status after check sources
     431              :  */
     432              : static GstFlowReturn
     433          429 : gst_tensor_demux_combine_flows (GstTensorDemux * tensor_demux,
     434              :     GstTensorPad * pad, GstFlowReturn ret)
     435              : {
     436              :   GSList *walk;
     437          429 :   pad->last_ret = ret;
     438              : 
     439          429 :   if (ret != GST_FLOW_NOT_LINKED)
     440          344 :     goto done;
     441              : 
     442           85 :   for (walk = tensor_demux->srcpads; walk; walk = g_slist_next (walk)) {
     443           85 :     GstTensorPad *opad = (GstTensorPad *) walk->data;
     444           85 :     ret = opad->last_ret;
     445           85 :     if (ret != GST_FLOW_NOT_LINKED)
     446           85 :       goto done;
     447              :   }
     448            0 : done:
     449          429 :   return ret;
     450              : }
     451              : 
     452              : /**
     453              :  * @brief chain function for sink (gst element vmethod)
     454              :  */
     455              : static GstFlowReturn
     456          151 : gst_tensor_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
     457              : {
     458              :   guint num_tensors, num_srcs, i, idx;
     459          151 :   GstFlowReturn res = GST_FLOW_OK;
     460              :   GstTensorDemux *tensor_demux;
     461          151 :   GList *list = NULL;
     462              :   GstTensorInfo *_info;
     463              : 
     464              :   UNUSED (pad);
     465          151 :   tensor_demux = GST_TENSOR_DEMUX (parent);
     466              : 
     467          151 :   buf = gst_tensor_buffer_from_config (buf, &tensor_demux->tensors_config);
     468              : 
     469              :   /**
     470              :    * The number of tensors in the buffer:
     471              :    * The number of tensors from caps and gst-buffer should be same when incoming buffer is static tensor.
     472              :    * If given buffer is flexible tensor, we cannot get exact number of tensors from config.
     473              :    */
     474          151 :   num_tensors = gst_tensor_buffer_get_count (buf);
     475          151 :   if (gst_tensors_config_is_static (&tensor_demux->tensors_config))
     476          144 :     g_assert (tensor_demux->tensors_config.info.num_tensors == num_tensors);
     477              : 
     478          151 :   GST_DEBUG_OBJECT (tensor_demux, " Number of Tensors: %d", num_tensors);
     479              : 
     480          151 :   num_srcs = num_tensors;
     481          151 :   if (tensor_demux->tensorpick != NULL) {
     482           44 :     num_srcs = g_list_length (tensor_demux->tensorpick);
     483           44 :     list = tensor_demux->tensorpick;
     484              :   }
     485              : 
     486          577 :   for (i = 0; i < num_srcs; i++) {
     487              :     GstTensorPad *srcpad;
     488              :     GstBuffer *outbuf;
     489              :     GstMemory *mem;
     490              :     gboolean created;
     491              :     GstClockTime ts;
     492              : 
     493          429 :     srcpad = gst_tensor_demux_get_tensor_pad (tensor_demux, &created, i,
     494              :         num_tensors);
     495          429 :     outbuf = gst_buffer_new ();
     496              : 
     497          429 :     if (tensor_demux->tensorpick != NULL) {
     498              :       guint num, j;
     499           67 :       gchar **strv = g_strsplit_set ((gchar *) list->data, ":+", -1);
     500              : 
     501           67 :       num = g_strv_length (strv);
     502          136 :       for (j = 0; j < num; j++) {
     503           69 :         idx = (guint) g_ascii_strtoll (strv[j], NULL, 10);
     504              :         _info =
     505           69 :             gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
     506              :             idx);
     507           69 :         mem = gst_tensor_buffer_get_nth_memory (buf, idx);
     508           69 :         if (!gst_tensor_buffer_append_memory (outbuf, mem, _info)) {
     509            0 :           gst_buffer_unref (outbuf);
     510            0 :           res = GST_FLOW_ERROR;
     511            0 :           goto error;
     512              :         }
     513              :       }
     514           67 :       g_strfreev (strv);
     515           67 :       list = list->next;
     516              :     } else {
     517              :       _info =
     518          362 :           gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info, i);
     519          362 :       mem = gst_tensor_buffer_get_nth_memory (buf, i);
     520          362 :       if (!gst_tensor_buffer_append_memory (outbuf, mem, _info)) {
     521            0 :         gst_buffer_unref (outbuf);
     522            0 :         res = GST_FLOW_ERROR;
     523            0 :         goto error;
     524              :       }
     525              :     }
     526              : 
     527          429 :     ts = GST_BUFFER_TIMESTAMP (buf);
     528              : 
     529          429 :     if (created) {
     530              :       GstSegment segment;
     531           86 :       gst_segment_init (&segment, GST_FORMAT_TIME);
     532           86 :       gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
     533              :     }
     534              : 
     535          429 :     outbuf = gst_buffer_make_writable (outbuf);
     536              : 
     537              :     /* metadata from incoming buffer */
     538          429 :     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
     539              : 
     540          429 :     if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
     541          429 :       srcpad->last_ts = ts;
     542              :     } else {
     543            0 :       GST_DEBUG_OBJECT (tensor_demux, "invalid timestamp %" GST_TIME_FORMAT,
     544              :           GST_TIME_ARGS (ts));
     545              :     }
     546              : 
     547          429 :     GST_DEBUG_OBJECT (tensor_demux,
     548              :         "pushing buffer with timestamp %" GST_TIME_FORMAT,
     549              :         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
     550          429 :     res = gst_pad_push (srcpad->pad, outbuf);
     551          429 :     res = gst_tensor_demux_combine_flows (tensor_demux, srcpad, res);
     552              : 
     553          429 :     if (res != GST_FLOW_OK)
     554            3 :       break;
     555              :   }
     556              : 
     557          148 : error:
     558          151 :   gst_buffer_unref (buf);
     559          151 :   return res;
     560              : }
     561              : 
     562              : /**
     563              :  * @brief change state (gst element vmethod)
     564              :  */
     565              : static GstStateChangeReturn
     566          186 : gst_tensor_demux_change_state (GstElement * element, GstStateChange transition)
     567              : {
     568              :   GstTensorDemux *tensor_demux;
     569              :   GstStateChangeReturn ret;
     570          186 :   tensor_demux = GST_TENSOR_DEMUX (element);
     571          186 :   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
     572          186 :   if (ret == GST_STATE_CHANGE_FAILURE)
     573            0 :     return ret;
     574          186 :   switch (transition) {
     575           30 :     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     576           30 :       break;
     577           31 :     case GST_STATE_CHANGE_PAUSED_TO_READY:
     578           31 :       tensor_demux->group_id = G_MAXUINT;
     579           31 :       tensor_demux->have_group_id = FALSE;
     580           31 :       gst_tensor_demux_remove_src_pads (tensor_demux);
     581           31 :       break;
     582           31 :     case GST_STATE_CHANGE_READY_TO_NULL:
     583           31 :       break;
     584           94 :     default:
     585           94 :       break;
     586              :   }
     587              : 
     588          186 :   return ret;
     589              : }
     590              : 
     591              : /**
     592              :  * @brief Get property (gst element vmethod)
     593              :  */
     594              : static void
     595           12 : gst_tensor_demux_set_property (GObject * object, guint prop_id,
     596              :     const GValue * value, GParamSpec * pspec)
     597              : {
     598           12 :   GstTensorDemux *filter = GST_TENSOR_DEMUX (object);
     599           12 :   switch (prop_id) {
     600            2 :     case PROP_SILENT:
     601            2 :       filter->silent = g_value_get_boolean (value);
     602            2 :       break;
     603           10 :     case PROP_TENSORPICK:
     604              :     {
     605              :       guint i;
     606           10 :       const gchar *param = g_value_get_string (value);
     607           10 :       gchar **strv = g_strsplit_set (param, ",.;/", -1);
     608           10 :       guint num = g_strv_length (strv);
     609              : 
     610              :       /* Before setting the new Tensor Pick data, the existing one should be removed. */
     611           10 :       if (filter->tensorpick) {
     612            0 :         g_list_free_full (filter->tensorpick, g_free);
     613            0 :         filter->tensorpick = NULL;
     614              :       }
     615           27 :       for (i = 0; i < num; i++) {
     616           17 :         gchar *tmp = g_strdup (strv[i]);
     617           17 :         filter->tensorpick = g_list_append (filter->tensorpick, tmp);
     618              :       }
     619           10 :       g_strfreev (strv);
     620           10 :       break;
     621              :     }
     622            0 :     default:
     623            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     624            0 :       break;
     625              :   }
     626           12 : }
     627              : 
     628              : /**
     629              :  * @brief Get property (gst element vmethod)
     630              :  */
     631              : static void
     632            6 : gst_tensor_demux_get_property (GObject * object, guint prop_id,
     633              :     GValue * value, GParamSpec * pspec)
     634              : {
     635            6 :   GstTensorDemux *filter = GST_TENSOR_DEMUX (object);
     636            6 :   switch (prop_id) {
     637            4 :     case PROP_SILENT:
     638            4 :       g_value_set_boolean (value, filter->silent);
     639            4 :       break;
     640            2 :     case PROP_TENSORPICK:
     641              :     {
     642              :       GList *list;
     643              :       char *p;
     644            2 :       GPtrArray *arr = g_ptr_array_new ();
     645              :       gchar **strings;
     646              : 
     647            6 :       for (list = filter->tensorpick; list != NULL; list = list->next) {
     648            4 :         g_ptr_array_add (arr, g_strdup_printf ("%s", (gchar *) list->data));
     649              :       }
     650            2 :       g_ptr_array_add (arr, NULL);
     651            2 :       strings = (gchar **) g_ptr_array_free (arr, FALSE);
     652            2 :       p = g_strjoinv (",", strings);
     653            2 :       g_strfreev (strings);
     654            2 :       g_value_take_string (value, p);
     655            2 :       break;
     656              :     }
     657            0 :     default:
     658            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     659            0 :       break;
     660              :   }
     661            6 : }
        

Generated by: LCOV version 2.0-1