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

            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              :  *
       8              :  * This library is free software; you can redistribute it and/or
       9              :  * modify it under the terms of the GNU Library General Public
      10              :  * License as published by the Free Software Foundation;
      11              :  * version 2.1 of the License.
      12              :  *
      13              :  * This library is distributed in the hope that it will be useful,
      14              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16              :  * Library General Public License for more details.
      17              :  *
      18              :  */
      19              : /**
      20              :  * @file        gsttensor_mux.c
      21              :  * @date        03 July 2018
      22              :  * @brief       GStreamer plugin to mux tensors (as a filter for other general neural network filters)
      23              :  * @see         https://github.com/nnstreamer/nnstreamer
      24              :  * @author      Jijoong Moon <jijoong.moon@samsung.com>
      25              :  * @bug         No known bugs except for NYI items
      26              :  *
      27              :  */
      28              : 
      29              : /**
      30              :  * SECTION:element-tensormux
      31              :  *
      32              :  * A Muxer that merge tensor stream to tensors stream for NN frameworks.
      33              :  * The output is always in the format of other/tensors
      34              :  *
      35              :  * <refsect2>
      36              :  * <title>Example launch line</title>
      37              :  * |[
      38              :  * gst-launch -v -m \
      39              :  * filesrc location=b.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1  ! tensor_converter ! mux.sink_0 \
      40              :  * filesrc location=b.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1  ! tensor_converter ! mux.sink_1 \
      41              :  * filesrc location=b.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1  ! tensor_converter ! mux.sink_2 \
      42              :  * tensor_mux name=mux ! fakesink
      43              :  * ]|
      44              :  *
      45              :  * |[
      46              :  * gst-launch -v -m \
      47              :  * multifilesrc location="testsequence_%1d.png" index=0 caps="image/png, framerate=(fraction)30/1" ! pngdec ! tensor_converter ! mux.sink_0 \
      48              :  * multifilesrc location="testsequence_%1d.png" index=0 caps="image/png, framerate=(fraction)30/1" ! pngdec ! tensor_converter ! mux.sink_1 \
      49              :  * multifilesrc location="testsequence_%1d.png" index=0 caps="image/png, framerate=(fraction)30/1" ! pngdec ! tensor_converter ! mux.sink_2 \
      50              :  * tensor_mux name=mux ! filesink location=mux.log
      51              :  * ]|
      52              :  * </refsect2 >
      53              :  *
      54              :  */
      55              : 
      56              : 
      57              : #ifdef HAVE_CONFIG_H
      58              : #include <config.h>
      59              : #endif
      60              : 
      61              : #include <string.h>
      62              : #include <gst/gst.h>
      63              : #include <glib.h>
      64              : #include <nnstreamer_util.h>
      65              : 
      66              : #include "gsttensor_mux.h"
      67              : 
      68              : GST_DEBUG_CATEGORY_STATIC (gst_tensor_mux_debug);
      69              : #define GST_CAT_DEFAULT gst_tensor_mux_debug
      70              : 
      71              : /**
      72              :  * @brief Macro for debug mode.
      73              :  */
      74              : #ifndef DBG
      75              : #define DBG (!tensor_mux->silent)
      76              : #endif
      77              : 
      78              : enum
      79              : {
      80              :   PROP_0,
      81              :   PROP_SILENT,
      82              :   PROP_SYNC_MODE,
      83              :   PROP_SYNC_OPTION,
      84              : };
      85              : 
      86              : /**
      87              :  * @brief Default caps string for sink pad.
      88              :  */
      89              : #define CAPS_STRING_SINK GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_MAKE ("{ static, flexible }")
      90              : 
      91              : /**
      92              :  * @brief Default caps string for src pad.
      93              :  */
      94              : #define CAPS_STRING_SRC GST_TENSORS_CAP_MAKE ("{ static, flexible }")
      95              : 
      96              : /**
      97              :  * @brief the capabilities of the inputs and outputs.
      98              :  * describe the real formats here.
      99              :  */
     100              : static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
     101              :     GST_PAD_SRC,
     102              :     GST_PAD_ALWAYS,
     103              :     GST_STATIC_CAPS (CAPS_STRING_SRC)
     104              :     );
     105              : 
     106              : static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink_%u",
     107              :     GST_PAD_SINK,
     108              :     GST_PAD_REQUEST,
     109              :     GST_STATIC_CAPS (CAPS_STRING_SINK)
     110              :     );
     111              : 
     112              : static gboolean gst_tensor_mux_src_event (GstPad * pad, GstObject * parent,
     113              :     GstEvent * event);
     114              : static GstPad *gst_tensor_mux_request_new_pad (GstElement * element,
     115              :     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
     116              : static GstStateChangeReturn gst_tensor_mux_change_state (GstElement * element,
     117              :     GstStateChange transition);
     118              : static gboolean gst_tensor_mux_sink_event (GstCollectPads * pads,
     119              :     GstCollectData * data, GstEvent * event, GstTensorMux * tensor_mux);
     120              : static GstFlowReturn gst_tensor_mux_collected (GstCollectPads * pads,
     121              :     GstTensorMux * tensor_mux);
     122              : static GstFlowReturn gst_tensor_mux_do_clip (GstCollectPads * pads,
     123              :     GstCollectData * data, GstBuffer * buffer, GstBuffer ** out,
     124              :     GstTensorMux * tensor_mux);
     125              : 
     126              : static void gst_tensor_mux_set_property (GObject * object, guint prop_id,
     127              :     const GValue * value, GParamSpec * pspec);
     128              : static void gst_tensor_mux_get_property (GObject * object, guint prop_id,
     129              :     GValue * value, GParamSpec * pspec);
     130              : static void gst_tensor_mux_finalize (GObject * object);
     131              : 
     132              : #define gst_tensor_mux_parent_class parent_class
     133         2689 : G_DEFINE_TYPE (GstTensorMux, gst_tensor_mux, GST_TYPE_ELEMENT);
     134              : 
     135              : /**
     136              :  * @brief initialize the tensor_mux's class
     137              :  */
     138              : static void
     139           76 : gst_tensor_mux_class_init (GstTensorMuxClass * klass)
     140              : {
     141              :   GObjectClass *gobject_class;
     142              :   GstElementClass *gstelement_class;
     143              : 
     144           76 :   GST_DEBUG_CATEGORY_INIT (gst_tensor_mux_debug, "tensor_mux", 0,
     145              :       "Element to merge tensor stream to tensors stream");
     146              : 
     147           76 :   gobject_class = (GObjectClass *) klass;
     148           76 :   gstelement_class = (GstElementClass *) klass;
     149              : 
     150           76 :   parent_class = g_type_class_peek_parent (klass);
     151              : 
     152           76 :   gobject_class->finalize = gst_tensor_mux_finalize;
     153           76 :   gobject_class->get_property = gst_tensor_mux_get_property;
     154           76 :   gobject_class->set_property = gst_tensor_mux_set_property;
     155              : 
     156           76 :   g_object_class_install_property (gobject_class, PROP_SILENT,
     157              :       g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
     158              :           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     159              : 
     160           76 :   g_object_class_install_property (gobject_class, PROP_SYNC_MODE,
     161              :       g_param_spec_string ("sync-mode", "Sync Mode",
     162              :           "Time synchronization mode?", "", G_PARAM_READWRITE));
     163              : 
     164           76 :   g_object_class_install_property (gobject_class, PROP_SYNC_OPTION,
     165              :       g_param_spec_string ("sync-option", "Sync Option",
     166              :           "Option for the time synchronization mode ?", "", G_PARAM_READWRITE));
     167              : 
     168           76 :   gstelement_class->request_new_pad =
     169           76 :       GST_DEBUG_FUNCPTR (gst_tensor_mux_request_new_pad);
     170           76 :   gstelement_class->change_state =
     171           76 :       GST_DEBUG_FUNCPTR (gst_tensor_mux_change_state);
     172              : 
     173           76 :   gst_element_class_add_pad_template (gstelement_class,
     174              :       gst_static_pad_template_get (&sink_templ));
     175           76 :   gst_element_class_add_pad_template (gstelement_class,
     176              :       gst_static_pad_template_get (&src_templ));
     177              : 
     178           76 :   gst_element_class_set_details_simple (gstelement_class,
     179              :       "TensorMux",
     180              :       "Muxer/Tensor",
     181              :       "Merge multiple tensor stream to tensors stream",
     182              :       "Jijoong Moon <jijoong.moon@samsung.com>");
     183              : 
     184           76 : }
     185              : 
     186              : /**
     187              :  * @brief initialize the new element
     188              :  * instantiate pads and add them to element
     189              :  * set pad callback functions
     190              :  * initialize instance structure
     191              :  */
     192              : static void
     193          127 : gst_tensor_mux_init (GstTensorMux * tensor_mux)
     194              : {
     195          127 :   GstElementClass *klass = GST_ELEMENT_GET_CLASS (tensor_mux);
     196              : 
     197          127 :   tensor_mux->srcpad =
     198          127 :       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
     199              :           "src"), "src");
     200          127 :   gst_pad_set_event_function (tensor_mux->srcpad, gst_tensor_mux_src_event);
     201              : 
     202          127 :   gst_element_add_pad (GST_ELEMENT (tensor_mux), tensor_mux->srcpad);
     203              : 
     204          127 :   tensor_mux->collect = gst_collect_pads_new ();
     205          127 :   gst_collect_pads_set_event_function (tensor_mux->collect,
     206              :       (GstCollectPadsEventFunction)
     207          127 :       GST_DEBUG_FUNCPTR (gst_tensor_mux_sink_event), tensor_mux);
     208          127 :   gst_collect_pads_set_function (tensor_mux->collect,
     209          127 :       (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_tensor_mux_collected),
     210              :       tensor_mux);
     211          127 :   gst_collect_pads_set_clip_function (tensor_mux->collect,
     212          127 :       (GstCollectPadsClipFunction) GST_DEBUG_FUNCPTR (gst_tensor_mux_do_clip),
     213              :       tensor_mux);
     214              : 
     215          127 :   tensor_mux->silent = TRUE;
     216          127 :   tensor_mux->sync.mode = SYNC_SLOWEST;
     217          127 :   tensor_mux->sync.option = NULL;
     218          127 :   tensor_mux->current_time = 0;
     219          127 :   tensor_mux->need_set_time = TRUE;
     220          127 :   gst_tensors_config_init (&tensor_mux->tensors_config);
     221          127 : }
     222              : 
     223              : /**
     224              :  * @brief finalize vmethod
     225              :  */
     226              : static void
     227          125 : gst_tensor_mux_finalize (GObject * object)
     228              : {
     229              :   GstTensorMux *tensor_mux;
     230              : 
     231          125 :   tensor_mux = GST_TENSOR_MUX (object);
     232              : 
     233          125 :   if (tensor_mux->collect) {
     234          125 :     gst_tensor_time_sync_flush (tensor_mux->collect);
     235          125 :     gst_object_unref (tensor_mux->collect);
     236          125 :     tensor_mux->collect = NULL;
     237              :   }
     238              : 
     239          125 :   if (tensor_mux->sync.option) {
     240           17 :     g_free (tensor_mux->sync.option);
     241           17 :     tensor_mux->sync.option = NULL;
     242              :   }
     243              : 
     244          125 :   gst_tensors_config_free (&tensor_mux->tensors_config);
     245              : 
     246          125 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     247          125 : }
     248              : 
     249              : /**
     250              :  * @brief making new request pad (gst element vmethod)
     251              :  */
     252              : static GstPad *
     253          409 : gst_tensor_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
     254              :     const gchar * req_name, const GstCaps * caps)
     255              : {
     256              :   GstPad *newpad;
     257          409 :   GSList *walk = NULL;
     258              :   GstTensorMux *tensor_mux;
     259              :   gchar *name;
     260              :   UNUSED (req_name);
     261              :   UNUSED (caps);
     262              : 
     263          409 :   g_return_val_if_fail (templ != NULL, NULL);
     264          409 :   g_return_val_if_fail (GST_IS_TENSOR_MUX (element), NULL);
     265              : 
     266          409 :   tensor_mux = GST_TENSOR_MUX (element);
     267          409 :   walk = tensor_mux->collect->data;
     268              : 
     269          409 :   name = g_strdup_printf ("sink_%u", g_slist_length (walk));
     270          409 :   newpad = gst_pad_new_from_template (templ, name);
     271          409 :   g_free (name);
     272              : 
     273          409 :   if (newpad) {
     274              :     GstTensorCollectPadData *tensormuxpad;
     275              :     gboolean locked, waiting;
     276              : 
     277          409 :     locked = waiting = TRUE;
     278              : 
     279          409 :     if (tensor_mux->sync.mode == SYNC_REFRESH) {
     280            2 :       locked = waiting = FALSE;
     281              :     }
     282              : 
     283              :     tensormuxpad = (GstTensorCollectPadData *)
     284          409 :         gst_collect_pads_add_pad (tensor_mux->collect, newpad,
     285              :         sizeof (GstTensorCollectPadData), NULL, locked);
     286              : 
     287              :     /* NOTE: if locked is TRUE, waiting flag is not effective */
     288          409 :     gst_collect_pads_set_waiting (tensor_mux->collect,
     289              :         (GstCollectData *) tensormuxpad, waiting);
     290              : 
     291          409 :     gst_pad_set_element_private (newpad, tensormuxpad);
     292          409 :     gst_element_add_pad (element, newpad);
     293              :   } else {
     294            0 :     GST_WARNING_OBJECT (tensor_mux, "failed to create request pad");
     295              :   }
     296          409 :   return newpad;
     297              : }
     298              : 
     299              : /**
     300              :  * @brief src event vmethod
     301              :  */
     302              : static gboolean
     303         5418 : gst_tensor_mux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
     304              : {
     305         5418 :   g_return_val_if_fail (event != NULL, FALSE);
     306              : 
     307         5418 :   switch (GST_EVENT_TYPE (event)) {
     308            0 :     case GST_EVENT_SEEK:
     309            0 :       gst_event_unref (event);
     310            0 :       return FALSE;
     311         5418 :     default:
     312         5418 :       break;
     313              :   }
     314              : 
     315         5418 :   return gst_pad_event_default (pad, parent, event);
     316              : }
     317              : 
     318              : /**
     319              :  * @brief set pads waiting property
     320              :  */
     321              : static void
     322        14333 : gst_tensor_mux_set_waiting (GstTensorMux * tensor_mux, gboolean waiting)
     323              : {
     324        14333 :   if (tensor_mux->sync.mode == SYNC_REFRESH) {
     325         9546 :     GstCollectPads *pads = tensor_mux->collect;
     326         9546 :     GSList *walk = pads->data;
     327              : 
     328        28638 :     while (walk) {
     329        19092 :       gst_collect_pads_set_waiting (pads, walk->data, waiting);
     330        19092 :       walk = g_slist_next (walk);
     331              :     }
     332              :   }
     333        14333 : }
     334              : 
     335              : /**
     336              :  * @brief sink event vmethod
     337              :  */
     338              : static gboolean
     339         1606 : gst_tensor_mux_sink_event (GstCollectPads * pads, GstCollectData * data,
     340              :     GstEvent * event, GstTensorMux * tensor_mux)
     341              : {
     342         1606 :   g_return_val_if_fail (event != NULL, FALSE);
     343              : 
     344         1606 :   switch (GST_EVENT_TYPE (event)) {
     345            0 :     case GST_EVENT_FLUSH_STOP:
     346            0 :       tensor_mux->need_segment = TRUE;
     347            0 :       tensor_mux->need_set_time = TRUE;
     348            0 :       gst_tensor_time_sync_flush (tensor_mux->collect);
     349            0 :       break;
     350          389 :     case GST_EVENT_EOS:
     351          389 :       gst_tensor_mux_set_waiting (tensor_mux, FALSE);
     352          389 :       break;
     353         1217 :     default:
     354         1217 :       break;
     355              :   }
     356              : 
     357         1606 :   return gst_collect_pads_event_default (pads, data, event, FALSE);
     358              : }
     359              : 
     360              : /**
     361              :  * @brief Looping to generete output buffer for srcpad
     362              :  * @param tensor_mux tensor muxer
     363              :  * @param tensors_buf output buffer for srcpad
     364              :  * @param is_eos boolean EOS ( End of Stream )
     365              :  * @return TRUE to push buffer to src pad
     366              :  */
     367              : static gboolean
     368         6123 : gst_tensor_mux_collect_buffer (GstTensorMux * tensor_mux,
     369              :     GstBuffer * tensors_buf, gboolean * is_eos)
     370              : {
     371         6123 :   if (tensor_mux->need_set_time) {
     372         5589 :     if (gst_tensor_time_sync_get_current_time (tensor_mux->collect,
     373              :             &tensor_mux->sync, &tensor_mux->current_time, tensors_buf)) {
     374              :       /* end-of-stream */
     375          174 :       *is_eos = TRUE;
     376          174 :       return FALSE;
     377              :     }
     378              : 
     379         5415 :     tensor_mux->need_set_time = FALSE;
     380         5415 :     silent_debug (tensor_mux, "Current Time : %" GST_TIME_FORMAT,
     381              :         GST_TIME_ARGS (tensor_mux->current_time));
     382              :   }
     383              : 
     384         5949 :   return gst_tensor_time_sync_buffer_from_collectpad (tensor_mux->collect,
     385              :       &tensor_mux->sync, tensor_mux->current_time, tensors_buf,
     386              :       &tensor_mux->tensors_config, is_eos);
     387              : }
     388              : 
     389              : /**
     390              :  * @brief Set src pad caps if src pad is not negotiated.
     391              :  */
     392              : static gboolean
     393         5415 : gst_tensor_mux_set_src_caps (GstTensorMux * tensor_mux)
     394              : {
     395         5415 :   if (!tensor_mux->negotiated) {
     396              :     GstCaps *caps;
     397              : 
     398          124 :     if (gst_tensors_config_validate (&tensor_mux->tensors_config)) {
     399          248 :       caps = gst_tensor_pad_caps_from_config (tensor_mux->srcpad,
     400          124 :           &tensor_mux->tensors_config);
     401              : 
     402          124 :       if (gst_pad_set_caps (tensor_mux->srcpad, caps)) {
     403          124 :         tensor_mux->negotiated = TRUE;
     404              :       }
     405              : 
     406          124 :       gst_caps_unref (caps);
     407              :     }
     408              :   }
     409              : 
     410         5415 :   if (!tensor_mux->negotiated) {
     411            0 :     GST_WARNING_OBJECT (tensor_mux, "failed to set caps");
     412            0 :     GST_ELEMENT_ERROR (tensor_mux, CORE, NEGOTIATION, (NULL), (NULL));
     413              :   }
     414              : 
     415         5415 :   return tensor_mux->negotiated;
     416              : }
     417              : 
     418              : /**
     419              :  * @brief Create a new segment event if necessary.
     420              :  */
     421              : static void
     422         5415 : gst_tensor_mux_send_segment_event (GstTensorMux * tensor_mux,
     423              :     GstClockTime pts, GstClockTime dts)
     424              : {
     425         5415 :   if (tensor_mux->need_segment) {
     426              :     GstSegment segment;
     427          124 :     GstClockTime time = 0;
     428              : 
     429          124 :     if (GST_CLOCK_TIME_IS_VALID (dts)) {
     430            2 :       time = dts;
     431          122 :     } else if (GST_CLOCK_TIME_IS_VALID (pts)) {
     432          122 :       time = pts;
     433              :     }
     434              : 
     435          124 :     gst_segment_init (&segment, GST_FORMAT_TIME);
     436          124 :     segment.start = time;
     437          124 :     gst_pad_push_event (tensor_mux->srcpad, gst_event_new_segment (&segment));
     438          124 :     tensor_mux->need_segment = FALSE;
     439              :   }
     440         5415 : }
     441              : 
     442              : /**
     443              :  * @brief Process flex tensor.
     444              :  */
     445              : static GstBuffer *
     446           25 : gst_tensor_mux_chain_flex_tensor (GstTensorMux * tensor_mux, GstBuffer * buf)
     447              : {
     448              :   GstBuffer *buffer;
     449              :   GstMemory *mem, *new_mem;
     450              :   GstTensorsInfo *info;
     451              :   GstTensorInfo *_info;
     452              :   GstTensorMetaInfo meta;
     453              :   guint i;
     454              : 
     455              :   /* If input is flexible, do nothing. It is already flexible tensor. */
     456           25 :   if (gst_tensors_config_is_flexible (&tensor_mux->tensors_config))
     457           25 :     return buf;
     458              : 
     459            2 :   info = &tensor_mux->tensors_config.info;
     460            2 :   buffer = gst_buffer_new ();
     461              : 
     462            6 :   for (i = 0; i < info->num_tensors; i++) {
     463            4 :     mem = gst_tensor_buffer_get_nth_memory (buf, i);
     464              : 
     465              :     /* append header */
     466            4 :     _info = gst_tensors_info_get_nth_info (info, i);
     467            4 :     gst_tensor_info_convert_to_meta (_info, &meta);
     468            4 :     new_mem = gst_tensor_meta_info_append_header (&meta, mem);
     469            4 :     gst_memory_unref (mem);
     470              : 
     471            4 :     gst_tensor_buffer_append_memory (buffer, new_mem, _info);
     472              :   }
     473              : 
     474            2 :   gst_buffer_copy_into (buffer, buf, GST_BUFFER_COPY_METADATA, 0, -1);
     475            2 :   gst_buffer_unref (buf);
     476            2 :   return buffer;
     477              : }
     478              : 
     479              : /**
     480              :  * @brief Gst Collect Pads Function which is called once collect pads done.
     481              :  * @param pads GstCollectPads
     482              :  * @param tensor_mux Muxer
     483              :  * @return GstFlowReturn
     484              :  */
     485              : static GstFlowReturn
     486         6123 : gst_tensor_mux_collected (GstCollectPads * pads, GstTensorMux * tensor_mux)
     487              : {
     488         6123 :   GstFlowReturn ret = GST_FLOW_OK;
     489              :   GstBuffer *tensors_buf;
     490         6123 :   gboolean isEOS = FALSE;
     491         6123 :   gboolean buf_collected = FALSE;
     492              : 
     493         6123 :   GST_DEBUG_OBJECT (tensor_mux, " all pads are collected ");
     494              : 
     495         6123 :   if (tensor_mux->need_stream_start) {
     496              :     /**
     497              :      * Cannot use gst-pad util to get stream ID (multiple sink pads).
     498              :      * Create stream ID using first sink pad.
     499              :      */
     500          124 :     GstCollectData *data = (GstCollectData *) pads->data->data;
     501          124 :     g_autofree gchar *sink_stream_id = gst_pad_get_stream_id (data->pad);
     502          124 :     g_autofree gchar *element_name = gst_element_get_name (tensor_mux);
     503          124 :     g_autofree gchar *pad_name = gst_pad_get_name (tensor_mux->srcpad);
     504          248 :     g_autofree gchar *stream_id = g_strdup_printf ("%s-%s-nnsmux-%s-%08x",
     505          124 :         GST_STR_NULL (sink_stream_id), element_name, pad_name, g_random_int ());
     506              : 
     507          124 :     gst_pad_push_event (tensor_mux->srcpad, gst_event_new_stream_start (stream_id));
     508          124 :     tensor_mux->need_stream_start = FALSE;
     509              :   }
     510              : 
     511         6123 :   if ((tensors_buf = gst_buffer_new ()) == NULL) {
     512            0 :     ml_logf ("gst_buffer_new() returns NULL. Out of memory?\n");
     513         6123 :     return GST_FLOW_ERROR;
     514              :   }
     515              : 
     516              :   buf_collected =
     517         6123 :       gst_tensor_mux_collect_buffer (tensor_mux, tensors_buf, &isEOS);
     518              : 
     519         6123 :   gst_tensor_mux_set_waiting (tensor_mux, TRUE);
     520              : 
     521         6123 :   if (!buf_collected) {
     522          708 :     if (isEOS) {
     523          174 :       gst_pad_push_event (tensor_mux->srcpad, gst_event_new_eos ());
     524          174 :       ret = GST_FLOW_EOS;
     525              :     }
     526              : 
     527          708 :     gst_buffer_unref (tensors_buf);
     528          708 :     return ret;
     529              :   }
     530              : 
     531         5415 :   if (!gst_tensor_mux_set_src_caps (tensor_mux)) {
     532            0 :     gst_buffer_unref (tensors_buf);
     533            0 :     return GST_FLOW_NOT_NEGOTIATED;
     534              :   }
     535              : 
     536         5415 :   gst_tensor_mux_send_segment_event (tensor_mux, GST_BUFFER_PTS (tensors_buf),
     537              :       GST_BUFFER_DTS (tensors_buf));
     538              : 
     539              :   /* add header if output is flexible */
     540         5415 :   if (gst_tensor_pad_caps_is_flexible (tensor_mux->srcpad))
     541           25 :     tensors_buf = gst_tensor_mux_chain_flex_tensor (tensor_mux, tensors_buf);
     542              : 
     543         5415 :   ret = gst_pad_push (tensor_mux->srcpad, tensors_buf);
     544         5415 :   tensor_mux->need_set_time = TRUE;
     545              : 
     546         5415 :   if (ret != GST_FLOW_OK) {
     547           17 :     GST_WARNING_OBJECT (tensor_mux, "pushed outbuf, result = %s",
     548              :         gst_flow_get_name (ret));
     549              :   }
     550              : 
     551         5415 :   return ret;
     552              : }
     553              : 
     554              : /**
     555              :  * @brief Gst Clip Pads Function which is called right after a buffer is received for each pad.
     556              :  */
     557              : static GstFlowReturn
     558         7821 : gst_tensor_mux_do_clip (GstCollectPads * pads, GstCollectData * data,
     559              :     GstBuffer * buffer, GstBuffer ** out, GstTensorMux * tensor_mux)
     560              : {
     561              :   UNUSED (pads);
     562              :   UNUSED (data);
     563         7821 :   gst_tensor_mux_set_waiting (tensor_mux, FALSE);
     564         7821 :   *out = buffer;
     565         7821 :   return GST_FLOW_OK;
     566              : }
     567              : 
     568              : /**
     569              :  * @brief Ready --> Pasuse State Change
     570              :  */
     571              : static void
     572          124 : gst_tensor_mux_ready_to_paused (GstTensorMux * tensor_mux)
     573              : {
     574          124 :   tensor_mux->need_stream_start = TRUE;
     575          124 :   tensor_mux->need_segment = TRUE;
     576          124 :   tensor_mux->negotiated = FALSE;
     577          124 :   gst_collect_pads_start (tensor_mux->collect);
     578          124 : }
     579              : 
     580              : /**
     581              :  * @brief change state (gst element vmethod)
     582              :  */
     583              : static GstStateChangeReturn
     584          732 : gst_tensor_mux_change_state (GstElement * element, GstStateChange transition)
     585              : {
     586              :   GstTensorMux *tensor_mux;
     587              :   GstStateChangeReturn ret;
     588          732 :   tensor_mux = GST_TENSOR_MUX (element);
     589          732 :   switch (transition) {
     590          124 :     case GST_STATE_CHANGE_READY_TO_PAUSED:
     591          124 :       gst_tensor_mux_ready_to_paused (tensor_mux);
     592          124 :       break;
     593          122 :     case GST_STATE_CHANGE_PAUSED_TO_READY:
     594          122 :       gst_collect_pads_stop (tensor_mux->collect);
     595          122 :       break;
     596          486 :     default:
     597          486 :       break;
     598              :   }
     599              : 
     600          732 :   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
     601          732 :   if (ret == GST_STATE_CHANGE_FAILURE)
     602            0 :     return ret;
     603          732 :   switch (transition) {
     604          122 :     case GST_STATE_CHANGE_PAUSED_TO_READY:
     605          122 :       break;
     606          610 :     default:
     607          610 :       break;
     608              :   }
     609              : 
     610          732 :   return ret;
     611              : }
     612              : 
     613              : /**
     614              :  * @brief Get property (gst element vmethod)
     615              :  */
     616              : static void
     617           70 : gst_tensor_mux_set_property (GObject * object, guint prop_id,
     618              :     const GValue * value, GParamSpec * pspec)
     619              : {
     620           70 :   GstTensorMux *tensor_mux = GST_TENSOR_MUX (object);
     621           70 :   switch (prop_id) {
     622            4 :     case PROP_SILENT:
     623            4 :       tensor_mux->silent = g_value_get_boolean (value);
     624            4 :       break;
     625           49 :     case PROP_SYNC_MODE:
     626           49 :       tensor_mux->sync.mode =
     627           49 :           gst_tensor_time_sync_get_mode (g_value_get_string (value));
     628           49 :       if (tensor_mux->sync.mode == SYNC_END) {
     629            0 :         tensor_mux->sync.mode = SYNC_SLOWEST;
     630              :       }
     631           49 :       silent_debug (tensor_mux, "Mode = %d(%s)\n", tensor_mux->sync.mode,
     632              :           gst_tensor_time_sync_get_mode_string (tensor_mux->sync.mode));
     633           49 :       gst_tensor_time_sync_set_option_data (&tensor_mux->sync);
     634           49 :       break;
     635           17 :     case PROP_SYNC_OPTION:
     636           17 :       tensor_mux->sync.option = g_value_dup_string (value);
     637           17 :       silent_debug (tensor_mux, "Option = %s\n", tensor_mux->sync.option);
     638           17 :       gst_tensor_time_sync_set_option_data (&tensor_mux->sync);
     639           17 :       break;
     640            0 :     default:
     641            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     642            0 :       break;
     643              :   }
     644           70 : }
     645              : 
     646              : /**
     647              :  * @brief Get property (gst element vmethod)
     648              :  */
     649              : static void
     650            4 : gst_tensor_mux_get_property (GObject * object, guint prop_id,
     651              :     GValue * value, GParamSpec * pspec)
     652              : {
     653            4 :   GstTensorMux *tensor_mux = GST_TENSOR_MUX (object);
     654            4 :   switch (prop_id) {
     655            2 :     case PROP_SILENT:
     656            2 :       g_value_set_boolean (value, tensor_mux->silent);
     657            2 :       break;
     658            1 :     case PROP_SYNC_MODE:
     659            1 :       g_value_set_string (value,
     660              :           gst_tensor_time_sync_get_mode_string (tensor_mux->sync.mode));
     661            1 :       break;
     662            1 :     case PROP_SYNC_OPTION:
     663            1 :       g_value_set_string (value, tensor_mux->sync.option);
     664            1 :       break;
     665            0 :     default:
     666            0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     667            0 :       break;
     668              :   }
     669            4 : }
        

Generated by: LCOV version 2.0-1