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#58eaa3c6edb7484955a5d8c32f47a60ba9501210 Lines: 99.2 % 619 614
Test Date: 2025-04-18 05:37:26 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         1612 : _gcd (gint a, gint b)
      68              : {
      69         3234 :   while (b != 0) {
      70         1622 :     int temp = a;
      71              : 
      72         1622 :     a = b;
      73         1622 :     b = temp % b;
      74              :   }
      75              : 
      76         1612 :   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          806 : _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          806 :   g_return_val_if_fail (a_d != 0 && b_d != 0, 0);
      90              : 
      91              :   /* Simplify */
      92          806 :   gcd = _gcd (a_n, a_d);
      93          806 :   a_n /= gcd;
      94          806 :   a_d /= gcd;
      95              : 
      96          806 :   gcd = _gcd (b_n, b_d);
      97          806 :   b_n /= gcd;
      98          806 :   b_d /= gcd;
      99              : 
     100              :   /* fractions are reduced when set, so we can quickly see if they're equal */
     101          806 :   if (a_n == b_n && a_d == b_d)
     102          801 :     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     12116043 : gst_tensor_info_init (GstTensorInfo * info)
     122              : {
     123              :   guint i;
     124              : 
     125     12116043 :   g_return_if_fail (info != NULL);
     126              : 
     127     12116043 :   info->name = NULL;
     128     12116043 :   info->type = _NNS_END;
     129              : 
     130    205972731 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     131    193856688 :     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      2957087 : gst_tensor_info_free (GstTensorInfo * info)
     141              : {
     142      2957087 :   g_return_if_fail (info != NULL);
     143              : 
     144      2957087 :   g_free (info->name);
     145              : 
     146              :   /* Init default */
     147      2957087 :   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       100981 : gst_tensor_info_get_size (const GstTensorInfo * info)
     157              : {
     158              :   gsize data_size;
     159              : 
     160       100981 :   g_return_val_if_fail (info != NULL, 0);
     161              : 
     162       100980 :   data_size = gst_tensor_get_element_count (info->dimension) *
     163       100980 :       gst_tensor_get_element_size (info->type);
     164              : 
     165       100980 :   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       271508 : gst_tensor_info_validate (const GstTensorInfo * info)
     175              : {
     176       271508 :   g_return_val_if_fail (info != NULL, FALSE);
     177              : 
     178       271505 :   if (info->type == _NNS_END) {
     179         2077 :     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         2077 :     _nnstreamer_error_write
     183              :         ("Failed to validate tensor info. type: %s. Please specify tensor type. e.g., type=uint8 ",
     184         2077 :         _STR_NULL (gst_tensor_get_type_string (info->type)));
     185         2077 :     return FALSE;
     186              :   }
     187              : 
     188              :   /* validate tensor dimension */
     189       269428 :   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         1523 : gst_tensor_info_is_equal (const GstTensorInfo * i1, const GstTensorInfo * i2)
     198              : {
     199         1523 :   if (!gst_tensor_info_validate (i1) || !gst_tensor_info_validate (i2)) {
     200            2 :     return FALSE;
     201              :   }
     202              : 
     203         1521 :   if (i1->type != i2->type) {
     204          153 :     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          153 :     return FALSE;
     208              :   }
     209              : 
     210         1368 :   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         1321 :   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        25642 : gst_tensor_info_copy_n (GstTensorInfo * dest, const GstTensorInfo * src,
     228              :     const guint n)
     229              : {
     230              :   guint i;
     231              : 
     232        25642 :   g_return_if_fail (dest != NULL);
     233        25642 :   g_return_if_fail (src != NULL);
     234              : 
     235        25642 :   dest->name = g_strdup (src->name);
     236        25642 :   dest->type = src->type;
     237              : 
     238       435914 :   for (i = 0; i < n; i++) {
     239       410272 :     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        25642 : gst_tensor_info_copy (GstTensorInfo * dest, const GstTensorInfo * src)
     249              : {
     250        25642 :   gst_tensor_info_copy_n (dest, src, NNS_TENSOR_RANK_LIMIT);
     251        25642 : }
     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          389 : gst_tensor_info_convert_to_meta (GstTensorInfo * info, GstTensorMetaInfo * meta)
     261              : {
     262              :   guint i;
     263              : 
     264          389 :   g_return_val_if_fail (gst_tensor_info_validate (info), FALSE);
     265          387 :   g_return_val_if_fail (meta != NULL, FALSE);
     266              : 
     267          386 :   gst_tensor_meta_info_init (meta);
     268              : 
     269          386 :   meta->type = info->type;
     270              : 
     271         6562 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     272              :     /** @todo handle rank from info.dimension */
     273         6176 :     meta->dimension[i] = info->dimension[i];
     274              :   }
     275              : 
     276          386 :   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          846 : gst_tensor_info_to_string (const GstTensorInfo * info)
     299              : {
     300              :   GString *gstr;
     301              :   const gchar *type;
     302              :   gchar *dim;
     303              : 
     304          846 :   g_return_val_if_fail (info != NULL, NULL);
     305              : 
     306          845 :   gstr = g_string_new (NULL);
     307              : 
     308          845 :   if (info->name)
     309          287 :     g_string_append_printf (gstr, "'%s' ", info->name);
     310              : 
     311          845 :   type = gst_tensor_get_type_string (info->type);
     312          845 :   dim = gst_tensor_get_dimension_string (info->dimension);
     313              : 
     314          845 :   g_string_append_printf (gstr, "%s (%s)", type, dim);
     315              : 
     316          845 :   g_free (dim);
     317          845 :   return g_string_free (gstr, FALSE);
     318              : }
     319              : 
     320              : /**
     321              :  * @brief Get the pointer of nth tensor information.
     322              :  */
     323              : GstTensorInfo *
     324       528378 : gst_tensors_info_get_nth_info (GstTensorsInfo * info, guint index)
     325              : {
     326              :   guint i;
     327              : 
     328       528378 :   g_return_val_if_fail (info != NULL, NULL);
     329              : 
     330       528378 :   if (index < NNS_TENSOR_MEMORY_MAX)
     331       469569 :     return &info->info[index];
     332              : 
     333        58809 :   if (index < NNS_TENSOR_SIZE_LIMIT) {
     334        58808 :     if (!info->extra) {
     335          206 :       info->extra = g_new0 (GstTensorInfo, NNS_TENSOR_SIZE_EXTRA_LIMIT);
     336              : 
     337        49646 :       for (i = 0; i < NNS_TENSOR_SIZE_EXTRA_LIMIT; ++i)
     338        49440 :         gst_tensor_info_init (&info->extra[i]);
     339              :     }
     340              : 
     341        58808 :     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       568893 : gst_tensors_info_init (GstTensorsInfo * info)
     355              : {
     356              :   guint i;
     357              : 
     358       568893 :   g_return_if_fail (info != NULL);
     359              : 
     360       568893 :   info->num_tensors = 0;
     361       568893 :   info->extra = NULL;
     362              : 
     363              :   /** @note default format is static */
     364       568893 :   info->format = _NNS_TENSOR_FORMAT_STATIC;
     365              : 
     366      9671181 :   for (i = 0; i < NNS_TENSOR_MEMORY_MAX; i++) {
     367      9102288 :     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       181779 : gst_tensors_info_free (GstTensorsInfo * info)
     377              : {
     378              :   guint i;
     379              : 
     380       181779 :   g_return_if_fail (info != NULL);
     381              : 
     382      3090243 :   for (i = 0; i < NNS_TENSOR_MEMORY_MAX; i++) {
     383      2908464 :     gst_tensor_info_free (&info->info[i]);
     384              :   }
     385              : 
     386       181779 :   if (info->extra) {
     387        48682 :     for (i = 0; i < NNS_TENSOR_SIZE_EXTRA_LIMIT; ++i)
     388        48480 :       gst_tensor_info_free (&info->extra[i]);
     389              : 
     390          202 :     g_clear_pointer (&info->extra, g_free);
     391              :   }
     392              : 
     393              :   /* Init default */
     394       181779 :   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          488 : gst_tensors_info_get_size (const GstTensorsInfo * info, gint index)
     405              : {
     406              :   GstTensorInfo *_info;
     407          488 :   gsize data_size = 0;
     408              :   guint i;
     409              : 
     410          488 :   g_return_val_if_fail (info != NULL, 0);
     411          487 :   g_return_val_if_fail (index < (gint) info->num_tensors, 0);
     412              : 
     413          486 :   if (index < 0) {
     414          245 :     for (i = 0; i < info->num_tensors; ++i) {
     415          137 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     416          137 :       data_size += gst_tensor_info_get_size (_info);
     417              :     }
     418              :   } else {
     419          378 :     _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, index);
     420          378 :     data_size = gst_tensor_info_get_size (_info);
     421              :   }
     422              : 
     423          486 :   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       198984 : gst_tensors_info_validate (const GstTensorsInfo * info)
     433              : {
     434              :   guint i;
     435              :   GstTensorInfo *_info;
     436              : 
     437       198984 :   g_return_val_if_fail (info != NULL, FALSE);
     438              : 
     439              :   /* tensor stream format */
     440       198983 :   if (info->format >= _NNS_TENSOR_FORMAT_END) {
     441            1 :     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            1 :     _nnstreamer_error_write
     446              :         ("Failed to validate tensors info, format: %s. format should be one of %s.",
     447            1 :         _STR_NULL (gst_tensor_get_format_string (info->format)),
     448              :         GST_TENSOR_FORMAT_ALL);
     449            1 :     return FALSE;
     450              :   }
     451              : 
     452              :   /* cannot check tensor info when tensor is not static */
     453       198982 :   if (info->format != _NNS_TENSOR_FORMAT_STATIC) {
     454          671 :     return TRUE;
     455              :   }
     456              : 
     457       198311 :   if (info->num_tensors < 1) {
     458         3155 :     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         3155 :     _nnstreamer_error_write
     462              :         ("Failed to validate tensors info. the number of tensors: %d. the number of tensors should be greater than 0.",
     463         3155 :         info->num_tensors);
     464         3155 :     return FALSE;
     465              :   }
     466              : 
     467       400783 :   for (i = 0; i < info->num_tensors; i++) {
     468       208339 :     _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     469              : 
     470       208339 :     if (!gst_tensor_info_validate (_info))
     471         2712 :       return FALSE;
     472              :   }
     473              : 
     474       192444 :   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         1307 : gst_tensors_info_is_equal (const GstTensorsInfo * i1, const GstTensorsInfo * i2)
     483              : {
     484              :   guint i;
     485              :   GstTensorInfo *_info1, *_info2;
     486              : 
     487         1307 :   g_return_val_if_fail (i1 != NULL, FALSE);
     488         1306 :   g_return_val_if_fail (i2 != NULL, FALSE);
     489              : 
     490         1305 :   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         1298 :   if (i1->format != _NNS_TENSOR_FORMAT_STATIC) {
     499           26 :     return TRUE;
     500              :   }
     501              : 
     502         1272 :   if (!gst_tensors_info_validate (i1) || !gst_tensors_info_validate (i2)) {
     503          107 :     return FALSE;
     504              :   }
     505              : 
     506         1165 :   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         2400 :   for (i = 0; i < i1->num_tensors; i++) {
     513         1443 :     _info1 = gst_tensors_info_get_nth_info ((GstTensorsInfo *) i1, i);
     514         1443 :     _info2 = gst_tensors_info_get_nth_info ((GstTensorsInfo *) i2, i);
     515              : 
     516         1443 :     if (!gst_tensor_info_is_equal (_info1, _info2)) {
     517          200 :       return FALSE;
     518              :     }
     519              :   }
     520              : 
     521              :   /* matched all */
     522          957 :   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         4716 : gst_tensors_info_copy (GstTensorsInfo * dest, const GstTensorsInfo * src)
     531              : {
     532              :   guint i, num;
     533              :   GstTensorInfo *_dest, *_src;
     534              : 
     535         4716 :   g_return_if_fail (dest != NULL);
     536         4716 :   g_return_if_fail (src != NULL);
     537              : 
     538         4716 :   gst_tensors_info_init (dest);
     539         4716 :   num = dest->num_tensors = src->num_tensors;
     540         4716 :   dest->format = src->format;
     541              : 
     542         4716 :   if (src->format != _NNS_TENSOR_FORMAT_STATIC)
     543          190 :     return;
     544              : 
     545        10473 :   for (i = 0; i < num; i++) {
     546         5947 :     _dest = gst_tensors_info_get_nth_info (dest, i);
     547         5947 :     _src = gst_tensors_info_get_nth_info ((GstTensorsInfo *) src, i);
     548              : 
     549         5947 :     gst_tensor_info_copy (_dest, _src);
     550              :   }
     551              : }
     552              : 
     553              : /**
     554              :  * @brief Parse the string of dimensions
     555              :  * @param info tensors info structure
     556              :  * @param dim_string string of dimensions
     557              :  * @return number of parsed dimensions
     558              :  */
     559              : guint
     560         9161 : gst_tensors_info_parse_dimensions_string (GstTensorsInfo * info,
     561              :     const gchar * dim_string)
     562              : {
     563         9161 :   guint num_dims = 0;
     564              :   GstTensorInfo *_info;
     565              : 
     566         9161 :   g_return_val_if_fail (info != NULL, 0);
     567              : 
     568         9160 :   if (dim_string) {
     569              :     guint i;
     570              :     gchar **str_dims;
     571              : 
     572         9159 :     str_dims = g_strsplit_set (dim_string, ",.", -1);
     573         9159 :     num_dims = g_strv_length (str_dims);
     574              : 
     575         9159 :     if (num_dims > NNS_TENSOR_SIZE_LIMIT) {
     576            1 :       nns_logw ("Invalid param, dimensions (%d) max (%d)\n",
     577              :           num_dims, NNS_TENSOR_SIZE_LIMIT);
     578              : 
     579            1 :       num_dims = NNS_TENSOR_SIZE_LIMIT;
     580              :     }
     581              : 
     582        28360 :     for (i = 0; i < num_dims; i++) {
     583        19201 :       _info = gst_tensors_info_get_nth_info (info, i);
     584        19201 :       gst_tensor_parse_dimension (str_dims[i], _info->dimension);
     585              :     }
     586              : 
     587         9159 :     g_strfreev (str_dims);
     588              :   }
     589              : 
     590         9160 :   return num_dims;
     591              : }
     592              : 
     593              : /**
     594              :  * @brief Parse the string of types
     595              :  * @param info tensors info structure
     596              :  * @param type_string string of types
     597              :  * @return number of parsed types
     598              :  */
     599              : guint
     600         9136 : gst_tensors_info_parse_types_string (GstTensorsInfo * info,
     601              :     const gchar * type_string)
     602              : {
     603         9136 :   guint num_types = 0;
     604              :   GstTensorInfo *_info;
     605              : 
     606         9136 :   g_return_val_if_fail (info != NULL, 0);
     607              : 
     608         9135 :   if (type_string) {
     609              :     guint i;
     610              :     gchar **str_types;
     611              : 
     612         9134 :     str_types = g_strsplit_set (type_string, ",.", -1);
     613         9134 :     num_types = g_strv_length (str_types);
     614              : 
     615         9134 :     if (num_types > NNS_TENSOR_SIZE_LIMIT) {
     616            1 :       nns_logw ("Invalid param, types (%d) max (%d)\n",
     617              :           num_types, NNS_TENSOR_SIZE_LIMIT);
     618              : 
     619            1 :       num_types = NNS_TENSOR_SIZE_LIMIT;
     620              :     }
     621              : 
     622        28323 :     for (i = 0; i < num_types; i++) {
     623        19189 :       _info = gst_tensors_info_get_nth_info (info, i);
     624        19189 :       _info->type = gst_tensor_get_type (str_types[i]);
     625              :     }
     626              : 
     627         9134 :     g_strfreev (str_types);
     628              :   }
     629              : 
     630         9135 :   return num_types;
     631              : }
     632              : 
     633              : /**
     634              :  * @brief Parse the string of names
     635              :  * @param info tensors info structure
     636              :  * @param name_string string of names
     637              :  * @return number of parsed names
     638              :  */
     639              : guint
     640           13 : gst_tensors_info_parse_names_string (GstTensorsInfo * info,
     641              :     const gchar * name_string)
     642              : {
     643           13 :   guint num_names = 0;
     644              :   GstTensorInfo *_info;
     645              : 
     646           13 :   g_return_val_if_fail (info != NULL, 0);
     647              : 
     648           12 :   if (name_string) {
     649              :     guint i;
     650              :     gchar **str_names;
     651              : 
     652           11 :     str_names = g_strsplit (name_string, ",", -1);
     653           11 :     num_names = g_strv_length (str_names);
     654              : 
     655           11 :     if (num_names > NNS_TENSOR_SIZE_LIMIT) {
     656            1 :       nns_logw ("Invalid param, names (%d) max (%d)\n",
     657              :           num_names, NNS_TENSOR_SIZE_LIMIT);
     658              : 
     659            1 :       num_names = NNS_TENSOR_SIZE_LIMIT;
     660              :     }
     661              : 
     662          309 :     for (i = 0; i < num_names; i++) {
     663              :       gchar *str_name;
     664              : 
     665          298 :       _info = gst_tensors_info_get_nth_info (info, i);
     666          298 :       g_clear_pointer (&_info->name, g_free);
     667              : 
     668          596 :       str_name = g_strstrip (g_strdup (str_names[i]));
     669          298 :       if (str_name && strlen (str_name))
     670          295 :         _info->name = str_name;
     671              :       else
     672            3 :         g_free (str_name);
     673              :     }
     674              : 
     675           11 :     g_strfreev (str_names);
     676              :   }
     677              : 
     678           12 :   return num_names;
     679              : }
     680              : 
     681              : /**
     682              :  * @brief Get the string of dimensions in tensors info
     683              :  * @param info tensors info structure
     684              :  * @return string of dimensions in tensors info (NULL if the number of tensors is 0)
     685              :  * @note The returned value should be freed with g_free()
     686              :  */
     687              : gchar *
     688         2865 : gst_tensors_info_get_dimensions_string (const GstTensorsInfo * info)
     689              : {
     690         2865 :   return gst_tensors_info_get_rank_dimensions_string (info,
     691              :       NNS_TENSOR_RANK_LIMIT, FALSE);
     692              : }
     693              : 
     694              : /**
     695              :  * @brief Get the string of dimensions in tensors info and rank count
     696              :  * @param info tensors info structure
     697              :  * @param rank rank count of given tensor dimension
     698              :  * @param padding fill 1 if actual rank is smaller than rank
     699              :  * @return Formatted string of given dimension
     700              :  * @note If rank count is 3, then returned string is 'd1:d2:d3`.
     701              :  * The returned value should be freed with g_free()
     702              :  */
     703              : gchar *
     704         8187 : gst_tensors_info_get_rank_dimensions_string (const GstTensorsInfo * info,
     705              :     const unsigned int rank, const gboolean padding)
     706              : {
     707         8187 :   gchar *dim_str = NULL;
     708              :   GstTensorInfo *_info;
     709              : 
     710         8187 :   g_return_val_if_fail (info != NULL, NULL);
     711              : 
     712         8186 :   if (info->num_tensors > 0) {
     713              :     guint i;
     714         8185 :     GString *dimensions = g_string_new (NULL);
     715              : 
     716        19647 :     for (i = 0; i < info->num_tensors; i++) {
     717        11462 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     718        11462 :       dim_str = gst_tensor_get_rank_dimension_string (_info->dimension,
     719              :           rank, padding);
     720              : 
     721              :       g_string_append (dimensions, dim_str);
     722              : 
     723        11462 :       if (i < info->num_tensors - 1) {
     724         6554 :         g_string_append (dimensions, ",");
     725              :       }
     726              : 
     727        11462 :       g_free (dim_str);
     728              :     }
     729              : 
     730         8185 :     dim_str = g_string_free (dimensions, FALSE);
     731              :   }
     732              : 
     733         8186 :   return dim_str;
     734              : }
     735              : 
     736              : /**
     737              :  * @brief Get the string of types in tensors info
     738              :  * @param info tensors info structure
     739              :  * @return string of types in tensors info (NULL if the number of tensors is 0)
     740              :  * @note The returned value should be freed with g_free()
     741              :  */
     742              : gchar *
     743         2865 : gst_tensors_info_get_types_string (const GstTensorsInfo * info)
     744              : {
     745         2865 :   gchar *type_str = NULL;
     746              :   GstTensorInfo *_info;
     747              : 
     748         2865 :   g_return_val_if_fail (info != NULL, NULL);
     749              : 
     750         2864 :   if (info->num_tensors > 0) {
     751              :     guint i;
     752         2863 :     GString *types = g_string_new (NULL);
     753              : 
     754         6853 :     for (i = 0; i < info->num_tensors; i++) {
     755         3990 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     756              : 
     757         3990 :       if (_info->type != _NNS_END)
     758         3835 :         g_string_append (types, gst_tensor_get_type_string (_info->type));
     759              : 
     760         3990 :       if (i < info->num_tensors - 1) {
     761         2254 :         g_string_append (types, ",");
     762              :       }
     763              :     }
     764              : 
     765         2863 :     type_str = g_string_free (types, FALSE);
     766              :   }
     767              : 
     768         2864 :   return type_str;
     769              : }
     770              : 
     771              : /**
     772              :  * @brief Get the string of tensor names in tensors info
     773              :  * @param info tensors info structure
     774              :  * @return string of names in tensors info (NULL if the number of tensors is 0)
     775              :  * @note The returned value should be freed with g_free()
     776              :  */
     777              : gchar *
     778           14 : gst_tensors_info_get_names_string (const GstTensorsInfo * info)
     779              : {
     780           14 :   gchar *name_str = NULL;
     781              :   GstTensorInfo *_info;
     782              : 
     783           14 :   g_return_val_if_fail (info != NULL, NULL);
     784              : 
     785           13 :   if (info->num_tensors > 0) {
     786              :     guint i;
     787           12 :     GString *names = g_string_new (NULL);
     788              : 
     789           68 :     for (i = 0; i < info->num_tensors; i++) {
     790           56 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     791              : 
     792           56 :       if (_info->name)
     793           33 :         g_string_append (names, _info->name);
     794              : 
     795           56 :       if (i < info->num_tensors - 1) {
     796           88 :         g_string_append (names, ",");
     797              :       }
     798              :     }
     799              : 
     800           12 :     name_str = g_string_free (names, FALSE);
     801              :   }
     802              : 
     803           13 :   return name_str;
     804              : }
     805              : 
     806              : /**
     807              :  * @brief GstTensorsInfo represented as a string.
     808              :  * @param info GstTensorsInfo structure.
     809              :  * @return The newly allocated string representing the tensors info. Caller should free the value using g_free().
     810              :  */
     811              : gchar *
     812          101 : gst_tensors_info_to_string (const GstTensorsInfo * info)
     813              : {
     814              :   GString *gstr;
     815              :   unsigned int i, limit;
     816              :   GstTensorInfo *_info;
     817              :   const gchar *format_str;
     818              :   gchar *info_str;
     819              : 
     820          101 :   g_return_val_if_fail (info != NULL, NULL);
     821              : 
     822          100 :   gstr = g_string_new (NULL);
     823              : 
     824          100 :   format_str = gst_tensor_get_format_string (info->format);
     825          100 :   g_string_append_printf (gstr, "Format = %s",
     826              :       format_str ? format_str : "unknown");
     827              : 
     828          100 :   if (info->format == _NNS_TENSOR_FORMAT_STATIC) {
     829          100 :     g_string_append_printf (gstr, ", Num_Tensors = %u", info->num_tensors);
     830              : 
     831          100 :     limit = info->num_tensors;
     832          100 :     if (limit > NNS_TENSOR_SIZE_LIMIT) {
     833            1 :       limit = NNS_TENSOR_SIZE_LIMIT;
     834              : 
     835            1 :       g_string_append_printf (gstr,
     836              :           " (Num_Tensors out of bound, showing %d only.)", limit);
     837              :     }
     838              : 
     839          100 :     if (limit > 0) {
     840          100 :       g_string_append_printf (gstr, ", Tensors = [");
     841              : 
     842          456 :       for (i = 0; i < limit; i++) {
     843          356 :         _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     844          356 :         info_str = gst_tensor_info_to_string (_info);
     845              : 
     846          356 :         g_string_append_printf (gstr, "{ %s }%s", info_str,
     847          356 :             (i == info->num_tensors - 1) ? "" : ", ");
     848              : 
     849          356 :         g_free (info_str);
     850              :       }
     851              : 
     852          100 :       g_string_append_printf (gstr, "]");
     853              :     }
     854              :   }
     855              : 
     856          100 :   return g_string_free (gstr, FALSE);
     857              : }
     858              : 
     859              : /**
     860              :  * @brief Printout the comparison results of two tensors as a string.
     861              :  * @param[in] info1 The tensors to be shown on the left hand side.
     862              :  * @param[in] info2 The tensors to be shown on the right hand side.
     863              :  * @return The printout string allocated. Caller should free the value using g_free().
     864              :  */
     865              : gchar *
     866          235 : gst_tensors_info_compare_to_string (const GstTensorsInfo * info1,
     867              :     const GstTensorsInfo * info2)
     868              : {
     869              :   GString *gstr;
     870              :   GstTensorInfo *_info;
     871              :   gchar *left, *right;
     872              :   guint i;
     873              : 
     874          235 :   g_return_val_if_fail (info1 != NULL && info2 != NULL, NULL);
     875              : 
     876          234 :   gstr = g_string_new (NULL);
     877              : 
     878          479 :   for (i = 0; i < NNS_TENSOR_SIZE_LIMIT; i++) {
     879          479 :     if (info1->num_tensors <= i && info2->num_tensors <= i)
     880          234 :       break;
     881              : 
     882          245 :     if (info1->num_tensors > i) {
     883          245 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info1, i);
     884          245 :       left = gst_tensor_info_to_string (_info);
     885              :     } else {
     886            0 :       left = g_strdup ("None");
     887              :     }
     888              : 
     889          245 :     if (info2->num_tensors > i) {
     890          244 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info2, i);
     891          244 :       right = gst_tensor_info_to_string (_info);
     892              :     } else {
     893            1 :       right = g_strdup ("None");
     894              :     }
     895              : 
     896          245 :     g_string_append_printf (gstr, "%3d : %s | %s %s\n", i, left, right,
     897          245 :         g_str_equal (left, right) ? "" : "Not equal");
     898              : 
     899          245 :     g_free (left);
     900          245 :     g_free (right);
     901              :   }
     902              : 
     903          234 :   return g_string_free (gstr, FALSE);
     904              : }
     905              : 
     906              : /**
     907              :  * @brief Initialize the tensors config info structure (for other/tensors)
     908              :  * @param config tensors config structure to be initialized
     909              :  */
     910              : void
     911       366131 : gst_tensors_config_init (GstTensorsConfig * config)
     912              : {
     913       366131 :   g_return_if_fail (config != NULL);
     914              : 
     915       366130 :   gst_tensors_info_init (&config->info);
     916              : 
     917       366130 :   config->rate_n = -1;
     918       366130 :   config->rate_d = -1;
     919              : }
     920              : 
     921              : /**
     922              :  * @brief Free allocated data in tensors config structure
     923              :  * @param config tensors config structure
     924              :  */
     925              : void
     926       171413 : gst_tensors_config_free (GstTensorsConfig * config)
     927              : {
     928       171413 :   g_return_if_fail (config != NULL);
     929              : 
     930       171412 :   gst_tensors_info_free (&config->info);
     931              : }
     932              : 
     933              : /**
     934              :  * @brief Check the tensors are all configured
     935              :  * @param config tensor config structure
     936              :  * @return TRUE if configured
     937              :  */
     938              : gboolean
     939       184195 : gst_tensors_config_validate (const GstTensorsConfig * config)
     940              : {
     941       184195 :   g_return_val_if_fail (config != NULL, FALSE);
     942              : 
     943              :   /* framerate (numerator >= 0 and denominator > 0) */
     944       184193 :   if (config->rate_n < 0 || config->rate_d <= 0) {
     945            5 :     nns_logd
     946              :         ("Failed to validate tensors config. framerate: %d/%d. framerate should be numerator >= 0 and denominator > 0.",
     947              :         config->rate_n, config->rate_d);
     948            5 :     _nnstreamer_error_write
     949              :         ("Failed to validate tensors config. framerate: %d/%d. framerate should be numerator >= 0 and denominator > 0.",
     950            5 :         config->rate_n, config->rate_d);
     951            5 :     return FALSE;
     952              :   }
     953              : 
     954       184188 :   return gst_tensors_info_validate (&config->info);
     955              : }
     956              : 
     957              : /**
     958              :  * @brief Compare tensor config info
     959              :  * @param TRUE if equal
     960              :  */
     961              : gboolean
     962          810 : gst_tensors_config_is_equal (const GstTensorsConfig * c1,
     963              :     const GstTensorsConfig * c2)
     964              : {
     965          810 :   g_return_val_if_fail (c1 != NULL, FALSE);
     966          809 :   g_return_val_if_fail (c2 != NULL, FALSE);
     967              : 
     968          808 :   if (!gst_tensors_config_validate (c1) || !gst_tensors_config_validate (c2)) {
     969            2 :     return FALSE;
     970              :   }
     971              : 
     972          806 :   if (_compare_rate (c1->rate_n, c1->rate_d, c2->rate_n, c2->rate_d)) {
     973            5 :     nns_logd ("Tensors config is not equal. framerate: %d/%d vs %d/%d.",
     974              :         c1->rate_n, c1->rate_d, c2->rate_n, c2->rate_d);
     975            5 :     return FALSE;
     976              :   }
     977              : 
     978          801 :   return gst_tensors_info_is_equal (&c1->info, &c2->info);
     979              : }
     980              : 
     981              : /**
     982              :  * @brief Copy tensors config
     983              :  */
     984              : void
     985          310 : gst_tensors_config_copy (GstTensorsConfig * dest, const GstTensorsConfig * src)
     986              : {
     987          310 :   g_return_if_fail (dest != NULL);
     988          310 :   g_return_if_fail (src != NULL);
     989              : 
     990          310 :   gst_tensors_info_copy (&dest->info, &src->info);
     991          310 :   dest->rate_n = src->rate_n;
     992          310 :   dest->rate_d = src->rate_d;
     993              : }
     994              : 
     995              : /**
     996              :  * @brief Tensor config represented as a string.
     997              :  * @param config tensor config structure.
     998              :  * @return The newly allocated string representing the config. Caller should free the value using g_free().
     999              :  */
    1000              : gchar *
    1001            2 : gst_tensors_config_to_string (const GstTensorsConfig * config)
    1002              : {
    1003              :   GString *gstr;
    1004              :   gchar *info_str;
    1005              : 
    1006            2 :   g_return_val_if_fail (config != NULL, NULL);
    1007              : 
    1008            1 :   gstr = g_string_new (NULL);
    1009            1 :   info_str = gst_tensors_info_to_string (&config->info);
    1010              : 
    1011            1 :   g_string_append_printf (gstr, "%s, Framerate = %d/%d", info_str,
    1012            1 :       config->rate_n, config->rate_d);
    1013              : 
    1014            1 :   g_free (info_str);
    1015            1 :   return g_string_free (gstr, FALSE);
    1016              : }
    1017              : 
    1018              : /**
    1019              :  * @brief Check the tensor dimension is valid
    1020              :  * @param dim tensor dimension
    1021              :  * @return TRUE if dimension is valid
    1022              :  */
    1023              : gboolean
    1024       280463 : gst_tensor_dimension_is_valid (const tensor_dim dim)
    1025              : {
    1026              :   guint i;
    1027       280463 :   gboolean is_valid = FALSE;
    1028              : 
    1029       280463 :   i = gst_tensor_dimension_get_rank (dim);
    1030       280463 :   if (i == 0)
    1031         2837 :     goto done;
    1032              : 
    1033      3595887 :   for (; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1034      3318267 :     if (dim[i] > 0)
    1035            6 :       goto done;
    1036              :   }
    1037              : 
    1038       277620 :   is_valid = TRUE;
    1039              : 
    1040       280463 : done:
    1041       280463 :   if (!is_valid) {
    1042         2843 :     nns_logd
    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         2843 :     _nnstreamer_error_write
    1045              :         ("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.");
    1046              :   }
    1047              : 
    1048       280463 :   return is_valid;
    1049              : }
    1050              : 
    1051              : /**
    1052              :  * @brief Compare the tensor dimension.
    1053              :  * @return TRUE if given tensors have same dimension.
    1054              :  */
    1055              : gboolean
    1056         1737 : gst_tensor_dimension_is_equal (const tensor_dim dim1, const tensor_dim dim2)
    1057              : {
    1058              :   guint i;
    1059              : 
    1060              :   /* Do not compare invalid dimensions. */
    1061         1737 :   if (!gst_tensor_dimension_is_valid (dim1) ||
    1062         1736 :       !gst_tensor_dimension_is_valid (dim2))
    1063            1 :     return FALSE;
    1064              : 
    1065        28734 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1066        27048 :     if (dim1[i] != dim2[i]) {
    1067              :       /* Supposed dimension is same if remained dimension is 1. */
    1068          451 :       if (dim1[i] > 1 || dim2[i] > 1)
    1069           50 :         return FALSE;
    1070              :     }
    1071              :   }
    1072              : 
    1073         1686 :   return TRUE;
    1074              : }
    1075              : 
    1076              : /**
    1077              :  * @brief Get the rank of tensor dimension.
    1078              :  * @param dim tensor dimension.
    1079              :  * @return tensor rank (Minimum rank is 1 if given dimension is valid)
    1080              :  */
    1081              : guint
    1082       294553 : gst_tensor_dimension_get_rank (const tensor_dim dim)
    1083              : {
    1084              :   guint i;
    1085              : 
    1086      1467569 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1087      1463693 :     if (dim[i] == 0)
    1088       290677 :       break;
    1089              :   }
    1090              : 
    1091       294553 :   return i;
    1092              : }
    1093              : 
    1094              : /**
    1095              :  * @brief Get the minimum rank of tensor dimension.
    1096              :  * @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.
    1097              :  * @param dim tensor dimension.
    1098              :  * @return tensor rank (Minimum rank is 1 if given dimension is valid)
    1099              :  */
    1100              : guint
    1101         6992 : gst_tensor_dimension_get_min_rank (const tensor_dim dim)
    1102              : {
    1103              :   guint i, rank;
    1104              : 
    1105         6992 :   rank = gst_tensor_dimension_get_rank (dim);
    1106         6992 :   if (rank == 0)
    1107            1 :     return 0;
    1108              : 
    1109        16020 :   for (i = rank - 1; i > 0; i--) {
    1110        13368 :     if (dim[i] > 1)
    1111         4339 :       break;
    1112              :   }
    1113              : 
    1114         6991 :   return (i + 1);
    1115              : }
    1116              : 
    1117              : /**
    1118              :  * @brief Parse tensor dimension parameter string
    1119              :  * @return The Rank. 0 if error.
    1120              :  * @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];
    1121              :  * @param dim dimension to be filled.
    1122              :  */
    1123              : guint
    1124       158027 : gst_tensor_parse_dimension (const gchar * dimstr, tensor_dim dim)
    1125              : {
    1126       158027 :   guint rank = 0;
    1127              :   guint64 val;
    1128              :   gchar **strv;
    1129              :   gchar *dim_string;
    1130              :   guint i, num_dims;
    1131              : 
    1132              :   /* 0-init */
    1133      2686459 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
    1134      2528432 :     dim[i] = 0;
    1135              : 
    1136       158027 :   if (dimstr == NULL)
    1137            1 :     return 0;
    1138              : 
    1139              :   /* remove spaces */
    1140       158026 :   dim_string = g_strstrip (g_strdup (dimstr));
    1141              : 
    1142       158026 :   strv = g_strsplit (dim_string, ":", NNS_TENSOR_RANK_LIMIT);
    1143       158026 :   num_dims = g_strv_length (strv);
    1144              : 
    1145       800265 :   for (i = 0; i < num_dims; i++) {
    1146       642239 :     g_strstrip (strv[i]);
    1147       642239 :     if (strv[i] == NULL || strlen (strv[i]) == 0)
    1148              :       break;
    1149              : 
    1150       642239 :     val = g_ascii_strtoull (strv[i], NULL, 10);
    1151       642239 :     dim[i] = (uint32_t) val;
    1152       642239 :     rank = i + 1;
    1153              :   }
    1154              : 
    1155       158026 :   g_strfreev (strv);
    1156       158026 :   g_free (dim_string);
    1157       158026 :   return rank;
    1158              : }
    1159              : 
    1160              : /**
    1161              :  * @brief Get dimension string from given tensor dimension.
    1162              :  * @param dim tensor dimension
    1163              :  * @return Formatted string of given dimension (d1:d2:d3:...:d15:d16).
    1164              :  * @note The returned value should be freed with g_free()
    1165              :  */
    1166              : gchar *
    1167         4300 : gst_tensor_get_dimension_string (const tensor_dim dim)
    1168              : {
    1169              :   gchar *res =
    1170         4300 :       gst_tensor_get_rank_dimension_string (dim, NNS_TENSOR_RANK_LIMIT, FALSE);
    1171              : 
    1172         4300 :   if (!res || *res == '\0') {
    1173          301 :     g_free (res);
    1174          301 :     return NULL;
    1175              :   }
    1176              : 
    1177         3999 :   return res;
    1178              : }
    1179              : 
    1180              : /**
    1181              :  * @brief Get dimension string from given tensor dimension and rank count.
    1182              :  * @param dim tensor dimension
    1183              :  * @param rank rank count of given tensor dimension
    1184              :  * @param padding fill 1 if actual rank is smaller than rank
    1185              :  * @return Formatted string of given dimension
    1186              :  * @note If rank count is 3, then returned string is 'd1:d2:d3`.
    1187              :  * The returned value should be freed with g_free().
    1188              :  */
    1189              : gchar *
    1190        22150 : gst_tensor_get_rank_dimension_string (const tensor_dim dim,
    1191              :     const unsigned int rank, const gboolean padding)
    1192              : {
    1193              :   guint i;
    1194              :   GString *dim_str;
    1195              :   guint actual_rank;
    1196              : 
    1197        22150 :   dim_str = g_string_new (NULL);
    1198              : 
    1199        22150 :   if (rank == 0 || rank > NNS_TENSOR_RANK_LIMIT)
    1200           10 :     actual_rank = NNS_TENSOR_RANK_LIMIT;
    1201              :   else
    1202        22140 :     actual_rank = rank;
    1203              : 
    1204        95578 :   for (i = 0; i < actual_rank; i++) {
    1205        86337 :     if (dim[i] == 0)
    1206        12909 :       break;
    1207              : 
    1208        73428 :     g_string_append_printf (dim_str, "%u", dim[i]);
    1209              : 
    1210        73428 :     if (i < actual_rank - 1 && dim[i + 1] > 0) {
    1211       103202 :       g_string_append (dim_str, ":");
    1212              :     }
    1213              :   }
    1214              : 
    1215        22150 :   if (rank > 0 && padding) {
    1216         6924 :     guint real_rank = gst_tensor_dimension_get_rank (dim);
    1217              : 
    1218         6924 :     if (real_rank < rank) {
    1219         7344 :       for (; i < rank; i++)
    1220         9936 :         g_string_append (dim_str, ":1");
    1221              :     }
    1222              :   }
    1223              : 
    1224        22150 :   return g_string_free (dim_str, FALSE);
    1225              : }
    1226              : 
    1227              : /**
    1228              :  * @brief Compare dimension strings
    1229              :  * @return TRUE if equal, FALSE if given dimension strings are invalid or not equal.
    1230              :  */
    1231              : gboolean
    1232          272 : gst_tensor_dimension_string_is_equal (const gchar * dimstr1,
    1233              :     const gchar * dimstr2)
    1234              : {
    1235              :   tensor_dim dim1, dim2;
    1236              :   guint rank1, rank2, i, j, num_tensors1, num_tensors2;
    1237              :   gchar **strv1;
    1238              :   gchar **strv2;
    1239          272 :   gboolean is_equal = FALSE;
    1240              : 
    1241          272 :   strv1 = g_strsplit_set (dimstr1, ",.", -1);
    1242          272 :   strv2 = g_strsplit_set (dimstr2, ",.", -1);
    1243              : 
    1244          272 :   num_tensors1 = g_strv_length (strv1);
    1245          272 :   num_tensors2 = g_strv_length (strv2);
    1246              : 
    1247          272 :   if (num_tensors1 != num_tensors2)
    1248            8 :     goto done;
    1249              : 
    1250          626 :   for (i = 0; i < num_tensors1; i++) {
    1251         6188 :     for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++)
    1252         5824 :       dim1[j] = dim2[j] = 0;
    1253              : 
    1254          364 :     rank1 = gst_tensor_parse_dimension (strv1[i], dim1);
    1255          364 :     rank2 = gst_tensor_parse_dimension (strv2[i], dim2);
    1256              : 
    1257              :     /* 'rank 0' means invalid dimension */
    1258          364 :     if (!rank1 || !rank2 || !gst_tensor_dimension_is_equal (dim1, dim2))
    1259            2 :       goto done;
    1260              :   }
    1261              : 
    1262              :   /* Compared all tensor dimensions from input string. */
    1263          262 :   is_equal = TRUE;
    1264              : 
    1265          272 : done:
    1266          272 :   g_strfreev (strv1);
    1267          272 :   g_strfreev (strv2);
    1268              : 
    1269          272 :   return is_equal;
    1270              : }
    1271              : 
    1272              : /**
    1273              :  * @brief Count the number of elements of a tensor
    1274              :  * @return The number of elements. 0 if error.
    1275              :  * @param dim The tensor dimension
    1276              :  */
    1277              : gulong
    1278       123162 : gst_tensor_get_element_count (const tensor_dim dim)
    1279              : {
    1280       123162 :   gulong count = 1;
    1281              :   guint i;
    1282              : 
    1283       556938 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1284       556061 :     if (dim[i] == 0)
    1285       122285 :       break;
    1286              : 
    1287       433776 :     count *= dim[i];
    1288              :   }
    1289              : 
    1290       123162 :   return (i > 0) ? count : 0;
    1291              : }
    1292              : 
    1293              : /**
    1294              :  * @brief Get element size of tensor type (byte per element)
    1295              :  */
    1296              : gsize
    1297     10309409 : gst_tensor_get_element_size (tensor_type type)
    1298              : {
    1299     10309409 :   g_return_val_if_fail (type >= 0 && type <= _NNS_END, 0);
    1300              : 
    1301     10309409 :   return tensor_element_size[type];
    1302              : }
    1303              : 
    1304              : /**
    1305              :  * @brief Get tensor type from string input.
    1306              :  * @return Corresponding tensor_type. _NNS_END if unrecognized value is there.
    1307              :  * @param typestr The string type name, supposed to be one of tensor_element_typename[]
    1308              :  */
    1309              : tensor_type
    1310       157303 : gst_tensor_get_type (const gchar * typestr)
    1311              : {
    1312              :   gsize size, len;
    1313              :   gchar *type_string;
    1314       157303 :   tensor_type type = _NNS_END;
    1315              : 
    1316       157303 :   if (typestr == NULL)
    1317            7 :     return _NNS_END;
    1318              : 
    1319              :   /* remove spaces */
    1320       157296 :   type_string = g_strdup (typestr);
    1321       157296 :   g_strstrip (type_string);
    1322              : 
    1323       157296 :   len = strlen (type_string);
    1324              : 
    1325       157296 :   if (len == 0) {
    1326            1 :     g_free (type_string);
    1327            1 :     return _NNS_END;
    1328              :   }
    1329              : 
    1330       157295 :   if (g_regex_match_simple ("^uint(8|16|32|64)$",
    1331              :           type_string, G_REGEX_CASELESS, 0)) {
    1332        89610 :     size = (gsize) g_ascii_strtoull (&type_string[4], NULL, 10);
    1333              : 
    1334        89610 :     switch (size) {
    1335        87380 :       case 8:
    1336        87380 :         type = _NNS_UINT8;
    1337        87380 :         break;
    1338          196 :       case 16:
    1339          196 :         type = _NNS_UINT16;
    1340          196 :         break;
    1341         1958 :       case 32:
    1342         1958 :         type = _NNS_UINT32;
    1343         1958 :         break;
    1344           76 :       case 64:
    1345           76 :         type = _NNS_UINT64;
    1346           76 :         break;
    1347              :     }
    1348        67685 :   } else if (g_regex_match_simple ("^int(8|16|32|64)$",
    1349              :           type_string, G_REGEX_CASELESS, 0)) {
    1350          903 :     size = (gsize) g_ascii_strtoull (&type_string[3], NULL, 10);
    1351              : 
    1352          903 :     switch (size) {
    1353          304 :       case 8:
    1354          304 :         type = _NNS_INT8;
    1355          304 :         break;
    1356          340 :       case 16:
    1357          340 :         type = _NNS_INT16;
    1358          340 :         break;
    1359          167 :       case 32:
    1360          167 :         type = _NNS_INT32;
    1361          167 :         break;
    1362           92 :       case 64:
    1363           92 :         type = _NNS_INT64;
    1364           92 :         break;
    1365              :     }
    1366        66782 :   } else if (g_regex_match_simple ("^float(16|32|64)$",
    1367              :           type_string, G_REGEX_CASELESS, 0)) {
    1368        66760 :     size = (gsize) g_ascii_strtoull (&type_string[5], NULL, 10);
    1369              : 
    1370        66760 :     switch (size) {
    1371           63 :       case 16:
    1372           63 :         type = _NNS_FLOAT16;
    1373           63 :         break;
    1374        66342 :       case 32:
    1375        66342 :         type = _NNS_FLOAT32;
    1376        66342 :         break;
    1377          355 :       case 64:
    1378          355 :         type = _NNS_FLOAT64;
    1379          355 :         break;
    1380              :     }
    1381              :   }
    1382              : 
    1383       157295 :   g_free (type_string);
    1384       157295 :   return type;
    1385              : }
    1386              : 
    1387              : /**
    1388              :  * @brief Get type string of tensor type.
    1389              :  */
    1390              : const gchar *
    1391        13235 : gst_tensor_get_type_string (tensor_type type)
    1392              : {
    1393        13235 :   g_return_val_if_fail (type >= 0 && type <= _NNS_END, NULL);
    1394              : 
    1395        13235 :   return tensor_element_typename[type];
    1396              : }
    1397              : 
    1398              : /**
    1399              :  * @brief Get tensor format from string input.
    1400              :  * @param format_str The string format name, supposed to be one of tensor_format_name[].
    1401              :  * @return Corresponding tensor_format. _NNS_TENSOR_FORMAT_END if unrecognized value is there.
    1402              :  */
    1403              : tensor_format
    1404        13269 : gst_tensor_get_format (const gchar * format_str)
    1405              : {
    1406              :   gint idx;
    1407        13269 :   tensor_format format = _NNS_TENSOR_FORMAT_END;
    1408              : 
    1409        13269 :   idx = find_key_strv (tensor_format_name, format_str);
    1410        13269 :   if (idx >= 0)
    1411        11784 :     format = (tensor_format) idx;
    1412              : 
    1413        13269 :   return format;
    1414              : }
    1415              : 
    1416              : /**
    1417              :  * @brief Get tensor format string.
    1418              :  */
    1419              : const gchar *
    1420          133 : gst_tensor_get_format_string (tensor_format format)
    1421              : {
    1422          133 :   g_return_val_if_fail (format >= 0 && format <= _NNS_TENSOR_FORMAT_END, NULL);
    1423              : 
    1424          131 :   return tensor_format_name[format];
    1425              : }
    1426              : 
    1427              : /**
    1428              :  * @brief Magic number of tensor meta.
    1429              :  */
    1430              : #define GST_TENSOR_META_MAGIC (0xfeedcced)
    1431              : 
    1432              : /**
    1433              :  * @brief Macro to check the tensor meta.
    1434              :  */
    1435              : #define GST_TENSOR_META_MAGIC_VALID(m) ((m) == GST_TENSOR_META_MAGIC)
    1436              : 
    1437              : /**
    1438              :  * @brief Macro to check the meta version.
    1439              :  */
    1440              : #define GST_TENSOR_META_VERSION_VALID(v) (((v) & 0xDE000000) == 0xDE000000)
    1441              : 
    1442              : /**
    1443              :  * @brief Macro to get the version of tensor meta.
    1444              :  */
    1445              : #define GST_TENSOR_META_MAKE_VERSION(major,minor) ((major) << 12 | (minor) | 0xDE000000)
    1446              : 
    1447              : /**
    1448              :  * @brief The version of tensor meta.
    1449              :  */
    1450              : #define GST_TENSOR_META_VERSION GST_TENSOR_META_MAKE_VERSION(1,0)
    1451              : 
    1452              : /**
    1453              :  * @brief Macro to check the version of tensor meta.
    1454              :  */
    1455              : #define GST_TENSOR_META_IS_V1(v) (GST_TENSOR_META_VERSION_VALID(v) && (((v) & 0x00FFF000) & GST_TENSOR_META_MAKE_VERSION(1,0)))
    1456              : 
    1457              : /**
    1458              :  * @brief Macro to check the meta is valid.
    1459              :  */
    1460              : #define GST_TENSOR_META_IS_VALID(m) ((m) && GST_TENSOR_META_MAGIC_VALID ((m)->magic) && GST_TENSOR_META_VERSION_VALID ((m)->version))
    1461              : 
    1462              : /**
    1463              :  * @brief Initialize the tensor meta info structure.
    1464              :  * @param[in,out] meta tensor meta structure to be initialized
    1465              :  */
    1466              : void
    1467       139973 : gst_tensor_meta_info_init (GstTensorMetaInfo * meta)
    1468              : {
    1469       139973 :   g_return_if_fail (meta != NULL);
    1470              : 
    1471              :   /* zero-init */
    1472       139973 :   memset (meta, 0, sizeof (GstTensorMetaInfo));
    1473              : 
    1474       139973 :   meta->magic = GST_TENSOR_META_MAGIC;
    1475       139973 :   meta->version = GST_TENSOR_META_VERSION;
    1476       139973 :   meta->type = _NNS_END;
    1477       139973 :   meta->format = _NNS_TENSOR_FORMAT_STATIC;
    1478       139973 :   meta->media_type = _NNS_TENSOR;
    1479              : }
    1480              : 
    1481              : /**
    1482              :  * @brief Get the version of tensor meta.
    1483              :  * @param[in] meta tensor meta structure
    1484              :  * @param[out] major pointer to get the major version number
    1485              :  * @param[out] minor pointer to get the minor version number
    1486              :  * @return TRUE if successfully get the version
    1487              :  */
    1488              : gboolean
    1489            3 : gst_tensor_meta_info_get_version (GstTensorMetaInfo * meta,
    1490              :     guint * major, guint * minor)
    1491              : {
    1492            3 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1493            2 :     return FALSE;
    1494              :   }
    1495              : 
    1496            1 :   if (major)
    1497            1 :     *major = (meta->version & 0x00FFF000) >> 12;
    1498              : 
    1499            1 :   if (minor)
    1500            1 :     *minor = (meta->version & 0x00000FFF);
    1501              : 
    1502            1 :   return TRUE;
    1503              : }
    1504              : 
    1505              : /**
    1506              :  * @brief Check the meta info is valid.
    1507              :  * @param[in] meta tensor meta structure
    1508              :  * @return TRUE if given meta is valid
    1509              :  */
    1510              : gboolean
    1511        53273 : gst_tensor_meta_info_validate (GstTensorMetaInfo * meta)
    1512              : {
    1513        53273 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1514        51267 :     return FALSE;
    1515              :   }
    1516              : 
    1517         2006 :   if (meta->type >= _NNS_END) {
    1518            1 :     nns_logd ("Failed to validate tensor meta info. type: %s. ",
    1519              :         _STR_NULL (gst_tensor_get_type_string (meta->type)));
    1520            1 :     return FALSE;
    1521              :   }
    1522              : 
    1523         2005 :   if (!gst_tensor_dimension_is_valid (meta->dimension)) {
    1524            1 :     gchar *dim_str = gst_tensor_get_dimension_string (meta->dimension);
    1525            1 :     nns_logd ("Failed to validate tensor meta info. Given dimension: %s",
    1526              :         dim_str);
    1527            1 :     g_free (dim_str);
    1528            1 :     return FALSE;
    1529              :   }
    1530              : 
    1531         2004 :   if (meta->format >= _NNS_TENSOR_FORMAT_END) {
    1532            1 :     nns_logd ("Failed to validate tensors meta info. format: %s. ",
    1533              :         _STR_NULL (gst_tensor_get_format_string (meta->format)));
    1534            1 :     return FALSE;
    1535              :   }
    1536              : 
    1537         2003 :   if (meta->media_type > _NNS_TENSOR) {
    1538            1 :     nns_logd ("Failed to validate tensor meta info. invalid media type: %d.",
    1539              :         meta->media_type);
    1540            1 :     return FALSE;
    1541              :   }
    1542              : 
    1543         2002 :   return TRUE;
    1544              : }
    1545              : 
    1546              : /**
    1547              :  * @brief Get the header size to handle a tensor meta.
    1548              :  * @param[in] meta tensor meta structure
    1549              :  * @return Header size for meta info (0 if meta is invalid)
    1550              :  */
    1551              : gsize
    1552        61339 : gst_tensor_meta_info_get_header_size (GstTensorMetaInfo * meta)
    1553              : {
    1554        61339 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1555            3 :     return 0;
    1556              :   }
    1557              : 
    1558              :   /* return fixed size for meta version */
    1559        61336 :   if (GST_TENSOR_META_IS_V1 (meta->version)) {
    1560        61336 :     return 128;
    1561              :   }
    1562              : 
    1563            0 :   return 0;
    1564              : }
    1565              : 
    1566              : /**
    1567              :  * @brief Get the data size calculated from tensor meta.
    1568              :  * @param[in] meta tensor meta structure
    1569              :  * @return The data size for meta info (0 if meta is invalid)
    1570              :  */
    1571              : gsize
    1572          149 : gst_tensor_meta_info_get_data_size (GstTensorMetaInfo * meta)
    1573              : {
    1574              :   gsize dsize;
    1575              : 
    1576          149 :   if (!GST_TENSOR_META_IS_VALID (meta)) {
    1577            3 :     return 0;
    1578              :   }
    1579              : 
    1580          146 :   dsize = gst_tensor_get_element_size (meta->type);
    1581              : 
    1582          146 :   if (meta->format == _NNS_TENSOR_FORMAT_SPARSE) {
    1583            3 :     return meta->sparse_info.nnz * (dsize + sizeof (guint));
    1584              :   }
    1585              : 
    1586          143 :   dsize *= gst_tensor_get_element_count (meta->dimension);
    1587              : 
    1588          143 :   return dsize;
    1589              : }
    1590              : 
    1591              : /**
    1592              :  * @brief Update header from tensor meta.
    1593              :  * @param[in] meta tensor meta structure
    1594              :  * @param[out] header pointer to header to be updated
    1595              :  * @return TRUE if successfully set the header
    1596              :  * @note User should allocate enough memory for header (see gst_tensor_meta_info_get_header_size()).
    1597              :  */
    1598              : gboolean
    1599          402 : gst_tensor_meta_info_update_header (GstTensorMetaInfo * meta, gpointer header)
    1600              : {
    1601              :   gsize hsize;
    1602              : 
    1603          402 :   g_return_val_if_fail (header != NULL, FALSE);
    1604          401 :   g_return_val_if_fail (gst_tensor_meta_info_validate (meta), FALSE);
    1605              : 
    1606          400 :   hsize = gst_tensor_meta_info_get_header_size (meta);
    1607              : 
    1608          400 :   memset (header, 0, hsize);
    1609              : 
    1610          400 :   memcpy (header, meta, sizeof (GstTensorMetaInfo));
    1611          400 :   return TRUE;
    1612              : }
    1613              : 
    1614              : /**
    1615              :  * @brief Parse header and fill the tensor meta.
    1616              :  * @param[out] meta tensor meta structure to be filled
    1617              :  * @param[in] header pointer to header to be parsed
    1618              :  * @return TRUE if successfully set the meta
    1619              :  */
    1620              : gboolean
    1621        52360 : gst_tensor_meta_info_parse_header (GstTensorMetaInfo * meta, gpointer header)
    1622              : {
    1623        52360 :   uint32_t *val = (uint32_t *) header;
    1624              : 
    1625        52360 :   g_return_val_if_fail (header != NULL, FALSE);
    1626        52359 :   g_return_val_if_fail (meta != NULL, FALSE);
    1627              : 
    1628        52358 :   gst_tensor_meta_info_init (meta);
    1629              : 
    1630        52358 :   meta->magic = val[0];
    1631        52358 :   meta->version = val[1];
    1632        52358 :   meta->type = val[2];
    1633        52358 :   memcpy (meta->dimension, &val[3], sizeof (uint32_t) * NNS_TENSOR_RANK_LIMIT);
    1634        52358 :   meta->format = val[19];
    1635        52358 :   meta->media_type = val[20];
    1636              : 
    1637        52358 :   switch ((tensor_format) meta->format) {
    1638          204 :     case _NNS_TENSOR_FORMAT_SPARSE:
    1639          204 :       meta->sparse_info.nnz = val[21];
    1640          204 :       break;
    1641        52154 :     default:
    1642        52154 :       break;
    1643              :   }
    1644              : 
    1645              :   /** @todo update meta info for each version */
    1646        52358 :   return gst_tensor_meta_info_validate (meta);
    1647              : }
    1648              : 
    1649              : /**
    1650              :  * @brief Convert GstTensorMetaInfo structure to GstTensorInfo.
    1651              :  * @param[in] meta tensor meta structure to be converted
    1652              :  * @param[out] info GstTensorInfo to be filled
    1653              :  * @return TRUE if successfully set the info
    1654              :  */
    1655              : gboolean
    1656          226 : gst_tensor_meta_info_convert (GstTensorMetaInfo * meta, GstTensorInfo * info)
    1657              : {
    1658              :   guint i;
    1659              : 
    1660          226 :   g_return_val_if_fail (info != NULL, FALSE);
    1661          225 :   g_return_val_if_fail (gst_tensor_meta_info_validate (meta), FALSE);
    1662              : 
    1663          224 :   gst_tensor_info_init (info);
    1664              : 
    1665          224 :   info->type = meta->type;
    1666              : 
    1667         3808 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
    1668         3584 :     info->dimension[i] = meta->dimension[i];
    1669              : 
    1670          224 :   return TRUE;
    1671              : }
    1672              : 
    1673              : /**
    1674              :  * @brief Find the index value of the given key string array
    1675              :  * @return Corresponding index. Returns -1 if not found.
    1676              :  * @param strv Null terminated array of gchar *
    1677              :  * @param key The key string value
    1678              :  */
    1679              : gint
    1680        13571 : find_key_strv (const gchar ** strv, const gchar * key)
    1681              : {
    1682        13571 :   gint cursor = 0;
    1683              : 
    1684        13571 :   if (strv == NULL) {
    1685            0 :     ml_logf_stacktrace
    1686              :         ("find_key_strv is called with a null pointer. Possible internal logic errors.\n");
    1687            0 :     return -1;
    1688              :   }
    1689        16087 :   while (strv[cursor] && key) {
    1690        14598 :     if (g_ascii_strcasecmp (strv[cursor], key) == 0)
    1691        12082 :       return cursor;
    1692         2516 :     cursor++;
    1693              :   }
    1694              : 
    1695              :   /* Not found */
    1696         1489 :   return -1;
    1697              : }
    1698              : 
    1699              : /**
    1700              :  * @brief Get the version of NNStreamer (string).
    1701              :  * @return Newly allocated string. The returned string should be freed with g_free().
    1702              :  */
    1703              : gchar *
    1704            1 : nnstreamer_version_string (void)
    1705              : {
    1706              :   gchar *version;
    1707              : 
    1708            1 :   version = g_strdup_printf ("NNStreamer %s", VERSION);
    1709            1 :   return version;
    1710              : }
    1711              : 
    1712              : /**
    1713              :  * @brief Get the version of NNStreamer (int, divided).
    1714              :  * @param[out] major MAJOR.minor.micro, won't set if it's null.
    1715              :  * @param[out] minor major.MINOR.micro, won't set if it's null.
    1716              :  * @param[out] micro major.minor.MICRO, won't set if it's null.
    1717              :  */
    1718              : void
    1719            1 : nnstreamer_version_fetch (guint * major, guint * minor, guint * micro)
    1720              : {
    1721            1 :   if (major)
    1722            1 :     *major = (NNSTREAMER_VERSION_MAJOR);
    1723            1 :   if (minor)
    1724            1 :     *minor = (NNSTREAMER_VERSION_MINOR);
    1725            1 :   if (micro)
    1726            1 :     *micro = (NNSTREAMER_VERSION_MICRO);
    1727            1 : }
        

Generated by: LCOV version 2.0-1