LCOV - code coverage report
Current view: top level - capi-machine-learning-inference-1.8.6/c/src - ml-api-inference-pipeline.c (source / functions) Coverage Total Hit
Test: ML API 1.8.6-0 nnstreamer/api#abde31caf90ada0ea14929b563b6d19f563740eb Lines: 82.5 % 1378 1137
Test Date: 2025-08-15 05:27:32 Functions: 94.0 % 84 79

            Line data    Source code
       1              : /* SPDX-License-Identifier: Apache-2.0 */
       2              : /**
       3              :  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved.
       4              :  *
       5              :  * @file ml-api-inference-pipeline.c
       6              :  * @date 11 March 2019
       7              :  * @brief NNStreamer/Pipeline(main) C-API Wrapper.
       8              :  *        This allows to construct and control NNStreamer pipelines.
       9              :  * @see https://github.com/nnstreamer/nnstreamer
      10              :  * @author MyungJoo Ham <myungjoo.ham@samsung.com>
      11              :  * @bug Thread safety for ml_tensors_data should be addressed.
      12              :  */
      13              : 
      14              : #include <string.h>
      15              : #include <glib.h>
      16              : #include <gst/gstbuffer.h>
      17              : #include <gst/app/app.h>        /* To push data to pipeline */
      18              : #include <nnstreamer_plugin_api.h>
      19              : #include <tensor_if.h>
      20              : #include <tensor_typedef.h>
      21              : #include <tensor_filter_custom_easy.h>
      22              : 
      23              : #include <nnstreamer.h>
      24              : #include <nnstreamer-tizen-internal.h>
      25              : 
      26              : #include "ml-api-internal.h"
      27              : #include "ml-api-inference-internal.h"
      28              : #include "ml-api-inference-pipeline-internal.h"
      29              : 
      30              : 
      31              : #define handle_init(name, h) \
      32              :   ml_pipeline_common_elem *name= (h); \
      33              :   ml_pipeline *p; \
      34              :   ml_pipeline_element *elem; \
      35              :   int ret = ML_ERROR_NONE; \
      36              :   check_feature_state (ML_FEATURE_INFERENCE); \
      37              :   if ((h) == NULL) { \
      38              :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER, \
      39              :         "The parameter, %s, (handle) is invalid (NULL). Please provide a valid handle.", \
      40              :         #h); \
      41              :   } \
      42              :   p = name->pipe; \
      43              :   elem = name->element; \
      44              :   if (p == NULL) \
      45              :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER, \
      46              :         "Internal error. The contents of parameter, %s, (handle), is invalid. The pipeline entry (%s->pipe) is NULL. The handle (%s) is either not properly created or application threads may have touched its contents.", \
      47              :         #h, #h, #h); \
      48              :   if (elem == NULL) \
      49              :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER, \
      50              :         "Internal error. The contents of parameter, %s, (handle), is invalid. The element entry (%s->element) is NULL. The handle (%s) is either not properly created or application threads may have touched its contents.", \
      51              :         #h, #h, #h); \
      52              :   if (elem->pipe == NULL) \
      53              :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER, \
      54              :         "Internal error. The contents of parameter, %s, (handle), is invalid. The pipeline entry of the element entry (%s->element->pipe) is NULL. The handle (%s) is either not properly created or application threads may have touched its contents.", \
      55              :         #h, #h, #h); \
      56              :   g_mutex_lock (&p->lock); \
      57              :   g_mutex_lock (&elem->lock); \
      58              :   if (NULL == g_list_find (elem->handles, name)) { \
      59              :     _ml_error_report \
      60              :         ("Internal error. The handle name, %s, does not exists in the list of %s->element->handles.", \
      61              :         #h, #h); \
      62              :     ret = ML_ERROR_INVALID_PARAMETER; \
      63              :     goto unlock_return; \
      64              :   }
      65              : 
      66              : #define handle_exit(h) \
      67              : unlock_return: \
      68              :   g_mutex_unlock (&elem->lock); \
      69              :   g_mutex_unlock (&p->lock); \
      70              :   return ret;
      71              : 
      72              : /**
      73              :  * @brief The enumeration for custom data type.
      74              :  */
      75              : typedef enum
      76              : {
      77              :   PIPE_CUSTOM_TYPE_NONE,
      78              :   PIPE_CUSTOM_TYPE_IF,
      79              :   PIPE_CUSTOM_TYPE_FILTER,
      80              : 
      81              :   PIPE_CUSTOM_TYPE_MAX
      82              : } pipe_custom_type_e;
      83              : 
      84              : /**
      85              :  * @brief The struct for custom data.
      86              :  */
      87              : typedef struct
      88              : {
      89              :   pipe_custom_type_e type;
      90              :   gchar *name;
      91              :   gpointer handle;
      92              : } pipe_custom_data_s;
      93              : 
      94              : static void ml_pipeline_custom_filter_ref (ml_custom_easy_filter_h custom);
      95              : static void ml_pipeline_custom_filter_unref (ml_custom_easy_filter_h custom);
      96              : static void ml_pipeline_if_custom_ref (ml_pipeline_if_h custom);
      97              : static void ml_pipeline_if_custom_unref (ml_pipeline_if_h custom);
      98              : 
      99              : /**
     100              :  * @brief Global lock for pipeline functions.
     101              :  */
     102              : G_LOCK_DEFINE_STATIC (g_ml_pipe_lock);
     103              : 
     104              : /**
     105              :  * @brief The list of custom data. This should be managed with lock.
     106              :  */
     107              : static GList *g_ml_custom_data = NULL;
     108              : 
     109              : /**
     110              :  * @brief Finds a position of custom data in the list.
     111              :  * @note This function should be called with lock.
     112              :  */
     113              : static GList *
     114           12 : pipe_custom_find_link (const pipe_custom_type_e type, const gchar * name)
     115              : {
     116              :   pipe_custom_data_s *data;
     117              :   GList *link;
     118              : 
     119           12 :   g_return_val_if_fail (name != NULL, NULL);
     120              : 
     121           12 :   link = g_ml_custom_data;
     122           12 :   while (link) {
     123           12 :     data = (pipe_custom_data_s *) link->data;
     124              : 
     125           12 :     if (data->type == type && g_str_equal (data->name, name))
     126           12 :       break;
     127              : 
     128            0 :     link = link->next;
     129              :   }
     130              : 
     131           12 :   return link;
     132              : }
     133              : 
     134              : /**
     135              :  * @brief Finds custom data matched with data type and name.
     136              :  */
     137              : static pipe_custom_data_s *
     138            6 : pipe_custom_find_data (const pipe_custom_type_e type, const gchar * name)
     139              : {
     140              :   pipe_custom_data_s *data;
     141              :   GList *link;
     142              : 
     143            6 :   G_LOCK (g_ml_pipe_lock);
     144              : 
     145            6 :   link = pipe_custom_find_link (type, name);
     146            6 :   data = (link != NULL) ? (pipe_custom_data_s *) link->data : NULL;
     147              : 
     148            6 :   G_UNLOCK (g_ml_pipe_lock);
     149            6 :   return data;
     150              : }
     151              : 
     152              : /**
     153              :  * @brief Adds new custom data into the list.
     154              :  */
     155              : static void
     156            6 : pipe_custom_add_data (const pipe_custom_type_e type, const gchar * name,
     157              :     gpointer handle)
     158              : {
     159              :   pipe_custom_data_s *data;
     160              : 
     161            6 :   data = g_new0 (pipe_custom_data_s, 1);
     162            6 :   data->type = type;
     163            6 :   data->name = g_strdup (name);
     164            6 :   data->handle = handle;
     165              : 
     166            6 :   G_LOCK (g_ml_pipe_lock);
     167            6 :   g_ml_custom_data = g_list_prepend (g_ml_custom_data, data);
     168            6 :   G_UNLOCK (g_ml_pipe_lock);
     169            6 : }
     170              : 
     171              : /**
     172              :  * @brief Removes custom data from the list.
     173              :  */
     174              : static void
     175            6 : pipe_custom_remove_data (const pipe_custom_type_e type, const gchar * name)
     176              : {
     177              :   pipe_custom_data_s *data;
     178              :   GList *link;
     179              : 
     180            6 :   G_LOCK (g_ml_pipe_lock);
     181              : 
     182            6 :   link = pipe_custom_find_link (type, name);
     183            6 :   if (link) {
     184            6 :     data = (pipe_custom_data_s *) link->data;
     185              : 
     186            6 :     g_ml_custom_data = g_list_delete_link (g_ml_custom_data, link);
     187              : 
     188            6 :     g_free (data->name);
     189            6 :     g_free (data);
     190              :   }
     191              : 
     192            6 :   G_UNLOCK (g_ml_pipe_lock);
     193            6 : }
     194              : 
     195              : /**
     196              :  * @brief The callback function called when the element node with custom data is released.
     197              :  */
     198              : static int
     199            6 : pipe_custom_destroy_cb (void *handle, void *user_data)
     200              : {
     201              :   pipe_custom_data_s *custom_data;
     202              : 
     203            6 :   custom_data = (pipe_custom_data_s *) handle;
     204            6 :   if (custom_data == NULL)
     205            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     206              :         "The parameter, handle, is NULL. It should be a valid internal object. This is possibly a bug in ml-api-inference-pipeline.c along with tensor-if or tensor-filter/custom function. Please report to https://github.com/nnstreamer/nnstreamer/issues");
     207              : 
     208            6 :   switch (custom_data->type) {
     209            3 :     case PIPE_CUSTOM_TYPE_IF:
     210            3 :       ml_pipeline_if_custom_unref (custom_data->handle);
     211            3 :       break;
     212            3 :     case PIPE_CUSTOM_TYPE_FILTER:
     213            3 :       ml_pipeline_custom_filter_unref (custom_data->handle);
     214            3 :       break;
     215            0 :     default:
     216            0 :       break;
     217              :   }
     218              : 
     219            6 :   return ML_ERROR_NONE;
     220              : }
     221              : 
     222              : /**
     223              :  * @brief Internal function to create a referable element in a pipeline
     224              :  */
     225              : static ml_pipeline_element *
     226          404 : construct_element (GstElement * e, ml_pipeline * p, const char *name,
     227              :     ml_pipeline_element_e t)
     228              : {
     229          404 :   ml_pipeline_element *ret = g_new0 (ml_pipeline_element, 1);
     230              : 
     231          404 :   if (ret == NULL)
     232            0 :     _ml_error_report_return (NULL,
     233              :         "Failed to allocate memory for the pipeline.");
     234              : 
     235          404 :   ret->element = e;
     236          404 :   ret->pipe = p;
     237          404 :   ret->name = g_strdup (name);
     238          404 :   ret->type = t;
     239          404 :   ret->handles = NULL;
     240          404 :   ret->src = NULL;
     241          404 :   ret->sink = NULL;
     242          404 :   ret->maxid = 0;
     243          404 :   ret->handle_id = 0;
     244          404 :   ret->is_media_stream = FALSE;
     245          404 :   ret->is_flexible_tensor = FALSE;
     246          404 :   g_mutex_init (&ret->lock);
     247          404 :   gst_tensors_info_init (&ret->tensors_info);
     248              : 
     249          404 :   return ret;
     250              : }
     251              : 
     252              : /**
     253              :  * @brief Internal function to get the tensors info from the element caps.
     254              :  */
     255              : static gboolean
     256        12172 : get_tensors_info_from_caps (const GstCaps * caps, GstTensorsInfo * info,
     257              :     gboolean * is_flexible)
     258              : {
     259              :   GstTensorsConfig config;
     260        12172 :   gboolean found = FALSE;
     261              : 
     262        12172 :   found = gst_tensors_config_from_caps (&config, caps, TRUE);
     263              : 
     264        12172 :   if (found) {
     265        12166 :     gst_tensors_info_free (info);
     266        12166 :     gst_tensors_info_copy (info, &config.info);
     267              : 
     268        12166 :     if (is_flexible) {
     269        12166 :       *is_flexible = gst_tensors_config_is_flexible (&config);
     270              :     }
     271              : 
     272        12166 :     gst_tensors_config_free (&config);
     273              :   }
     274              : 
     275        12172 :   return found;
     276              : }
     277              : 
     278              : /**
     279              :  * @brief Handle a sink element for registered ml_pipeline_sink_cb
     280              :  */
     281              : static void
     282         6116 : cb_sink_event (GstElement * e, GstBuffer * b, gpointer user_data)
     283              : {
     284         6116 :   ml_pipeline_element *elem = user_data;
     285              : 
     286              :   /** @todo CRITICAL if the pipeline is being killed, don't proceed! */
     287              :   GstMemory *mem[ML_TENSOR_SIZE_LIMIT];
     288              :   GstMapInfo map[ML_TENSOR_SIZE_LIMIT];
     289              :   guint i, num_tensors;
     290              :   GList *l;
     291         6116 :   ml_tensors_data_s *_data = NULL;
     292              :   GstTensorsInfo gst_info;
     293              :   int status;
     294              : 
     295         6116 :   gst_tensors_info_init (&gst_info);
     296         6116 :   gst_info.num_tensors = num_tensors = gst_tensor_buffer_get_count (b);
     297              : 
     298              :   /* Set tensor data. The handle for tensors-info in data should be added. */
     299              :   status =
     300         6116 :       _ml_tensors_data_create_no_alloc (NULL, (ml_tensors_data_h *) & _data);
     301         6116 :   if (status != ML_ERROR_NONE) {
     302            0 :     _ml_loge (_ml_detail
     303              :         ("Failed to allocate memory for tensors data in sink callback, which is registered by ml_pipeline_sink_register ()."));
     304         6116 :     return;
     305              :   }
     306              : 
     307         6116 :   g_mutex_lock (&elem->lock);
     308              : 
     309         6116 :   _data->num_tensors = num_tensors;
     310        12709 :   for (i = 0; i < num_tensors; i++) {
     311         6593 :     mem[i] = gst_tensor_buffer_get_nth_memory (b, i);
     312         6593 :     if (!gst_memory_map (mem[i], &map[i], GST_MAP_READ)) {
     313            0 :       _ml_loge (_ml_detail
     314              :           ("Failed to map the output in sink '%s' callback, which is registered by ml_pipeline_sink_register ()",
     315              :               elem->name));
     316            0 :       gst_memory_unref (mem[i]);
     317            0 :       num_tensors = i;
     318            0 :       goto error;
     319              :     }
     320              : 
     321         6593 :     _data->tensors[i].data = map[i].data;
     322         6593 :     _data->tensors[i].size = map[i].size;
     323              :   }
     324              : 
     325              :   /** @todo This assumes that padcap is static */
     326         6116 :   if (elem->sink == NULL) {
     327           28 :     gboolean found = FALSE;
     328           28 :     gboolean flexible = FALSE;
     329              : 
     330              :     /* Get the sink-pad-cap */
     331           28 :     elem->sink = gst_element_get_static_pad (elem->element, "sink");
     332              : 
     333           28 :     if (elem->sink) {
     334              :       /* sinkpadcap available (negotiated) */
     335           28 :       GstCaps *caps = gst_pad_get_current_caps (elem->sink);
     336              : 
     337           28 :       if (caps) {
     338           28 :         found = get_tensors_info_from_caps (caps, &elem->tensors_info,
     339              :             &flexible);
     340           28 :         gst_caps_unref (caps);
     341              :       }
     342              :     }
     343              : 
     344           28 :     if (found) {
     345           28 :       elem->is_flexible_tensor = flexible;
     346              :     } else {
     347              :       /* It is not valid */
     348            0 :       if (elem->sink) {
     349            0 :         gst_object_unref (elem->sink);
     350            0 :         elem->sink = NULL;
     351              :       }
     352              : 
     353            0 :       goto error;
     354              :     }
     355              :   }
     356              : 
     357              :   /* Prepare output and set data. */
     358         6116 :   if (elem->is_flexible_tensor) {
     359              :     GstTensorMetaInfo meta;
     360              :     gsize hsize;
     361              : 
     362              :     /* handle header for flex tensor */
     363           12 :     for (i = 0; i < num_tensors; i++) {
     364            9 :       gst_tensor_meta_info_parse_header (&meta, map[i].data);
     365            9 :       hsize = gst_tensor_meta_info_get_header_size (&meta);
     366              : 
     367            9 :       gst_tensor_meta_info_convert (&meta,
     368              :           gst_tensors_info_get_nth_info (&gst_info, i));
     369              : 
     370            9 :       _data->tensors[i].data = map[i].data + hsize;
     371            9 :       _data->tensors[i].size = map[i].size - hsize;
     372              :     }
     373              :   } else {
     374         6113 :     gst_tensors_info_copy (&gst_info, &elem->tensors_info);
     375              : 
     376              :     /* Compare output info and buffer if gst-buffer is not flexible. */
     377         6113 :     if (gst_info.num_tensors != num_tensors) {
     378            0 :       _ml_loge (_ml_detail
     379              :           ("The sink event of [%s] cannot be handled because the number of tensors mismatches.",
     380              :               elem->name));
     381              : 
     382            0 :       gst_object_unref (elem->sink);
     383            0 :       elem->sink = NULL;
     384            0 :       goto error;
     385              :     }
     386              : 
     387        12697 :     for (i = 0; i < num_tensors; i++) {
     388         6584 :       size_t sz = gst_tensors_info_get_size (&gst_info, i);
     389              : 
     390              :       /* Not configured, yet. */
     391         6584 :       if (sz == 0)
     392            0 :         _ml_loge (_ml_detail
     393              :             ("The caps for sink(%s) is not configured.", elem->name));
     394              : 
     395         6584 :       if (sz != map[i].size) {
     396            0 :         _ml_loge (_ml_detail
     397              :             ("The sink event of [%s] cannot be handled because the tensor dimension mismatches.",
     398              :                 elem->name));
     399              : 
     400            0 :         gst_object_unref (elem->sink);
     401            0 :         elem->sink = NULL;
     402            0 :         goto error;
     403              :       }
     404              :     }
     405              :   }
     406              : 
     407              :   /* Create new output info, data handle should be updated here. */
     408         6116 :   _ml_tensors_info_create_from_gst (&_data->info, &gst_info);
     409              : 
     410              :   /* Iterate e->handles, pass the data to them */
     411        12238 :   for (l = elem->handles; l != NULL; l = l->next) {
     412              :     ml_pipeline_sink_cb callback;
     413         6122 :     ml_pipeline_common_elem *sink = l->data;
     414         6122 :     if (sink->callback_info == NULL)
     415            3 :       continue;
     416              : 
     417         6119 :     callback = sink->callback_info->sink_cb;
     418         6119 :     if (callback)
     419         6119 :       callback (_data, _data->info, sink->callback_info->sink_pdata);
     420              : 
     421              :     /** @todo Measure time. Warn if it takes long. Kill if it takes too long. */
     422              :   }
     423              : 
     424         6116 : error:
     425         6116 :   g_mutex_unlock (&elem->lock);
     426              : 
     427        12709 :   for (i = 0; i < num_tensors; i++) {
     428         6593 :     gst_memory_unmap (mem[i], &map[i]);
     429         6593 :     gst_memory_unref (mem[i]);
     430              :   }
     431              : 
     432         6116 :   _ml_tensors_data_destroy_internal (_data, FALSE);
     433         6116 :   _data = NULL;
     434              : 
     435         6116 :   gst_tensors_info_free (&gst_info);
     436         6116 :   return;
     437              : }
     438              : 
     439              : /**
     440              :  * @brief Handle a appsink element for registered ml_pipeline_sink_cb
     441              :  */
     442              : static GstFlowReturn
     443            9 : cb_appsink_new_sample (GstElement * e, gpointer user_data)
     444              : {
     445              :   GstSample *sample;
     446              :   GstBuffer *buffer;
     447              : 
     448              :   /* get the sample from appsink */
     449            9 :   sample = gst_app_sink_pull_sample (GST_APP_SINK (e));
     450            9 :   buffer = gst_sample_get_buffer (sample);
     451              : 
     452            9 :   cb_sink_event (e, buffer, user_data);
     453              : 
     454            9 :   gst_sample_unref (sample);
     455            9 :   return GST_FLOW_OK;
     456              : }
     457              : 
     458              : /**
     459              :  * @brief Callback for bus message.
     460              :  */
     461              : static void
     462         5408 : cb_bus_sync_message (GstBus * bus, GstMessage * message, gpointer user_data)
     463              : {
     464              :   ml_pipeline *pipe_h;
     465              : 
     466         5408 :   pipe_h = (ml_pipeline *) user_data;
     467              : 
     468         5408 :   if (pipe_h == NULL)
     469            0 :     return;
     470              : 
     471         5408 :   switch (GST_MESSAGE_TYPE (message)) {
     472            7 :     case GST_MESSAGE_EOS:
     473            7 :       pipe_h->isEOS = TRUE;
     474            7 :       break;
     475         4391 :     case GST_MESSAGE_STATE_CHANGED:
     476         4391 :       if (GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipe_h->element)) {
     477              :         GstState old_state, new_state;
     478              : 
     479          507 :         gst_message_parse_state_changed (message, &old_state, &new_state, NULL);
     480          507 :         pipe_h->pipe_state = (ml_pipeline_state_e) new_state;
     481              : 
     482          507 :         _ml_logd (_ml_detail ("The pipeline state changed from %s to %s.",
     483              :                 gst_element_state_get_name (old_state),
     484              :                 gst_element_state_get_name (new_state)));
     485              : 
     486          507 :         if (pipe_h->state_cb.cb) {
     487           11 :           pipe_h->state_cb.cb (pipe_h->pipe_state, pipe_h->state_cb.user_data);
     488              :         }
     489              :       }
     490         4391 :       break;
     491         1010 :     default:
     492         1010 :       break;
     493              :   }
     494              : }
     495              : 
     496              : /**
     497              :  * @brief Clean up each element of the pipeline.
     498              :  */
     499              : static void
     500          151 : free_element_handle (gpointer data)
     501              : {
     502          151 :   ml_pipeline_common_elem *item = (ml_pipeline_common_elem *) data;
     503              :   ml_pipeline_element *elem;
     504              : 
     505          151 :   if (!(item && item->callback_info)) {
     506          109 :     g_free (item);
     507          109 :     return;
     508              :   }
     509              : 
     510              :   /* clear callbacks */
     511           42 :   item->callback_info->sink_cb = NULL;
     512           42 :   elem = item->element;
     513           42 :   if (elem && elem->type == ML_PIPELINE_ELEMENT_APP_SRC) {
     514            2 :     GstAppSrcCallbacks appsrc_cb = { 0, };
     515            2 :     gst_app_src_set_callbacks (GST_APP_SRC (elem->element), &appsrc_cb,
     516              :         NULL, NULL);
     517              :   }
     518              : 
     519           42 :   g_free (item->callback_info);
     520           42 :   item->callback_info = NULL;
     521           42 :   g_free (item);
     522              : }
     523              : 
     524              : /**
     525              :  * @brief Private function for ml_pipeline_destroy, cleaning up nodes in namednodes
     526              :  */
     527              : static void
     528          394 : cleanup_node (gpointer data)
     529              : {
     530          394 :   ml_pipeline_element *e = data;
     531              : 
     532          394 :   g_mutex_lock (&e->lock);
     533              :   /** @todo CRITICAL. Stop the handle callbacks if they are running/ready */
     534          394 :   if (e->handle_id > 0) {
     535           27 :     g_signal_handler_disconnect (e->element, e->handle_id);
     536           27 :     e->handle_id = 0;
     537              :   }
     538              : 
     539              :   /* clear all handles first */
     540          394 :   if (e->handles)
     541           63 :     g_list_free_full (e->handles, free_element_handle);
     542          394 :   e->handles = NULL;
     543              : 
     544          394 :   if (e->type == ML_PIPELINE_ELEMENT_APP_SRC) {
     545           55 :     ml_pipeline *p = e->pipe;
     546              : 
     547           55 :     if (p && !p->isEOS) {
     548           55 :       int eos_check_cnt = 0;
     549              : 
     550              :       /** to push EOS event, the pipeline should be in PAUSED state */
     551           55 :       gst_element_set_state (p->element, GST_STATE_PAUSED);
     552              : 
     553           55 :       if (gst_app_src_end_of_stream (GST_APP_SRC (e->element)) != GST_FLOW_OK) {
     554            0 :         _ml_logw (_ml_detail
     555              :             ("Cleaning up a pipeline has failed to set End-Of-Stream for the pipeline element of %s",
     556              :                 e->name));
     557              :       }
     558              : 
     559           55 :       g_mutex_unlock (&e->lock);
     560         5500 :       while (!p->isEOS) {
     561         5500 :         eos_check_cnt++;
     562              :         /** check EOS every 1ms */
     563         5500 :         g_usleep (1000);
     564         5500 :         if (eos_check_cnt >= EOS_MESSAGE_TIME_LIMIT) {
     565           55 :           _ml_loge (_ml_detail
     566              :               ("Cleaning up a pipeline has requested to set End-Of-Stream. However, the pipeline has not become EOS after the timeout. It has failed to become EOS with the element of %s.",
     567              :                   e->name));
     568           55 :           break;
     569              :         }
     570              :       }
     571           55 :       g_mutex_lock (&e->lock);
     572              :     }
     573              :   }
     574              : 
     575          394 :   if (e->custom_destroy) {
     576            6 :     e->custom_destroy (e->custom_data, e);
     577              :   }
     578              : 
     579          394 :   g_free (e->name);
     580          394 :   if (e->src)
     581           41 :     gst_object_unref (e->src);
     582          394 :   if (e->sink)
     583           28 :     gst_object_unref (e->sink);
     584              : 
     585          394 :   gst_object_unref (e->element);
     586              : 
     587          394 :   gst_tensors_info_free (&e->tensors_info);
     588              : 
     589          394 :   g_mutex_unlock (&e->lock);
     590          394 :   g_mutex_clear (&e->lock);
     591              : 
     592          394 :   g_free (e);
     593          394 : }
     594              : 
     595              : /**
     596              :  * @brief Private function to release the pipeline resources
     597              :  */
     598              : static void
     599            0 : cleanup_resource (gpointer data)
     600              : {
     601            0 :   pipeline_resource_s *res = data;
     602              : 
     603              :   /* check resource type and free data */
     604            0 :   if (g_str_has_prefix (res->type, "tizen")) {
     605            0 :     release_tizen_resource (res->handle, res->type);
     606              :   }
     607              : 
     608            0 :   g_free (res->type);
     609            0 :   g_free (res);
     610            0 : }
     611              : 
     612              : /**
     613              :  * @brief Converts predefined element in pipeline description.
     614              :  */
     615              : static int
     616          148 : convert_description (ml_pipeline_h pipe, const gchar * description,
     617              :     gchar ** result, gboolean is_internal)
     618              : {
     619              :   gchar *converted;
     620          148 :   int status = ML_ERROR_NONE;
     621              : 
     622          296 :   g_return_val_if_fail (pipe, ML_ERROR_INVALID_PARAMETER);
     623          148 :   g_return_val_if_fail (description && result, ML_ERROR_INVALID_PARAMETER);
     624              : 
     625              :   /* init null */
     626          148 :   *result = NULL;
     627              : 
     628          148 :   converted = _ml_convert_predefined_entity (description);
     629              : 
     630              :   /* convert pre-defined element for Tizen */
     631          148 :   status = convert_tizen_element (pipe, &converted, is_internal);
     632              : 
     633          148 :   if (status == ML_ERROR_NONE) {
     634          148 :     _ml_logd (_ml_detail
     635              :         ("Pipeline element converted with aliases for gstreamer (Tizen element aliases): %s",
     636              :             converted));
     637          148 :     *result = converted;
     638              :   } else {
     639            0 :     g_free (converted);
     640            0 :     _ml_error_report_continue
     641              :         ("Failed to convert element: convert_tizen_element() returned %d",
     642              :         status);
     643              :   }
     644              : 
     645          148 :   return status;
     646              : }
     647              : 
     648              : /**
     649              :  * @brief Handle tensor-filter options.
     650              :  */
     651              : static void
     652           39 : process_tensor_filter_option (ml_pipeline_element * e)
     653              : {
     654           39 :   gchar *fw = NULL;
     655           39 :   gchar *model = NULL;
     656              :   pipe_custom_data_s *custom_data;
     657              : 
     658           39 :   g_object_get (G_OBJECT (e->element), "framework", &fw, "model", &model, NULL);
     659              : 
     660           39 :   if (fw && g_ascii_strcasecmp (fw, "custom-easy") == 0) {
     661              :     /* ref to tensor-filter custom-easy handle. */
     662            3 :     custom_data = pipe_custom_find_data (PIPE_CUSTOM_TYPE_FILTER, model);
     663            3 :     if (custom_data) {
     664            3 :       ml_pipeline_custom_filter_ref (custom_data->handle);
     665              : 
     666            3 :       e->custom_destroy = pipe_custom_destroy_cb;
     667            3 :       e->custom_data = custom_data;
     668              :     }
     669              :   }
     670              : 
     671           39 :   g_free (fw);
     672           39 :   g_free (model);
     673           39 : }
     674              : 
     675              : /**
     676              :  * @brief Handle tensor-if options.
     677              :  */
     678              : static void
     679            3 : process_tensor_if_option (ml_pipeline_element * e)
     680              : {
     681            3 :   gint cv = 0;
     682            3 :   gchar *cv_option = NULL;
     683              :   pipe_custom_data_s *custom_data;
     684              : 
     685            3 :   g_object_get (G_OBJECT (e->element), "compared-value", &cv,
     686              :       "compared-value-option", &cv_option, NULL);
     687              : 
     688            3 :   if (cv == 5) {
     689              :     /* cv is TIFCV_CUSTOM, ref to tensor-if custom handle. */
     690            3 :     custom_data = pipe_custom_find_data (PIPE_CUSTOM_TYPE_IF, cv_option);
     691            3 :     if (custom_data) {
     692            3 :       ml_pipeline_if_custom_ref (custom_data->handle);
     693              : 
     694            3 :       e->custom_destroy = pipe_custom_destroy_cb;
     695            3 :       e->custom_data = custom_data;
     696              :     }
     697              :   }
     698              : 
     699            3 :   g_free (cv_option);
     700            3 : }
     701              : 
     702              : /**
     703              :  * @brief Initializes the GStreamer library. This is internal function.
     704              :  */
     705              : int
     706          233 : _ml_initialize_gstreamer (void)
     707              : {
     708          233 :   GError *err = NULL;
     709              : 
     710          233 :   if (!gst_init_check (NULL, NULL, &err)) {
     711            0 :     if (err) {
     712            0 :       _ml_error_report
     713              :           ("Initrializing ML-API failed: GStreamer has the following error from gst_init_check(): %s",
     714              :           err->message);
     715            0 :       g_clear_error (&err);
     716              :     } else {
     717            0 :       _ml_error_report ("Cannot initialize GStreamer. Unknown reason.");
     718              :     }
     719              : 
     720          233 :     return ML_ERROR_STREAMS_PIPE;
     721              :   }
     722              : 
     723          233 :   return ML_ERROR_NONE;
     724              : }
     725              : 
     726              : /**
     727              :  * @brief Checks the element is registered and available on the pipeline.
     728              :  */
     729              : int
     730           79 : ml_check_element_availability (const char *element_name, bool *available)
     731              : {
     732              :   GstElementFactory *factory;
     733              :   int status;
     734              : 
     735           79 :   check_feature_state (ML_FEATURE_INFERENCE);
     736              : 
     737           79 :   if (!element_name)
     738            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     739              :         "The parameter, element_name, is NULL. It should be a name (string) to be queried if it exists as a GStreamer/NNStreamer element.");
     740              : 
     741           78 :   if (!available)
     742            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     743              :         "The parameter, available, is NULL. It should be a valid pointer to a bool entry so that the API (ml_check_element_availability) may return the queried result via \"available\" parameter. E.g., bool available; ml_check_element_availability (\"tensor_converter\", &available);");
     744              : 
     745           77 :   _ml_error_report_return_continue_iferr (_ml_initialize_gstreamer (),
     746              :       "Internal error of _ml_initialize_gstreamer(). Check the availability of gstreamer libraries in your system.");
     747              : 
     748              :   /* init false */
     749           77 :   *available = false;
     750              : 
     751           77 :   factory = gst_element_factory_find (element_name);
     752           77 :   if (factory) {
     753           76 :     GstPluginFeature *feature = GST_PLUGIN_FEATURE (factory);
     754           76 :     const gchar *plugin_name = gst_plugin_feature_get_plugin_name (feature);
     755              : 
     756              :     /* check restricted element */
     757           76 :     status = _ml_check_plugin_availability (plugin_name, element_name);
     758           76 :     if (status == ML_ERROR_NONE)
     759           63 :       *available = true;
     760              : 
     761           76 :     gst_object_unref (factory);
     762              :   }
     763              : 
     764           77 :   return ML_ERROR_NONE;
     765              : }
     766              : 
     767              : /**
     768              :  * @brief Checks the availability of the plugin.
     769              :  */
     770              : int
     771          927 : _ml_check_plugin_availability (const char *plugin_name,
     772              :     const char *element_name)
     773              : {
     774              :   static gboolean list_loaded = FALSE;
     775              :   static gchar **allowed_elements = NULL;
     776              : 
     777          927 :   if (!plugin_name)
     778            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     779              :         "The parameter, plugin_name, is NULL. It should be a valid string.");
     780              : 
     781          926 :   if (!element_name)
     782            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     783              :         "The parameter, element_name, is NULL. It should be a valid string.");
     784              : 
     785          925 :   if (!list_loaded) {
     786              :     gboolean restricted;
     787              : 
     788              :     restricted =
     789            7 :         nnsconf_get_custom_value_bool ("element-restriction",
     790              :         "enable_element_restriction", FALSE);
     791            7 :     if (restricted) {
     792              :       gchar *elements;
     793              : 
     794              :       /* check white-list of available plugins */
     795              :       elements =
     796            7 :           nnsconf_get_custom_value_string ("element-restriction",
     797              :           "allowed_elements");
     798            7 :       if (elements) {
     799            7 :         allowed_elements = g_strsplit_set (elements, " ,;", -1);
     800            7 :         g_free (elements);
     801              :       }
     802              :     }
     803              : 
     804            7 :     list_loaded = TRUE;
     805              :   }
     806              : 
     807              :   /* nnstreamer elements */
     808          925 :   if (g_str_has_prefix (plugin_name, "nnstreamer") &&
     809          272 :       g_str_has_prefix (element_name, "tensor_")) {
     810          272 :     return ML_ERROR_NONE;
     811              :   }
     812              : 
     813          653 :   if (allowed_elements &&
     814          653 :       find_key_strv ((const gchar **) allowed_elements, element_name) < 0) {
     815           13 :     _ml_error_report_return (ML_ERROR_NOT_SUPPORTED,
     816              :         "The element %s is restricted.", element_name);
     817              :   }
     818              : 
     819          640 :   return ML_ERROR_NONE;
     820              : }
     821              : 
     822              : /**
     823              :  * @brief Get the ml_pipeline_element_e type from its element name
     824              :  */
     825              : static ml_pipeline_element_e
     826          860 : get_elem_type_from_name (GHashTable * table, const gchar * name)
     827              : {
     828          860 :   gpointer value = g_hash_table_lookup (table, name);
     829          860 :   if (!value)
     830          504 :     return ML_PIPELINE_ELEMENT_UNKNOWN;
     831              : 
     832          356 :   return GPOINTER_TO_INT (value);
     833              : }
     834              : 
     835              : /**
     836              :  * @brief Iterate elements and prepare element handle.
     837              :  */
     838              : static int
     839          145 : iterate_element (ml_pipeline * pipe_h, GstElement * pipeline,
     840              :     gboolean is_internal)
     841              : {
     842          145 :   GstIterator *it = NULL;
     843          145 :   int status = ML_ERROR_NONE;
     844              : 
     845          145 :   g_return_val_if_fail (pipe_h && pipeline, ML_ERROR_INVALID_PARAMETER);
     846              : 
     847          145 :   g_mutex_lock (&pipe_h->lock);
     848              : 
     849          145 :   it = gst_bin_iterate_elements (GST_BIN (pipeline));
     850          145 :   if (it != NULL) {
     851          145 :     gboolean done = FALSE;
     852          145 :     GValue item = G_VALUE_INIT;
     853              :     GObject *obj;
     854              :     gchar *name;
     855              : 
     856              :     /* Fill in the hashtable, "namednodes" with named Elements */
     857         1295 :     while (!done) {
     858         1005 :       switch (gst_iterator_next (it, &item)) {
     859          860 :         case GST_ITERATOR_OK:
     860          860 :           obj = g_value_get_object (&item);
     861              : 
     862          860 :           if (GST_IS_ELEMENT (obj)) {
     863          860 :             GstElement *elem = GST_ELEMENT (obj);
     864              :             GstPluginFeature *feature =
     865          860 :                 GST_PLUGIN_FEATURE (gst_element_get_factory (elem));
     866              :             const gchar *plugin_name =
     867          860 :                 gst_plugin_feature_get_plugin_name (feature);
     868          860 :             const gchar *element_name = gst_plugin_feature_get_name (feature);
     869              : 
     870              :             /* validate the availability of the plugin */
     871          860 :             if (!is_internal && _ml_check_plugin_availability (plugin_name,
     872              :                     element_name) != ML_ERROR_NONE) {
     873            0 :               _ml_error_report_continue
     874              :                   ("There is a pipeline element (filter) that is not allowed for applications via ML-API (privilege not granted) or now available: '%s'/'%s'.",
     875              :                   plugin_name, element_name);
     876            0 :               status = ML_ERROR_NOT_SUPPORTED;
     877            0 :               done = TRUE;
     878            0 :               break;
     879              :             }
     880              : 
     881          860 :             name = gst_element_get_name (elem);
     882          860 :             if (name != NULL) {
     883              :               ml_pipeline_element_e element_type =
     884          860 :                   get_elem_type_from_name (pipe_h->pipe_elm_type, element_name);
     885              : 
     886              :               /* check 'sync' property in sink element */
     887          860 :               if (element_type == ML_PIPELINE_ELEMENT_SINK ||
     888              :                   element_type == ML_PIPELINE_ELEMENT_APP_SINK) {
     889          137 :                 gboolean sync = FALSE;
     890              : 
     891          137 :                 g_object_get (G_OBJECT (elem), "sync", &sync, NULL);
     892          137 :                 if (sync) {
     893            1 :                   _ml_logw (_ml_detail
     894              :                       ("It is recommended to apply 'sync=false' property to a sink element in most AI applications. Otherwise, inference results of large neural networks will be frequently dropped by the synchronization mechanism at the sink element."));
     895              :                 }
     896              :               }
     897              : 
     898          860 :               if (element_type != ML_PIPELINE_ELEMENT_UNKNOWN) {
     899              :                 ml_pipeline_element *e;
     900              : 
     901          356 :                 e = construct_element (gst_object_ref (elem), pipe_h, name,
     902              :                     element_type);
     903          356 :                 if (e != NULL) {
     904          356 :                   if (g_str_equal (element_name, "tensor_if"))
     905            3 :                     process_tensor_if_option (e);
     906          353 :                   else if (g_str_equal (element_name, "tensor_filter"))
     907           39 :                     process_tensor_filter_option (e);
     908              : 
     909          356 :                   g_hash_table_insert (pipe_h->namednodes, g_strdup (name), e);
     910              :                 } else {
     911              :                   /* allocation failure */
     912            0 :                   gst_object_unref (elem);
     913            0 :                   _ml_error_report_continue
     914              :                       ("Cannot allocate memory with construct_element().");
     915            0 :                   status = ML_ERROR_OUT_OF_MEMORY;
     916            0 :                   done = TRUE;
     917              :                 }
     918              :               }
     919              : 
     920          860 :               g_free (name);
     921              :             }
     922              :           }
     923              : 
     924          860 :           g_value_reset (&item);
     925          860 :           break;
     926            0 :         case GST_ITERATOR_RESYNC:
     927              :         case GST_ITERATOR_ERROR:
     928            0 :           _ml_logw (_ml_detail
     929              :               ("There is an error or a resync-event while inspecting a pipeline. However, we can still execute the pipeline."));
     930              :           /* fallthrough */
     931          145 :         case GST_ITERATOR_DONE:
     932          145 :           done = TRUE;
     933              :       }
     934              :     }
     935              : 
     936          145 :     g_value_unset (&item);
     937              :     /** @todo CRITICAL check the validity of elem=item registered in e */
     938          145 :     gst_iterator_free (it);
     939              :   }
     940              : 
     941          145 :   g_mutex_unlock (&pipe_h->lock);
     942          145 :   return status;
     943              : }
     944              : 
     945              : /**
     946              :  * @brief Internal function to create the hash table for managing internal resources
     947              :  */
     948              : static void
     949          148 : create_internal_hash (ml_pipeline * pipe_h)
     950              : {
     951          148 :   pipe_h->namednodes =
     952          148 :       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, cleanup_node);
     953          148 :   pipe_h->resources =
     954          148 :       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, cleanup_resource);
     955              : 
     956          148 :   pipe_h->pipe_elm_type =
     957          148 :       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
     958          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("tensor_sink"),
     959              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_SINK));
     960          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("appsrc"),
     961              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_APP_SRC));
     962          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("appsink"),
     963              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_APP_SINK));
     964          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("valve"),
     965              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_VALVE));
     966          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("input-selector"),
     967              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_SWITCH_INPUT));
     968          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("output-selector"),
     969              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_SWITCH_OUTPUT));
     970          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("tensor_if"),
     971              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_COMMON));
     972          148 :   g_hash_table_insert (pipe_h->pipe_elm_type, g_strdup ("tensor_filter"),
     973              :       GINT_TO_POINTER (ML_PIPELINE_ELEMENT_COMMON));
     974          148 : }
     975              : 
     976              : /**
     977              :  * @brief Internal function to construct the pipeline.
     978              :  * If is_internal is true, this will ignore the permission in Tizen.
     979              :  */
     980              : static int
     981          150 : construct_pipeline_internal (const char *pipeline_description,
     982              :     ml_pipeline_state_cb cb, void *user_data, ml_pipeline_h * pipe,
     983              :     gboolean is_internal)
     984              : {
     985          150 :   GError *err = NULL;
     986              :   GstElement *pipeline;
     987          150 :   gchar *description = NULL;
     988          150 :   int status = ML_ERROR_NONE;
     989              : 
     990              :   ml_pipeline *pipe_h;
     991              : 
     992          300 :   check_feature_state (ML_FEATURE_INFERENCE);
     993              : 
     994          150 :   if (!pipe)
     995            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     996              :         "ml_pipeline_construct error: parameter pipe is NULL. It should be a valid ml_pipeline_h pointer. E.g., ml_pipeline_h pipe; ml_pipeline_construct (..., &pip);");
     997              : 
     998          149 :   if (!pipeline_description)
     999            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1000              :         "ml_pipeline_construct error: parameter pipeline_description is NULL. It should be a valid string of Gstreamer/NNStreamer pipeline description.");
    1001              : 
    1002              :   /* init null */
    1003          148 :   *pipe = NULL;
    1004              : 
    1005          148 :   _ml_error_report_return_continue_iferr (_ml_initialize_gstreamer (),
    1006              :       "ml_pipeline_construct error: it has failed to initialize gstreamer(). Please check if you have a valid GStreamer library installed in your system.");
    1007              : 
    1008              :   /* prepare pipeline handle */
    1009          148 :   pipe_h = g_new0 (ml_pipeline, 1);
    1010          148 :   if (pipe_h == NULL)
    1011            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
    1012              :         "ml_pipeline_construct error: failed to allocate memory for pipeline handle. Out of memory?");
    1013              : 
    1014          148 :   g_mutex_init (&pipe_h->lock);
    1015              : 
    1016          148 :   pipe_h->isEOS = FALSE;
    1017          148 :   pipe_h->pipe_state = ML_PIPELINE_STATE_UNKNOWN;
    1018              : 
    1019          148 :   create_internal_hash (pipe_h);
    1020              : 
    1021              :   /* convert predefined element and launch the pipeline */
    1022          148 :   status = convert_description ((ml_pipeline_h) pipe_h, pipeline_description,
    1023              :       &description, is_internal);
    1024          148 :   if (status != ML_ERROR_NONE) {
    1025            0 :     _ml_error_report_continue
    1026              :         ("ml_pipeline_construct error: failed while converting pipeline description for GStreamer w/ convert_description() function, which has returned %d",
    1027              :         status);
    1028            0 :     goto failed;
    1029              :   }
    1030              : 
    1031          148 :   pipeline = gst_parse_launch (description, &err);
    1032          148 :   g_free (description);
    1033              : 
    1034          148 :   if (pipeline == NULL || err) {
    1035            3 :     _ml_error_report
    1036              :         ("ml_pipeline_construct error: gst_parse_launch cannot parse and launch the given pipeline = [%s]. The error message from gst_parse_launch is '%s'.",
    1037              :         pipeline_description, (err) ? err->message : "unknown reason");
    1038            3 :     g_clear_error (&err);
    1039              : 
    1040            3 :     if (pipeline)
    1041            3 :       gst_object_unref (pipeline);
    1042              : 
    1043            3 :     status = ML_ERROR_STREAMS_PIPE;
    1044            3 :     goto failed;
    1045              :   }
    1046              : 
    1047          145 :   g_assert (GST_IS_PIPELINE (pipeline));
    1048          145 :   pipe_h->element = pipeline;
    1049              : 
    1050              :   /* bus and message callback */
    1051          145 :   pipe_h->bus = gst_element_get_bus (pipeline);
    1052          145 :   g_assert (pipe_h->bus);
    1053              : 
    1054          145 :   gst_bus_enable_sync_message_emission (pipe_h->bus);
    1055          145 :   pipe_h->signal_msg = g_signal_connect (pipe_h->bus, "sync-message",
    1056              :       G_CALLBACK (cb_bus_sync_message), pipe_h);
    1057              : 
    1058              :   /* state change callback */
    1059          145 :   pipe_h->state_cb.cb = cb;
    1060          145 :   pipe_h->state_cb.user_data = user_data;
    1061              : 
    1062              :   /* iterate elements and prepare element handle */
    1063          145 :   status = iterate_element (pipe_h, pipeline, is_internal);
    1064          145 :   if (status != ML_ERROR_NONE) {
    1065            0 :     _ml_error_report_continue ("ml_pipeline_construct error: ...");
    1066            0 :     goto failed;
    1067              :   }
    1068              : 
    1069              :   /* finally set pipeline state to PAUSED */
    1070          145 :   status = ml_pipeline_stop ((ml_pipeline_h) pipe_h);
    1071              : 
    1072          145 :   if (status == ML_ERROR_NONE) {
    1073              :     /**
    1074              :      * Let's wait until the pipeline state is changed to paused.
    1075              :      * Otherwise, the following APIs like 'set_property' may incur
    1076              :      * unintended behaviors. But, don't need to return any error
    1077              :      * even if this state change is not finished within the timeout,
    1078              :      * just replying on the caller.
    1079              :      */
    1080          144 :     gst_element_get_state (pipeline, NULL, NULL, 10 * GST_MSECOND);
    1081              :   } else {
    1082            1 :     _ml_error_report_continue
    1083              :         ("ml_pipeline_construct error: ml_pipeline_stop has failed with %d return. The pipeline should be able to be stopped when it is constructed.",
    1084              :         status);
    1085              :   }
    1086              : 
    1087          148 : failed:
    1088          148 :   if (status != ML_ERROR_NONE) {
    1089              :     /* failed to construct the pipeline */
    1090            4 :     ml_pipeline_destroy ((ml_pipeline_h) pipe_h);
    1091              :   } else {
    1092          144 :     *pipe = pipe_h;
    1093              :   }
    1094              : 
    1095          148 :   return status;
    1096              : }
    1097              : 
    1098              : /**
    1099              :  * @brief Construct the pipeline (more info in nnstreamer.h)
    1100              :  */
    1101              : int
    1102          148 : ml_pipeline_construct (const char *pipeline_description,
    1103              :     ml_pipeline_state_cb cb, void *user_data, ml_pipeline_h * pipe)
    1104              : {
    1105              :   /* not an internal pipeline construction */
    1106          148 :   return construct_pipeline_internal (pipeline_description, cb, user_data, pipe,
    1107              :       FALSE);
    1108              : }
    1109              : 
    1110              : #if defined (__TIZEN__)
    1111              : /**
    1112              :  * @brief Construct the pipeline (Tizen internal, see nnstreamer-tizen-internal.h)
    1113              :  */
    1114              : int
    1115            2 : ml_pipeline_construct_internal (const char *pipeline_description,
    1116              :     ml_pipeline_state_cb cb, void *user_data, ml_pipeline_h * pipe)
    1117              : {
    1118              :   /* Tizen internal pipeline construction */
    1119            2 :   return construct_pipeline_internal (pipeline_description, cb, user_data, pipe,
    1120              :       TRUE);
    1121              : }
    1122              : #endif /* __TIZEN__ */
    1123              : 
    1124              : /**
    1125              :  * @brief Destroy the pipeline (more info in nnstreamer.h)
    1126              :  */
    1127              : int
    1128          143 : ml_pipeline_destroy (ml_pipeline_h pipe)
    1129              : {
    1130          143 :   ml_pipeline *p = pipe;
    1131              :   GstStateChangeReturn scret;
    1132              :   GstState state;
    1133          143 :   guint check_paused_cnt = 0;
    1134              : 
    1135          286 :   check_feature_state (ML_FEATURE_INFERENCE);
    1136              : 
    1137          143 :   if (p == NULL)
    1138            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1139              :         "The parameter, pipe, is NULL. It should be a valid ml_pipeline_h handle instance, usually created by ml_pipeline_construct().");
    1140              : 
    1141          143 :   g_mutex_lock (&p->lock);
    1142              : 
    1143              :   /* Before changing the state, remove all callbacks. */
    1144          143 :   p->state_cb.cb = NULL;
    1145              : 
    1146              :   /* Destroy registered callback handles and resources */
    1147          143 :   g_hash_table_destroy (p->namednodes);
    1148          143 :   g_hash_table_destroy (p->resources);
    1149          143 :   g_hash_table_destroy (p->pipe_elm_type);
    1150          143 :   p->namednodes = p->resources = p->pipe_elm_type = NULL;
    1151              : 
    1152          143 :   if (p->element) {
    1153              :     /* Pause the pipeline if it's playing */
    1154          140 :     scret = gst_element_get_state (p->element, &state, NULL, 10 * GST_MSECOND); /* 10ms */
    1155          140 :     if (scret != GST_STATE_CHANGE_FAILURE && state == GST_STATE_PLAYING) {
    1156            3 :       scret = gst_element_set_state (p->element, GST_STATE_PAUSED);
    1157            3 :       if (scret == GST_STATE_CHANGE_FAILURE) {
    1158            0 :         g_mutex_unlock (&p->lock);
    1159            0 :         _ml_error_report_return (ML_ERROR_STREAMS_PIPE,
    1160              :             "gst_element_get_state() has failed to wait until state changed from PLAYING to PAUSED and returned GST_STATE_CHANGE_FAILURE. For the detail, please check the GStreamer log messages (or dlog messages in Tizen). It is possible that there is a filter or neural network that is taking too much time to finish.");
    1161              :       }
    1162              :     }
    1163              : 
    1164          140 :     g_mutex_unlock (&p->lock);
    1165          239 :     while (p->pipe_state == ML_PIPELINE_STATE_PLAYING) {
    1166          100 :       check_paused_cnt++;
    1167              :       /** check PAUSED every 1ms */
    1168          100 :       g_usleep (1000);
    1169          100 :       if (check_paused_cnt >= WAIT_PAUSED_TIME_LIMIT) {
    1170            1 :         _ml_error_report
    1171              :             ("Timeout while waiting for a state change to 'PAUSED' from a 'sync-message' signal from the pipeline. It is possible that there is a filter or neural network that is taking too much time to finish.");
    1172            1 :         break;
    1173              :       }
    1174              :     }
    1175          140 :     g_mutex_lock (&p->lock);
    1176              : 
    1177              :     /* Stop (NULL State) the pipeline */
    1178          140 :     scret = gst_element_set_state (p->element, GST_STATE_NULL);
    1179          140 :     if (scret != GST_STATE_CHANGE_SUCCESS) {
    1180            0 :       g_mutex_unlock (&p->lock);
    1181            0 :       _ml_error_report_return (ML_ERROR_STREAMS_PIPE,
    1182              :           "gst_element_set_state to stop the pipeline has failed after trying to stop the pipeline with PAUSE and waiting for stopping. For the detail, please check the GStreamer log messages. It is possible that there is a filter of neural network that is taking too much time to finish.");
    1183              :     }
    1184              : 
    1185          140 :     if (p->bus) {
    1186          140 :       g_signal_handler_disconnect (p->bus, p->signal_msg);
    1187          140 :       gst_object_unref (p->bus);
    1188              :     }
    1189              : 
    1190          140 :     gst_object_unref (p->element);
    1191          140 :     p->element = NULL;
    1192              :   }
    1193              : 
    1194          143 :   g_mutex_unlock (&p->lock);
    1195          143 :   g_mutex_clear (&p->lock);
    1196              : 
    1197          143 :   g_free (p);
    1198          143 :   return ML_ERROR_NONE;
    1199              : }
    1200              : 
    1201              : /**
    1202              :  * @brief Get the pipeline state (more info in nnstreamer.h)
    1203              :  */
    1204              : int
    1205           43 : ml_pipeline_get_state (ml_pipeline_h pipe, ml_pipeline_state_e * state)
    1206              : {
    1207           43 :   ml_pipeline *p = pipe;
    1208              :   GstState _state;
    1209              :   GstStateChangeReturn scret;
    1210              : 
    1211           86 :   check_feature_state (ML_FEATURE_INFERENCE);
    1212              : 
    1213           43 :   if (p == NULL)
    1214            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1215              :         "The parameter, pipe, is NULL. It should be a valid ml_pipeline_h handle, which is usually created by ml_pipeline_construct ().");
    1216           43 :   if (state == NULL)
    1217            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1218              :         "The parameter, state, is NULL. It should be a valid pointer of ml_pipeline_state_e. E.g., ml_pipeline_state_e state; ml_pipeline_get_state(pipe, &state);");
    1219              : 
    1220           43 :   *state = ML_PIPELINE_STATE_UNKNOWN;
    1221              : 
    1222           43 :   g_mutex_lock (&p->lock);
    1223           43 :   scret = gst_element_get_state (p->element, &_state, NULL, GST_MSECOND);       /* Do it within 1ms! */
    1224           43 :   g_mutex_unlock (&p->lock);
    1225              : 
    1226           43 :   if (scret == GST_STATE_CHANGE_FAILURE)
    1227            0 :     _ml_error_report_return (ML_ERROR_STREAMS_PIPE,
    1228              :         "Failed to get the state of the pipeline. For the detail, please check the GStreamer log messages.");
    1229              : 
    1230           43 :   *state = (ml_pipeline_state_e) _state;
    1231           43 :   return ML_ERROR_NONE;
    1232              : }
    1233              : 
    1234              : /****************************************************
    1235              :  ** NNStreamer Pipeline Start/Stop Control         **
    1236              :  ****************************************************/
    1237              : /**
    1238              :  * @brief Start/Resume the pipeline! (more info in nnstreamer.h)
    1239              :  */
    1240              : int
    1241           53 : ml_pipeline_start (ml_pipeline_h pipe)
    1242              : {
    1243           53 :   ml_pipeline *p = pipe;
    1244              :   GstStateChangeReturn scret;
    1245           53 :   int status = ML_ERROR_NONE;
    1246              : 
    1247           53 :   check_feature_state (ML_FEATURE_INFERENCE);
    1248              : 
    1249           53 :   if (p == NULL)
    1250            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1251              :         "The parameter, pipe, is NULL. It should be a valid ml_pipeline_h handle, which is usually created by ml_pipeline_construct ().");
    1252              : 
    1253           53 :   g_mutex_lock (&p->lock);
    1254              : 
    1255              :   /* check the resources when starting the pipeline */
    1256           53 :   if (g_hash_table_size (p->resources)) {
    1257              :     GHashTableIter iter;
    1258              :     gpointer key, value;
    1259              : 
    1260              :     /* iterate all handle and acquire res if released */
    1261            0 :     g_hash_table_iter_init (&iter, p->resources);
    1262            0 :     while (g_hash_table_iter_next (&iter, &key, &value)) {
    1263            0 :       if (g_str_has_prefix (key, "tizen")) {
    1264            0 :         status = get_tizen_resource (pipe, key);
    1265            0 :         if (status != ML_ERROR_NONE) {
    1266            0 :           _ml_error_report_continue
    1267              :               ("Internal API _ml_tizen_get_resource () has failed: Tizen mm resource manager has failed to acquire the resource of '%s'",
    1268              :               (gchar *) key);
    1269            0 :           goto done;
    1270              :         }
    1271              :       }
    1272              :     }
    1273              :   }
    1274              : 
    1275           53 :   scret = gst_element_set_state (p->element, GST_STATE_PLAYING);
    1276           53 :   if (scret == GST_STATE_CHANGE_FAILURE) {
    1277            0 :     _ml_error_report
    1278              :         ("Failed to set the state of the pipeline to PLAYING. For the detail, please check the GStreamer log messages.");
    1279            0 :     status = ML_ERROR_STREAMS_PIPE;
    1280              :   }
    1281              : 
    1282           53 : done:
    1283           53 :   g_mutex_unlock (&p->lock);
    1284           53 :   return status;
    1285              : }
    1286              : 
    1287              : /**
    1288              :  * @brief Pause the pipeline! (more info in nnstreamer.h)
    1289              :  */
    1290              : int
    1291          193 : ml_pipeline_stop (ml_pipeline_h pipe)
    1292              : {
    1293          193 :   ml_pipeline *p = pipe;
    1294              :   GstStateChangeReturn scret;
    1295              : 
    1296          193 :   check_feature_state (ML_FEATURE_INFERENCE);
    1297              : 
    1298          193 :   if (p == NULL)
    1299            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1300              :         "The parameter, pipe, is NULL. It should be a valid ml_pipeline_h instance, which is usually created by ml_pipeline_construct().");
    1301              : 
    1302          193 :   g_mutex_lock (&p->lock);
    1303          193 :   scret = gst_element_set_state (p->element, GST_STATE_PAUSED);
    1304          193 :   g_mutex_unlock (&p->lock);
    1305              : 
    1306          193 :   if (scret == GST_STATE_CHANGE_FAILURE)
    1307            1 :     _ml_error_report_return (ML_ERROR_STREAMS_PIPE,
    1308              :         "Failed to set the state of the pipeline to PAUSED. For the detail, please check the GStreamer log messages.");
    1309              : 
    1310          192 :   return ML_ERROR_NONE;
    1311              : }
    1312              : 
    1313              : /**
    1314              :  * @brief Clears all data and resets the running-time of the pipeline (more info in nnstreamer.h)
    1315              :  */
    1316              : int
    1317            2 : ml_pipeline_flush (ml_pipeline_h pipe, bool start)
    1318              : {
    1319            2 :   ml_pipeline *p = pipe;
    1320            2 :   int status = ML_ERROR_NONE;
    1321              : 
    1322            2 :   check_feature_state (ML_FEATURE_INFERENCE);
    1323              : 
    1324            2 :   if (p == NULL)
    1325            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1326              :         "The parameter, pipe, is NULL. It should be a valid ml_pipeline_h instance, which is usually created by ml_pipeline_construct().");
    1327              : 
    1328            1 :   _ml_error_report_return_continue_iferr (ml_pipeline_stop (pipe),
    1329              :       "Failed to stop the pipeline with ml_pipeline_stop (). It has returned %d.",
    1330              :       _ERRNO);
    1331              : 
    1332            1 :   _ml_logi ("The pipeline is stopped, clear all data from the pipeline.");
    1333              : 
    1334              :   /* send flush event to pipeline */
    1335            1 :   g_mutex_lock (&p->lock);
    1336            1 :   if (!gst_element_send_event (p->element, gst_event_new_flush_start ())) {
    1337            0 :     _ml_logw ("Error occurs while sending flush_start event.");
    1338              :   }
    1339              : 
    1340            1 :   if (!gst_element_send_event (p->element, gst_event_new_flush_stop (TRUE))) {
    1341            0 :     _ml_logw ("Error occurs while sending flush_stop event.");
    1342              :   }
    1343            1 :   g_mutex_unlock (&p->lock);
    1344              : 
    1345            1 :   if (start && status == ML_ERROR_NONE)
    1346            1 :     status = ml_pipeline_start (pipe);
    1347              : 
    1348            1 :   return status;
    1349              : }
    1350              : 
    1351              : /****************************************************
    1352              :  ** NNStreamer Pipeline Sink/Src Control           **
    1353              :  ****************************************************/
    1354              : /**
    1355              :  * @brief Register a callback for sink (more info in nnstreamer.h)
    1356              :  */
    1357              : int
    1358           46 : ml_pipeline_sink_register (ml_pipeline_h pipe, const char *sink_name,
    1359              :     ml_pipeline_sink_cb cb, void *user_data, ml_pipeline_sink_h * h)
    1360              : {
    1361              :   ml_pipeline_element *elem;
    1362           46 :   ml_pipeline *p = pipe;
    1363              :   ml_pipeline_common_elem *sink;
    1364           46 :   int ret = ML_ERROR_NONE;
    1365              : 
    1366           46 :   check_feature_state (ML_FEATURE_INFERENCE);
    1367              : 
    1368           46 :   if (h == NULL)
    1369            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1370              :         "The argument, h (ml_pipeline_sink_h), is NULL. It should be a valid pointer to a new ml_pipeline_sink_h instance. E.g., ml_pipeline_sink_h h; ml_pipeline_sink_register (...., &h);");
    1371              : 
    1372              :   /* init null */
    1373           45 :   *h = NULL;
    1374              : 
    1375           45 :   if (pipe == NULL)
    1376            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1377              :         "The argument, pipe (ml_pipeline_h), is NULL. It should be a valid ml_pipeline_h instance, usually created by ml_pipeline_construct.");
    1378              : 
    1379           44 :   if (sink_name == NULL)
    1380            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1381              :         "The argument, sink_name (const char *), is NULL. It should be a valid string naming the sink handle (h).");
    1382              : 
    1383           43 :   if (cb == NULL)
    1384            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1385              :         "The argument, cb (ml_pipeline_sink_cb), is NULL. It should be a call-back function called for data-sink events.");
    1386              : 
    1387           42 :   g_mutex_lock (&p->lock);
    1388           42 :   elem = g_hash_table_lookup (p->namednodes, sink_name);
    1389              : 
    1390           42 :   if (elem == NULL) {
    1391            1 :     _ml_error_report
    1392              :         ("There is no element named [%s](sink_name) in the pipeline. Please check your pipeline description.",
    1393              :         sink_name);
    1394            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1395            1 :     goto unlock_return;
    1396              :   }
    1397              : 
    1398           41 :   if (elem->type != ML_PIPELINE_ELEMENT_SINK &&
    1399            5 :       elem->type != ML_PIPELINE_ELEMENT_APP_SINK) {
    1400            1 :     _ml_error_report
    1401              :         ("The element [%s](sink_name) in the pipeline is not a sink element. Please supply the name of tensor_sink or appsink.",
    1402              :         sink_name);
    1403            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1404            1 :     goto unlock_return;
    1405              :   }
    1406              : 
    1407           40 :   if (elem->handle_id > 0) {
    1408              :     /* no need to connect signal to sink element */
    1409            1 :     _ml_logw ("Sink callback is already registered.");
    1410              :   } else {
    1411              :     /* set callback for new data */
    1412           39 :     if (elem->type == ML_PIPELINE_ELEMENT_SINK) {
    1413              :       /* tensor_sink */
    1414           36 :       g_object_set (G_OBJECT (elem->element), "emit-signal", (gboolean) TRUE,
    1415              :           NULL);
    1416           36 :       elem->handle_id =
    1417           36 :           g_signal_connect (elem->element, "new-data",
    1418              :           G_CALLBACK (cb_sink_event), elem);
    1419              :     } else {
    1420              :       /* appsink */
    1421            3 :       g_object_set (G_OBJECT (elem->element), "emit-signals", (gboolean) TRUE,
    1422              :           NULL);
    1423            3 :       elem->handle_id =
    1424            3 :           g_signal_connect (elem->element, "new-sample",
    1425              :           G_CALLBACK (cb_appsink_new_sample), elem);
    1426              :     }
    1427              : 
    1428           39 :     if (elem->handle_id == 0) {
    1429            0 :       _ml_error_report
    1430              :           ("Failed to connect a signal to the element [%s](sink_name). g_signal_connect has returned NULL.",
    1431              :           sink_name);
    1432            0 :       ret = ML_ERROR_STREAMS_PIPE;
    1433            0 :       goto unlock_return;
    1434              :     }
    1435              :   }
    1436              : 
    1437           40 :   sink = g_new0 (ml_pipeline_common_elem, 1);
    1438           40 :   if (sink == NULL) {
    1439            0 :     _ml_error_report
    1440              :         ("Failed to allocate memory for the sink handle of %s. Out of memory?",
    1441              :         sink_name);
    1442            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    1443            0 :     goto unlock_return;
    1444              :   }
    1445              : 
    1446           40 :   sink->callback_info = g_new0 (callback_info_s, 1);
    1447           40 :   if (sink->callback_info == NULL) {
    1448            0 :     g_free (sink);
    1449            0 :     _ml_error_report
    1450              :         ("Failed to allocate memory for the sink handle of %s. Out of memory?",
    1451              :         sink_name);
    1452            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    1453            0 :     goto unlock_return;
    1454              :   }
    1455              : 
    1456           40 :   sink->pipe = p;
    1457           40 :   sink->element = elem;
    1458           40 :   sink->callback_info->sink_cb = cb;
    1459           40 :   sink->callback_info->sink_pdata = user_data;
    1460           40 :   *h = sink;
    1461              : 
    1462           40 :   g_mutex_lock (&elem->lock);
    1463              : 
    1464           40 :   elem->maxid++;
    1465           40 :   sink->id = elem->maxid;
    1466           40 :   elem->handles = g_list_append (elem->handles, sink);
    1467              : 
    1468           40 :   g_mutex_unlock (&elem->lock);
    1469              : 
    1470           42 : unlock_return:
    1471           42 :   g_mutex_unlock (&p->lock);
    1472           42 :   return ret;
    1473              : }
    1474              : 
    1475              : /**
    1476              :  * @brief Unregister a callback for sink (more info in nnstreamer.h)
    1477              :  */
    1478              : int
    1479           13 : ml_pipeline_sink_unregister (ml_pipeline_sink_h h)
    1480              : {
    1481           13 :   handle_init (sink, h);
    1482              : 
    1483           13 :   if (elem->handle_id > 0) {
    1484           12 :     g_signal_handler_disconnect (elem->element, elem->handle_id);
    1485           12 :     elem->handle_id = 0;
    1486              :   }
    1487              : 
    1488           13 :   elem->handles = g_list_remove (elem->handles, sink);
    1489           13 :   free_element_handle (sink);
    1490              : 
    1491           13 :   handle_exit (h);
    1492              : }
    1493              : 
    1494              : /**
    1495              :  * @brief Parse tensors info of src element.
    1496              :  */
    1497              : static int
    1498        12144 : ml_pipeline_src_parse_tensors_info (ml_pipeline_element * elem)
    1499              : {
    1500        12144 :   GstCaps *caps = NULL;
    1501        12144 :   gboolean found = FALSE, flexible = FALSE;
    1502              : 
    1503        12144 :   if (elem->src == NULL) {
    1504           41 :     elem->src = gst_element_get_static_pad (elem->element, "src");
    1505              :   }
    1506              : 
    1507        12144 :   if (elem->src == NULL) {
    1508            0 :     _ml_error_report
    1509              :         ("Failed to get the src pad of the element[%s]. The designated source element does not have available src pad? For the detail, please check the GStreamer log messages.",
    1510              :         elem->name);
    1511        12144 :     return ML_ERROR_STREAMS_PIPE;
    1512              :   }
    1513              : 
    1514              :   /* If caps is given, use it. e.g. Use cap "image/png" when the pipeline is */
    1515              :   /* given as "appsrc caps=image/png ! pngdec ! ... " */
    1516        12144 :   caps = gst_pad_get_current_caps (elem->src);
    1517        12144 :   if (!caps)
    1518        12080 :     caps = gst_pad_get_allowed_caps (elem->src);
    1519              : 
    1520        12144 :   if (!caps) {
    1521            0 :     _ml_logw
    1522              :         ("Cannot find caps. The pipeline is not yet negotiated for src element [%s].",
    1523              :         elem->name);
    1524            0 :     gst_object_unref (elem->src);
    1525            0 :     elem->src = NULL;
    1526            0 :     return ML_ERROR_TRY_AGAIN;
    1527              :   }
    1528              : 
    1529        12144 :   found = get_tensors_info_from_caps (caps, &elem->tensors_info, &flexible);
    1530              : 
    1531        12144 :   if (found) {
    1532        12138 :     elem->is_flexible_tensor = flexible;
    1533              :   } else {
    1534            6 :     if (gst_caps_is_fixed (caps)) {
    1535            5 :       GstStructure *st = gst_caps_get_structure (caps, 0);
    1536            5 :       elem->is_media_stream = !gst_structure_is_tensor_stream (st);
    1537              :     }
    1538              :   }
    1539              : 
    1540        12144 :   gst_caps_unref (caps);
    1541        12144 :   return ML_ERROR_NONE;
    1542              : }
    1543              : 
    1544              : /**
    1545              :  * @brief Get a handle to operate a src (more info in nnstreamer.h)
    1546              :  */
    1547              : int
    1548           48 : ml_pipeline_src_get_handle (ml_pipeline_h pipe, const char *src_name,
    1549              :     ml_pipeline_src_h * h)
    1550              : {
    1551           48 :   ml_pipeline *p = pipe;
    1552              :   ml_pipeline_element *elem;
    1553              :   ml_pipeline_common_elem *src;
    1554           48 :   int ret = ML_ERROR_NONE;
    1555              : 
    1556           48 :   check_feature_state (ML_FEATURE_INFERENCE);
    1557              : 
    1558           48 :   if (h == NULL)
    1559            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1560              :         "The parameter, h (ml_pipeline_src_h), is NULL. It should be a valid pointer to a new (or to be cleared) instance. E.g., ml_pipeline_src_h h; ml_pipeline_src_get_handle (..., &h);");
    1561              : 
    1562              :   /* init null */
    1563           47 :   *h = NULL;
    1564              : 
    1565           47 :   if (pipe == NULL)
    1566            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1567              :         "The parameter, pipe (ml_pipeline_h), is NULL. It should be a valid ml_pipeline_h instance, which is usually created by ml_pipeline_construct().");
    1568              : 
    1569           46 :   if (src_name == NULL)
    1570            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1571              :         "The parameter, src_name (const char *), is NULL. This string is the name of source element (appsrc) you want to push data stream from your application threads.");
    1572              : 
    1573           45 :   g_mutex_lock (&p->lock);
    1574              : 
    1575           45 :   elem = g_hash_table_lookup (p->namednodes, src_name);
    1576              : 
    1577           45 :   if (elem == NULL) {
    1578            1 :     _ml_error_report
    1579              :         ("Cannot find the name, '%s': there is no element named [%s] in the given pipeline.",
    1580              :         src_name, src_name);
    1581            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1582            1 :     goto unlock_return;
    1583              :   }
    1584              : 
    1585           44 :   if (elem->type != ML_PIPELINE_ELEMENT_APP_SRC) {
    1586            1 :     _ml_error_report
    1587              :         ("The element designated by '%s' is not a source element (appsrc). Please provide a name of source element for ml_pipeline_src_get_handle API.",
    1588              :         src_name);
    1589            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1590            1 :     goto unlock_return;
    1591              :   }
    1592              : 
    1593           43 :   src = *h = g_new0 (ml_pipeline_common_elem, 1);
    1594           43 :   if (src == NULL) {
    1595            0 :     _ml_error_report
    1596              :         ("Failed to allocate the src handle for %s. Out of memory?", src_name);
    1597            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    1598            0 :     goto unlock_return;
    1599              :   }
    1600              : 
    1601           43 :   src->pipe = p;
    1602           43 :   src->element = elem;
    1603              : 
    1604           43 :   g_mutex_lock (&elem->lock);
    1605              : 
    1606           43 :   elem->maxid++;
    1607           43 :   src->id = elem->maxid;
    1608           43 :   elem->handles = g_list_append (elem->handles, src);
    1609              : 
    1610           43 :   ml_pipeline_src_parse_tensors_info (elem);
    1611           43 :   g_mutex_unlock (&elem->lock);
    1612              : 
    1613           45 : unlock_return:
    1614           45 :   g_mutex_unlock (&p->lock);
    1615              : 
    1616           45 :   return ret;
    1617              : }
    1618              : 
    1619              : /**
    1620              :  * @brief Close a src node (more info in nnstreamer.h)
    1621              :  */
    1622              : int
    1623            7 : ml_pipeline_src_release_handle (ml_pipeline_src_h h)
    1624              : {
    1625            7 :   handle_init (src, h);
    1626              : 
    1627            7 :   elem->handles = g_list_remove (elem->handles, src);
    1628            7 :   free_element_handle (src);
    1629              : 
    1630            7 :   handle_exit (h);
    1631              : }
    1632              : 
    1633              : /**
    1634              :  * @brief Push a data frame to a src (more info in nnstreamer.h)
    1635              :  */
    1636              : int
    1637         6093 : ml_pipeline_src_input_data (ml_pipeline_src_h h, ml_tensors_data_h data,
    1638              :     ml_pipeline_buf_policy_e policy)
    1639              : {
    1640              :   GstBuffer *buffer;
    1641              :   GstMemory *mem, *tmp;
    1642              :   gpointer mem_data;
    1643              :   gsize mem_size;
    1644              :   GstFlowReturn gret;
    1645              :   GstTensorsInfo gst_info;
    1646              :   ml_tensors_data_s *_data;
    1647              :   unsigned int i;
    1648              : 
    1649        12186 :   handle_init (src, h);
    1650              : 
    1651         6093 :   _data = (ml_tensors_data_s *) data;
    1652         6093 :   if (!_data) {
    1653            1 :     _ml_error_report
    1654              :         ("The given parameter, data (ml_tensors_data_h), is NULL. It should be a valid ml_tensor_data_h instance, which is usually created by ml_tensors_data_create().");
    1655            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1656            1 :     goto unlock_return;
    1657              :   }
    1658         6092 :   G_LOCK_UNLESS_NOLOCK (*_data);
    1659              : 
    1660         6092 :   if (_data->num_tensors < 1 || _data->num_tensors > ML_TENSOR_SIZE_LIMIT) {
    1661            0 :     _ml_error_report
    1662              :         ("The number of tensors of the given data (ml_tensors_data_h) is invalid. The number of tensors of data is %u. It should be between 1 and %u.",
    1663              :         _data->num_tensors, ML_TENSOR_SIZE_LIMIT);
    1664            0 :     ret = ML_ERROR_INVALID_PARAMETER;
    1665            0 :     goto dont_destroy_data;
    1666              :   }
    1667              : 
    1668         6092 :   ret = ml_pipeline_src_parse_tensors_info (elem);
    1669              : 
    1670         6092 :   if (ret != ML_ERROR_NONE) {
    1671            0 :     if (ret == ML_ERROR_TRY_AGAIN)
    1672            0 :       _ml_error_report_continue
    1673              :           ("The pipeline is not ready to accept input streams. The input is ignored.");
    1674              :     else
    1675            0 :       _ml_error_report_continue
    1676              :           ("The pipeline is either not ready to accept input streams, yet, or does not have appropriate source elements to accept input streams.");
    1677            0 :     goto dont_destroy_data;
    1678              :   }
    1679              : 
    1680         6092 :   if (!elem->is_media_stream && !elem->is_flexible_tensor) {
    1681         6085 :     if (elem->tensors_info.num_tensors != _data->num_tensors) {
    1682            0 :       _ml_error_report
    1683              :           ("The src push of [%s] cannot be handled because the number of tensors in a frame mismatches. %u != %u",
    1684              :           elem->name, elem->tensors_info.num_tensors, _data->num_tensors);
    1685              : 
    1686            0 :       ret = ML_ERROR_INVALID_PARAMETER;
    1687            0 :       goto dont_destroy_data;
    1688              :     }
    1689              : 
    1690        12323 :     for (i = 0; i < _data->num_tensors; i++) {
    1691         6240 :       size_t sz = gst_tensors_info_get_size (&elem->tensors_info, i);
    1692              : 
    1693         6240 :       if (sz != _data->tensors[i].size) {
    1694            2 :         _ml_error_report
    1695              :             ("The given input tensor size (%d'th, %zu bytes) mismatches the source pad (%zu bytes)",
    1696              :             i, _data->tensors[i].size, sz);
    1697              : 
    1698            2 :         ret = ML_ERROR_INVALID_PARAMETER;
    1699            2 :         goto dont_destroy_data;
    1700              :       }
    1701              :     }
    1702              :   }
    1703              : 
    1704              :   /* Create buffer to be pushed from buf[] */
    1705         6090 :   buffer = gst_buffer_new ();
    1706         6090 :   _ml_tensors_info_copy_from_ml (&gst_info, _data->info);
    1707              : 
    1708        12341 :   for (i = 0; i < _data->num_tensors; i++) {
    1709              :     GstTensorInfo *_gst_tensor_info =
    1710         6251 :         gst_tensors_info_get_nth_info (&gst_info, i);
    1711         6251 :     mem_data = _data->tensors[i].data;
    1712         6251 :     mem_size = _data->tensors[i].size;
    1713              : 
    1714         6251 :     mem = tmp = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
    1715              :         mem_data, mem_size, 0, mem_size, mem_data,
    1716              :         (policy == ML_PIPELINE_BUF_POLICY_AUTO_FREE) ? g_free : NULL);
    1717              : 
    1718              :     /* flex tensor, append header. */
    1719         6251 :     if (elem->is_flexible_tensor) {
    1720              :       GstTensorMetaInfo meta;
    1721              : 
    1722            9 :       gst_tensor_info_convert_to_meta (_gst_tensor_info, &meta);
    1723              : 
    1724            9 :       mem = gst_tensor_meta_info_append_header (&meta, tmp);
    1725            9 :       gst_memory_unref (tmp);
    1726              :     }
    1727              : 
    1728         6251 :     gst_tensor_buffer_append_memory (buffer, mem, _gst_tensor_info);
    1729              :     /** @todo Verify that gst_buffer_append lists tensors/gstmem in the correct order */
    1730              :   }
    1731              : 
    1732         6090 :   gst_tensors_info_free (&gst_info);
    1733              : 
    1734              :   /* Unlock if it's not auto-free. We do not know when it'll be freed. */
    1735         6090 :   if (policy != ML_PIPELINE_BUF_POLICY_AUTO_FREE)
    1736           55 :     G_UNLOCK_UNLESS_NOLOCK (*_data);
    1737              : 
    1738              :   /* Push the data! */
    1739         6090 :   gret = gst_app_src_push_buffer (GST_APP_SRC (elem->element), buffer);
    1740              : 
    1741              :   /* Free data ptr if buffer policy is auto-free */
    1742         6090 :   if (policy == ML_PIPELINE_BUF_POLICY_AUTO_FREE) {
    1743         6035 :     G_UNLOCK_UNLESS_NOLOCK (*_data);
    1744         6035 :     _ml_tensors_data_destroy_internal (_data, FALSE);
    1745         6035 :     _data = NULL;
    1746              :   }
    1747              : 
    1748         6090 :   if (gret == GST_FLOW_FLUSHING) {
    1749            0 :     _ml_logw
    1750              :         ("The pipeline is not in PAUSED/PLAYING. The input may be ignored.");
    1751            0 :     ret = ML_ERROR_TRY_AGAIN;
    1752         6090 :   } else if (gret == GST_FLOW_EOS) {
    1753            0 :     _ml_logw ("THe pipeline is in EOS state. The input is ignored.");
    1754            0 :     ret = ML_ERROR_STREAMS_PIPE;
    1755              :   }
    1756              : 
    1757         6090 :   goto unlock_return;
    1758              : 
    1759            2 : dont_destroy_data:
    1760            2 :   G_UNLOCK_UNLESS_NOLOCK (*_data);
    1761              : 
    1762         6093 :   handle_exit (h);
    1763              : }
    1764              : 
    1765              : /**
    1766              :  * @brief Internal function to fetch ml_pipeline_src_callbacks_s pointer
    1767              :  */
    1768              : static ml_pipeline_src_callbacks_s *
    1769         6005 : get_app_src_callback (ml_pipeline_common_elem * src_h, void **data)
    1770              : {
    1771         6005 :   ml_pipeline_src_callbacks_s *src_cb = NULL;
    1772              : 
    1773         6005 :   if (src_h->callback_info) {
    1774         6005 :     src_cb = &src_h->callback_info->src_cb;
    1775         6005 :     *data = src_h->callback_info->src_pdata;
    1776              :   }
    1777              : 
    1778         6005 :   return src_cb;
    1779              : }
    1780              : 
    1781              : /**
    1782              :  * @brief Internal function for appsrc callback - need_data.
    1783              :  */
    1784              : static void
    1785         6005 : _pipe_src_cb_need_data (GstAppSrc * src, guint length, gpointer user_data)
    1786              : {
    1787              :   ml_pipeline_common_elem *src_h;
    1788         6005 :   ml_pipeline_src_callbacks_s *src_cb = NULL;
    1789         6005 :   void *pdata = NULL;
    1790              : 
    1791         6005 :   src_h = (ml_pipeline_common_elem *) user_data;
    1792         6005 :   if (!src_h)
    1793            0 :     return;
    1794              : 
    1795         6005 :   src_cb = get_app_src_callback (src_h, &pdata);
    1796         6005 :   if (src_cb && src_cb->need_data)
    1797         6005 :     src_cb->need_data (src_h, length, pdata);
    1798              : }
    1799              : 
    1800              : /**
    1801              :  * @brief Internal function for appsrc callback - enough_data.
    1802              :  */
    1803              : static void
    1804            0 : _pipe_src_cb_enough_data (GstAppSrc * src, gpointer user_data)
    1805              : {
    1806              :   ml_pipeline_common_elem *src_h;
    1807            0 :   ml_pipeline_src_callbacks_s *src_cb = NULL;
    1808            0 :   void *pdata = NULL;
    1809              : 
    1810            0 :   src_h = (ml_pipeline_common_elem *) user_data;
    1811            0 :   if (!src_h)
    1812            0 :     return;
    1813              : 
    1814            0 :   src_cb = get_app_src_callback (src_h, &pdata);
    1815            0 :   if (src_cb && src_cb->enough_data)
    1816            0 :     src_cb->enough_data (src_h, pdata);
    1817              : }
    1818              : 
    1819              : /**
    1820              :  * @brief Internal function for appsrc callback - seek_data.
    1821              :  */
    1822              : static gboolean
    1823            0 : _pipe_src_cb_seek_data (GstAppSrc * src, guint64 offset, gpointer user_data)
    1824              : {
    1825              :   ml_pipeline_common_elem *src_h;
    1826            0 :   ml_pipeline_src_callbacks_s *src_cb = NULL;
    1827            0 :   void *pdata = NULL;
    1828              : 
    1829            0 :   src_h = (ml_pipeline_common_elem *) user_data;
    1830            0 :   if (!src_h)
    1831            0 :     return TRUE;
    1832              : 
    1833            0 :   src_cb = get_app_src_callback (src_h, &pdata);
    1834            0 :   if (src_cb && src_cb->seek_data)
    1835            0 :     src_cb->seek_data (src_h, offset, pdata);
    1836              : 
    1837            0 :   return TRUE;
    1838              : }
    1839              : 
    1840              : /**
    1841              :  * @brief Register callbacks for src events (more info in nnstreamer.h)
    1842              :  */
    1843              : int
    1844            4 : ml_pipeline_src_set_event_cb (ml_pipeline_src_h src_handle,
    1845              :     ml_pipeline_src_callbacks_s * cb, void *user_data)
    1846              : {
    1847            4 :   GstAppSrcCallbacks appsrc_cb = { 0, };
    1848              : 
    1849            7 :   handle_init (src, src_handle);
    1850              : 
    1851            3 :   if (cb == NULL) {
    1852            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1853            1 :     goto unlock_return;
    1854              :   }
    1855              : 
    1856            2 :   if (src->callback_info == NULL)
    1857            2 :     src->callback_info = g_new0 (callback_info_s, 1);
    1858            2 :   if (src->callback_info == NULL) {
    1859            0 :     _ml_error_report
    1860              :         ("Failed to allocate memory of the callback info for %s. Out of memory?",
    1861              :         elem->name);
    1862            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    1863            0 :     goto unlock_return;
    1864              :   }
    1865              : 
    1866            2 :   src->callback_info->src_cb = *cb;
    1867            2 :   src->callback_info->src_pdata = user_data;
    1868              : 
    1869            2 :   appsrc_cb.need_data = _pipe_src_cb_need_data;
    1870            2 :   appsrc_cb.enough_data = _pipe_src_cb_enough_data;
    1871            2 :   appsrc_cb.seek_data = _pipe_src_cb_seek_data;
    1872              : 
    1873            2 :   gst_app_src_set_callbacks (GST_APP_SRC (elem->element), &appsrc_cb,
    1874              :       src_handle, NULL);
    1875              : 
    1876            3 :   handle_exit (src_handle);
    1877              : }
    1878              : 
    1879              : /**
    1880              :  * @brief Gets a handle for the tensors metadata of given src node.
    1881              :  */
    1882              : int
    1883         6009 : ml_pipeline_src_get_tensors_info (ml_pipeline_src_h h, ml_tensors_info_h * info)
    1884              : {
    1885         6009 :   handle_init (src, h);
    1886              : 
    1887         6009 :   if (info == NULL) {
    1888            0 :     _ml_error_report
    1889              :         ("The parameter, info (ml_tensors_info_h *), is NULL. It should be a valid pointer to a ml_tensors_info_h instance, which is usually created by ml_tensors_info_create().");
    1890            0 :     ret = ML_ERROR_INVALID_PARAMETER;
    1891            0 :     goto unlock_return;
    1892              :   }
    1893              : 
    1894         6009 :   ret = ml_pipeline_src_parse_tensors_info (elem);
    1895              : 
    1896         6009 :   if (ret == ML_ERROR_NONE) {
    1897         6009 :     ret = _ml_tensors_info_create_from_gst (info, &elem->tensors_info);
    1898              :   } else {
    1899            0 :     _ml_error_report_continue
    1900              :         ("ml_pipeline_src_parse_tensors_info () has returned error; it cannot fetch input tensor info (metadata of input stream) for the given ml_pipeline_src_h handle (h). ml_pipeline_src_get_tensors_info () cannot continue.");
    1901              :   }
    1902              : 
    1903         6009 :   handle_exit (h);
    1904              : }
    1905              : 
    1906              : /****************************************************
    1907              :  ** NNStreamer Pipeline Switch/Valve Control       **
    1908              :  ****************************************************/
    1909              : 
    1910              : /**
    1911              :  * @brief Get a handle to operate a selector (more info in nnstreamer.h)
    1912              :  */
    1913              : int
    1914           10 : ml_pipeline_switch_get_handle (ml_pipeline_h pipe, const char *switch_name,
    1915              :     ml_pipeline_switch_e * type, ml_pipeline_switch_h * h)
    1916              : {
    1917              :   ml_pipeline_element *elem;
    1918           10 :   ml_pipeline *p = pipe;
    1919              :   ml_pipeline_common_elem *swtc;
    1920           10 :   int ret = ML_ERROR_NONE;
    1921              : 
    1922           10 :   check_feature_state (ML_FEATURE_INFERENCE);
    1923              : 
    1924           10 :   if (h == NULL)
    1925            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1926              :         "The parameter, h (ml_pipeline_switch_h *), is NULL. It should be a new or to-be-cleared instance of ml_pipeline_switch_h. E.g., ml_pipeline_switch_h h; ml_pipeline_switch_get_handle (..., &h);");
    1927              : 
    1928              :   /* init null */
    1929            9 :   *h = NULL;
    1930              : 
    1931            9 :   if (pipe == NULL)
    1932            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1933              :         "The parameter, pipe (ml_pipeline_h), is NULL. It should be a valid ml_pipeline_h pipeline instance, which is usually created by ml_pipeline_construct().");
    1934              : 
    1935            8 :   if (switch_name == NULL)
    1936            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1937              :         "The parameter, switch_name, is NULL. It should be a valid string of the corresponding name of a switch element.");
    1938              : 
    1939            7 :   g_mutex_lock (&p->lock);
    1940            7 :   elem = g_hash_table_lookup (p->namednodes, switch_name);
    1941              : 
    1942            7 :   if (elem == NULL) {
    1943            1 :     _ml_error_report
    1944              :         ("The parameter, switch_name (%s), is invalid. An element with the name, '%s', cannot be found in the supplied pipeline (pipe)",
    1945              :         switch_name, switch_name);
    1946            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1947            1 :     goto unlock_return;
    1948              :   }
    1949              : 
    1950            6 :   if (elem->type == ML_PIPELINE_ELEMENT_SWITCH_INPUT) {
    1951            4 :     if (type)
    1952            1 :       *type = ML_PIPELINE_SWITCH_INPUT_SELECTOR;
    1953            2 :   } else if (elem->type == ML_PIPELINE_ELEMENT_SWITCH_OUTPUT) {
    1954            1 :     if (type)
    1955            1 :       *type = ML_PIPELINE_SWITCH_OUTPUT_SELECTOR;
    1956              :   } else {
    1957            1 :     _ml_error_report
    1958              :         ("An element with the given name, '%s', is found; however, it is not a 'switch' element. A switch-handle cannot be fetched from a non-switch element. It should be either input-selector or output-selector.",
    1959              :         switch_name);
    1960            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    1961            1 :     goto unlock_return;
    1962              :   }
    1963              : 
    1964            5 :   swtc = *h = g_new0 (ml_pipeline_common_elem, 1);
    1965            5 :   if (swtc == NULL) {
    1966            0 :     _ml_error_report
    1967              :         ("Failed to allocate memory of the switch handle, %s. Out of memory?",
    1968              :         switch_name);
    1969            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    1970            0 :     goto unlock_return;
    1971              :   }
    1972              : 
    1973            5 :   swtc->pipe = p;
    1974            5 :   swtc->element = elem;
    1975              : 
    1976            5 :   g_mutex_lock (&elem->lock);
    1977              : 
    1978            5 :   elem->maxid++;
    1979            5 :   swtc->id = elem->maxid;
    1980            5 :   elem->handles = g_list_append (elem->handles, swtc);
    1981              : 
    1982            5 :   g_mutex_unlock (&elem->lock);
    1983              : 
    1984            7 : unlock_return:
    1985            7 :   g_mutex_unlock (&p->lock);
    1986            7 :   return ret;
    1987              : }
    1988              : 
    1989              : /**
    1990              :  * @brief Close the given switch handle (more info in nnstreamer.h)
    1991              :  */
    1992              : int
    1993            5 : ml_pipeline_switch_release_handle (ml_pipeline_switch_h h)
    1994              : {
    1995            5 :   handle_init (swtc, h);
    1996              : 
    1997            5 :   elem->handles = g_list_remove (elem->handles, swtc);
    1998            5 :   free_element_handle (swtc);
    1999              : 
    2000            5 :   handle_exit (h);
    2001              : }
    2002              : 
    2003              : /**
    2004              :  * @brief Control the switch (more info in nnstreamer.h)
    2005              :  */
    2006              : int
    2007            5 : ml_pipeline_switch_select (ml_pipeline_switch_h h, const char *pad_name)
    2008              : {
    2009              :   GstPad *active_pad, *new_pad;
    2010              :   gchar *active_name;
    2011              : 
    2012            9 :   handle_init (swtc, h);
    2013              : 
    2014            4 :   if (pad_name == NULL) {
    2015            1 :     _ml_error_report
    2016              :         ("The parameter, pad_name (const char *), is NULL. It should be a valid name of a pad (GSTPAD) in the given switch, h.");
    2017            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    2018            1 :     goto unlock_return;
    2019              :   }
    2020              : 
    2021            3 :   g_object_get (G_OBJECT (elem->element), "active-pad", &active_pad, NULL);
    2022            3 :   active_name = gst_pad_get_name (active_pad);
    2023              : 
    2024            3 :   if (g_strcmp0 (pad_name, active_name) == 0) {
    2025            0 :     _ml_logi ("Switch is called, but there is no effective changes: %s->%s.",
    2026              :         active_name, pad_name);
    2027            0 :     g_free (active_name);
    2028            0 :     gst_object_unref (active_pad);
    2029              : 
    2030            0 :     goto unlock_return;
    2031              :   }
    2032              : 
    2033            3 :   g_free (active_name);
    2034            3 :   gst_object_unref (active_pad);
    2035              : 
    2036            3 :   new_pad = gst_element_get_static_pad (elem->element, pad_name);
    2037            3 :   if (new_pad == NULL) {
    2038              :     /* Not Found! */
    2039            1 :     _ml_error_report
    2040              :         ("Cannot find the pad, [%s], from the switch, [%s]. Please check the pad name. You may use ml_pipeline_switch_pad_list() to fetch the valid pad names.",
    2041              :         pad_name, elem->name);
    2042            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    2043            1 :     goto unlock_return;
    2044              :   }
    2045              : 
    2046            2 :   g_object_set (G_OBJECT (elem->element), "active-pad", new_pad, NULL);
    2047            2 :   gst_object_unref (new_pad);
    2048              : 
    2049            2 :   _ml_logi ("Switched to [%s] successfully at switch [%s].", pad_name,
    2050              :       elem->name);
    2051              : 
    2052            4 :   handle_exit (h);
    2053              : }
    2054              : 
    2055              : /**
    2056              :  * @brief Gets the pad names of a switch.
    2057              :  */
    2058              : int
    2059            2 : ml_pipeline_switch_get_pad_list (ml_pipeline_switch_h h, char ***list)
    2060              : {
    2061              :   GstIterator *it;
    2062            2 :   GValue item = G_VALUE_INIT;
    2063            2 :   gboolean done = FALSE;
    2064            2 :   GList *dllist = NULL;
    2065              :   GstPad *pad;
    2066            2 :   int counter = 0;
    2067              : 
    2068            4 :   handle_init (swtc, h);
    2069              : 
    2070            2 :   if (list == NULL) {
    2071            0 :     _ml_error_report
    2072              :         ("The parameter, list (char ***), is NULL. It should be a valid pointer to store a list of strings. E.g., char **list; ml_pipeline_switch_get_pad_list (h, &list);");
    2073            0 :     ret = ML_ERROR_INVALID_PARAMETER;
    2074            0 :     goto unlock_return;
    2075              :   }
    2076              : 
    2077              :   /* init null */
    2078            2 :   *list = NULL;
    2079              : 
    2080            2 :   if (elem->type == ML_PIPELINE_ELEMENT_SWITCH_INPUT)
    2081            1 :     it = gst_element_iterate_sink_pads (elem->element);
    2082            1 :   else if (elem->type == ML_PIPELINE_ELEMENT_SWITCH_OUTPUT)
    2083            1 :     it = gst_element_iterate_src_pads (elem->element);
    2084              :   else {
    2085            0 :     _ml_error_report
    2086              :         ("The element, [%s], is supposed to be input/output switch, but it is not. Internal data structure is broken.",
    2087              :         elem->name);
    2088            0 :     ret = ML_ERROR_STREAMS_PIPE;
    2089            0 :     goto unlock_return;
    2090              :   }
    2091              : 
    2092            8 :   while (!done) {
    2093            6 :     switch (gst_iterator_next (it, &item)) {
    2094            4 :       case GST_ITERATOR_OK:
    2095            4 :         pad = GST_PAD (g_value_get_object (&item));
    2096            4 :         dllist = g_list_append (dllist, gst_pad_get_name (pad));
    2097            4 :         counter++;
    2098            4 :         g_value_reset (&item);
    2099            4 :         break;
    2100            0 :       case GST_ITERATOR_RESYNC:
    2101            0 :         g_list_free_full (dllist, g_free);      /* This frees all strings as well */
    2102            0 :         dllist = NULL;
    2103            0 :         counter = 0;
    2104            0 :         gst_iterator_resync (it);
    2105            0 :         break;
    2106            0 :       case GST_ITERATOR_ERROR:
    2107            0 :         _ml_error_report
    2108              :             ("Cannot access the list of pad properly of a switch, [%s]. Internal data structure is broken?",
    2109              :             elem->name);
    2110            0 :         ret = ML_ERROR_STREAMS_PIPE;
    2111            0 :         break;
    2112            2 :       case GST_ITERATOR_DONE:
    2113            2 :         done = TRUE;
    2114            2 :         break;
    2115              :     }
    2116              :   }
    2117              : 
    2118            2 :   gst_iterator_free (it);
    2119              : 
    2120              :   /* There has been no error with that "while" loop. */
    2121            2 :   if (ret == ML_ERROR_NONE) {
    2122            2 :     int i = 0;
    2123              :     GList *l;
    2124              : 
    2125            2 :     *list = g_malloc0 (sizeof (char *) * (counter + 1));
    2126            2 :     if (*list == NULL) {
    2127            0 :       _ml_error_report
    2128              :           ("Failed to allocate memory for pad list (parameter list). Out of memory?");
    2129            0 :       ret = ML_ERROR_OUT_OF_MEMORY;
    2130            0 :       g_list_free_full (dllist, g_free);
    2131            0 :       goto unlock_return;
    2132              :     }
    2133              : 
    2134            6 :     for (l = dllist; l != NULL; l = l->next) {
    2135            4 :       (*list)[i] = l->data;     /* Allocated by gst_pad_get_name(). Caller has to free it */
    2136            4 :       i++;
    2137              : 
    2138            4 :       if (i > counter) {
    2139            0 :         g_list_free_full (dllist, g_free);      /* This frees all strings as well */
    2140            0 :         g_free (*list);
    2141            0 :         *list = NULL;
    2142              : 
    2143            0 :         _ml_error_report
    2144              :             ("Internal data inconsistency. This could be a bug in nnstreamer. Switch [%s].",
    2145              :             elem->name);
    2146            0 :         ret = ML_ERROR_STREAMS_PIPE;
    2147            0 :         goto unlock_return;
    2148              :       }
    2149              :     }
    2150              :   }
    2151            2 :   g_list_free (dllist);         /* This does not free the strings.. fortunately. */
    2152              : 
    2153            2 :   handle_exit (h);
    2154              : }
    2155              : 
    2156              : /**
    2157              :  * @brief Get a handle to operate a Valve (more info in nnstreamer.h)
    2158              :  */
    2159              : int
    2160            6 : ml_pipeline_valve_get_handle (ml_pipeline_h pipe, const char *valve_name,
    2161              :     ml_pipeline_valve_h * h)
    2162              : {
    2163              :   ml_pipeline_element *elem;
    2164            6 :   ml_pipeline *p = pipe;
    2165              :   ml_pipeline_common_elem *valve;
    2166            6 :   int ret = ML_ERROR_NONE;
    2167              : 
    2168            6 :   check_feature_state (ML_FEATURE_INFERENCE);
    2169              : 
    2170            6 :   if (h == NULL)
    2171            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2172              :         "The parameter, h (ml_pipeline_valve_h), is NULL. It should be a valid pointer of ml_pipeline_valve_h. E.g., ml_pipeline_valve_h h; ml_pipeline_valve_get_handle (..., &h);");
    2173              : 
    2174              :   /* init null */
    2175            5 :   *h = NULL;
    2176              : 
    2177            5 :   if (pipe == NULL)
    2178            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2179              :         "The parameter, pipe (ml_pipeline_h), is NULL. It should be a valid ml_pipeline_h instance, which is usually created by ml_pipeline_construct().");
    2180              : 
    2181            4 :   if (valve_name == NULL)
    2182            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2183              :         "The parameter, valve_name (const char *), is NULL. It should be a valid string of the valve name.");
    2184              : 
    2185            3 :   g_mutex_lock (&p->lock);
    2186            3 :   elem = g_hash_table_lookup (p->namednodes, valve_name);
    2187              : 
    2188            3 :   if (elem == NULL) {
    2189            1 :     _ml_error_report
    2190              :         ("Cannot find the valve with the given name, '%s', in the pipeline. There is no element in the pipeline with such a name. Please check if you have a value with the appropriate name.",
    2191              :         valve_name);
    2192            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    2193            1 :     goto unlock_return;
    2194              :   }
    2195              : 
    2196            2 :   if (elem->type != ML_PIPELINE_ELEMENT_VALVE) {
    2197            1 :     _ml_error_report
    2198              :         ("Cannot find the value with the given name, '%s', in the pipeline. There is an element with such a name; however, the element is not a valve. Please correct the names of element in the pipeline.",
    2199              :         valve_name);
    2200            1 :     ret = ML_ERROR_INVALID_PARAMETER;
    2201            1 :     goto unlock_return;
    2202              :   }
    2203              : 
    2204            1 :   valve = *h = g_new0 (ml_pipeline_common_elem, 1);
    2205            1 :   if (valve == NULL) {
    2206            0 :     _ml_error_report
    2207              :         ("Cannot allocate memory for valve handle of %s. Out of memory?",
    2208              :         valve_name);
    2209            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    2210            0 :     goto unlock_return;
    2211              :   }
    2212              : 
    2213            1 :   valve->pipe = p;
    2214            1 :   valve->element = elem;
    2215              : 
    2216            1 :   g_mutex_lock (&elem->lock);
    2217              : 
    2218            1 :   elem->maxid++;
    2219            1 :   valve->id = elem->maxid;
    2220            1 :   elem->handles = g_list_append (elem->handles, valve);
    2221              : 
    2222            1 :   g_mutex_unlock (&elem->lock);
    2223              : 
    2224            3 : unlock_return:
    2225            3 :   g_mutex_unlock (&p->lock);
    2226            3 :   return ret;
    2227              : }
    2228              : 
    2229              : /**
    2230              :  * @brief Close the given valve handle (more info in nnstreamer.h)
    2231              :  */
    2232              : int
    2233            1 : ml_pipeline_valve_release_handle (ml_pipeline_valve_h h)
    2234              : {
    2235            1 :   handle_init (valve, h);
    2236              : 
    2237            1 :   elem->handles = g_list_remove (elem->handles, valve);
    2238            1 :   free_element_handle (valve);
    2239              : 
    2240            1 :   handle_exit (h);
    2241              : }
    2242              : 
    2243              : /**
    2244              :  * @brief Control the valve with the given handle (more info in nnstreamer.h)
    2245              :  */
    2246              : int
    2247            2 : ml_pipeline_valve_set_open (ml_pipeline_valve_h h, bool open)
    2248              : {
    2249            2 :   gboolean drop = FALSE;
    2250            4 :   handle_init (valve, h);
    2251              : 
    2252            2 :   g_object_get (G_OBJECT (elem->element), "drop", &drop, NULL);
    2253              : 
    2254            2 :   if ((open != false) != (drop != FALSE)) {
    2255              :     /* Nothing to do */
    2256            0 :     _ml_logi ("Valve is called, but there is no effective changes");
    2257            0 :     goto unlock_return;
    2258              :   }
    2259              : 
    2260            2 :   drop = (open) ? FALSE : TRUE;
    2261            2 :   g_object_set (G_OBJECT (elem->element), "drop", drop, NULL);
    2262              : 
    2263            2 :   handle_exit (h);
    2264              : }
    2265              : 
    2266              : /********************************************************
    2267              :  ** NNStreamer Element Property Control in Pipeline    **
    2268              :  ********************************************************/
    2269              : /**
    2270              :  * @brief Gets an element handle in NNStreamer pipelines to control its properties.
    2271              :  */
    2272              : int
    2273           64 : ml_pipeline_element_get_handle (ml_pipeline_h pipe, const char *element_name,
    2274              :     ml_pipeline_element_h * elem_h)
    2275              : {
    2276           64 :   int ret = ML_ERROR_NONE;
    2277              :   ml_pipeline_element *elem;
    2278              :   ml_pipeline_common_elem *common_elem;
    2279           64 :   ml_pipeline *p = pipe;
    2280              : 
    2281              :   /* Check input parameter */
    2282           64 :   if (pipe == NULL)
    2283            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2284              :         "The parameter, pipe (ml_pipeline_h), is NULL. It should be a valid ml_pipeline_h instance, which is usually created by ml_pipeline_construct().");
    2285              : 
    2286           64 :   if (element_name == NULL)
    2287            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2288              :         "The parameter, element_name (const char *), is NULL. It should be a valid string of the element name to be searched.");
    2289              : 
    2290           63 :   if (elem_h == NULL)
    2291            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2292              :         "The parameter, elem_h (ml_pipeline_element_h), is NULL. It should be a valid pointer of ml_pipeline_element_h. E.g., ml_pipeline_element_h eh; ml_pipeline_element_get_handle (..., &eh);");
    2293           63 :   *elem_h = NULL;
    2294              : 
    2295           63 :   g_mutex_lock (&p->lock);
    2296              : 
    2297              :   /* 1. Search element in lookup table first */
    2298           63 :   elem = g_hash_table_lookup (p->namednodes, element_name);
    2299           63 :   if (elem == NULL) {
    2300              :     /* 2. Search element in pipeline itself */
    2301              :     GstElement *gst_elem;
    2302              : 
    2303           49 :     gst_elem = gst_bin_get_by_name (GST_BIN (p->element), element_name);
    2304           49 :     if (gst_elem == NULL) {
    2305            1 :       _ml_error_report
    2306              :           ("Cannot find the element with the given name, '%s', in the pipeline. There is no element in the pipeline with such a name. Please check if you have an element with the appropriate name.",
    2307              :           element_name);
    2308            1 :       ret = ML_ERROR_INVALID_PARAMETER;
    2309            1 :       goto unlock_return;
    2310              :     }
    2311              : 
    2312              :     /* Caching for next search */
    2313           48 :     elem = construct_element (gst_elem, pipe, element_name,
    2314              :         ML_PIPELINE_ELEMENT_COMMON);
    2315           48 :     if (elem == NULL) {
    2316            0 :       _ml_error_report
    2317              :           ("Cannot allocate memory for element handle of %s. Out of memory?",
    2318              :           element_name);
    2319            0 :       ret = ML_ERROR_OUT_OF_MEMORY;
    2320            0 :       goto unlock_return;
    2321              :     }
    2322           48 :     g_hash_table_insert (p->namednodes, g_strdup (element_name), elem);
    2323              :   }
    2324              : 
    2325              :   /* Type checking */
    2326           62 :   if (elem->type == ML_PIPELINE_ELEMENT_UNKNOWN) {
    2327            0 :     _ml_error_report
    2328              :         ("There is an element named [%s] in the pipeline, but its type is unknown. It is possible that the app thread has touched ML-API's internal data structure.",
    2329              :         element_name);
    2330            0 :     ret = ML_ERROR_INVALID_PARAMETER;
    2331            0 :     goto unlock_return;
    2332              :   }
    2333              : 
    2334           62 :   common_elem = *elem_h = g_new0 (ml_pipeline_common_elem, 1);
    2335           62 :   if (common_elem == NULL) {
    2336            0 :     _ml_error_report
    2337              :         ("Failed to allocate the internal handler for %s. Out of memory?",
    2338              :         element_name);
    2339            0 :     ret = ML_ERROR_OUT_OF_MEMORY;
    2340            0 :     goto unlock_return;
    2341              :   }
    2342              : 
    2343           62 :   common_elem->pipe = p;
    2344           62 :   common_elem->element = elem;
    2345              : 
    2346           62 :   g_mutex_lock (&elem->lock);
    2347           62 :   elem->maxid++;
    2348           62 :   common_elem->id = elem->maxid;
    2349           62 :   elem->handles = g_list_append (elem->handles, common_elem);
    2350           62 :   g_mutex_unlock (&elem->lock);
    2351              : 
    2352           63 : unlock_return:
    2353           63 :   g_mutex_unlock (&p->lock);
    2354           63 :   return ret;
    2355              : }
    2356              : 
    2357              : /**
    2358              :  * @brief Releases the given element handle.
    2359              :  */
    2360              : int
    2361           62 : ml_pipeline_element_release_handle (ml_pipeline_element_h elem_h)
    2362              : {
    2363           62 :   handle_init (common_elem, elem_h);
    2364              : 
    2365           61 :   elem->handles = g_list_remove (elem->handles, common_elem);
    2366           61 :   free_element_handle (common_elem);
    2367              : 
    2368           61 :   handle_exit (elem_h);
    2369              : }
    2370              : 
    2371              : /**
    2372              :  * @brief Check property existence and its type.
    2373              :  */
    2374              : static bool
    2375          109 : ml_pipeline_element_check_property (GObjectClass * klass,
    2376              :     const char *property_name, const GType type)
    2377              : {
    2378          109 :   GParamSpec *pspec = NULL;
    2379              : 
    2380              :   /* Check property existence */
    2381          109 :   pspec = g_object_class_find_property (klass, property_name);
    2382          109 :   if (pspec == NULL) {
    2383           16 :     _ml_logw ("The property name [%s] does not exist.", property_name);
    2384           16 :     return FALSE;
    2385              :   }
    2386              : 
    2387              :   /* Compare property's type with given type */
    2388          109 :   if (!((pspec->value_type == type) ||
    2389           33 :           (type == G_TYPE_ENUM && G_TYPE_IS_ENUM (pspec->value_type)) ||
    2390           22 :           (type == G_TYPE_INT64 && pspec->value_type == G_TYPE_LONG) ||
    2391           22 :           (type == G_TYPE_UINT64 && pspec->value_type == G_TYPE_ULONG) ||
    2392           22 :           (type == G_TYPE_INT && G_TYPE_IS_ENUM (pspec->value_type)) ||
    2393            5 :           (type == G_TYPE_UINT && G_TYPE_IS_ENUM (pspec->value_type)) ||
    2394            2 :           (type == G_TYPE_DOUBLE && pspec->value_type == G_TYPE_FLOAT))) {
    2395           16 :     _ml_logw ("The type of property name [%s] is '%s'", property_name,
    2396              :         g_type_name (pspec->value_type));
    2397           16 :     return FALSE;
    2398              :   }
    2399           77 :   return TRUE;
    2400              : }
    2401              : 
    2402              : /**
    2403              :  * @brief Sets the value of given element's property in NNStreamer pipelines.
    2404              :  */
    2405              : static int
    2406           83 : ml_pipeline_element_set_property (ml_pipeline_element_h elem_h,
    2407              :     const char *property_name, gpointer value, GType type)
    2408              : {
    2409           83 :   handle_init (common_elem, elem_h);
    2410              : 
    2411              :   /* Check the input parameter */
    2412           75 :   if (property_name == NULL) {
    2413            0 :     _ml_error_report
    2414              :         ("The parameter, property_name (const char *), is NULL. It should be a valid string of property name.");
    2415            0 :     ret = ML_ERROR_INVALID_PARAMETER;
    2416            0 :     goto unlock_return;
    2417              :   }
    2418              : 
    2419              :   /* Check property existence & its type */
    2420           75 :   if (!ml_pipeline_element_check_property (G_OBJECT_GET_CLASS (elem->element),
    2421              :           property_name, type)) {
    2422           16 :     _ml_error_report
    2423              :         ("The property ('%s') of the element, '%s', cannot be checked. It looks like this property does not exist in this element.",
    2424              :         property_name, elem->name);
    2425           16 :     ret = ML_ERROR_INVALID_PARAMETER;
    2426           16 :     goto unlock_return;
    2427              :   }
    2428              : 
    2429              :   /* Set property */
    2430           59 :   if (type == G_TYPE_DOUBLE || type == G_TYPE_FLOAT) {
    2431            7 :     g_object_set (G_OBJECT (elem->element), property_name,
    2432              :         *(double *) value, NULL);
    2433           52 :   } else if (type == G_TYPE_INT64) {
    2434            7 :     g_object_set (G_OBJECT (elem->element), property_name,
    2435              :         *(int64_t *) value, NULL);
    2436           45 :   } else if (type == G_TYPE_UINT64) {
    2437            7 :     g_object_set (G_OBJECT (elem->element), property_name,
    2438              :         *(uint64_t *) value, NULL);
    2439              :   } else {
    2440           38 :     g_object_set (G_OBJECT (elem->element), property_name, value, NULL);
    2441              :   }
    2442              : 
    2443           75 :   handle_exit (elem_h);
    2444              : }
    2445              : 
    2446              : /**
    2447              :  * @brief Gets the value of given element's property in NNStreamer pipelines.
    2448              :  */
    2449              : static int
    2450           50 : ml_pipeline_element_get_property (ml_pipeline_element_h elem_h,
    2451              :     const char *property_name, GType type, gpointer pvalue)
    2452              : {
    2453           50 :   handle_init (common_elem, elem_h);
    2454              : 
    2455              :   /* Check the input parameter */
    2456           42 :   if (property_name == NULL) {
    2457            0 :     _ml_error_report
    2458              :         ("The parameter, property_name (const char *), is NULL. It should be a valid string of the property name of an element.");
    2459            0 :     ret = ML_ERROR_INVALID_PARAMETER;
    2460            0 :     goto unlock_return;
    2461              :   }
    2462              : 
    2463           42 :   if (pvalue == NULL) {
    2464            8 :     _ml_error_report
    2465              :         ("The parameter, pvalue (gpointer / a pointer of a value), is NULL. It should be a valid gpointer (a pointer of a value). E.g., char *str; ... ml_pipeline_get_property_string (... &str); ... int32_t val; ... ml_pipeline_get_property_int32 (..., &val);");
    2466            8 :     ret = ML_ERROR_INVALID_PARAMETER;
    2467            8 :     goto unlock_return;
    2468              :   }
    2469              : 
    2470              :   /* Check property existence & its type */
    2471           34 :   if (!ml_pipeline_element_check_property (G_OBJECT_GET_CLASS (elem->element),
    2472              :           property_name, type)) {
    2473           16 :     _ml_error_report
    2474              :         ("Cannot check the property ('%s') or the element ('%s'). Please check if you have the corresponding element in the pipeline.",
    2475              :         property_name, elem->name);
    2476           16 :     ret = ML_ERROR_INVALID_PARAMETER;
    2477           16 :     goto unlock_return;
    2478              :   }
    2479              : 
    2480              :   /* Get property */
    2481           18 :   g_object_get (G_OBJECT (elem->element), property_name, pvalue, NULL);
    2482              : 
    2483           42 :   handle_exit (elem_h);
    2484              : }
    2485              : 
    2486              : /**
    2487              :  * @brief Sets the boolean value of element's property in NNStreamer pipelines.
    2488              :  */
    2489              : int
    2490           11 : ml_pipeline_element_set_property_bool (ml_pipeline_element_h elem_h,
    2491              :     const char *property_name, const int32_t value)
    2492              : {
    2493           11 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2494           11 :       GINT_TO_POINTER (value), G_TYPE_BOOLEAN);
    2495              : }
    2496              : 
    2497              : /**
    2498              :  * @brief Sets the string value of element's property in NNStreamer pipelines.
    2499              :  */
    2500              : int
    2501            6 : ml_pipeline_element_set_property_string (ml_pipeline_element_h elem_h,
    2502              :     const char *property_name, const char *value)
    2503              : {
    2504            6 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2505              :       (gpointer) value, G_TYPE_STRING);
    2506              : }
    2507              : 
    2508              : /**
    2509              :  * @brief Sets the integer value of element's property in NNStreamer pipelines.
    2510              :  */
    2511              : int
    2512           12 : ml_pipeline_element_set_property_int32 (ml_pipeline_element_h elem_h,
    2513              :     const char *property_name, const int32_t value)
    2514              : {
    2515           12 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2516           12 :       GINT_TO_POINTER (value), G_TYPE_INT);
    2517              : }
    2518              : 
    2519              : /**
    2520              :  * @brief Sets the integer 64bit value of element's property in NNStreamer pipelines.
    2521              :  */
    2522              : int
    2523           10 : ml_pipeline_element_set_property_int64 (ml_pipeline_element_h elem_h,
    2524              :     const char *property_name, const int64_t value)
    2525              : {
    2526           10 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2527              :       (gpointer) (&value), G_TYPE_INT64);
    2528              : }
    2529              : 
    2530              : /**
    2531              :  * @brief Sets the unsigned integer value of element's property in NNStreamer pipelines.
    2532              :  */
    2533              : int
    2534           12 : ml_pipeline_element_set_property_uint32 (ml_pipeline_element_h elem_h,
    2535              :     const char *property_name, const uint32_t value)
    2536              : {
    2537           12 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2538           12 :       GUINT_TO_POINTER (value), G_TYPE_UINT);
    2539              : }
    2540              : 
    2541              : /**
    2542              :  * @brief Sets the unsigned integer 64bit value of element's property in NNStreamer pipelines.
    2543              :  */
    2544              : int
    2545           10 : ml_pipeline_element_set_property_uint64 (ml_pipeline_element_h elem_h,
    2546              :     const char *property_name, const uint64_t value)
    2547              : {
    2548           10 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2549              :       (gpointer) (&value), G_TYPE_UINT64);
    2550              : }
    2551              : 
    2552              : /**
    2553              :  * @brief Sets the floating point value of element's property in NNStreamer pipelines.
    2554              :  */
    2555              : int
    2556           10 : ml_pipeline_element_set_property_double (ml_pipeline_element_h elem_h,
    2557              :     const char *property_name, const double value)
    2558              : {
    2559           10 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2560              :       (gpointer) (&value), G_TYPE_DOUBLE);
    2561              : }
    2562              : 
    2563              : /**
    2564              :  * @brief Sets the enumeration value of element's property in NNStreamer pipelines.
    2565              :  */
    2566              : int
    2567           12 : ml_pipeline_element_set_property_enum (ml_pipeline_element_h elem_h,
    2568              :     const char *property_name, const uint32_t value)
    2569              : {
    2570           12 :   return ml_pipeline_element_set_property (elem_h, property_name,
    2571           12 :       GUINT_TO_POINTER (value), G_TYPE_ENUM);
    2572              : }
    2573              : 
    2574              : /**
    2575              :  * @brief Gets the boolean value of element's property in NNStreamer pipelines.
    2576              :  */
    2577              : int
    2578            6 : ml_pipeline_element_get_property_bool (ml_pipeline_element_h elem_h,
    2579              :     const char *property_name, int32_t * value)
    2580              : {
    2581            6 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2582              :       G_TYPE_BOOLEAN, (gpointer) value);
    2583              : }
    2584              : 
    2585              : /**
    2586              :  * @brief Gets the string value of element's property in NNStreamer pipelines.
    2587              :  */
    2588              : int
    2589            6 : ml_pipeline_element_get_property_string (ml_pipeline_element_h elem_h,
    2590              :     const char *property_name, char **value)
    2591              : {
    2592            6 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2593              :       G_TYPE_STRING, (gpointer) value);
    2594              : }
    2595              : 
    2596              : /**
    2597              :  * @brief Gets the integer value of element's property in NNStreamer pipelines.
    2598              :  */
    2599              : int
    2600            7 : ml_pipeline_element_get_property_int32 (ml_pipeline_element_h elem_h,
    2601              :     const char *property_name, int32_t * value)
    2602              : {
    2603            7 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2604              :       G_TYPE_INT, (gpointer) value);
    2605              : }
    2606              : 
    2607              : /**
    2608              :  * @brief Gets the integer 64bit value of element's property in NNStreamer pipelines.
    2609              :  */
    2610              : int
    2611            6 : ml_pipeline_element_get_property_int64 (ml_pipeline_element_h elem_h,
    2612              :     const char *property_name, int64_t * value)
    2613              : {
    2614            6 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2615              :       G_TYPE_INT64, (gpointer) value);
    2616              : }
    2617              : 
    2618              : /**
    2619              :  * @brief Gets the unsigned integer value of element's property in NNStreamer pipelines.
    2620              :  */
    2621              : int
    2622            7 : ml_pipeline_element_get_property_uint32 (ml_pipeline_element_h elem_h,
    2623              :     const char *property_name, uint32_t * value)
    2624              : {
    2625            7 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2626              :       G_TYPE_UINT, (gpointer) value);
    2627              : }
    2628              : 
    2629              : /**
    2630              :  * @brief Gets the unsigned integer 64bit value of element's property in NNStreamer pipelines.
    2631              :  */
    2632              : int
    2633            6 : ml_pipeline_element_get_property_uint64 (ml_pipeline_element_h elem_h,
    2634              :     const char *property_name, uint64_t * value)
    2635              : {
    2636            6 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2637              :       G_TYPE_UINT64, (gpointer) value);
    2638              : }
    2639              : 
    2640              : /**
    2641              :  * @brief Gets the floating point value of element's property in NNStreamer pipelines.
    2642              :  */
    2643              : int
    2644            6 : ml_pipeline_element_get_property_double (ml_pipeline_element_h elem_h,
    2645              :     const char *property_name, double *value)
    2646              : {
    2647            6 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2648              :       G_TYPE_DOUBLE, (gpointer) value);
    2649              : }
    2650              : 
    2651              : /**
    2652              :  * @brief Gets the enumeration value of element's property in NNStreamer pipelines.
    2653              :  */
    2654              : int
    2655            6 : ml_pipeline_element_get_property_enum (ml_pipeline_element_h elem_h,
    2656              :     const char *property_name, uint32_t * value)
    2657              : {
    2658            6 :   return ml_pipeline_element_get_property (elem_h, property_name,
    2659              :       G_TYPE_ENUM, (gpointer) value);
    2660              : }
    2661              : 
    2662              : /**
    2663              :  * @brief Gets the element of pipeline itself (GstElement).
    2664              :  */
    2665              : GstElement *
    2666            0 : _ml_pipeline_get_gst_pipeline (ml_pipeline_h pipe)
    2667              : {
    2668            0 :   ml_pipeline *p = (ml_pipeline *) pipe;
    2669            0 :   GstElement *element = NULL;
    2670              : 
    2671            0 :   if (p) {
    2672            0 :     g_mutex_lock (&p->lock);
    2673              : 
    2674            0 :     element = p->element;
    2675            0 :     if (element)
    2676            0 :       gst_object_ref (element);
    2677              : 
    2678            0 :     g_mutex_unlock (&p->lock);
    2679              :   }
    2680              : 
    2681            0 :   return element;
    2682              : }
    2683              : 
    2684              : /**
    2685              :  * @brief Gets the element in pipeline (GstElement).
    2686              :  */
    2687              : GstElement *
    2688            0 : _ml_pipeline_get_gst_element (ml_pipeline_element_h handle)
    2689              : {
    2690            0 :   ml_pipeline_common_elem *e = (ml_pipeline_common_elem *) handle;
    2691            0 :   GstElement *element = NULL;
    2692              : 
    2693            0 :   if (e && e->element) {
    2694            0 :     ml_pipeline_element *elem = e->element;
    2695              : 
    2696            0 :     g_mutex_lock (&elem->lock);
    2697              : 
    2698            0 :     element = elem->element;
    2699            0 :     if (element)
    2700            0 :       gst_object_ref (element);
    2701              : 
    2702            0 :     g_mutex_unlock (&elem->lock);
    2703              :   }
    2704              : 
    2705            0 :   return element;
    2706              : }
    2707              : 
    2708              : /**
    2709              :  * @brief Increases ref count of custom-easy filter.
    2710              :  */
    2711              : static void
    2712            3 : ml_pipeline_custom_filter_ref (ml_custom_easy_filter_h custom)
    2713              : {
    2714            3 :   ml_custom_filter_s *c = (ml_custom_filter_s *) custom;
    2715              : 
    2716            3 :   if (c) {
    2717            3 :     g_mutex_lock (&c->lock);
    2718            3 :     c->ref_count++;
    2719            3 :     g_mutex_unlock (&c->lock);
    2720              :   }
    2721            3 : }
    2722              : 
    2723              : /**
    2724              :  * @brief Decreases ref count of custom-easy filter.
    2725              :  */
    2726              : static void
    2727            3 : ml_pipeline_custom_filter_unref (ml_custom_easy_filter_h custom)
    2728              : {
    2729            3 :   ml_custom_filter_s *c = (ml_custom_filter_s *) custom;
    2730              : 
    2731            3 :   if (!c)
    2732            0 :     return;
    2733              : 
    2734            3 :   g_mutex_lock (&c->lock);
    2735            3 :   if (c->ref_count > 0)
    2736            3 :     c->ref_count--;
    2737            3 :   g_mutex_unlock (&c->lock);
    2738              : }
    2739              : 
    2740              : /**
    2741              :  * @brief Releases custom filter handle.
    2742              :  */
    2743              : static void
    2744            4 : ml_pipeline_custom_free_handle (ml_custom_filter_s * custom)
    2745              : {
    2746            4 :   if (custom) {
    2747            4 :     g_mutex_lock (&custom->lock);
    2748              : 
    2749            4 :     g_free (custom->name);
    2750            4 :     ml_tensors_info_destroy (custom->in_info);
    2751            4 :     ml_tensors_info_destroy (custom->out_info);
    2752              : 
    2753            4 :     g_mutex_unlock (&custom->lock);
    2754            4 :     g_mutex_clear (&custom->lock);
    2755              : 
    2756            4 :     g_free (custom);
    2757              :   }
    2758            4 : }
    2759              : 
    2760              : /**
    2761              :  * @brief Invoke callback for custom-easy filter.
    2762              :  */
    2763              : static int
    2764            5 : ml_pipeline_custom_invoke (void *data, const GstTensorFilterProperties * prop,
    2765              :     const GstTensorMemory * in, GstTensorMemory * out)
    2766              : {
    2767              :   int status;
    2768              :   ml_custom_filter_s *c;
    2769              :   ml_tensors_data_h in_data, out_data;
    2770              :   ml_tensors_data_s *_data;
    2771              :   guint i;
    2772              : 
    2773            5 :   in_data = out_data = NULL;
    2774            5 :   c = (ml_custom_filter_s *) data;
    2775              : 
    2776              :   /* internal error? */
    2777            5 :   if (!c || !c->cb)
    2778            5 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2779              :         "Internal error of callback function, ml_pipeline_custom_invoke. Its internal data structure is broken.");
    2780              : 
    2781            5 :   g_mutex_lock (&c->lock);
    2782              : 
    2783              :   /* prepare invoke */
    2784            5 :   status = _ml_tensors_data_create_no_alloc (c->in_info, &in_data);
    2785            5 :   if (status != ML_ERROR_NONE) {
    2786            0 :     _ml_error_report_continue ("_ml_tensors_data_create_no_alloc has failed.");
    2787            0 :     goto done;
    2788              :   }
    2789              : 
    2790            5 :   _data = (ml_tensors_data_s *) in_data;
    2791           10 :   for (i = 0; i < _data->num_tensors; i++)
    2792            5 :     _data->tensors[i].data = in[i].data;
    2793              : 
    2794            5 :   status = _ml_tensors_data_create_no_alloc (c->out_info, &out_data);
    2795            5 :   if (status != ML_ERROR_NONE) {
    2796            0 :     _ml_error_report_continue ("_ml_tensors_data_create_no_alloc has failed.");
    2797            0 :     goto done;
    2798              :   }
    2799              : 
    2800            5 :   _data = (ml_tensors_data_s *) out_data;
    2801           10 :   for (i = 0; i < _data->num_tensors; i++)
    2802            5 :     _data->tensors[i].data = out[i].data;
    2803              : 
    2804              :   /* call invoke callback */
    2805            5 :   status = c->cb (in_data, out_data, c->pdata);
    2806              : 
    2807            5 : done:
    2808            5 :   g_mutex_unlock (&c->lock);
    2809              :   /* NOTE: DO NOT free tensor data */
    2810            5 :   _ml_tensors_data_destroy_internal (in_data, FALSE);
    2811            5 :   _ml_tensors_data_destroy_internal (out_data, FALSE);
    2812              : 
    2813            5 :   return status;
    2814              : }
    2815              : 
    2816              : /**
    2817              :  * @brief Registers a custom filter.
    2818              :  */
    2819              : int
    2820           11 : ml_pipeline_custom_easy_filter_register (const char *name,
    2821              :     const ml_tensors_info_h in, const ml_tensors_info_h out,
    2822              :     ml_custom_easy_invoke_cb cb, void *user_data,
    2823              :     ml_custom_easy_filter_h * custom)
    2824              : {
    2825           11 :   int status = ML_ERROR_NONE;
    2826              :   ml_custom_filter_s *c;
    2827              :   GstTensorsInfo in_info, out_info;
    2828              : 
    2829           22 :   check_feature_state (ML_FEATURE_INFERENCE);
    2830              : 
    2831           11 :   if (!name)
    2832            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2833              :         "The parameter, name (const char *), is NULL. It should be a valid string of the filter name.");
    2834           10 :   if (!cb)
    2835            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2836              :         "The parameter, cb (ml_custom_easy_invoke_cb), is NULL. It should be a valid call-back struct containing function pointer and its related data.");
    2837            9 :   if (!custom)
    2838            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2839              :         "The parameter, custom (ml_custom_easy_filter_h *), is NULL. It should be a valid pointer of ml_custom_easy_filter. E.g., ml_custom_easy_filter_h custom; ml_pipeline_custom_easy_filter_register (..., &custom);");
    2840              : 
    2841              :   /* init null */
    2842            8 :   *custom = NULL;
    2843              : 
    2844            8 :   if (!ml_tensors_info_is_valid (in))
    2845            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2846              :         "The parameter, in (const ml_tensors_info_h), is not valid. ml_tensors_info_is_valid(in) has returned FALSE. Please check if its cloned/fetched from a valid object or if you have configured it properly.");
    2847            6 :   if (!ml_tensors_info_is_valid (out))
    2848            2 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2849              :         "The parameter, out (const ml_tensors_info_h), is not valid. ml_tensors_info_is_valid(in) has returned FALSE. Please check if its cloned/fetched from a valid object or if you have configured it properly.");
    2850              : 
    2851              :   /* create and init custom handle */
    2852            4 :   if ((c = g_new0 (ml_custom_filter_s, 1)) == NULL)
    2853            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
    2854              :         "Cannot allocate memory. Out of memory?");
    2855              : 
    2856            4 :   g_mutex_init (&c->lock);
    2857              : 
    2858              :   /** no need to acquire c->lock as its created locally */
    2859            4 :   c->name = g_strdup (name);
    2860            4 :   c->ref_count = 0;
    2861            4 :   c->cb = cb;
    2862            4 :   c->pdata = user_data;
    2863            4 :   ml_tensors_info_create_extended (&c->in_info);
    2864            4 :   ml_tensors_info_create_extended (&c->out_info);
    2865              : 
    2866            4 :   status = ml_tensors_info_clone (c->in_info, in);
    2867            4 :   if (status != ML_ERROR_NONE) {
    2868            0 :     _ml_error_report_continue
    2869              :         ("ml_tensors_info_clone has failed with %d. Cannot fetch input tensor-info (metadata).",
    2870              :         status);
    2871            0 :     goto exit;
    2872              :   }
    2873              : 
    2874            4 :   status = ml_tensors_info_clone (c->out_info, out);
    2875            4 :   if (status != ML_ERROR_NONE) {
    2876            0 :     _ml_error_report_continue
    2877              :         ("ml_tensors_info_clone has filed with %d. Cannot fetch output tensor-info (metadata).",
    2878              :         status);
    2879            0 :     goto exit;
    2880              :   }
    2881              : 
    2882              :   /* register custom filter */
    2883            4 :   _ml_tensors_info_copy_from_ml (&in_info, c->in_info);
    2884            4 :   _ml_tensors_info_copy_from_ml (&out_info, c->out_info);
    2885              : 
    2886            4 :   status = NNS_custom_easy_register (name, ml_pipeline_custom_invoke, c,
    2887              :       &in_info, &out_info);
    2888            4 :   if (status != 0) {
    2889            1 :     char buf[255] = { 0 };
    2890            1 :     if (status == -EINVAL) {
    2891            1 :       status = ML_ERROR_INVALID_PARAMETER;
    2892            1 :       strncpy (buf, "invalid parameters are given.", 254);
    2893            0 :     } else if (status == -ENOMEM) {
    2894            0 :       status = ML_ERROR_OUT_OF_MEMORY;
    2895            0 :       strncpy (buf, "out of memory. cannot allocate.", 254);
    2896              :     } else {
    2897            0 :       status = ML_ERROR_UNKNOWN;
    2898            0 :       strncpy (buf, "unknown error.", 254);
    2899              :     }
    2900            1 :     _ml_error_report
    2901              :         ("Failed to register custom filter %s with NNStreamer API, NNS_custom_easy_register(). It has returned %d, which means '%s'.",
    2902              :         name, status, buf);
    2903              :   }
    2904              : 
    2905            3 : exit:
    2906            4 :   if (status == ML_ERROR_NONE) {
    2907            3 :     pipe_custom_add_data (PIPE_CUSTOM_TYPE_FILTER, name, c);
    2908            3 :     *custom = c;
    2909              :   } else {
    2910            1 :     ml_pipeline_custom_free_handle (c);
    2911              :   }
    2912              : 
    2913            4 :   return status;
    2914              : }
    2915              : 
    2916              : /**
    2917              :  * @brief Unregisters the custom filter.
    2918              :  */
    2919              : int
    2920            6 : ml_pipeline_custom_easy_filter_unregister (ml_custom_easy_filter_h custom)
    2921              : {
    2922              :   ml_custom_filter_s *c;
    2923            6 :   int status = ML_ERROR_NONE;
    2924              : 
    2925            6 :   check_feature_state (ML_FEATURE_INFERENCE);
    2926              : 
    2927            6 :   if (!custom)
    2928            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    2929              :         "The parameter, custom (ml_custom_easy_filter_h), is NULL. It should be a valid ml_custom_easy_filter_h instance, usually created by ml_pipeline_custom_easy_filter_register().");
    2930              : 
    2931            5 :   c = (ml_custom_filter_s *) custom;
    2932            5 :   g_mutex_lock (&c->lock);
    2933              : 
    2934            5 :   if (c->ref_count > 0) {
    2935            2 :     _ml_error_report
    2936              :         ("Failed to unregister custom filter %s, it is used in the pipeline. Its reference counter value is %u.",
    2937              :         c->name, c->ref_count);
    2938            2 :     status = ML_ERROR_INVALID_PARAMETER;
    2939            2 :     goto done;
    2940              :   }
    2941              : 
    2942            3 :   status = NNS_custom_easy_unregister (c->name);
    2943            3 :   if (status != 0) {
    2944            0 :     _ml_error_report
    2945              :         ("Failed to unregister custom filter %s. It is possible that this is already unregistered or not registered.",
    2946              :         c->name);
    2947            0 :     status = ML_ERROR_INVALID_PARAMETER;
    2948            0 :     goto done;
    2949              :   }
    2950              : 
    2951            3 : done:
    2952            5 :   g_mutex_unlock (&c->lock);
    2953              : 
    2954            5 :   if (status == ML_ERROR_NONE) {
    2955            3 :     pipe_custom_remove_data (PIPE_CUSTOM_TYPE_FILTER, c->name);
    2956            3 :     ml_pipeline_custom_free_handle (c);
    2957              :   }
    2958              : 
    2959            5 :   return status;
    2960              : }
    2961              : 
    2962              : /**
    2963              :  * @brief Increases ref count of tensor_if custom condition.
    2964              :  */
    2965              : static void
    2966            3 : ml_pipeline_if_custom_ref (ml_pipeline_if_h custom)
    2967              : {
    2968            3 :   ml_if_custom_s *c = (ml_if_custom_s *) custom;
    2969              : 
    2970            3 :   if (c) {
    2971            3 :     g_mutex_lock (&c->lock);
    2972            3 :     c->ref_count++;
    2973            3 :     g_mutex_unlock (&c->lock);
    2974              :   }
    2975            3 : }
    2976              : 
    2977              : /**
    2978              :  * @brief Decreases ref count of tensor_if custom condition.
    2979              :  */
    2980              : static void
    2981            3 : ml_pipeline_if_custom_unref (ml_pipeline_if_h custom)
    2982              : {
    2983            3 :   ml_if_custom_s *c = (ml_if_custom_s *) custom;
    2984              : 
    2985            3 :   if (c) {
    2986            3 :     g_mutex_lock (&c->lock);
    2987            3 :     if (c->ref_count > 0)
    2988            3 :       c->ref_count--;
    2989            3 :     g_mutex_unlock (&c->lock);
    2990              :   }
    2991            3 : }
    2992              : 
    2993              : /**
    2994              :  * @brief Callback for tensor_if custom condition.
    2995              :  */
    2996              : static gboolean
    2997           10 : ml_pipeline_if_custom (const GstTensorsInfo * info,
    2998              :     const GstTensorMemory * input, void *data, gboolean * result)
    2999              : {
    3000           10 :   int status = 0;
    3001              :   guint i;
    3002              :   ml_if_custom_s *c;
    3003           10 :   ml_tensors_data_h in_data = NULL;
    3004              :   ml_tensors_data_s *_data;
    3005           10 :   ml_tensors_info_h ml_info = NULL;
    3006           10 :   gboolean ret = FALSE;
    3007              : 
    3008           10 :   c = (ml_if_custom_s *) data;
    3009              : 
    3010              :   /* internal error? */
    3011           10 :   if (!c || !c->cb)
    3012           10 :     _ml_error_report_return (FALSE,
    3013              :         "Internal error: the parameter, data, is not valid. App thread might have touched internal data structure.");
    3014              : 
    3015           10 :   status = _ml_tensors_info_create_from_gst (&ml_info, info);
    3016           10 :   if (status != ML_ERROR_NONE)
    3017            0 :     _ml_error_report_return_continue (FALSE,
    3018              :         "Cannot create tensors-info from the parameter, info (const GstTensorsInfo). _ml_tensors_info_create_from_gst has returned %d.",
    3019              :         status);
    3020           10 :   status = _ml_tensors_data_create_no_alloc (ml_info, &in_data);
    3021           10 :   if (status != ML_ERROR_NONE) {
    3022            0 :     _ml_error_report_continue
    3023              :         ("Cannot create data entry from the given metadata, info (const GstTensorMemory, although we could create tensor-info from info. _ml_tensors_data_create_no_alloc() has returned %d.",
    3024              :         status);
    3025            0 :     goto done;
    3026              :   }
    3027              : 
    3028           10 :   _data = (ml_tensors_data_s *) in_data;
    3029           20 :   for (i = 0; i < _data->num_tensors; i++)
    3030           10 :     _data->tensors[i].data = input[i].data;
    3031              : 
    3032              :   /* call invoke callback */
    3033           10 :   g_mutex_lock (&c->lock);
    3034           10 :   status = c->cb (in_data, ml_info, result, c->pdata);
    3035           10 :   g_mutex_unlock (&c->lock);
    3036              : 
    3037           10 :   ret = (status == ML_ERROR_NONE);
    3038           10 :   if (!ret)
    3039            0 :     _ml_error_report
    3040              :         ("The callback function of if-statement has returned error: %d.",
    3041              :         status);
    3042              : 
    3043           10 : done:
    3044           10 :   ml_tensors_info_destroy (ml_info);
    3045           10 :   _ml_tensors_data_destroy_internal (in_data, FALSE);
    3046              : 
    3047           10 :   return ret;
    3048              : }
    3049              : 
    3050              : /**
    3051              :  * @brief Releases tensor_if custom condition.
    3052              :  */
    3053              : static void
    3054            4 : ml_pipeline_if_custom_free (ml_if_custom_s * custom)
    3055              : {
    3056            4 :   if (custom) {
    3057            4 :     g_mutex_lock (&custom->lock);
    3058              : 
    3059            4 :     g_free (custom->name);
    3060              : 
    3061            4 :     g_mutex_unlock (&custom->lock);
    3062            4 :     g_mutex_clear (&custom->lock);
    3063              : 
    3064            4 :     g_free (custom);
    3065              :   }
    3066            4 : }
    3067              : 
    3068              : /**
    3069              :  * @brief Registers the tensor_if custom callback.
    3070              :  */
    3071              : int
    3072            7 : ml_pipeline_tensor_if_custom_register (const char *name,
    3073              :     ml_pipeline_if_custom_cb cb, void *user_data, ml_pipeline_if_h * if_custom)
    3074              : {
    3075            7 :   int status = ML_ERROR_NONE;
    3076              :   ml_if_custom_s *c;
    3077              : 
    3078            7 :   check_feature_state (ML_FEATURE_INFERENCE);
    3079              : 
    3080            7 :   if (!name)
    3081            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    3082              :         "The parameter, name (const char *), is NULL. It should be a valid string of the tensor_if element in your pipeline.");
    3083            6 :   if (!cb)
    3084            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    3085              :         "The parameter, cb (ml_pipeline_if_custom_cb callback function pointer), is NULL. It should be a valid function pointer that determines if the 'if' statement is TRUE or FALSE from the given tensor data frame.");
    3086            5 :   if (!if_custom)
    3087            1 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    3088              :         "The parameter, if_custom (ml_pipeline_if_h *), is NULL. It should be a valid pointer to the pipeline-if handle instance. E.g., ml_pipeline_if_h h; ml_pipeline_tensor_if_custom_register (..., &h);");
    3089              : 
    3090              :   /* init null */
    3091            4 :   *if_custom = NULL;
    3092              : 
    3093              :   /* create and init custom handle */
    3094            4 :   if ((c = g_try_new0 (ml_if_custom_s, 1)) == NULL)
    3095            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
    3096              :         "Cannot allocate memory. Out of memory?");
    3097              : 
    3098            4 :   g_mutex_init (&c->lock);
    3099              : 
    3100            4 :   g_mutex_lock (&c->lock);
    3101            4 :   c->name = g_strdup (name);
    3102            4 :   c->ref_count = 0;
    3103            4 :   c->cb = cb;
    3104            4 :   c->pdata = user_data;
    3105              : 
    3106            4 :   status = nnstreamer_if_custom_register (name, ml_pipeline_if_custom, c);
    3107            4 :   if (status != 0) {
    3108            1 :     if (status == -ENOMEM) {
    3109            0 :       _ml_error_report
    3110              :           ("Failed to register tensor_if custom condition %s because nnstreamer_if_custom_register has failed to allocate memory. Out of memory?",
    3111              :           name);
    3112            0 :       status = ML_ERROR_OUT_OF_MEMORY;
    3113            1 :     } else if (status == -EINVAL) {
    3114            1 :       _ml_error_report
    3115              :           ("Failed to register tensor_if custom condition %s because nnstreamer_if_custom_register has reported that an invalid parameter is given to the API call. Please check if the given name is 0-length or duplicated (already registered), memory is full, or the name is not allowed ('any', 'auto' are not allowed).",
    3116              :           name);
    3117            1 :       status = ML_ERROR_INVALID_PARAMETER;
    3118              :     } else {
    3119            0 :       _ml_error_report
    3120              :           ("Failed to register tensor_if custom condition %s because nnstreamer_if_custom_register has returned unknown error.",
    3121              :           name);
    3122            0 :       status = ML_ERROR_UNKNOWN;
    3123              :     }
    3124              :   }
    3125            4 :   g_mutex_unlock (&c->lock);
    3126              : 
    3127            4 :   if (status == ML_ERROR_NONE) {
    3128            3 :     pipe_custom_add_data (PIPE_CUSTOM_TYPE_IF, name, c);
    3129            3 :     *if_custom = c;
    3130              :   } else {
    3131            1 :     ml_pipeline_if_custom_free (c);
    3132              :   }
    3133              : 
    3134            4 :   return status;
    3135              : }
    3136              : 
    3137              : /**
    3138              :  * @brief Unregisters the tensor_if custom callback.
    3139              :  */
    3140              : int
    3141            6 : ml_pipeline_tensor_if_custom_unregister (ml_pipeline_if_h if_custom)
    3142              : {
    3143              :   ml_if_custom_s *c;
    3144            6 :   int status = ML_ERROR_NONE;
    3145              : 
    3146            6 :   check_feature_state (ML_FEATURE_INFERENCE);
    3147              : 
    3148            6 :   if (!if_custom)
    3149            1 :     return ML_ERROR_INVALID_PARAMETER;
    3150              : 
    3151            5 :   c = (ml_if_custom_s *) if_custom;
    3152            5 :   g_mutex_lock (&c->lock);
    3153              : 
    3154            5 :   if (c->ref_count > 0) {
    3155            2 :     _ml_error_report
    3156              :         ("Failed to unregister custom condition %s, it is used in the pipeline.",
    3157              :         c->name);
    3158            2 :     status = ML_ERROR_INVALID_PARAMETER;
    3159            2 :     goto done;
    3160              :   }
    3161              : 
    3162            3 :   status = nnstreamer_if_custom_unregister (c->name);
    3163            3 :   if (status != 0) {
    3164            0 :     if (status == -EINVAL)
    3165            0 :       _ml_error_report
    3166              :           ("Failed to unregister tensor_if custom condition %s. It appears that it is already unregistered or not yet registered.",
    3167              :           c->name);
    3168              :     else
    3169            0 :       _ml_error_report
    3170              :           ("Failed to unregister tensor_if custom condition %s with unknown reason. Internal error?",
    3171              :           c->name);
    3172            0 :     status = ML_ERROR_STREAMS_PIPE;
    3173            0 :     goto done;
    3174              :   }
    3175              : 
    3176            3 : done:
    3177            5 :   g_mutex_unlock (&c->lock);
    3178              : 
    3179            5 :   if (status == ML_ERROR_NONE) {
    3180            3 :     pipe_custom_remove_data (PIPE_CUSTOM_TYPE_IF, c->name);
    3181            3 :     ml_pipeline_if_custom_free (c);
    3182              :   }
    3183              : 
    3184            5 :   return status;
    3185              : }
        

Generated by: LCOV version 2.0-1