LCOV - code coverage report
Current view: top level - nnstreamer-2.4.2/gst/nnstreamer - nnstreamer_plugin_api_util_impl.c (source / functions) Coverage Total Hit
Test: nnstreamer 2.4.2-0 nnstreamer/nnstreamer#873b01ed4bdf7c3269bce413c4247b2979b35b75 Lines: 99.0 % 613 607
Test Date: 2025-08-28 05:39:39 Functions: 100.0 % 59 59

            Line data    Source code
       1              : /* SPDX-License-Identifier: LGPL-2.1-only */
       2              : /**
       3              :  * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
       4              :  *
       5              :  * @file nnstreamer_plugin_api_util_impl.c
       6              :  * @date 28 Jan 2022
       7              :  * @brief Tensor common util functions for NNStreamer. (No gst dependency)
       8              :  * @see https://github.com/nnstreamer/nnstreamer
       9              :  * @author Gichan Jang <gichan2.jang@samsung.com>
      10              :  * @bug No known bugs except for NYI items
      11              :  */
      12              : 
      13              : #include <string.h>
      14              : #include "nnstreamer_plugin_api_util.h"
      15              : #include "nnstreamer_log.h"
      16              : 
      17              : /**
      18              :  * @brief String representations for each tensor element type.
      19              :  */
      20              : static const gchar *tensor_element_typename[] = {
      21              :   [_NNS_INT32] = "int32",
      22              :   [_NNS_UINT32] = "uint32",
      23              :   [_NNS_INT16] = "int16",
      24              :   [_NNS_UINT16] = "uint16",
      25              :   [_NNS_INT8] = "int8",
      26              :   [_NNS_UINT8] = "uint8",
      27              :   [_NNS_FLOAT64] = "float64",
      28              :   [_NNS_FLOAT32] = "float32",
      29              :   [_NNS_INT64] = "int64",
      30              :   [_NNS_UINT64] = "uint64",
      31              :   [_NNS_FLOAT16] = "float16",
      32              :   [_NNS_END] = NULL,
      33              : };
      34              : 
      35              : /**
      36              :  * @brief Byte-per-element of each tensor element type.
      37              :  */
      38              : static const guint tensor_element_size[] = {
      39              :   [_NNS_INT32] = 4,
      40              :   [_NNS_UINT32] = 4,
      41              :   [_NNS_INT16] = 2,
      42              :   [_NNS_UINT16] = 2,
      43              :   [_NNS_INT8] = 1,
      44              :   [_NNS_UINT8] = 1,
      45              :   [_NNS_FLOAT64] = 8,
      46              :   [_NNS_FLOAT32] = 4,
      47              :   [_NNS_INT64] = 8,
      48              :   [_NNS_UINT64] = 8,
      49              :   [_NNS_FLOAT16] = 2,
      50              :   [_NNS_END] = 0,
      51              : };
      52              : 
      53              : /**
      54              :  * @brief String representations for tensor format.
      55              :  */
      56              : static const gchar *tensor_format_name[] = {
      57              :   [_NNS_TENSOR_FORMAT_STATIC] = "static",
      58              :   [_NNS_TENSOR_FORMAT_FLEXIBLE] = "flexible",
      59              :   [_NNS_TENSOR_FORMAT_SPARSE] = "sparse",
      60              :   [_NNS_TENSOR_FORMAT_END] = NULL
      61              : };
      62              : 
      63              : /**
      64              :  * @brief Internal function, copied from gst_util_greatest_common_divisor() to remove dependency of gstreamer.
      65              :  */
      66              : static gint
      67         1620 : _gcd (gint a, gint b)
      68              : {
      69         3250 :   while (b != 0) {
      70         1630 :     int temp = a;
      71              : 
      72         1630 :     a = b;
      73         1630 :     b = temp % b;
      74              :   }
      75              : 
      76         1620 :   return ABS (a);
      77              : }
      78              : 
      79              : /**
      80              :  * @brief Internal function, copied from gst_util_fraction_compare() to remove dependency of gstreamer.
      81              :  */
      82              : static gint
      83          810 : _compare_rate (gint a_n, gint a_d, gint b_n, gint b_d)
      84              : {
      85              :   gint64 new_num_1;
      86              :   gint64 new_num_2;
      87              :   gint gcd;
      88              : 
      89          810 :   g_return_val_if_fail (a_d != 0 && b_d != 0, 0);
      90              : 
      91              :   /* Simplify */
      92          810 :   gcd = _gcd (a_n, a_d);
      93          810 :   a_n /= gcd;
      94          810 :   a_d /= gcd;
      95              : 
      96          810 :   gcd = _gcd (b_n, b_d);
      97          810 :   b_n /= gcd;
      98          810 :   b_d /= gcd;
      99              : 
     100              :   /* fractions are reduced when set, so we can quickly see if they're equal */
     101          810 :   if (a_n == b_n && a_d == b_d)
     102          805 :     return 0;
     103              : 
     104              :   /* extend to 64 bits */
     105            5 :   new_num_1 = ((gint64) a_n) * b_d;
     106            5 :   new_num_2 = ((gint64) b_n) * a_d;
     107            5 :   if (new_num_1 < new_num_2)
     108            4 :     return -1;
     109            1 :   if (new_num_1 > new_num_2)
     110            1 :     return 1;
     111              : 
     112              :   /* Should not happen because a_d and b_d are not 0 */
     113            0 :   g_return_val_if_reached (0);
     114              : }
     115              : 
     116              : /**
     117              :  * @brief Initialize the tensor info structure
     118              :  * @param info tensor info structure to be initialized
     119              :  */
     120              : void
     121     12304716 : gst_tensor_info_init (GstTensorInfo * info)
     122              : {
     123              :   guint i;
     124              : 
     125     12304716 :   g_return_if_fail (info != NULL);
     126              : 
     127     12304716 :   info->name = NULL;
     128     12304716 :   info->type = _NNS_END;
     129              : 
     130    209180172 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     131    196875456 :     info->dimension[i] = 0;
     132              :   }
     133              : }
     134              : 
     135              : /**
     136              :  * @brief Free allocated data in tensor info structure
     137              :  * @param info tensor info structure
     138              :  */
     139              : void
     140      3014733 : gst_tensor_info_free (GstTensorInfo * info)
     141              : {
     142      3014733 :   g_return_if_fail (info != NULL);
     143              : 
     144      3014733 :   g_free (info->name);
     145              : 
     146              :   /* Init default */
     147      3014733 :   gst_tensor_info_init (info);
     148              : }
     149              : 
     150              : /**
     151              :  * @brief Get data size of single tensor
     152              :  * @param info tensor info structure
     153              :  * @return data size
     154              :  */
     155              : gsize
     156       102058 : gst_tensor_info_get_size (const GstTensorInfo * info)
     157              : {
     158              :   gsize data_size;
     159              : 
     160       102058 :   g_return_val_if_fail (info != NULL, 0);
     161              : 
     162       102057 :   data_size = gst_tensor_get_element_count (info->dimension) *
     163       102057 :       gst_tensor_get_element_size (info->type);
     164              : 
     165       102057 :   return data_size;
     166              : }
     167              : 
     168              : /**
     169              :  * @brief Check the tensor info is valid
     170              :  * @param info tensor info structure
     171              :  * @return TRUE if info is valid
     172              :  */
     173              : gboolean
     174       279025 : gst_tensor_info_validate (const GstTensorInfo * info)
     175              : {
     176       279025 :   g_return_val_if_fail (info != NULL, FALSE);
     177              : 
     178       279022 :   if (info->type == _NNS_END) {
     179         4388 :     nns_logd
     180              :         ("Failed to validate tensor info. type: %s. Please specify tensor type. e.g., type=uint8 ",
     181              :         _STR_NULL (gst_tensor_get_type_string (info->type)));
     182         4388 :     _nnstreamer_error_write
     183              :         ("Failed to validate tensor info. type: %s. Please specify tensor type. e.g., type=uint8 ",
     184         4388 :         _STR_NULL (gst_tensor_get_type_string (info->type)));
     185         4388 :     return FALSE;
     186              :   }
     187              : 
     188              :   /* validate tensor dimension */
     189       274634 :   return gst_tensor_dimension_is_valid (info->dimension);
     190              : }
     191              : 
     192              : /**
     193              :  * @brief Compare tensor info
     194              :  * @return TRUE if equal, FALSE if given tensor infos are invalid or not equal.
     195              :  */
     196              : gboolean
     197         1524 : gst_tensor_info_is_equal (const GstTensorInfo * i1, const GstTensorInfo * i2)
     198              : {
     199         1524 :   if (!gst_tensor_info_validate (i1) || !gst_tensor_info_validate (i2)) {
     200            2 :     return FALSE;
     201              :   }
     202              : 
     203         1522 :   if (i1->type != i2->type) {
     204          148 :     nns_logd ("Tensor info is not equal. Given tensor types %s vs %s",
     205              :         _STR_NULL (gst_tensor_get_type_string (i1->type)),
     206              :         _STR_NULL (gst_tensor_get_type_string (i2->type)));
     207          148 :     return FALSE;
     208              :   }
     209              : 
     210         1374 :   if (!gst_tensor_dimension_is_equal (i1->dimension, i2->dimension)) {
     211           47 :     g_autofree gchar *_dim1 = gst_tensor_get_dimension_string (i1->dimension);
     212           47 :     g_autofree gchar *_dim2 = gst_tensor_get_dimension_string (i2->dimension);
     213           47 :     nns_logd ("Tensor info is not equal. Given tensor dimensions %s vs %s",
     214              :         _dim1, _dim2);
     215           47 :     return FALSE;
     216              :   }
     217              : 
     218              :   /* matched all */
     219         1327 :   return TRUE;
     220              : }
     221              : 
     222              : /**
     223              :  * @brief Copy tensor info up to n elements
     224              :  * @note Copied info should be freed with gst_tensor_info_free()
     225              :  */
     226              : void
     227        30528 : gst_tensor_info_copy_n (GstTensorInfo * dest, const GstTensorInfo * src,
     228              :     const guint n)
     229              : {
     230              :   guint i;
     231              : 
     232        30528 :   g_return_if_fail (dest != NULL);
     233        30528 :   g_return_if_fail (src != NULL);
     234              : 
     235        30528 :   dest->name = g_strdup (src->name);
     236        30528 :   dest->type = src->type;
     237              : 
     238       518976 :   for (i = 0; i < n; i++) {
     239       488448 :     dest->dimension[i] = src->dimension[i];
     240              :   }
     241              : }
     242              : 
     243              : /**
     244              :  * @brief Copy tensor info
     245              :  * @note Copied info should be freed with gst_tensor_info_free()
     246              :  */
     247              : void
     248        30528 : gst_tensor_info_copy (GstTensorInfo * dest, const GstTensorInfo * src)
     249              : {
     250        30528 :   gst_tensor_info_copy_n (dest, src, NNS_TENSOR_RANK_LIMIT);
     251        30528 : }
     252              : 
     253              : /**
     254              :  * @brief Convert GstTensorInfo structure to GstTensorMetaInfo.
     255              :  * @param[in] info GstTensorInfo to be converted
     256              :  * @param[out] meta tensor meta structure to be filled
     257              :  * @return TRUE if successfully set the meta
     258              :  */
     259              : gboolean
     260          402 : gst_tensor_info_convert_to_meta (GstTensorInfo * info, GstTensorMetaInfo * meta)
     261              : {
     262              :   guint i;
     263              : 
     264          402 :   g_return_val_if_fail (gst_tensor_info_validate (info), FALSE);
     265          400 :   g_return_val_if_fail (meta != NULL, FALSE);
     266              : 
     267          399 :   gst_tensor_meta_info_init (meta);
     268              : 
     269          399 :   meta->type = info->type;
     270              : 
     271         6783 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     272              :     /** @todo handle rank from info.dimension */
     273         6384 :     meta->dimension[i] = info->dimension[i];
     274              :   }
     275              : 
     276          399 :   return TRUE;
     277              : }
     278              : 
     279              : /**
     280              :  * @brief Get tensor rank
     281              :  * @param info tensor info structure
     282              :  * @return tensor rank (Minimum rank is 1 if given info is valid)
     283              :  */
     284              : guint
     285          174 : gst_tensor_info_get_rank (const GstTensorInfo * info)
     286              : {
     287          174 :   g_return_val_if_fail (info != NULL, 0);
     288              : 
     289          173 :   return gst_tensor_dimension_get_rank (info->dimension);
     290              : }
     291              : 
     292              : /**
     293              :  * @brief GstTensorInfo represented as a string.
     294              :  * @param info GstTensorInfo structure.
     295              :  * @return The newly allocated string representing the tensor info. Caller should free the value using g_free().
     296              :  */
     297              : gchar *
     298          864 : gst_tensor_info_to_string (const GstTensorInfo * info)
     299              : {
     300              :   GString *gstr;
     301              :   const gchar *type;
     302              :   gchar *dim;
     303              : 
     304          864 :   g_return_val_if_fail (info != NULL, NULL);
     305              : 
     306          863 :   gstr = g_string_new (NULL);
     307              : 
     308          863 :   if (info->name)
     309          299 :     g_string_append_printf (gstr, "'%s' ", info->name);
     310              : 
     311          863 :   type = gst_tensor_get_type_string (info->type);
     312          863 :   dim = gst_tensor_get_dimension_string (info->dimension);
     313              : 
     314          863 :   g_string_append_printf (gstr, "%s (%s)", type, dim);
     315              : 
     316          863 :   g_free (dim);
     317          863 :   return g_string_free (gstr, FALSE);
     318              : }
     319              : 
     320              : /**
     321              :  * @brief Get the pointer of nth tensor information.
     322              :  */
     323              : GstTensorInfo *
     324       559313 : gst_tensors_info_get_nth_info (GstTensorsInfo * info, guint index)
     325              : {
     326              :   guint i;
     327              : 
     328       559313 :   g_return_val_if_fail (info != NULL, NULL);
     329              : 
     330       559313 :   if (index < NNS_TENSOR_MEMORY_MAX)
     331       499544 :     return &info->info[index];
     332              : 
     333        59769 :   if (index < NNS_TENSOR_SIZE_LIMIT) {
     334        59768 :     if (!info->extra) {
     335          208 :       info->extra = g_new0 (GstTensorInfo, NNS_TENSOR_SIZE_EXTRA_LIMIT);
     336              : 
     337        50128 :       for (i = 0; i < NNS_TENSOR_SIZE_EXTRA_LIMIT; ++i)
     338        49920 :         gst_tensor_info_init (&info->extra[i]);
     339              :     }
     340              : 
     341        59768 :     return &info->extra[index - NNS_TENSOR_MEMORY_MAX];
     342              :   }
     343              : 
     344            1 :   nns_loge ("Failed to get the information, invalid index %u (max %d).",
     345              :       index, NNS_TENSOR_SIZE_LIMIT);
     346            1 :   return NULL;
     347              : }
     348              : 
     349              : /**
     350              :  * @brief Initialize the tensors info structure
     351              :  * @param info tensors info structure to be initialized
     352              :  */
     353              : void
     354       577052 : gst_tensors_info_init (GstTensorsInfo * info)
     355              : {
     356              :   guint i;
     357              : 
     358       577052 :   g_return_if_fail (info != NULL);
     359              : 
     360       577052 :   info->num_tensors = 0;
     361       577052 :   info->extra = NULL;
     362              : 
     363              :   /** @note default format is static */
     364       577052 :   info->format = _NNS_TENSOR_FORMAT_STATIC;
     365              : 
     366      9809884 :   for (i = 0; i < NNS_TENSOR_MEMORY_MAX; i++) {
     367      9232832 :     gst_tensor_info_init (&info->info[i]);
     368              :   }
     369              : }
     370              : 
     371              : /**
     372              :  * @brief Free allocated data in tensors info structure
     373              :  * @param info tensors info structure
     374              :  */
     375              : void
     376       185352 : gst_tensors_info_free (GstTensorsInfo * info)
     377              : {
     378              :   guint i;
     379              : 
     380       185352 :   g_return_if_fail (info != NULL);
     381              : 
     382      3150984 :   for (i = 0; i < NNS_TENSOR_MEMORY_MAX; i++) {
     383      2965632 :     gst_tensor_info_free (&info->info[i]);
     384              :   }
     385              : 
     386       185352 :   if (info->extra) {
     387        49164 :     for (i = 0; i < NNS_TENSOR_SIZE_EXTRA_LIMIT; ++i)
     388        48960 :       gst_tensor_info_free (&info->extra[i]);
     389              : 
     390          204 :     g_clear_pointer (&info->extra, g_free);
     391              :   }
     392              : 
     393              :   /* Init default */
     394       185352 :   gst_tensors_info_init (info);
     395              : }
     396              : 
     397              : /**
     398              :  * @brief Get data size of single tensor
     399              :  * @param info tensors info structure
     400              :  * @param index the index of tensor (-1 to get total size of tensors)
     401              :  * @return data size
     402              :  */
     403              : gsize
     404          493 : gst_tensors_info_get_size (const GstTensorsInfo * info, gint index)
     405              : {
     406              :   GstTensorInfo *_info;
     407          493 :   gsize data_size = 0;
     408              :   guint i;
     409              : 
     410          493 :   g_return_val_if_fail (info != NULL, 0);
     411          492 :   g_return_val_if_fail (index < (gint) info->num_tensors, 0);
     412              : 
     413          491 :   if (index < 0) {
     414          249 :     for (i = 0; i < info->num_tensors; ++i) {
     415          139 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     416          139 :       data_size += gst_tensor_info_get_size (_info);
     417              :     }
     418              :   } else {
     419          381 :     _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, index);
     420          381 :     data_size = gst_tensor_info_get_size (_info);
     421              :   }
     422              : 
     423          491 :   return data_size;
     424              : }
     425              : 
     426              : /**
     427              :  * @brief Check the tensors info is valid
     428              :  * @param info tensors info structure
     429              :  * @return TRUE if info is valid
     430              :  */
     431              : gboolean
     432       204892 : gst_tensors_info_validate (const GstTensorsInfo * info)
     433              : {
     434              :   guint i;
     435              :   GstTensorInfo *_info;
     436              : 
     437       204892 :   g_return_val_if_fail (info != NULL, FALSE);
     438              : 
     439              :   /* tensor stream format */
     440       204891 :   if (info->format >= _NNS_TENSOR_FORMAT_END) {
     441           49 :     nns_logd
     442              :         ("Failed to validate tensors info, format: %s. format should be one of %s.",
     443              :         _STR_NULL (gst_tensor_get_format_string (info->format)),
     444              :         GST_TENSOR_FORMAT_ALL);
     445           49 :     _nnstreamer_error_write
     446              :         ("Failed to validate tensors info, format: %s. format should be one of %s.",
     447           49 :         _STR_NULL (gst_tensor_get_format_string (info->format)),
     448              :         GST_TENSOR_FORMAT_ALL);
     449           49 :     return FALSE;
     450              :   }
     451              : 
     452              :   /* cannot check tensor info when tensor is not static */
     453       204842 :   if (info->format != _NNS_TENSOR_FORMAT_STATIC) {
     454          703 :     return TRUE;
     455              :   }
     456              : 
     457       204139 :   if (info->num_tensors < 1) {
     458         2191 :     nns_logd
     459              :         ("Failed to validate tensors info. the number of tensors: %d. the number of tensors should be greater than 0.",
     460              :         info->num_tensors);
     461         2191 :     _nnstreamer_error_write
     462              :         ("Failed to validate tensors info. the number of tensors: %d. the number of tensors should be greater than 0.",
     463         2191 :         info->num_tensors);
     464         2191 :     return FALSE;
     465              :   }
     466              : 
     467       411081 :   for (i = 0; i < info->num_tensors; i++) {
     468       215135 :     _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     469              : 
     470       215135 :     if (!gst_tensor_info_validate (_info))
     471         6002 :       return FALSE;
     472              :   }
     473              : 
     474       195946 :   return TRUE;
     475              : }
     476              : 
     477              : /**
     478              :  * @brief Compare tensors info
     479              :  * @return TRUE if equal, FALSE if given tensor infos are invalid or not equal.
     480              :  */
     481              : gboolean
     482         1312 : gst_tensors_info_is_equal (const GstTensorsInfo * i1, const GstTensorsInfo * i2)
     483              : {
     484              :   guint i;
     485              :   GstTensorInfo *_info1, *_info2;
     486              : 
     487         1312 :   g_return_val_if_fail (i1 != NULL, FALSE);
     488         1311 :   g_return_val_if_fail (i2 != NULL, FALSE);
     489              : 
     490         1310 :   if (i1->format != i2->format || i1->format == _NNS_TENSOR_FORMAT_END) {
     491            7 :     nns_logd ("Tensors info is not equal. format: %s vs %s ",
     492              :         _STR_NULL (gst_tensor_get_format_string (i1->format)),
     493              :         _STR_NULL (gst_tensor_get_format_string (i2->format)));
     494            7 :     return FALSE;
     495              :   }
     496              : 
     497              :   /* cannot compare tensor info when tensor is not static */
     498         1303 :   if (i1->format != _NNS_TENSOR_FORMAT_STATIC) {
     499           26 :     return TRUE;
     500              :   }
     501              : 
     502         1277 :   if (!gst_tensors_info_validate (i1) || !gst_tensors_info_validate (i2)) {
     503          111 :     return FALSE;
     504              :   }
     505              : 
     506         1166 :   if (i1->num_tensors != i2->num_tensors) {
     507            8 :     nns_logd ("Tensors info is not equal. the number of tensors: %d vs %d. ",
     508              :         i1->num_tensors, i2->num_tensors);
     509            8 :     return FALSE;
     510              :   }
     511              : 
     512         2407 :   for (i = 0; i < i1->num_tensors; i++) {
     513         1444 :     _info1 = gst_tensors_info_get_nth_info ((GstTensorsInfo *) i1, i);
     514         1444 :     _info2 = gst_tensors_info_get_nth_info ((GstTensorsInfo *) i2, i);
     515              : 
     516         1444 :     if (!gst_tensor_info_is_equal (_info1, _info2)) {
     517          195 :       return FALSE;
     518              :     }
     519              :   }
     520              : 
     521              :   /* matched all */
     522          963 :   return TRUE;
     523              : }
     524              : 
     525              : /**
     526              :  * @brief Copy tensor info
     527              :  * @note Copied info should be freed with gst_tensors_info_free()
     528              :  */
     529              : void
     530        11876 : gst_tensors_info_copy (GstTensorsInfo * dest, const GstTensorsInfo * src)
     531              : {
     532              :   guint i, num;
     533              :   GstTensorInfo *_dest, *_src;
     534              : 
     535        11876 :   g_return_if_fail (dest != NULL);
     536        11876 :   g_return_if_fail (src != NULL);
     537              : 
     538        11876 :   gst_tensors_info_init (dest);
     539        11876 :   num = dest->num_tensors = src->num_tensors;
     540        11876 :   dest->format = src->format;
     541              : 
     542              :   /* Try to copy tensor info even if its format is not static. */
     543        22127 :   for (i = 0; i < num; i++) {
     544        10251 :     _dest = gst_tensors_info_get_nth_info (dest, i);
     545        10251 :     _src = gst_tensors_info_get_nth_info ((GstTensorsInfo *) src, i);
     546              : 
     547        10251 :     gst_tensor_info_copy (_dest, _src);
     548              :   }
     549              : }
     550              : 
     551              : /**
     552              :  * @brief Parse the string of dimensions
     553              :  * @param info tensors info structure
     554              :  * @param dim_string string of dimensions
     555              :  * @return number of parsed dimensions
     556              :  */
     557              : guint
     558         8897 : gst_tensors_info_parse_dimensions_string (GstTensorsInfo * info,
     559              :     const gchar * dim_string)
     560              : {
     561         8897 :   guint num_dims = 0;
     562              :   GstTensorInfo *_info;
     563              : 
     564         8897 :   g_return_val_if_fail (info != NULL, 0);
     565              : 
     566         8896 :   if (dim_string) {
     567              :     guint i;
     568              :     gchar **str_dims;
     569              : 
     570         8895 :     str_dims = g_strsplit_set (dim_string, ",.", -1);
     571         8895 :     num_dims = g_strv_length (str_dims);
     572              : 
     573         8895 :     if (num_dims > NNS_TENSOR_SIZE_LIMIT) {
     574            1 :       nns_logw ("Invalid param, dimensions (%d) max (%d)\n",
     575              :           num_dims, NNS_TENSOR_SIZE_LIMIT);
     576              : 
     577            1 :       num_dims = NNS_TENSOR_SIZE_LIMIT;
     578              :     }
     579              : 
     580        27844 :     for (i = 0; i < num_dims; i++) {
     581        18949 :       _info = gst_tensors_info_get_nth_info (info, i);
     582        18949 :       gst_tensor_parse_dimension (str_dims[i], _info->dimension);
     583              :     }
     584              : 
     585         8895 :     g_strfreev (str_dims);
     586              :   }
     587              : 
     588         8896 :   return num_dims;
     589              : }
     590              : 
     591              : /**
     592              :  * @brief Parse the string of types
     593              :  * @param info tensors info structure
     594              :  * @param type_string string of types
     595              :  * @return number of parsed types
     596              :  */
     597              : guint
     598         9014 : gst_tensors_info_parse_types_string (GstTensorsInfo * info,
     599              :     const gchar * type_string)
     600              : {
     601         9014 :   guint num_types = 0;
     602              :   GstTensorInfo *_info;
     603              : 
     604         9014 :   g_return_val_if_fail (info != NULL, 0);
     605              : 
     606         9013 :   if (type_string) {
     607              :     guint i;
     608              :     gchar **str_types;
     609              : 
     610         9012 :     str_types = g_strsplit_set (type_string, ",.", -1);
     611         9012 :     num_types = g_strv_length (str_types);
     612              : 
     613         9012 :     if (num_types > NNS_TENSOR_SIZE_LIMIT) {
     614            1 :       nns_logw ("Invalid param, types (%d) max (%d)\n",
     615              :           num_types, NNS_TENSOR_SIZE_LIMIT);
     616              : 
     617            1 :       num_types = NNS_TENSOR_SIZE_LIMIT;
     618              :     }
     619              : 
     620        28083 :     for (i = 0; i < num_types; i++) {
     621        19071 :       _info = gst_tensors_info_get_nth_info (info, i);
     622        19071 :       _info->type = gst_tensor_get_type (str_types[i]);
     623              :     }
     624              : 
     625         9012 :     g_strfreev (str_types);
     626              :   }
     627              : 
     628         9013 :   return num_types;
     629              : }
     630              : 
     631              : /**
     632              :  * @brief Parse the string of names
     633              :  * @param info tensors info structure
     634              :  * @param name_string string of names
     635              :  * @return number of parsed names
     636              :  */
     637              : guint
     638           13 : gst_tensors_info_parse_names_string (GstTensorsInfo * info,
     639              :     const gchar * name_string)
     640              : {
     641           13 :   guint num_names = 0;
     642              :   GstTensorInfo *_info;
     643              : 
     644           13 :   g_return_val_if_fail (info != NULL, 0);
     645              : 
     646           12 :   if (name_string) {
     647              :     guint i;
     648              :     gchar **str_names;
     649              : 
     650           11 :     str_names = g_strsplit (name_string, ",", -1);
     651           11 :     num_names = g_strv_length (str_names);
     652              : 
     653           11 :     if (num_names > NNS_TENSOR_SIZE_LIMIT) {
     654            1 :       nns_logw ("Invalid param, names (%d) max (%d)\n",
     655              :           num_names, NNS_TENSOR_SIZE_LIMIT);
     656              : 
     657            1 :       num_names = NNS_TENSOR_SIZE_LIMIT;
     658              :     }
     659              : 
     660          309 :     for (i = 0; i < num_names; i++) {
     661              :       gchar *str_name;
     662              : 
     663          298 :       _info = gst_tensors_info_get_nth_info (info, i);
     664          298 :       g_clear_pointer (&_info->name, g_free);
     665              : 
     666          596 :       str_name = g_strstrip (g_strdup (str_names[i]));
     667          298 :       if (str_name && strlen (str_name))
     668          295 :         _info->name = str_name;
     669              :       else
     670            3 :         g_free (str_name);
     671              :     }
     672              : 
     673           11 :     g_strfreev (str_names);
     674              :   }
     675              : 
     676           12 :   return num_names;
     677              : }
     678              : 
     679              : /**
     680              :  * @brief Get the string of dimensions in tensors info
     681              :  * @param info tensors info structure
     682              :  * @return string of dimensions in tensors info (NULL if the number of tensors is 0)
     683              :  * @note The returned value should be freed with g_free()
     684              :  */
     685              : gchar *
     686         6417 : gst_tensors_info_get_dimensions_string (const GstTensorsInfo * info)
     687              : {
     688         6417 :   return gst_tensors_info_get_rank_dimensions_string (info,
     689              :       NNS_TENSOR_RANK_LIMIT, FALSE);
     690              : }
     691              : 
     692              : /**
     693              :  * @brief Get the string of dimensions in tensors info and rank count
     694              :  * @param info tensors info structure
     695              :  * @param rank rank count of given tensor dimension
     696              :  * @param padding fill 1 if actual rank is smaller than rank
     697              :  * @return Formatted string of given dimension
     698              :  * @note If rank count is 3, then returned string is 'd1:d2:d3`.
     699              :  * The returned value should be freed with g_free()
     700              :  */
     701              : gchar *
     702        13477 : gst_tensors_info_get_rank_dimensions_string (const GstTensorsInfo * info,
     703              :     const unsigned int rank, const gboolean padding)
     704              : {
     705        13477 :   gchar *dim_str = NULL;
     706              :   GstTensorInfo *_info;
     707              : 
     708        13477 :   g_return_val_if_fail (info != NULL, NULL);
     709              : 
     710        13476 :   if (info->num_tensors > 0) {
     711              :     guint i;
     712        13475 :     GString *dimensions = g_string_new (NULL);
     713              : 
     714        30245 :     for (i = 0; i < info->num_tensors; i++) {
     715        16770 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     716        16770 :       dim_str = gst_tensor_get_rank_dimension_string (_info->dimension,
     717              :           rank, padding);
     718              : 
     719              :       g_string_append (dimensions, dim_str);
     720              : 
     721        16770 :       if (i < info->num_tensors - 1) {
     722         6590 :         g_string_append (dimensions, ",");
     723              :       }
     724              : 
     725        16770 :       g_free (dim_str);
     726              :     }
     727              : 
     728        13475 :     dim_str = g_string_free (dimensions, FALSE);
     729              :   }
     730              : 
     731        13476 :   return dim_str;
     732              : }
     733              : 
     734              : /**
     735              :  * @brief Get the string of types in tensors info
     736              :  * @param info tensors info structure
     737              :  * @return string of types in tensors info (NULL if the number of tensors is 0)
     738              :  * @note The returned value should be freed with g_free()
     739              :  */
     740              : gchar *
     741         6417 : gst_tensors_info_get_types_string (const GstTensorsInfo * info)
     742              : {
     743         6417 :   gchar *type_str = NULL;
     744              :   GstTensorInfo *_info;
     745              : 
     746         6417 :   g_return_val_if_fail (info != NULL, NULL);
     747              : 
     748         6416 :   if (info->num_tensors > 0) {
     749              :     guint i;
     750         6415 :     GString *types = g_string_new (NULL);
     751              : 
     752        13963 :     for (i = 0; i < info->num_tensors; i++) {
     753         7548 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     754              : 
     755         7548 :       if (_info->type != _NNS_END)
     756         5484 :         g_string_append (types, gst_tensor_get_type_string (_info->type));
     757              : 
     758         7548 :       if (i < info->num_tensors - 1) {
     759         2266 :         g_string_append (types, ",");
     760              :       }
     761              :     }
     762              : 
     763         6415 :     type_str = g_string_free (types, FALSE);
     764              :   }
     765              : 
     766         6416 :   return type_str;
     767              : }
     768              : 
     769              : /**
     770              :  * @brief Get the string of tensor names in tensors info
     771              :  * @param info tensors info structure
     772              :  * @return string of names in tensors info (NULL if the number of tensors is 0)
     773              :  * @note The returned value should be freed with g_free()
     774              :  */
     775              : gchar *
     776           14 : gst_tensors_info_get_names_string (const GstTensorsInfo * info)
     777              : {
     778           14 :   gchar *name_str = NULL;
     779              :   GstTensorInfo *_info;
     780              : 
     781           14 :   g_return_val_if_fail (info != NULL, NULL);
     782              : 
     783           13 :   if (info->num_tensors > 0) {
     784              :     guint i;
     785           12 :     GString *names = g_string_new (NULL);
     786              : 
     787           68 :     for (i = 0; i < info->num_tensors; i++) {
     788           56 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     789              : 
     790           56 :       if (_info->name)
     791           33 :         g_string_append (names, _info->name);
     792              : 
     793           56 :       if (i < info->num_tensors - 1) {
     794           88 :         g_string_append (names, ",");
     795              :       }
     796              :     }
     797              : 
     798           12 :     name_str = g_string_free (names, FALSE);
     799              :   }
     800              : 
     801           13 :   return name_str;
     802              : }
     803              : 
     804              : /**
     805              :  * @brief GstTensorsInfo represented as a string.
     806              :  * @param info GstTensorsInfo structure.
     807              :  * @return The newly allocated string representing the tensors info. Caller should free the value using g_free().
     808              :  */
     809              : gchar *
     810          121 : gst_tensors_info_to_string (const GstTensorsInfo * info)
     811              : {
     812              :   GString *gstr;
     813              :   unsigned int i, limit;
     814              :   GstTensorInfo *_info;
     815              :   const gchar *format_str;
     816              :   gchar *info_str;
     817              : 
     818          121 :   g_return_val_if_fail (info != NULL, NULL);
     819              : 
     820          120 :   gstr = g_string_new (NULL);
     821              : 
     822          120 :   format_str = gst_tensor_get_format_string (info->format);
     823          120 :   g_string_append_printf (gstr, "Format = %s",
     824              :       format_str ? format_str : "unknown");
     825              : 
     826          120 :   if (info->format == _NNS_TENSOR_FORMAT_STATIC) {
     827          120 :     g_string_append_printf (gstr, ", Num_Tensors = %u", info->num_tensors);
     828              : 
     829          120 :     limit = info->num_tensors;
     830          120 :     if (limit > NNS_TENSOR_SIZE_LIMIT) {
     831            1 :       limit = NNS_TENSOR_SIZE_LIMIT;
     832              : 
     833            1 :       g_string_append_printf (gstr,
     834              :           " (Num_Tensors out of bound, showing %d only.)", limit);
     835              :     }
     836              : 
     837          120 :     if (limit > 0) {
     838          120 :       g_string_append_printf (gstr, ", Tensors = [");
     839              : 
     840          496 :       for (i = 0; i < limit; i++) {
     841          376 :         _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     842          376 :         info_str = gst_tensor_info_to_string (_info);
     843              : 
     844          376 :         g_string_append_printf (gstr, "{ %s }%s", info_str,
     845          376 :             (i == info->num_tensors - 1) ? "" : ", ");
     846              : 
     847          376 :         g_free (info_str);
     848              :       }
     849              : 
     850          120 :       g_string_append_printf (gstr, "]");
     851              :     }
     852              :   }
     853              : 
     854          120 :   return g_string_free (gstr, FALSE);
     855              : }
     856              : 
     857              : /**
     858              :  * @brief Printout the comparison results of two tensors as a string.
     859              :  * @param[in] info1 The tensors to be shown on the left hand side.
     860              :  * @param[in] info2 The tensors to be shown on the right hand side.
     861              :  * @return The printout string allocated. Caller should free the value using g_free().
     862              :  */
     863              : gchar *
     864          234 : gst_tensors_info_compare_to_string (const GstTensorsInfo * info1,
     865              :     const GstTensorsInfo * info2)
     866              : {
     867              :   GString *gstr;
     868              :   GstTensorInfo *_info;
     869              :   gchar *left, *right;
     870              :   guint i;
     871              : 
     872          234 :   g_return_val_if_fail (info1 != NULL && info2 != NULL, NULL);
     873              : 
     874          233 :   gstr = g_string_new (NULL);
     875              : 
     876          477 :   for (i = 0; i < NNS_TENSOR_SIZE_LIMIT; i++) {
     877          477 :     if (info1->num_tensors <= i && info2->num_tensors <= i)
     878          233 :       break;
     879              : 
     880          244 :     if (info1->num_tensors > i) {
     881          244 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info1, i);
     882          244 :       left = gst_tensor_info_to_string (_info);
     883              :     } else {
     884            0 :       left = g_strdup ("None");
     885              :     }
     886              : 
     887          244 :     if (info2->num_tensors > i) {
     888          243 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info2, i);
     889          243 :       right = gst_tensor_info_to_string (_info);
     890              :     } else {
     891            1 :       right = g_strdup ("None");
     892              :     }
     893              : 
     894          244 :     g_string_append_printf (gstr, "%3d : %s | %s %s\n", i, left, right,
     895          244 :         g_str_equal (left, right) ? "" : "Not equal");
     896              : 
     897          244 :     g_free (left);
     898          244 :     g_free (right);
     899              :   }
     900              : 
     901          233 :   return g_string_free (gstr, FALSE);
     902              : }
     903              : 
     904              : /**
     905              :  * @brief Initialize the tensors config info structure (for other/tensors)
     906              :  * @param config tensors config structure to be initialized
     907              :  */
     908              : void
     909       364800 : gst_tensors_config_init (GstTensorsConfig * config)
     910              : {
     911       364800 :   g_return_if_fail (config != NULL);
     912              : 
     913       364799 :   gst_tensors_info_init (&config->info);
     914              : 
     915       364799 :   config->rate_n = -1;
     916       364799 :   config->rate_d = -1;
     917              : }
     918              : 
     919              : /**
     920              :  * @brief Free allocated data in tensors config structure
     921              :  * @param config tensors config structure
     922              :  */
     923              : void
     924       175038 : gst_tensors_config_free (GstTensorsConfig * config)
     925              : {
     926       175038 :   g_return_if_fail (config != NULL);
     927              : 
     928       175037 :   gst_tensors_info_free (&config->info);
     929              : }
     930              : 
     931              : /**
     932              :  * @brief Check the tensors are all configured
     933              :  * @param config tensor config structure
     934              :  * @return TRUE if configured
     935              :  */
     936              : gboolean
     937       186346 : gst_tensors_config_validate (const GstTensorsConfig * config)
     938              : {
     939       186346 :   g_return_val_if_fail (config != NULL, FALSE);
     940              : 
     941              :   /* framerate (numerator >= 0 and denominator > 0) */
     942       186344 :   if (config->rate_n < 0 || config->rate_d <= 0) {
     943            5 :     nns_logd
     944              :         ("Failed to validate tensors config. framerate: %d/%d. framerate should be numerator >= 0 and denominator > 0.",
     945              :         config->rate_n, config->rate_d);
     946            5 :     _nnstreamer_error_write
     947              :         ("Failed to validate tensors config. framerate: %d/%d. framerate should be numerator >= 0 and denominator > 0.",
     948            5 :         config->rate_n, config->rate_d);
     949            5 :     return FALSE;
     950              :   }
     951              : 
     952       186339 :   return gst_tensors_info_validate (&config->info);
     953              : }
     954              : 
     955              : /**
     956              :  * @brief Compare tensor config info
     957              :  * @param TRUE if equal
     958              :  */
     959              : gboolean
     960          814 : gst_tensors_config_is_equal (const GstTensorsConfig * c1,
     961              :     const GstTensorsConfig * c2)
     962              : {
     963          814 :   g_return_val_if_fail (c1 != NULL, FALSE);
     964          813 :   g_return_val_if_fail (c2 != NULL, FALSE);
     965              : 
     966          812 :   if (!gst_tensors_config_validate (c1) || !gst_tensors_config_validate (c2)) {
     967            2 :     return FALSE;
     968              :   }
     969              : 
     970          810 :   if (_compare_rate (c1->rate_n, c1->rate_d, c2->rate_n, c2->rate_d)) {
     971            5 :     nns_logd ("Tensors config is not equal. framerate: %d/%d vs %d/%d.",
     972              :         c1->rate_n, c1->rate_d, c2->rate_n, c2->rate_d);
     973            5 :     return FALSE;
     974              :   }
     975              : 
     976          805 :   return gst_tensors_info_is_equal (&c1->info, &c2->info);
     977              : }
     978              : 
     979              : /**
     980              :  * @brief Copy tensors config
     981              :  */
     982              : void
     983         7493 : gst_tensors_config_copy (GstTensorsConfig * dest, const GstTensorsConfig * src)
     984              : {
     985         7493 :   g_return_if_fail (dest != NULL);
     986         7493 :   g_return_if_fail (src != NULL);
     987              : 
     988         7493 :   gst_tensors_info_copy (&dest->info, &src->info);
     989         7493 :   dest->rate_n = src->rate_n;
     990         7493 :   dest->rate_d = src->rate_d;
     991              : }
     992              : 
     993              : /**
     994              :  * @brief Tensor config represented as a string.
     995              :  * @param config tensor config structure.
     996              :  * @return The newly allocated string representing the config. Caller should free the value using g_free().
     997              :  */
     998              : gchar *
     999            2 : gst_tensors_config_to_string (const GstTensorsConfig * config)
    1000              : {
    1001              :   GString *gstr;
    1002              :   gchar *info_str;
    1003              : 
    1004            2 :   g_return_val_if_fail (config != NULL, NULL);
    1005              : 
    1006            1 :   gstr = g_string_new (NULL);
    1007            1 :   info_str = gst_tensors_info_to_string (&config->info);
    1008              : 
    1009            1 :   g_string_append_printf (gstr, "%s, Framerate = %d/%d", info_str,
    1010            1 :       config->rate_n, config->rate_d);
    1011              : 
    1012            1 :   g_free (info_str);
    1013            1 :   return g_string_free (gstr, FALSE);
    1014              : }
    1015              : 
    1016              : /**
    1017              :  * @brief Check the tensor dimension is valid
    1018              :  * @param dim tensor dimension
    1019              :  * @return TRUE if dimension is valid
    1020              :  */
    1021              : gboolean
    1022       287429 : gst_tensor_dimension_is_valid (const tensor_dim dim)
    1023              : {
    1024              :   guint i;
    1025       287429 :   gboolean is_valid = FALSE;
    1026              : 
    1027       287429 :   i = gst_tensor_dimension_get_rank (dim);
    1028       287429 :   if (i == 0)
    1029         4817 :     goto done;
    1030              : 
    1031      3662362 :   for (; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1032      3379756 :     if (dim[i] > 0)
    1033            6 :       goto done;
    1034              :   }
    1035              : 
    1036       282606 :   is_valid = TRUE;
    1037              : 
    1038       287429 : done:
    1039       287429 :   if (!is_valid) {
    1040         4823 :     nns_logd
    1041              :         ("Failed to validate tensor dimension. The dimension string should be in the form of d1:...:d8, d1:d2:d3:d4, d1:d2:d3, d1:d2, or d1. Here, dN is a positive integer.");
    1042         4823 :     _nnstreamer_error_write
    1043              :         ("Failed to validate tensor dimension. The dimension string should be in the form of d1:...:d8, d1:d2:d3:d4, d1:d2:d3, d1:d2, or d1. Here, dN is a positive integer.");
    1044              :   }
    1045              : 
    1046       287429 :   return is_valid;
    1047              : }
    1048              : 
    1049              : /**
    1050              :  * @brief Compare the tensor dimension.
    1051              :  * @return TRUE if given tensors have same dimension.
    1052              :  */
    1053              : gboolean
    1054         1764 : gst_tensor_dimension_is_equal (const tensor_dim dim1, const tensor_dim dim2)
    1055              : {
    1056              :   guint i;
    1057              : 
    1058              :   /* Do not compare invalid dimensions. */
    1059         1764 :   if (!gst_tensor_dimension_is_valid (dim1) ||
    1060         1763 :       !gst_tensor_dimension_is_valid (dim2))
    1061            1 :     return FALSE;
    1062              : 
    1063        29193 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1064        27480 :     if (dim1[i] != dim2[i]) {
    1065              :       /* Supposed dimension is same if remained dimension is 1. */
    1066          455 :       if (dim1[i] > 1 || dim2[i] > 1)
    1067           50 :         return FALSE;
    1068              :     }
    1069              :   }
    1070              : 
    1071         1713 :   return TRUE;
    1072              : }
    1073              : 
    1074              : /**
    1075              :  * @brief Get the rank of tensor dimension.
    1076              :  * @param dim tensor dimension.
    1077              :  * @return tensor rank (Minimum rank is 1 if given dimension is valid)
    1078              :  */
    1079              : guint
    1080       304229 : gst_tensor_dimension_get_rank (const tensor_dim dim)
    1081              : {
    1082              :   guint i;
    1083              : 
    1084      1504466 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1085      1500590 :     if (dim[i] == 0)
    1086       300353 :       break;
    1087              :   }
    1088              : 
    1089       304229 :   return i;
    1090              : }
    1091              : 
    1092              : /**
    1093              :  * @brief Get the minimum rank of tensor dimension.
    1094              :  * @details The C-arrays with dim 4:4:4 and 4:4:4:1 have same data. In this case, this function returns min rank 3.
    1095              :  * @param dim tensor dimension.
    1096              :  * @return tensor rank (Minimum rank is 1 if given dimension is valid)
    1097              :  */
    1098              : guint
    1099         8355 : gst_tensor_dimension_get_min_rank (const tensor_dim dim)
    1100              : {
    1101              :   guint i, rank;
    1102              : 
    1103         8355 :   rank = gst_tensor_dimension_get_rank (dim);
    1104         8355 :   if (rank == 0)
    1105            1 :     return 0;
    1106              : 
    1107        18935 :   for (i = rank - 1; i > 0; i--) {
    1108        15715 :     if (dim[i] > 1)
    1109         5134 :       break;
    1110              :   }
    1111              : 
    1112         8354 :   return (i + 1);
    1113              : }
    1114              : 
    1115              : /**
    1116              :  * @brief Parse tensor dimension parameter string
    1117              :  * @return The Rank. 0 if error.
    1118              :  * @param dimstr The dimension string in the format of d1:...:d16, d1:d2:d3, d1:d2, or d1, where dN is a positive integer and d1 is the innermost dimension; i.e., dim[d16]...[d1];
    1119              :  * @param dim dimension to be filled.
    1120              :  */
    1121              : guint
    1122       160013 : gst_tensor_parse_dimension (const gchar * dimstr, tensor_dim dim)
    1123              : {
    1124       160013 :   guint rank = 0;
    1125              :   guint64 val;
    1126              :   gchar **strv;
    1127              :   gchar *dim_string;
    1128              :   guint i, num_dims;
    1129              : 
    1130              :   /* 0-init */
    1131      2720221 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
    1132      2560208 :     dim[i] = 0;
    1133              : 
    1134       160013 :   if (dimstr == NULL)
    1135            1 :     return 0;
    1136              : 
    1137              :   /* remove spaces */
    1138       160012 :   dim_string = g_strstrip (g_strdup (dimstr));
    1139              : 
    1140       160012 :   strv = g_strsplit (dim_string, ":", NNS_TENSOR_RANK_LIMIT);
    1141       160012 :   num_dims = g_strv_length (strv);
    1142              : 
    1143       810164 :   for (i = 0; i < num_dims; i++) {
    1144       650152 :     g_strstrip (strv[i]);
    1145       650152 :     if (strv[i] == NULL || strlen (strv[i]) == 0)
    1146              :       break;
    1147              : 
    1148       650152 :     val = g_ascii_strtoull (strv[i], NULL, 10);
    1149       650152 :     dim[i] = (uint32_t) val;
    1150       650152 :     rank = i + 1;
    1151              :   }
    1152              : 
    1153       160012 :   g_strfreev (strv);
    1154       160012 :   g_free (dim_string);
    1155       160012 :   return rank;
    1156              : }
    1157              : 
    1158              : /**
    1159              :  * @brief Get dimension string from given tensor dimension.
    1160              :  * @param dim tensor dimension
    1161              :  * @return Formatted string of given dimension (d1:d2:d3:...:d15:d16).
    1162              :  * @note The returned value should be freed with g_free()
    1163              :  */
    1164              : gchar *
    1165         4993 : gst_tensor_get_dimension_string (const tensor_dim dim)
    1166              : {
    1167         4993 :   return gst_tensor_get_rank_dimension_string (dim,
    1168              :       NNS_TENSOR_RANK_LIMIT, FALSE);
    1169              : }
    1170              : 
    1171              : /**
    1172              :  * @brief Get dimension string from given tensor dimension and rank count.
    1173              :  * @param dim tensor dimension
    1174              :  * @param rank rank count of given tensor dimension
    1175              :  * @param padding fill 1 if actual rank is smaller than rank
    1176              :  * @return Formatted string of given dimension
    1177              :  * @note If rank count is 3, then returned string is 'd1:d2:d3`.
    1178              :  * The returned value should be freed with g_free().
    1179              :  */
    1180              : gchar *
    1181        29095 : gst_tensor_get_rank_dimension_string (const tensor_dim dim,
    1182              :     const unsigned int rank, const gboolean padding)
    1183              : {
    1184              :   guint i;
    1185              :   GString *dim_str;
    1186              :   guint actual_rank;
    1187              : 
    1188        29095 :   dim_str = g_string_new (NULL);
    1189              : 
    1190        29095 :   if (rank == 0 || rank > NNS_TENSOR_RANK_LIMIT)
    1191           10 :     actual_rank = NNS_TENSOR_RANK_LIMIT;
    1192              :   else
    1193        29085 :     actual_rank = rank;
    1194              : 
    1195       117498 :   for (i = 0; i < actual_rank; i++) {
    1196       106427 :     if (dim[i] == 0)
    1197        18024 :       break;
    1198              : 
    1199        88403 :     g_string_append_printf (dim_str, "%u", dim[i]);
    1200              : 
    1201        88403 :     if (i < actual_rank - 1 && dim[i + 1] > 0) {
    1202       124180 :       g_string_append (dim_str, ":");
    1203              :     }
    1204              :   }
    1205              : 
    1206        29095 :   if (rank > 0 && padding) {
    1207         8271 :     guint real_rank = gst_tensor_dimension_get_rank (dim);
    1208              : 
    1209         8271 :     if (real_rank < rank) {
    1210         8750 :       for (; i < rank; i++)
    1211        11884 :         g_string_append (dim_str, ":1");
    1212              :     }
    1213              :   }
    1214              : 
    1215        29095 :   return g_string_free (dim_str, FALSE);
    1216              : }
    1217              : 
    1218              : /**
    1219              :  * @brief Compare dimension strings
    1220              :  * @return TRUE if equal, FALSE if given dimension strings are invalid or not equal.
    1221              :  */
    1222              : gboolean
    1223          285 : gst_tensor_dimension_string_is_equal (const gchar * dimstr1,
    1224              :     const gchar * dimstr2)
    1225              : {
    1226              :   tensor_dim dim1, dim2;
    1227              :   guint rank1, rank2, i, j, num_tensors1, num_tensors2;
    1228              :   gchar **strv1;
    1229              :   gchar **strv2;
    1230          285 :   gboolean is_equal = FALSE;
    1231              : 
    1232          285 :   strv1 = g_strsplit_set (dimstr1, ",.", -1);
    1233          285 :   strv2 = g_strsplit_set (dimstr2, ",.", -1);
    1234              : 
    1235          285 :   num_tensors1 = g_strv_length (strv1);
    1236          285 :   num_tensors2 = g_strv_length (strv2);
    1237              : 
    1238          285 :   if (num_tensors1 != num_tensors2)
    1239            0 :     goto done;
    1240              : 
    1241          668 :   for (i = 0; i < num_tensors1; i++) {
    1242         6545 :     for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++)
    1243         6160 :       dim1[j] = dim2[j] = 0;
    1244              : 
    1245          385 :     rank1 = gst_tensor_parse_dimension (strv1[i], dim1);
    1246          385 :     rank2 = gst_tensor_parse_dimension (strv2[i], dim2);
    1247              : 
    1248              :     /* 'rank 0' means invalid dimension */
    1249          385 :     if (!rank1 || !rank2 || !gst_tensor_dimension_is_equal (dim1, dim2))
    1250            2 :       goto done;
    1251              :   }
    1252              : 
    1253              :   /* Compared all tensor dimensions from input string. */
    1254          283 :   is_equal = TRUE;
    1255              : 
    1256          285 : done:
    1257          285 :   g_strfreev (strv1);
    1258          285 :   g_strfreev (strv2);
    1259              : 
    1260          285 :   return is_equal;
    1261              : }
    1262              : 
    1263              : /**
    1264              :  * @brief Count the number of elements of a tensor
    1265              :  * @return The number of elements. 0 if error.
    1266              :  * @param dim The tensor dimension
    1267              :  */
    1268              : gulong
    1269       124600 : gst_tensor_get_element_count (const tensor_dim dim)
    1270              : {
    1271       124600 :   gulong count = 1;
    1272              :   guint i;
    1273              : 
    1274       564059 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1275       563182 :     if (dim[i] == 0)
    1276       123723 :       break;
    1277              : 
    1278       439459 :     count *= dim[i];
    1279              :   }
    1280              : 
    1281       124600 :   return (i > 0) ? count : 0;
    1282              : }
    1283              : 
    1284              : /**
    1285              :  * @brief Get element size of tensor type (byte per element)
    1286              :  */
    1287              : gsize
    1288     10310832 : gst_tensor_get_element_size (tensor_type type)
    1289              : {
    1290     10310832 :   g_return_val_if_fail (type >= 0 && type <= _NNS_END, 0);
    1291              : 
    1292     10310832 :   return tensor_element_size[type];
    1293              : }
    1294              : 
    1295              : /**
    1296              :  * @brief Get tensor type from string input.
    1297              :  * @return Corresponding tensor_type. _NNS_END if unrecognized value is there.
    1298              :  * @param typestr The string type name, supposed to be one of tensor_element_typename[]
    1299              :  */
    1300              : tensor_type
    1301       159405 : gst_tensor_get_type (const gchar * typestr)
    1302              : {
    1303              :   gsize size, len;
    1304              :   gchar *type_string;
    1305       159405 :   tensor_type type = _NNS_END;
    1306              : 
    1307       159405 :   if (typestr == NULL)
    1308            7 :     return _NNS_END;
    1309              : 
    1310              :   /* remove spaces */
    1311       159398 :   type_string = g_strdup (typestr);
    1312       159398 :   g_strstrip (type_string);
    1313              : 
    1314       159398 :   len = strlen (type_string);
    1315              : 
    1316       159398 :   if (len == 0) {
    1317            1 :     g_free (type_string);
    1318            1 :     return _NNS_END;
    1319              :   }
    1320              : 
    1321       159397 :   if (g_regex_match_simple ("^uint(8|16|32|64)$",
    1322              :           type_string, G_REGEX_CASELESS, 0)) {
    1323        90400 :     size = (gsize) g_ascii_strtoull (&type_string[4], NULL, 10);
    1324              : 
    1325        90400 :     switch (size) {
    1326        88146 :       case 8:
    1327        88146 :         type = _NNS_UINT8;
    1328        88146 :         break;
    1329          210 :       case 16:
    1330          210 :         type = _NNS_UINT16;
    1331          210 :         break;
    1332         1966 :       case 32:
    1333         1966 :         type = _NNS_UINT32;
    1334         1966 :         break;
    1335           78 :       case 64:
    1336           78 :         type = _NNS_UINT64;
    1337           78 :         break;
    1338              :     }
    1339        68997 :   } else if (g_regex_match_simple ("^int(8|16|32|64)$",
    1340              :           type_string, G_REGEX_CASELESS, 0)) {
    1341         1011 :     size = (gsize) g_ascii_strtoull (&type_string[3], NULL, 10);
    1342              : 
    1343         1011 :     switch (size) {
    1344          391 :       case 8:
    1345          391 :         type = _NNS_INT8;
    1346          391 :         break;
    1347          342 :       case 16:
    1348          342 :         type = _NNS_INT16;
    1349          342 :         break;
    1350          168 :       case 32:
    1351          168 :         type = _NNS_INT32;
    1352          168 :         break;
    1353          110 :       case 64:
    1354          110 :         type = _NNS_INT64;
    1355          110 :         break;
    1356              :     }
    1357        67986 :   } else if (g_regex_match_simple ("^float(16|32|64)$",
    1358              :           type_string, G_REGEX_CASELESS, 0)) {
    1359        67964 :     size = (gsize) g_ascii_strtoull (&type_string[5], NULL, 10);
    1360              : 
    1361        67964 :     switch (size) {
    1362           54 :       case 16:
    1363           54 :         type = _NNS_FLOAT16;
    1364           54 :         break;
    1365        67504 :       case 32:
    1366        67504 :         type = _NNS_FLOAT32;
    1367        67504 :         break;
    1368          406 :       case 64:
    1369          406 :         type = _NNS_FLOAT64;
    1370          406 :         break;
    1371              :     }
    1372              :   }
    1373              : 
    1374       159397 :   g_free (type_string);
    1375       159397 :   return type;
    1376              : }
    1377              : 
    1378              : /**
    1379              :  * @brief Get type string of tensor type.
    1380              :  */
    1381              : const gchar *
    1382        20197 : gst_tensor_get_type_string (tensor_type type)
    1383              : {
    1384        20197 :   g_return_val_if_fail (type >= 0 && type <= _NNS_END, NULL);
    1385              : 
    1386        20197 :   return tensor_element_typename[type];
    1387              : }
    1388              : 
    1389              : /**
    1390              :  * @brief Get tensor format from string input.
    1391              :  * @param format_str The string format name, supposed to be one of tensor_format_name[].
    1392              :  * @return Corresponding tensor_format. _NNS_TENSOR_FORMAT_END if unrecognized value is there.
    1393              :  */
    1394              : tensor_format
    1395        13661 : gst_tensor_get_format (const gchar * format_str)
    1396              : {
    1397              :   gint idx;
    1398        13661 :   tensor_format format = _NNS_TENSOR_FORMAT_END;
    1399              : 
    1400        13661 :   idx = find_key_strv (tensor_format_name, format_str);
    1401        13661 :   if (idx >= 0)
    1402        12006 :     format = (tensor_format) idx;
    1403              : 
    1404        13661 :   return format;
    1405              : }
    1406              : 
    1407              : /**
    1408              :  * @brief Get tensor format string.
    1409              :  */
    1410              : const gchar *
    1411          249 : gst_tensor_get_format_string (tensor_format format)
    1412              : {
    1413          249 :   g_return_val_if_fail (format >= 0 && format <= _NNS_TENSOR_FORMAT_END, NULL);
    1414              : 
    1415          247 :   return tensor_format_name[format];
    1416              : }
    1417              : 
    1418              : /**
    1419              :  * @brief Magic number of tensor meta.
    1420              :  */
    1421              : #define GST_TENSOR_META_MAGIC (0xfeedcced)
    1422              : 
    1423              : /**
    1424              :  * @brief Macro to check the tensor meta.
    1425              :  */
    1426              : #define GST_TENSOR_META_MAGIC_VALID(m) ((m) == GST_TENSOR_META_MAGIC)
    1427              : 
    1428              : /**
    1429              :  * @brief Macro to check the meta version.
    1430              :  */
    1431              : #define GST_TENSOR_META_VERSION_VALID(v) (((v) & 0xDE000000) == 0xDE000000)
    1432              : 
    1433              : /**
    1434              :  * @brief Macro to get the version of tensor meta.
    1435              :  */
    1436              : #define GST_TENSOR_META_MAKE_VERSION(major,minor) ((major) << 12 | (minor) | 0xDE000000)
    1437              : 
    1438              : /**
    1439              :  * @brief The version of tensor meta.
    1440              :  */
    1441              : #define GST_TENSOR_META_VERSION GST_TENSOR_META_MAKE_VERSION(1,0)
    1442              : 
    1443              : /**
    1444              :  * @brief Macro to check the version of tensor meta.
    1445              :  */
    1446              : #define GST_TENSOR_META_IS_V1(v) (GST_TENSOR_META_VERSION_VALID(v) && (((v) & 0x00FFF000) & GST_TENSOR_META_MAKE_VERSION(1,0)))
    1447              : 
    1448              : /**
    1449              :  * @brief Macro to check the meta is valid.
    1450              :  */
    1451              : #define GST_TENSOR_META_IS_VALID(m) ((m) && GST_TENSOR_META_MAGIC_VALID ((m)->magic) && GST_TENSOR_META_VERSION_VALID ((m)->version))
    1452              : 
    1453              : /**
    1454              :  * @brief Initialize the tensor meta info structure.
    1455              :  * @param[in,out] meta tensor meta structure to be initialized
    1456              :  */
    1457              : void
    1458       141416 : gst_tensor_meta_info_init (GstTensorMetaInfo * meta)
    1459              : {
    1460       141416 :   g_return_if_fail (meta != NULL);
    1461              : 
    1462              :   /* zero-init */
    1463       141416 :   memset (meta, 0, sizeof (GstTensorMetaInfo));
    1464              : 
    1465       141416 :   meta->magic = GST_TENSOR_META_MAGIC;
    1466       141416 :   meta->version = GST_TENSOR_META_VERSION;
    1467       141416 :   meta->type = _NNS_END;
    1468       141416 :   meta->format = _NNS_TENSOR_FORMAT_STATIC;
    1469       141416 :   meta->media_type = _NNS_TENSOR;
    1470              : }
    1471              : 
    1472              : /**
    1473              :  * @brief Get the version of tensor meta.
    1474              :  * @param[in] meta tensor meta structure
    1475              :  * @param[out] major pointer to get the major version number
    1476              :  * @param[out] minor pointer to get the minor version number
    1477              :  * @return TRUE if successfully get the version
    1478              :  */
    1479              : gboolean
    1480            3 : gst_tensor_meta_info_get_version (GstTensorMetaInfo * meta,
    1481              :     guint * major, guint * minor)
    1482              : {
    1483            3 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1484            2 :     return FALSE;
    1485              :   }
    1486              : 
    1487            1 :   if (major)
    1488            1 :     *major = (meta->version & 0x00FFF000) >> 12;
    1489              : 
    1490            1 :   if (minor)
    1491            1 :     *minor = (meta->version & 0x00000FFF);
    1492              : 
    1493            1 :   return TRUE;
    1494              : }
    1495              : 
    1496              : /**
    1497              :  * @brief Check the meta info is valid.
    1498              :  * @param[in] meta tensor meta structure
    1499              :  * @return TRUE if given meta is valid
    1500              :  */
    1501              : gboolean
    1502        54010 : gst_tensor_meta_info_validate (GstTensorMetaInfo * meta)
    1503              : {
    1504        54010 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1505        51974 :     return FALSE;
    1506              :   }
    1507              : 
    1508         2036 :   if (meta->type >= _NNS_END) {
    1509            1 :     nns_logd ("Failed to validate tensor meta info. type: %s. ",
    1510              :         _STR_NULL (gst_tensor_get_type_string (meta->type)));
    1511            1 :     return FALSE;
    1512              :   }
    1513              : 
    1514         2035 :   if (!gst_tensor_dimension_is_valid (meta->dimension)) {
    1515            1 :     gchar *dim_str = gst_tensor_get_dimension_string (meta->dimension);
    1516            1 :     nns_logd ("Failed to validate tensor meta info. Given dimension: %s",
    1517              :         dim_str);
    1518            1 :     g_free (dim_str);
    1519            1 :     return FALSE;
    1520              :   }
    1521              : 
    1522         2034 :   if (meta->format >= _NNS_TENSOR_FORMAT_END) {
    1523            1 :     nns_logd ("Failed to validate tensors meta info. format: %s. ",
    1524              :         _STR_NULL (gst_tensor_get_format_string (meta->format)));
    1525            1 :     return FALSE;
    1526              :   }
    1527              : 
    1528         2033 :   if (meta->media_type > _NNS_TENSOR) {
    1529            1 :     nns_logd ("Failed to validate tensor meta info. invalid media type: %d.",
    1530              :         meta->media_type);
    1531            1 :     return FALSE;
    1532              :   }
    1533              : 
    1534         2032 :   return TRUE;
    1535              : }
    1536              : 
    1537              : /**
    1538              :  * @brief Get the header size to handle a tensor meta.
    1539              :  * @param[in] meta tensor meta structure
    1540              :  * @return Header size for meta info (0 if meta is invalid)
    1541              :  */
    1542              : gsize
    1543        62086 : gst_tensor_meta_info_get_header_size (GstTensorMetaInfo * meta)
    1544              : {
    1545        62086 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1546            3 :     return 0;
    1547              :   }
    1548              : 
    1549              :   /* return fixed size for meta version */
    1550        62083 :   if (GST_TENSOR_META_IS_V1 (meta->version)) {
    1551        62083 :     return 128;
    1552              :   }
    1553              : 
    1554            0 :   return 0;
    1555              : }
    1556              : 
    1557              : /**
    1558              :  * @brief Get the data size calculated from tensor meta.
    1559              :  * @param[in] meta tensor meta structure
    1560              :  * @return The data size for meta info (0 if meta is invalid)
    1561              :  */
    1562              : gsize
    1563          151 : gst_tensor_meta_info_get_data_size (GstTensorMetaInfo * meta)
    1564              : {
    1565              :   gsize dsize;
    1566              : 
    1567          151 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1568            3 :     return 0;
    1569              :   }
    1570              : 
    1571          148 :   dsize = gst_tensor_get_element_size (meta->type);
    1572              : 
    1573          148 :   if (meta->format == _NNS_TENSOR_FORMAT_SPARSE) {
    1574            3 :     return meta->sparse_info.nnz * (dsize + sizeof (guint));
    1575              :   }
    1576              : 
    1577          145 :   dsize *= gst_tensor_get_element_count (meta->dimension);
    1578              : 
    1579          145 :   return dsize;
    1580              : }
    1581              : 
    1582              : /**
    1583              :  * @brief Update header from tensor meta.
    1584              :  * @param[in] meta tensor meta structure
    1585              :  * @param[out] header pointer to header to be updated
    1586              :  * @return TRUE if successfully set the header
    1587              :  * @note User should allocate enough memory for header (see gst_tensor_meta_info_get_header_size()).
    1588              :  */
    1589              : gboolean
    1590          415 : gst_tensor_meta_info_update_header (GstTensorMetaInfo * meta, gpointer header)
    1591              : {
    1592              :   gsize hsize;
    1593              : 
    1594          415 :   g_return_val_if_fail (header != NULL, FALSE);
    1595          414 :   g_return_val_if_fail (gst_tensor_meta_info_validate (meta), FALSE);
    1596              : 
    1597          413 :   hsize = gst_tensor_meta_info_get_header_size (meta);
    1598              : 
    1599          413 :   memset (header, 0, hsize);
    1600              : 
    1601          413 :   memcpy (header, meta, sizeof (GstTensorMetaInfo));
    1602          413 :   return TRUE;
    1603              : }
    1604              : 
    1605              : /**
    1606              :  * @brief Parse header and fill the tensor meta.
    1607              :  * @param[out] meta tensor meta structure to be filled
    1608              :  * @param[in] header pointer to header to be parsed
    1609              :  * @return TRUE if successfully set the meta
    1610              :  */
    1611              : gboolean
    1612        53079 : gst_tensor_meta_info_parse_header (GstTensorMetaInfo * meta, gpointer header)
    1613              : {
    1614        53079 :   uint32_t *val = (uint32_t *) header;
    1615              : 
    1616        53079 :   g_return_val_if_fail (header != NULL, FALSE);
    1617        53078 :   g_return_val_if_fail (meta != NULL, FALSE);
    1618              : 
    1619        53077 :   gst_tensor_meta_info_init (meta);
    1620              : 
    1621        53077 :   meta->magic = val[0];
    1622        53077 :   meta->version = val[1];
    1623        53077 :   meta->type = val[2];
    1624        53077 :   memcpy (meta->dimension, &val[3], sizeof (uint32_t) * NNS_TENSOR_RANK_LIMIT);
    1625        53077 :   meta->format = val[19];
    1626        53077 :   meta->media_type = val[20];
    1627              : 
    1628        53077 :   switch ((tensor_format) meta->format) {
    1629          204 :     case _NNS_TENSOR_FORMAT_SPARSE:
    1630          204 :       meta->sparse_info.nnz = val[21];
    1631          204 :       break;
    1632        52873 :     default:
    1633        52873 :       break;
    1634              :   }
    1635              : 
    1636              :   /** @todo update meta info for each version */
    1637        53077 :   return gst_tensor_meta_info_validate (meta);
    1638              : }
    1639              : 
    1640              : /**
    1641              :  * @brief Convert GstTensorMetaInfo structure to GstTensorInfo.
    1642              :  * @param[in] meta tensor meta structure to be converted
    1643              :  * @param[out] info GstTensorInfo to be filled
    1644              :  * @return TRUE if successfully set the info
    1645              :  */
    1646              : gboolean
    1647          229 : gst_tensor_meta_info_convert (GstTensorMetaInfo * meta, GstTensorInfo * info)
    1648              : {
    1649              :   guint i;
    1650              : 
    1651          229 :   g_return_val_if_fail (info != NULL, FALSE);
    1652          228 :   g_return_val_if_fail (gst_tensor_meta_info_validate (meta), FALSE);
    1653              : 
    1654          227 :   gst_tensor_info_init (info);
    1655              : 
    1656          227 :   info->type = meta->type;
    1657              : 
    1658         3859 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
    1659         3632 :     info->dimension[i] = meta->dimension[i];
    1660              : 
    1661          227 :   return TRUE;
    1662              : }
    1663              : 
    1664              : /**
    1665              :  * @brief Find the index value of the given key string array
    1666              :  * @return Corresponding index. Returns -1 if not found.
    1667              :  * @param strv Null terminated array of gchar *
    1668              :  * @param key The key string value
    1669              :  */
    1670              : gint
    1671        13966 : find_key_strv (const gchar ** strv, const gchar * key)
    1672              : {
    1673        13966 :   gint cursor = 0;
    1674              : 
    1675        13966 :   if (strv == NULL) {
    1676            0 :     ml_logf_stacktrace
    1677              :         ("find_key_strv is called with a null pointer. Possible internal logic errors.\n");
    1678            0 :     return -1;
    1679              :   }
    1680        16789 :   while (strv[cursor] && key) {
    1681        15130 :     if (g_ascii_strcasecmp (strv[cursor], key) == 0)
    1682        12307 :       return cursor;
    1683         2823 :     cursor++;
    1684              :   }
    1685              : 
    1686              :   /* Not found */
    1687         1659 :   return -1;
    1688              : }
    1689              : 
    1690              : /**
    1691              :  * @brief Get the version of NNStreamer (string).
    1692              :  * @return Newly allocated string. The returned string should be freed with g_free().
    1693              :  */
    1694              : gchar *
    1695            1 : nnstreamer_version_string (void)
    1696              : {
    1697              :   gchar *version;
    1698              : 
    1699            1 :   version = g_strdup_printf ("NNStreamer %s", VERSION);
    1700            1 :   return version;
    1701              : }
    1702              : 
    1703              : /**
    1704              :  * @brief Get the version of NNStreamer (int, divided).
    1705              :  * @param[out] major MAJOR.minor.micro, won't set if it's null.
    1706              :  * @param[out] minor major.MINOR.micro, won't set if it's null.
    1707              :  * @param[out] micro major.minor.MICRO, won't set if it's null.
    1708              :  */
    1709              : void
    1710            1 : nnstreamer_version_fetch (guint * major, guint * minor, guint * micro)
    1711              : {
    1712            1 :   if (major)
    1713            1 :     *major = (NNSTREAMER_VERSION_MAJOR);
    1714            1 :   if (minor)
    1715            1 :     *minor = (NNSTREAMER_VERSION_MINOR);
    1716            1 :   if (micro)
    1717            1 :     *micro = (NNSTREAMER_VERSION_MICRO);
    1718            1 : }
        

Generated by: LCOV version 2.0-1