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#eca68b8d050408568af95d831a8eef62aaee7784 Lines: 95.3 % 591 563
Test Date: 2025-03-13 05:38:21 Functions: 98.2 % 57 56

            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         1596 : _gcd (gint a, gint b)
      68              : {
      69         3202 :   while (b != 0) {
      70         1606 :     int temp = a;
      71              : 
      72         1606 :     a = b;
      73         1606 :     b = temp % b;
      74              :   }
      75              : 
      76         1596 :   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          798 : _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          798 :   g_return_val_if_fail (a_d != 0 && b_d != 0, 0);
      90              : 
      91              :   /* Simplify */
      92          798 :   gcd = _gcd (a_n, a_d);
      93          798 :   a_n /= gcd;
      94          798 :   a_d /= gcd;
      95              : 
      96          798 :   gcd = _gcd (b_n, b_d);
      97          798 :   b_n /= gcd;
      98          798 :   b_d /= gcd;
      99              : 
     100              :   /* fractions are reduced when set, so we can quickly see if they're equal */
     101          798 :   if (a_n == b_n && a_d == b_d)
     102          794 :     return 0;
     103              : 
     104              :   /* extend to 64 bits */
     105            4 :   new_num_1 = ((gint64) a_n) * b_d;
     106            4 :   new_num_2 = ((gint64) b_n) * a_d;
     107            4 :   if (new_num_1 < new_num_2)
     108            4 :     return -1;
     109            0 :   if (new_num_1 > new_num_2)
     110            0 :     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      9427544 : gst_tensor_info_init (GstTensorInfo * info)
     122              : {
     123              :   guint i;
     124              : 
     125      9427544 :   g_return_if_fail (info != NULL);
     126              : 
     127      9427544 :   info->name = NULL;
     128      9427544 :   info->type = _NNS_END;
     129              : 
     130    160268248 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     131    150840704 :     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      2823550 : gst_tensor_info_free (GstTensorInfo * info)
     141              : {
     142      2823550 :   g_return_if_fail (info != NULL);
     143              : 
     144      2823550 :   g_free (info->name);
     145              : 
     146              :   /* Init default */
     147      2823550 :   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       103011 : gst_tensor_info_get_size (const GstTensorInfo * info)
     157              : {
     158              :   gsize data_size;
     159              : 
     160       103011 :   g_return_val_if_fail (info != NULL, 0);
     161              : 
     162       103010 :   data_size = gst_tensor_get_element_count (info->dimension) *
     163       103010 :       gst_tensor_get_element_size (info->type);
     164              : 
     165       103010 :   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       139079 : gst_tensor_info_validate (const GstTensorInfo * info)
     175              : {
     176       139079 :   g_return_val_if_fail (info != NULL, FALSE);
     177              : 
     178       139076 :   if (info->type == _NNS_END) {
     179         2058 :     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         2058 :     _nnstreamer_error_write
     183              :         ("Failed to validate tensor info. type: %s. Please specify tensor type. e.g., type=uint8 ",
     184         2058 :         _STR_NULL (gst_tensor_get_type_string (info->type)));
     185         2058 :     return FALSE;
     186              :   }
     187              : 
     188              :   /* validate tensor dimension */
     189       137018 :   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         1508 : gst_tensor_info_is_equal (const GstTensorInfo * i1, const GstTensorInfo * i2)
     198              : {
     199         1508 :   if (!gst_tensor_info_validate (i1) || !gst_tensor_info_validate (i2)) {
     200            2 :     return FALSE;
     201              :   }
     202              : 
     203         1506 :   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         1353 :   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         1306 :   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        23534 : gst_tensor_info_copy_n (GstTensorInfo * dest, const GstTensorInfo * src,
     228              :     const guint n)
     229              : {
     230              :   guint i;
     231              : 
     232        23534 :   g_return_if_fail (dest != NULL);
     233        23534 :   g_return_if_fail (src != NULL);
     234              : 
     235        23534 :   dest->name = g_strdup (src->name);
     236        23534 :   dest->type = src->type;
     237              : 
     238       400078 :   for (i = 0; i < n; i++) {
     239       376544 :     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        23534 : gst_tensor_info_copy (GstTensorInfo * dest, const GstTensorInfo * src)
     249              : {
     250        23534 :   gst_tensor_info_copy_n (dest, src, NNS_TENSOR_RANK_LIMIT);
     251        23534 : }
     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          388 : gst_tensor_info_convert_to_meta (GstTensorInfo * info, GstTensorMetaInfo * meta)
     261              : {
     262              :   guint i;
     263              : 
     264          388 :   g_return_val_if_fail (gst_tensor_info_validate (info), FALSE);
     265          386 :   g_return_val_if_fail (meta != NULL, FALSE);
     266              : 
     267          385 :   gst_tensor_meta_info_init (meta);
     268              : 
     269          385 :   meta->type = info->type;
     270              : 
     271         6545 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     272              :     /** @todo handle rank from info.dimension */
     273         6160 :     meta->dimension[i] = info->dimension[i];
     274              :   }
     275              : 
     276          385 :   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 Get the pointer of nth tensor information.
     294              :  */
     295              : GstTensorInfo *
     296       380478 : gst_tensors_info_get_nth_info (GstTensorsInfo * info, guint index)
     297              : {
     298              :   guint i;
     299              : 
     300       380478 :   g_return_val_if_fail (info != NULL, NULL);
     301              : 
     302       380478 :   if (index < NNS_TENSOR_MEMORY_MAX)
     303       323894 :     return &info->info[index];
     304              : 
     305        56584 :   if (!info->extra) {
     306          205 :     info->extra = g_new0 (GstTensorInfo, NNS_TENSOR_SIZE_EXTRA_LIMIT);
     307              : 
     308        49405 :     for (i = 0; i < NNS_TENSOR_SIZE_EXTRA_LIMIT; ++i)
     309        49200 :       gst_tensor_info_init (&info->extra[i]);
     310              :   }
     311              : 
     312        56584 :   if (index < NNS_TENSOR_SIZE_LIMIT)
     313        56584 :     return &info->extra[index - NNS_TENSOR_MEMORY_MAX];
     314              : 
     315            0 :   nns_loge ("Failed to get the information, invalid index %u (max %d).",
     316              :       index, NNS_TENSOR_SIZE_LIMIT);
     317            0 :   return NULL;
     318              : }
     319              : 
     320              : /**
     321              :  * @brief Initialize the tensors info structure
     322              :  * @param info tensors info structure to be initialized
     323              :  */
     324              : void
     325       409223 : gst_tensors_info_init (GstTensorsInfo * info)
     326              : {
     327              :   guint i;
     328              : 
     329       409223 :   g_return_if_fail (info != NULL);
     330              : 
     331       409223 :   info->num_tensors = 0;
     332       409223 :   info->extra = NULL;
     333              : 
     334              :   /** @note default format is static */
     335       409223 :   info->format = _NNS_TENSOR_FORMAT_STATIC;
     336              : 
     337      6956791 :   for (i = 0; i < NNS_TENSOR_MEMORY_MAX; i++) {
     338      6547568 :     gst_tensor_info_init (&info->info[i]);
     339              :   }
     340              : }
     341              : 
     342              : /**
     343              :  * @brief Free allocated data in tensors info structure
     344              :  * @param info tensors info structure
     345              :  */
     346              : void
     347       173433 : gst_tensors_info_free (GstTensorsInfo * info)
     348              : {
     349              :   guint i;
     350              : 
     351       173433 :   g_return_if_fail (info != NULL);
     352              : 
     353      2948361 :   for (i = 0; i < NNS_TENSOR_MEMORY_MAX; i++) {
     354      2774928 :     gst_tensor_info_free (&info->info[i]);
     355              :   }
     356              : 
     357       173433 :   if (info->extra) {
     358        48682 :     for (i = 0; i < NNS_TENSOR_SIZE_EXTRA_LIMIT; ++i)
     359        48480 :       gst_tensor_info_free (&info->extra[i]);
     360              : 
     361          202 :     g_free (info->extra);
     362          202 :     info->extra = NULL;
     363              :   }
     364              : 
     365              :   /* Init default */
     366       173433 :   gst_tensors_info_init (info);
     367              : }
     368              : 
     369              : /**
     370              :  * @brief Get data size of single tensor
     371              :  * @param info tensors info structure
     372              :  * @param index the index of tensor (-1 to get total size of tensors)
     373              :  * @return data size
     374              :  */
     375              : gsize
     376          490 : gst_tensors_info_get_size (const GstTensorsInfo * info, gint index)
     377              : {
     378              :   GstTensorInfo *_info;
     379          490 :   gsize data_size = 0;
     380              :   guint i;
     381              : 
     382          490 :   g_return_val_if_fail (info != NULL, 0);
     383          489 :   g_return_val_if_fail (index < (gint) info->num_tensors, 0);
     384              : 
     385          488 :   if (index < 0) {
     386          245 :     for (i = 0; i < info->num_tensors; ++i) {
     387          137 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     388          137 :       data_size += gst_tensor_info_get_size (_info);
     389              :     }
     390              :   } else {
     391          380 :     _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, index);
     392          380 :     data_size = gst_tensor_info_get_size (_info);
     393              :   }
     394              : 
     395          488 :   return data_size;
     396              : }
     397              : 
     398              : /**
     399              :  * @brief Check the tensors info is valid
     400              :  * @param info tensors info structure
     401              :  * @return TRUE if info is valid
     402              :  */
     403              : gboolean
     404        75049 : gst_tensors_info_validate (const GstTensorsInfo * info)
     405              : {
     406              :   guint i;
     407              :   GstTensorInfo *_info;
     408              : 
     409        75049 :   g_return_val_if_fail (info != NULL, FALSE);
     410              : 
     411              :   /* tensor stream format */
     412        75048 :   if (info->format >= _NNS_TENSOR_FORMAT_END) {
     413            0 :     nns_logd
     414              :         ("Failed to validate tensors info, format: %s. format should be one of %s.",
     415              :         _STR_NULL (gst_tensor_get_format_string (info->format)),
     416              :         GST_TENSOR_FORMAT_ALL);
     417            0 :     _nnstreamer_error_write
     418              :         ("Failed to validate tensors info, format: %s. format should be one of %s.",
     419            0 :         _STR_NULL (gst_tensor_get_format_string (info->format)),
     420              :         GST_TENSOR_FORMAT_ALL);
     421            0 :     return FALSE;
     422              :   }
     423              : 
     424              :   /* cannot check tensor info when tensor is not static */
     425        75048 :   if (info->format != _NNS_TENSOR_FORMAT_STATIC) {
     426          281 :     return TRUE;
     427              :   }
     428              : 
     429        74767 :   if (info->num_tensors < 1) {
     430         3156 :     nns_logd
     431              :         ("Failed to validate tensors info. the number of tensors: %d. the number of tensors should be greater than 0.",
     432              :         info->num_tensors);
     433         3156 :     _nnstreamer_error_write
     434              :         ("Failed to validate tensors info. the number of tensors: %d. the number of tensors should be greater than 0.",
     435         3156 :         info->num_tensors);
     436         3156 :     return FALSE;
     437              :   }
     438              : 
     439       145265 :   for (i = 0; i < info->num_tensors; i++) {
     440        76347 :     _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     441              : 
     442        76347 :     if (!gst_tensor_info_validate (_info))
     443         2693 :       return FALSE;
     444              :   }
     445              : 
     446        68918 :   return TRUE;
     447              : }
     448              : 
     449              : /**
     450              :  * @brief Compare tensors info
     451              :  * @return TRUE if equal, FALSE if given tensor infos are invalid or not equal.
     452              :  */
     453              : gboolean
     454         1292 : gst_tensors_info_is_equal (const GstTensorsInfo * i1, const GstTensorsInfo * i2)
     455              : {
     456              :   guint i;
     457              :   GstTensorInfo *_info1, *_info2;
     458              : 
     459         1292 :   g_return_val_if_fail (i1 != NULL, FALSE);
     460         1291 :   g_return_val_if_fail (i2 != NULL, FALSE);
     461              : 
     462         1290 :   if (i1->format != i2->format || i1->format == _NNS_TENSOR_FORMAT_END) {
     463            7 :     nns_logd ("Tensors info is not equal. format: %s vs %s ",
     464              :         _STR_NULL (gst_tensor_get_format_string (i1->format)),
     465              :         _STR_NULL (gst_tensor_get_format_string (i2->format)));
     466            7 :     return FALSE;
     467              :   }
     468              : 
     469              :   /* cannot compare tensor info when tensor is not static */
     470         1283 :   if (i1->format != _NNS_TENSOR_FORMAT_STATIC) {
     471           26 :     return TRUE;
     472              :   }
     473              : 
     474         1257 :   if (!gst_tensors_info_validate (i1) || !gst_tensors_info_validate (i2)) {
     475          107 :     return FALSE;
     476              :   }
     477              : 
     478         1150 :   if (i1->num_tensors != i2->num_tensors) {
     479            8 :     nns_logd ("Tensors info is not equal. the number of tensors: %d vs %d. ",
     480              :         i1->num_tensors, i2->num_tensors);
     481            8 :     return FALSE;
     482              :   }
     483              : 
     484         2370 :   for (i = 0; i < i1->num_tensors; i++) {
     485         1428 :     _info1 = gst_tensors_info_get_nth_info ((GstTensorsInfo *) i1, i);
     486         1428 :     _info2 = gst_tensors_info_get_nth_info ((GstTensorsInfo *) i2, i);
     487              : 
     488         1428 :     if (!gst_tensor_info_is_equal (_info1, _info2)) {
     489          200 :       return FALSE;
     490              :     }
     491              :   }
     492              : 
     493              :   /* matched all */
     494          942 :   return TRUE;
     495              : }
     496              : 
     497              : /**
     498              :  * @brief Copy tensor info
     499              :  * @note Copied info should be freed with gst_tensors_info_free()
     500              :  */
     501              : void
     502         4532 : gst_tensors_info_copy (GstTensorsInfo * dest, const GstTensorsInfo * src)
     503              : {
     504              :   guint i, num;
     505              :   GstTensorInfo *_dest, *_src;
     506              : 
     507         4532 :   g_return_if_fail (dest != NULL);
     508         4532 :   g_return_if_fail (src != NULL);
     509              : 
     510         4532 :   gst_tensors_info_init (dest);
     511         4532 :   num = dest->num_tensors = src->num_tensors;
     512         4532 :   dest->format = src->format;
     513              : 
     514         4532 :   if (src->format != _NNS_TENSOR_FORMAT_STATIC)
     515          190 :     return;
     516              : 
     517        10105 :   for (i = 0; i < num; i++) {
     518         5763 :     _dest = gst_tensors_info_get_nth_info (dest, i);
     519         5763 :     _src = gst_tensors_info_get_nth_info ((GstTensorsInfo *) src, i);
     520              : 
     521         5763 :     gst_tensor_info_copy (_dest, _src);
     522              :   }
     523              : }
     524              : 
     525              : /**
     526              :  * @brief Parse the string of dimensions
     527              :  * @param info tensors info structure
     528              :  * @param dim_string string of dimensions
     529              :  * @return number of parsed dimensions
     530              :  */
     531              : guint
     532         8159 : gst_tensors_info_parse_dimensions_string (GstTensorsInfo * info,
     533              :     const gchar * dim_string)
     534              : {
     535         8159 :   guint num_dims = 0;
     536              :   GstTensorInfo *_info;
     537              : 
     538         8159 :   g_return_val_if_fail (info != NULL, 0);
     539              : 
     540         8158 :   if (dim_string) {
     541              :     guint i;
     542              :     gchar **str_dims;
     543              : 
     544         8157 :     str_dims = g_strsplit_set (dim_string, ",.", -1);
     545         8157 :     num_dims = g_strv_length (str_dims);
     546              : 
     547         8157 :     if (num_dims > NNS_TENSOR_SIZE_LIMIT) {
     548            1 :       nns_logw ("Invalid param, dimensions (%d) max (%d)\n",
     549              :           num_dims, NNS_TENSOR_SIZE_LIMIT);
     550              : 
     551            1 :       num_dims = NNS_TENSOR_SIZE_LIMIT;
     552              :     }
     553              : 
     554        25463 :     for (i = 0; i < num_dims; i++) {
     555        17306 :       _info = gst_tensors_info_get_nth_info (info, i);
     556        17306 :       gst_tensor_parse_dimension (str_dims[i], _info->dimension);
     557              :     }
     558              : 
     559         8157 :     g_strfreev (str_dims);
     560              :   }
     561              : 
     562         8158 :   return num_dims;
     563              : }
     564              : 
     565              : /**
     566              :  * @brief Parse the string of types
     567              :  * @param info tensors info structure
     568              :  * @param type_string string of types
     569              :  * @return number of parsed types
     570              :  */
     571              : guint
     572         8134 : gst_tensors_info_parse_types_string (GstTensorsInfo * info,
     573              :     const gchar * type_string)
     574              : {
     575         8134 :   guint num_types = 0;
     576              :   GstTensorInfo *_info;
     577              : 
     578         8134 :   g_return_val_if_fail (info != NULL, 0);
     579              : 
     580         8133 :   if (type_string) {
     581              :     guint i;
     582              :     gchar **str_types;
     583              : 
     584         8132 :     str_types = g_strsplit_set (type_string, ",.", -1);
     585         8132 :     num_types = g_strv_length (str_types);
     586              : 
     587         8132 :     if (num_types > NNS_TENSOR_SIZE_LIMIT) {
     588            1 :       nns_logw ("Invalid param, types (%d) max (%d)\n",
     589              :           num_types, NNS_TENSOR_SIZE_LIMIT);
     590              : 
     591            1 :       num_types = NNS_TENSOR_SIZE_LIMIT;
     592              :     }
     593              : 
     594        25426 :     for (i = 0; i < num_types; i++) {
     595        17294 :       _info = gst_tensors_info_get_nth_info (info, i);
     596        17294 :       _info->type = gst_tensor_get_type (str_types[i]);
     597              :     }
     598              : 
     599         8132 :     g_strfreev (str_types);
     600              :   }
     601              : 
     602         8133 :   return num_types;
     603              : }
     604              : 
     605              : /**
     606              :  * @brief Parse the string of names
     607              :  * @param info tensors info structure
     608              :  * @param name_string string of names
     609              :  * @return number of parsed names
     610              :  */
     611              : guint
     612           13 : gst_tensors_info_parse_names_string (GstTensorsInfo * info,
     613              :     const gchar * name_string)
     614              : {
     615           13 :   guint num_names = 0;
     616              :   GstTensorInfo *_info;
     617              : 
     618           13 :   g_return_val_if_fail (info != NULL, 0);
     619              : 
     620           12 :   if (name_string) {
     621              :     guint i;
     622              :     gchar **str_names;
     623              : 
     624           11 :     str_names = g_strsplit (name_string, ",", -1);
     625           11 :     num_names = g_strv_length (str_names);
     626              : 
     627           11 :     if (num_names > NNS_TENSOR_SIZE_LIMIT) {
     628            1 :       nns_logw ("Invalid param, names (%d) max (%d)\n",
     629              :           num_names, NNS_TENSOR_SIZE_LIMIT);
     630              : 
     631            1 :       num_names = NNS_TENSOR_SIZE_LIMIT;
     632              :     }
     633              : 
     634          309 :     for (i = 0; i < num_names; i++) {
     635              :       gchar *str_name;
     636              : 
     637          298 :       _info = gst_tensors_info_get_nth_info (info, i);
     638          298 :       g_free (_info->name);
     639          298 :       _info->name = NULL;
     640              : 
     641          596 :       str_name = g_strstrip (g_strdup (str_names[i]));
     642          298 :       if (str_name && strlen (str_name))
     643          295 :         _info->name = str_name;
     644              :       else
     645            3 :         g_free (str_name);
     646              :     }
     647              : 
     648           11 :     g_strfreev (str_names);
     649              :   }
     650              : 
     651           12 :   return num_names;
     652              : }
     653              : 
     654              : /**
     655              :  * @brief Get the string of dimensions in tensors info
     656              :  * @param info tensors info structure
     657              :  * @return string of dimensions in tensors info (NULL if the number of tensors is 0)
     658              :  * @note The returned value should be freed with g_free()
     659              :  */
     660              : gchar *
     661         2717 : gst_tensors_info_get_dimensions_string (const GstTensorsInfo * info)
     662              : {
     663         2717 :   return gst_tensors_info_get_rank_dimensions_string (info,
     664              :       NNS_TENSOR_RANK_LIMIT);
     665              : }
     666              : 
     667              : /**
     668              :  * @brief Get the string of dimensions in tensors info and rank count
     669              :  * @param info tensors info structure
     670              :  * @param rank rank count of given tensor dimension
     671              :  * @return Formatted string of given dimension
     672              :  * @note If rank count is 3, then returned string is 'd1:d2:d3`.
     673              :  * The returned value should be freed with g_free()
     674              :  */
     675              : gchar *
     676         2786 : gst_tensors_info_get_rank_dimensions_string (const GstTensorsInfo * info,
     677              :     const unsigned int rank)
     678              : {
     679         2786 :   gchar *dim_str = NULL;
     680              :   GstTensorInfo *_info;
     681              : 
     682         2786 :   g_return_val_if_fail (info != NULL, NULL);
     683              : 
     684         2785 :   if (info->num_tensors > 0) {
     685              :     guint i;
     686         2784 :     GString *dimensions = g_string_new (NULL);
     687              : 
     688         6684 :     for (i = 0; i < info->num_tensors; i++) {
     689         3900 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     690         3900 :       dim_str = gst_tensor_get_rank_dimension_string (_info->dimension, rank);
     691              : 
     692              :       g_string_append (dimensions, dim_str);
     693              : 
     694         3900 :       if (i < info->num_tensors - 1) {
     695         2232 :         g_string_append (dimensions, ",");
     696              :       }
     697              : 
     698         3900 :       g_free (dim_str);
     699              :     }
     700              : 
     701         2784 :     dim_str = g_string_free (dimensions, FALSE);
     702              :   }
     703              : 
     704         2785 :   return dim_str;
     705              : }
     706              : 
     707              : /**
     708              :  * @brief Get the string of types in tensors info
     709              :  * @param info tensors info structure
     710              :  * @return string of types in tensors info (NULL if the number of tensors is 0)
     711              :  * @note The returned value should be freed with g_free()
     712              :  */
     713              : gchar *
     714         2725 : gst_tensors_info_get_types_string (const GstTensorsInfo * info)
     715              : {
     716         2725 :   gchar *type_str = NULL;
     717              :   GstTensorInfo *_info;
     718              : 
     719         2725 :   g_return_val_if_fail (info != NULL, NULL);
     720              : 
     721         2724 :   if (info->num_tensors > 0) {
     722              :     guint i;
     723         2723 :     GString *types = g_string_new (NULL);
     724              : 
     725         6573 :     for (i = 0; i < info->num_tensors; i++) {
     726         3850 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     727              : 
     728         3850 :       if (_info->type != _NNS_END)
     729         3705 :         g_string_append (types, gst_tensor_get_type_string (_info->type));
     730              : 
     731         3850 :       if (i < info->num_tensors - 1) {
     732         2254 :         g_string_append (types, ",");
     733              :       }
     734              :     }
     735              : 
     736         2723 :     type_str = g_string_free (types, FALSE);
     737              :   }
     738              : 
     739         2724 :   return type_str;
     740              : }
     741              : 
     742              : /**
     743              :  * @brief Get the string of tensor names in tensors info
     744              :  * @param info tensors info structure
     745              :  * @return string of names in tensors info (NULL if the number of tensors is 0)
     746              :  * @note The returned value should be freed with g_free()
     747              :  */
     748              : gchar *
     749           14 : gst_tensors_info_get_names_string (const GstTensorsInfo * info)
     750              : {
     751           14 :   gchar *name_str = NULL;
     752              :   GstTensorInfo *_info;
     753              : 
     754           14 :   g_return_val_if_fail (info != NULL, NULL);
     755              : 
     756           13 :   if (info->num_tensors > 0) {
     757              :     guint i;
     758           12 :     GString *names = g_string_new (NULL);
     759              : 
     760           68 :     for (i = 0; i < info->num_tensors; i++) {
     761           56 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     762              : 
     763           56 :       if (_info->name)
     764           33 :         g_string_append (names, _info->name);
     765              : 
     766           56 :       if (i < info->num_tensors - 1) {
     767           88 :         g_string_append (names, ",");
     768              :       }
     769              :     }
     770              : 
     771           12 :     name_str = g_string_free (names, FALSE);
     772              :   }
     773              : 
     774           13 :   return name_str;
     775              : }
     776              : 
     777              : /**
     778              :  * @brief GstTensorsInfo represented as a string. Caller should free it.
     779              :  * @param info GstTensorsInfo structure
     780              :  * @return The newly allocated string representing the tensors info. Free after use.
     781              :  */
     782              : gchar *
     783          110 : gst_tensors_info_to_string (const GstTensorsInfo * info)
     784              : {
     785          110 :   GString *gstr = g_string_new (NULL);
     786              :   unsigned int i;
     787          110 :   unsigned int limit = info->num_tensors;
     788              :   GstTensorInfo *_info;
     789              : 
     790          110 :   g_string_append_printf (gstr, "Format = %s",
     791          110 :       gst_tensor_get_format_string (info->format));
     792          110 :   g_string_append_printf (gstr, ", Num_Tensors = %u", info->num_tensors);
     793              : 
     794          110 :   if (info->format == _NNS_TENSOR_FORMAT_STATIC) {
     795          110 :     g_string_append_printf (gstr, ", Tensors = [");
     796          110 :     if (limit > NNS_TENSOR_SIZE_LIMIT) {
     797            0 :       limit = NNS_TENSOR_SIZE_LIMIT;
     798            0 :       g_string_append_printf (gstr,
     799              :           "(Num_Tensors out of bound. Showing %d only)", limit);
     800              :     }
     801              : 
     802          220 :     for (i = 0; i < limit; i++) {
     803              :       const gchar *name;
     804              :       const gchar *type;
     805              :       gchar *dim;
     806              : 
     807          110 :       _info = gst_tensors_info_get_nth_info ((GstTensorsInfo *) info, i);
     808          110 :       name = _info->name;
     809          110 :       type = gst_tensor_get_type_string (_info->type);
     810          110 :       dim = gst_tensor_get_dimension_string (_info->dimension);
     811              : 
     812          110 :       g_string_append_printf (gstr, "{\"%s\", %s, %s}%s",
     813              :           name ? name : "", type, dim,
     814          110 :           (i == info->num_tensors - 1) ? "" : ", ");
     815              : 
     816          110 :       g_free (dim);
     817              :     }
     818              : 
     819          110 :     g_string_append_printf (gstr, "]");
     820              :   }
     821              : 
     822          110 :   return g_string_free (gstr, FALSE);
     823              : }
     824              : 
     825              : /**
     826              :  * @brief Initialize the tensors config info structure (for other/tensors)
     827              :  * @param config tensors config structure to be initialized
     828              :  */
     829              : void
     830       216902 : gst_tensors_config_init (GstTensorsConfig * config)
     831              : {
     832       216902 :   g_return_if_fail (config != NULL);
     833              : 
     834       216902 :   gst_tensors_info_init (&config->info);
     835              : 
     836       216902 :   config->rate_n = -1;
     837       216902 :   config->rate_d = -1;
     838              : }
     839              : 
     840              : /**
     841              :  * @brief Free allocated data in tensors config structure
     842              :  * @param config tensors config structure
     843              :  */
     844              : void
     845       163484 : gst_tensors_config_free (GstTensorsConfig * config)
     846              : {
     847       163484 :   g_return_if_fail (config != NULL);
     848              : 
     849       163484 :   gst_tensors_info_free (&config->info);
     850              : }
     851              : 
     852              : /**
     853              :  * @brief Check the tensors are all configured
     854              :  * @param config tensor config structure
     855              :  * @return TRUE if configured
     856              :  */
     857              : gboolean
     858        66896 : gst_tensors_config_validate (const GstTensorsConfig * config)
     859              : {
     860        66896 :   g_return_val_if_fail (config != NULL, FALSE);
     861              : 
     862              :   /* framerate (numerator >= 0 and denominator > 0) */
     863        66892 :   if (config->rate_n < 0 || config->rate_d <= 0) {
     864         6327 :     nns_logd
     865              :         ("Failed to validate tensors config. framerate: %d/%d. framerate should be numerator >= 0 and denominator > 0.",
     866              :         config->rate_n, config->rate_d);
     867         6327 :     _nnstreamer_error_write
     868              :         ("Failed to validate tensors config. framerate: %d/%d. framerate should be numerator >= 0 and denominator > 0.",
     869         6327 :         config->rate_n, config->rate_d);
     870         6327 :     return FALSE;
     871              :   }
     872              : 
     873        60565 :   return gst_tensors_info_validate (&config->info);
     874              : }
     875              : 
     876              : /**
     877              :  * @brief Compare tensor config info
     878              :  * @param TRUE if equal
     879              :  */
     880              : gboolean
     881          802 : gst_tensors_config_is_equal (const GstTensorsConfig * c1,
     882              :     const GstTensorsConfig * c2)
     883              : {
     884          802 :   g_return_val_if_fail (c1 != NULL, FALSE);
     885          801 :   g_return_val_if_fail (c2 != NULL, FALSE);
     886              : 
     887          800 :   if (!gst_tensors_config_validate (c1) || !gst_tensors_config_validate (c2)) {
     888            2 :     return FALSE;
     889              :   }
     890              : 
     891          798 :   if (_compare_rate (c1->rate_n, c1->rate_d, c2->rate_n, c2->rate_d)) {
     892            4 :     nns_logd ("Tensors config is not equal. framerate: %d/%d vs %d/%d.",
     893              :         c1->rate_n, c1->rate_d, c2->rate_n, c2->rate_d);
     894            4 :     return FALSE;
     895              :   }
     896              : 
     897          794 :   return gst_tensors_info_is_equal (&c1->info, &c2->info);
     898              : }
     899              : 
     900              : /**
     901              :  * @brief Copy tensors config
     902              :  */
     903              : void
     904          294 : gst_tensors_config_copy (GstTensorsConfig * dest, const GstTensorsConfig * src)
     905              : {
     906          294 :   g_return_if_fail (dest != NULL);
     907          294 :   g_return_if_fail (src != NULL);
     908              : 
     909          294 :   gst_tensors_info_copy (&dest->info, &src->info);
     910          294 :   dest->rate_n = src->rate_n;
     911          294 :   dest->rate_d = src->rate_d;
     912              : }
     913              : 
     914              : /**
     915              :  * @brief Tensor config represented as a string. Caller should free it.
     916              :  * @param config tensor config structure
     917              :  * @return The newly allocated string representing the config. Free after use.
     918              :  */
     919              : gchar *
     920            0 : gst_tensors_config_to_string (const GstTensorsConfig * config)
     921              : {
     922            0 :   GString *gstr = g_string_new (NULL);
     923            0 :   const gchar *fmt = gst_tensor_get_format_string (config->info.format);
     924            0 :   g_string_append_printf (gstr, "Format = %s, Framerate = %d/%d",
     925            0 :       fmt, config->rate_n, config->rate_d);
     926            0 :   if (config->info.format == _NNS_TENSOR_FORMAT_STATIC) {
     927            0 :     gchar *infostr = gst_tensors_info_to_string (&config->info);
     928            0 :     g_string_append_printf (gstr, ", %s", infostr);
     929            0 :     g_free (infostr);
     930              :   }
     931            0 :   return g_string_free (gstr, FALSE);
     932              : }
     933              : 
     934              : /**
     935              :  * @brief Check the tensor dimension is valid
     936              :  * @param dim tensor dimension
     937              :  * @return TRUE if dimension is valid
     938              :  */
     939              : gboolean
     940       147734 : gst_tensor_dimension_is_valid (const tensor_dim dim)
     941              : {
     942              :   guint i;
     943       147734 :   gboolean is_valid = FALSE;
     944              : 
     945       147734 :   i = gst_tensor_dimension_get_rank (dim);
     946       147734 :   if (i == 0)
     947         2839 :     goto done;
     948              : 
     949      1873055 :   for (; i < NNS_TENSOR_RANK_LIMIT; i++) {
     950      1728166 :     if (dim[i] > 0)
     951            6 :       goto done;
     952              :   }
     953              : 
     954       144889 :   is_valid = TRUE;
     955              : 
     956       147734 : done:
     957       147734 :   if (!is_valid) {
     958         2845 :     nns_logd
     959              :         ("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.");
     960         2845 :     _nnstreamer_error_write
     961              :         ("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.");
     962              :   }
     963              : 
     964       147734 :   return is_valid;
     965              : }
     966              : 
     967              : /**
     968              :  * @brief Compare the tensor dimension.
     969              :  * @return TRUE if given tensors have same dimension.
     970              :  */
     971              : gboolean
     972         1650 : gst_tensor_dimension_is_equal (const tensor_dim dim1, const tensor_dim dim2)
     973              : {
     974              :   guint i;
     975              : 
     976              :   /* Do not compare invalid dimensions. */
     977         1650 :   if (!gst_tensor_dimension_is_valid (dim1) ||
     978         1649 :       !gst_tensor_dimension_is_valid (dim2))
     979            1 :     return FALSE;
     980              : 
     981        27255 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
     982        25656 :     if (dim1[i] != dim2[i]) {
     983              :       /* Supposed dimension is same if remained dimension is 1. */
     984          242 :       if (dim1[i] > 1 || dim2[i] > 1)
     985           50 :         return FALSE;
     986              :     }
     987              :   }
     988              : 
     989         1599 :   return TRUE;
     990              : }
     991              : 
     992              : /**
     993              :  * @brief Get the rank of tensor dimension.
     994              :  * @param dim tensor dimension.
     995              :  * @return tensor rank (Minimum rank is 1 if given dimension is valid)
     996              :  */
     997              : guint
     998       159203 : gst_tensor_dimension_get_rank (const tensor_dim dim)
     999              : {
    1000              :   guint i;
    1001              : 
    1002       791599 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1003       788486 :     if (dim[i] == 0)
    1004       156090 :       break;
    1005              :   }
    1006              : 
    1007       159203 :   return i;
    1008              : }
    1009              : 
    1010              : /**
    1011              :  * @brief Get the minimum rank of tensor dimension.
    1012              :  * @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.
    1013              :  * @param dim tensor dimension.
    1014              :  * @return tensor rank (Minimum rank is 1 if given dimension is valid)
    1015              :  */
    1016              : guint
    1017         5648 : gst_tensor_dimension_get_min_rank (const tensor_dim dim)
    1018              : {
    1019              :   guint i, rank;
    1020              : 
    1021         5648 :   rank = gst_tensor_dimension_get_rank (dim);
    1022         5648 :   if (rank == 0)
    1023            0 :     return 0;
    1024              : 
    1025        13130 :   for (i = rank - 1; i > 0; i--) {
    1026        11406 :     if (dim[i] > 1)
    1027         3924 :       break;
    1028              :   }
    1029              : 
    1030         5648 :   return (i + 1);
    1031              : }
    1032              : 
    1033              : /**
    1034              :  * @brief Parse tensor dimension parameter string
    1035              :  * @return The Rank. 0 if error.
    1036              :  * @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];
    1037              :  * @param dim dimension to be filled.
    1038              :  */
    1039              : guint
    1040       156695 : gst_tensor_parse_dimension (const gchar * dimstr, tensor_dim dim)
    1041              : {
    1042       156695 :   guint rank = 0;
    1043              :   guint64 val;
    1044              :   gchar **strv;
    1045              :   gchar *dim_string;
    1046              :   guint i, num_dims;
    1047              : 
    1048              :   /* 0-init */
    1049      2663815 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
    1050      2507120 :     dim[i] = 0;
    1051              : 
    1052       156695 :   if (dimstr == NULL)
    1053            0 :     return 0;
    1054              : 
    1055              :   /* remove spaces */
    1056       156695 :   dim_string = g_strstrip (g_strdup (dimstr));
    1057              : 
    1058       156695 :   strv = g_strsplit (dim_string, ":", NNS_TENSOR_RANK_LIMIT);
    1059       156695 :   num_dims = g_strv_length (strv);
    1060              : 
    1061       792346 :   for (i = 0; i < num_dims; i++) {
    1062       635651 :     g_strstrip (strv[i]);
    1063       635651 :     if (strv[i] == NULL || strlen (strv[i]) == 0)
    1064              :       break;
    1065              : 
    1066       635651 :     val = g_ascii_strtoull (strv[i], NULL, 10);
    1067       635651 :     dim[i] = (uint32_t) val;
    1068       635651 :     rank = i + 1;
    1069              :   }
    1070              : 
    1071       156695 :   g_strfreev (strv);
    1072       156695 :   g_free (dim_string);
    1073       156695 :   return rank;
    1074              : }
    1075              : 
    1076              : /**
    1077              :  * @brief Get dimension string from given tensor dimension.
    1078              :  * @param dim tensor dimension
    1079              :  * @return Formatted string of given dimension (d1:d2:d3:...:d15:d16).
    1080              :  * @note The returned value should be freed with g_free()
    1081              :  */
    1082              : gchar *
    1083         3894 : gst_tensor_get_dimension_string (const tensor_dim dim)
    1084              : {
    1085              :   gchar *res =
    1086         3894 :       gst_tensor_get_rank_dimension_string (dim, NNS_TENSOR_RANK_LIMIT);
    1087              : 
    1088         3894 :   if (!res)
    1089            0 :     return NULL;
    1090         3894 :   if (*res == '\0') {
    1091           57 :     g_free (res);
    1092           57 :     return NULL;
    1093              :   }
    1094              : 
    1095         3837 :   return res;
    1096              : }
    1097              : 
    1098              : /**
    1099              :  * @brief Get dimension string from given tensor dimension and rank count.
    1100              :  * @param dim tensor dimension
    1101              :  * @param rank rank count of given tensor dimension
    1102              :  * @return Formatted string of given dimension
    1103              :  * @note If rank count is 3, then returned string is 'd1:d2:d3`.
    1104              :  * The returned value should be freed with g_free().
    1105              :  */
    1106              : gchar *
    1107         7883 : gst_tensor_get_rank_dimension_string (const tensor_dim dim,
    1108              :     const unsigned int rank)
    1109              : {
    1110              :   guint i;
    1111              :   GString *dim_str;
    1112              :   guint actual_rank;
    1113              : 
    1114         7883 :   dim_str = g_string_new (NULL);
    1115              : 
    1116         7883 :   if (rank == 0 || rank > NNS_TENSOR_RANK_LIMIT)
    1117           10 :     actual_rank = NNS_TENSOR_RANK_LIMIT;
    1118              :   else
    1119         7873 :     actual_rank = rank;
    1120              : 
    1121        35538 :   for (i = 0; i < actual_rank; i++) {
    1122        35258 :     if (dim[i] == 0)
    1123         7603 :       break;
    1124              : 
    1125        27655 :     g_string_append_printf (dim_str, "%u", dim[i]);
    1126              : 
    1127        27655 :     if (i < actual_rank - 1 && dim[i + 1] > 0) {
    1128        39702 :       g_string_append (dim_str, ":");
    1129              :     }
    1130              :   }
    1131              : 
    1132         7883 :   return g_string_free (dim_str, FALSE);
    1133              : }
    1134              : 
    1135              : /**
    1136              :  * @brief Compare dimension strings
    1137              :  * @return TRUE if equal, FALSE if given dimension strings are invalid or not equal.
    1138              :  */
    1139              : gboolean
    1140          231 : gst_tensor_dimension_string_is_equal (const gchar * dimstr1,
    1141              :     const gchar * dimstr2)
    1142              : {
    1143              :   tensor_dim dim1, dim2;
    1144              :   guint rank1, rank2, i, j, num_tensors1, num_tensors2;
    1145              :   gchar **strv1;
    1146              :   gchar **strv2;
    1147          231 :   gboolean is_equal = FALSE;
    1148              : 
    1149          231 :   strv1 = g_strsplit_set (dimstr1, ",.", -1);
    1150          231 :   strv2 = g_strsplit_set (dimstr2, ",.", -1);
    1151              : 
    1152          231 :   num_tensors1 = g_strv_length (strv1);
    1153          231 :   num_tensors2 = g_strv_length (strv2);
    1154              : 
    1155          231 :   if (num_tensors1 != num_tensors2)
    1156            8 :     goto done;
    1157              : 
    1158          513 :   for (i = 0; i < num_tensors1; i++) {
    1159         4964 :     for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++)
    1160         4672 :       dim1[j] = dim2[j] = 0;
    1161              : 
    1162          292 :     rank1 = gst_tensor_parse_dimension (strv1[i], dim1);
    1163          292 :     rank2 = gst_tensor_parse_dimension (strv2[i], dim2);
    1164              : 
    1165              :     /* 'rank 0' means invalid dimension */
    1166          292 :     if (!rank1 || !rank2 || !gst_tensor_dimension_is_equal (dim1, dim2))
    1167            2 :       goto done;
    1168              :   }
    1169              : 
    1170              :   /* Compared all tensor dimensions from input string. */
    1171          221 :   is_equal = TRUE;
    1172              : 
    1173          231 : done:
    1174          231 :   g_strfreev (strv1);
    1175          231 :   g_strfreev (strv2);
    1176              : 
    1177          231 :   return is_equal;
    1178              : }
    1179              : 
    1180              : /**
    1181              :  * @brief Count the number of elements of a tensor
    1182              :  * @return The number of elements. 0 if error.
    1183              :  * @param dim The tensor dimension
    1184              :  */
    1185              : gulong
    1186       125891 : gst_tensor_get_element_count (const tensor_dim dim)
    1187              : {
    1188       125891 :   gulong count = 1;
    1189              :   guint i;
    1190              : 
    1191       570835 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
    1192       569958 :     if (dim[i] == 0)
    1193       125014 :       break;
    1194              : 
    1195       444944 :     count *= dim[i];
    1196              :   }
    1197              : 
    1198       125891 :   return (i > 0) ? count : 0;
    1199              : }
    1200              : 
    1201              : /**
    1202              :  * @brief Get element size of tensor type (byte per element)
    1203              :  */
    1204              : gsize
    1205     10311249 : gst_tensor_get_element_size (tensor_type type)
    1206              : {
    1207     10311249 :   g_return_val_if_fail (type >= 0 && type <= _NNS_END, 0);
    1208              : 
    1209     10311249 :   return tensor_element_size[type];
    1210              : }
    1211              : 
    1212              : /**
    1213              :  * @brief Get tensor type from string input.
    1214              :  * @return Corresponding tensor_type. _NNS_END if unrecognized value is there.
    1215              :  * @param typestr The string type name, supposed to be one of tensor_element_typename[]
    1216              :  */
    1217              : tensor_type
    1218       156126 : gst_tensor_get_type (const gchar * typestr)
    1219              : {
    1220              :   gsize size, len;
    1221              :   gchar *type_string;
    1222       156126 :   tensor_type type = _NNS_END;
    1223              : 
    1224       156126 :   if (typestr == NULL)
    1225            7 :     return _NNS_END;
    1226              : 
    1227              :   /* remove spaces */
    1228       156119 :   type_string = g_strdup (typestr);
    1229       156119 :   g_strstrip (type_string);
    1230              : 
    1231       156119 :   len = strlen (type_string);
    1232              : 
    1233       156119 :   if (len == 0) {
    1234            1 :     g_free (type_string);
    1235            1 :     return _NNS_END;
    1236              :   }
    1237              : 
    1238       156118 :   if (g_regex_match_simple ("^uint(8|16|32|64)$",
    1239              :           type_string, G_REGEX_CASELESS, 0)) {
    1240        86426 :     size = (gsize) g_ascii_strtoull (&type_string[4], NULL, 10);
    1241              : 
    1242        86426 :     switch (size) {
    1243        84199 :       case 8:
    1244        84199 :         type = _NNS_UINT8;
    1245        84199 :         break;
    1246          195 :       case 16:
    1247          195 :         type = _NNS_UINT16;
    1248          195 :         break;
    1249         1957 :       case 32:
    1250         1957 :         type = _NNS_UINT32;
    1251         1957 :         break;
    1252           75 :       case 64:
    1253           75 :         type = _NNS_UINT64;
    1254              :     }
    1255        69692 :   } else if (g_regex_match_simple ("^int(8|16|32|64)$",
    1256              :           type_string, G_REGEX_CASELESS, 0)) {
    1257          900 :     size = (gsize) g_ascii_strtoull (&type_string[3], NULL, 10);
    1258              : 
    1259          900 :     switch (size) {
    1260          303 :       case 8:
    1261          303 :         type = _NNS_INT8;
    1262          303 :         break;
    1263          339 :       case 16:
    1264          339 :         type = _NNS_INT16;
    1265          339 :         break;
    1266          167 :       case 32:
    1267          167 :         type = _NNS_INT32;
    1268          167 :         break;
    1269           91 :       case 64:
    1270           91 :         type = _NNS_INT64;
    1271              :     }
    1272        68792 :   } else if (g_regex_match_simple ("^float(16|32|64)$",
    1273              :           type_string, G_REGEX_CASELESS, 0)) {
    1274        68770 :     size = (gsize) g_ascii_strtoull (&type_string[5], NULL, 10);
    1275              : 
    1276        68770 :     switch (size) {
    1277           63 :       case 16:
    1278           63 :         type = _NNS_FLOAT16;
    1279           63 :         break;
    1280        68353 :       case 32:
    1281        68353 :         type = _NNS_FLOAT32;
    1282        68353 :         break;
    1283          354 :       case 64:
    1284          354 :         type = _NNS_FLOAT64;
    1285              :     }
    1286              :   }
    1287              : 
    1288       156118 :   g_free (type_string);
    1289       156118 :   return type;
    1290              : }
    1291              : 
    1292              : /**
    1293              :  * @brief Get type string of tensor type.
    1294              :  */
    1295              : const gchar *
    1296        12671 : gst_tensor_get_type_string (tensor_type type)
    1297              : {
    1298        12671 :   g_return_val_if_fail (type >= 0 && type <= _NNS_END, NULL);
    1299              : 
    1300        12671 :   return tensor_element_typename[type];
    1301              : }
    1302              : 
    1303              : /**
    1304              :  * @brief Get tensor format from string input.
    1305              :  * @param format_str The string format name, supposed to be one of tensor_format_name[].
    1306              :  * @return Corresponding tensor_format. _NNS_TENSOR_FORMAT_END if unrecognized value is there.
    1307              :  */
    1308              : tensor_format
    1309        12356 : gst_tensor_get_format (const gchar * format_str)
    1310              : {
    1311              :   gint idx;
    1312        12356 :   tensor_format format = _NNS_TENSOR_FORMAT_END;
    1313              : 
    1314        12356 :   idx = find_key_strv (tensor_format_name, format_str);
    1315        12356 :   if (idx >= 0)
    1316        10868 :     format = (tensor_format) idx;
    1317              : 
    1318        12356 :   return format;
    1319              : }
    1320              : 
    1321              : /**
    1322              :  * @brief Get tensor format string.
    1323              :  */
    1324              : const gchar *
    1325          141 : gst_tensor_get_format_string (tensor_format format)
    1326              : {
    1327          141 :   g_return_val_if_fail (format >= 0 && format <= _NNS_TENSOR_FORMAT_END, NULL);
    1328              : 
    1329          139 :   return tensor_format_name[format];
    1330              : }
    1331              : 
    1332              : /**
    1333              :  * @brief Magic number of tensor meta.
    1334              :  */
    1335              : #define GST_TENSOR_META_MAGIC (0xfeedcced)
    1336              : 
    1337              : /**
    1338              :  * @brief Macro to check the tensor meta.
    1339              :  */
    1340              : #define GST_TENSOR_META_MAGIC_VALID(m) ((m) == GST_TENSOR_META_MAGIC)
    1341              : 
    1342              : /**
    1343              :  * @brief Macro to check the meta version.
    1344              :  */
    1345              : #define GST_TENSOR_META_VERSION_VALID(v) (((v) & 0xDE000000) == 0xDE000000)
    1346              : 
    1347              : /**
    1348              :  * @brief Macro to get the version of tensor meta.
    1349              :  */
    1350              : #define GST_TENSOR_META_MAKE_VERSION(major,minor) ((major) << 12 | (minor) | 0xDE000000)
    1351              : 
    1352              : /**
    1353              :  * @brief The version of tensor meta.
    1354              :  */
    1355              : #define GST_TENSOR_META_VERSION GST_TENSOR_META_MAKE_VERSION(1,0)
    1356              : 
    1357              : /**
    1358              :  * @brief Macro to check the version of tensor meta.
    1359              :  */
    1360              : #define GST_TENSOR_META_IS_V1(v) (GST_TENSOR_META_VERSION_VALID(v) && (((v) & 0x00FFF000) & GST_TENSOR_META_MAKE_VERSION(1,0)))
    1361              : 
    1362              : /**
    1363              :  * @brief Macro to check the meta is valid.
    1364              :  */
    1365              : #define GST_TENSOR_META_IS_VALID(m) ((m) && GST_TENSOR_META_MAGIC_VALID ((m)->magic) && GST_TENSOR_META_VERSION_VALID ((m)->version))
    1366              : 
    1367              : /**
    1368              :  * @brief Initialize the tensor meta info structure.
    1369              :  * @param[in,out] meta tensor meta structure to be initialized
    1370              :  */
    1371              : void
    1372       140073 : gst_tensor_meta_info_init (GstTensorMetaInfo * meta)
    1373              : {
    1374       140073 :   g_return_if_fail (meta != NULL);
    1375              : 
    1376              :   /* zero-init */
    1377       140073 :   memset (meta, 0, sizeof (GstTensorMetaInfo));
    1378              : 
    1379       140073 :   meta->magic = GST_TENSOR_META_MAGIC;
    1380       140073 :   meta->version = GST_TENSOR_META_VERSION;
    1381       140073 :   meta->type = _NNS_END;
    1382       140073 :   meta->format = _NNS_TENSOR_FORMAT_STATIC;
    1383       140073 :   meta->media_type = _NNS_TENSOR;
    1384              : }
    1385              : 
    1386              : /**
    1387              :  * @brief Get the version of tensor meta.
    1388              :  * @param[in] meta tensor meta structure
    1389              :  * @param[out] major pointer to get the major version number
    1390              :  * @param[out] minor pointer to get the minor version number
    1391              :  */
    1392              : void
    1393            1 : gst_tensor_meta_info_get_version (GstTensorMetaInfo * meta,
    1394              :     guint * major, guint * minor)
    1395              : {
    1396            1 :   g_return_if_fail (meta != NULL);
    1397              : 
    1398            1 :   if (!GST_TENSOR_META_IS_VALID (meta))
    1399            0 :     return;
    1400              : 
    1401            1 :   if (major)
    1402            1 :     *major = (meta->version & 0x00FFF000) >> 12;
    1403              : 
    1404            1 :   if (minor)
    1405            1 :     *minor = (meta->version & 0x00000FFF);
    1406              : }
    1407              : 
    1408              : /**
    1409              :  * @brief Check the meta info is valid.
    1410              :  * @param[in] meta tensor meta structure
    1411              :  * @return TRUE if given meta is valid
    1412              :  */
    1413              : gboolean
    1414        53779 : gst_tensor_meta_info_validate (GstTensorMetaInfo * meta)
    1415              : {
    1416        53779 :   g_return_val_if_fail (meta != NULL, FALSE);
    1417              : 
    1418        53775 :   if (!GST_TENSOR_META_IS_VALID (meta))
    1419        51773 :     return FALSE;
    1420              : 
    1421         2002 :   if (meta->type >= _NNS_END) {
    1422            1 :     nns_logd ("Failed to validate tensor meta info. type: %s. ",
    1423              :         _STR_NULL (gst_tensor_get_type_string (meta->type)));
    1424            1 :     return FALSE;
    1425              :   }
    1426              : 
    1427         2001 :   if (!gst_tensor_dimension_is_valid (meta->dimension)) {
    1428            1 :     gchar *dim_str = gst_tensor_get_dimension_string (meta->dimension);
    1429            1 :     nns_logd ("Failed to validate tensor meta info. Given dimension: %s",
    1430              :         dim_str);
    1431            1 :     g_free (dim_str);
    1432            1 :     return FALSE;
    1433              :   }
    1434              : 
    1435         2000 :   if (meta->format >= _NNS_TENSOR_FORMAT_END) {
    1436            1 :     nns_logd ("Failed to validate tensors meta info. format: %s. ",
    1437              :         _STR_NULL (gst_tensor_get_format_string (meta->format)));
    1438            1 :     return FALSE;
    1439              :   }
    1440              : 
    1441         1999 :   if (meta->media_type > _NNS_TENSOR) {
    1442            1 :     nns_logd ("Failed to validate tensor meta info. invalid media type: %d.",
    1443              :         meta->media_type);
    1444            1 :     return FALSE;
    1445              :   }
    1446              : 
    1447         1998 :   return TRUE;
    1448              : }
    1449              : 
    1450              : /**
    1451              :  * @brief Get the header size to handle a tensor meta.
    1452              :  * @param[in] meta tensor meta structure
    1453              :  * @return Header size for meta info (0 if meta is invalid)
    1454              :  */
    1455              : gsize
    1456        60929 : gst_tensor_meta_info_get_header_size (GstTensorMetaInfo * meta)
    1457              : {
    1458        60929 :   g_return_val_if_fail (meta != NULL, 0);
    1459              : 
    1460        60928 :   if (!GST_TENSOR_META_IS_VALID (meta))
    1461            2 :     return 0;
    1462              : 
    1463              :   /* return fixed size for meta version */
    1464        60926 :   if (GST_TENSOR_META_IS_V1 (meta->version)) {
    1465        60926 :     return 128;
    1466              :   }
    1467              : 
    1468            0 :   return 0;
    1469              : }
    1470              : 
    1471              : /**
    1472              :  * @brief Get the data size calculated from tensor meta.
    1473              :  * @param[in] meta tensor meta structure
    1474              :  * @return The data size for meta info (0 if meta is invalid)
    1475              :  */
    1476              : gsize
    1477          148 : gst_tensor_meta_info_get_data_size (GstTensorMetaInfo * meta)
    1478              : {
    1479              :   gsize dsize;
    1480              : 
    1481          148 :   g_return_val_if_fail (meta != NULL, 0);
    1482              : 
    1483          147 :   if (!GST_TENSOR_META_IS_VALID (meta))
    1484            2 :     return 0;
    1485              : 
    1486          145 :   dsize = gst_tensor_get_element_size (meta->type);
    1487              : 
    1488          145 :   if (meta->format == _NNS_TENSOR_FORMAT_SPARSE) {
    1489            3 :     return meta->sparse_info.nnz * (dsize + sizeof (guint));
    1490              :   }
    1491              : 
    1492          142 :   dsize *= gst_tensor_get_element_count (meta->dimension);
    1493              : 
    1494          142 :   return dsize;
    1495              : }
    1496              : 
    1497              : /**
    1498              :  * @brief Update header from tensor meta.
    1499              :  * @param[in] meta tensor meta structure
    1500              :  * @param[out] header pointer to header to be updated
    1501              :  * @return TRUE if successfully set the header
    1502              :  * @note User should allocate enough memory for header (see gst_tensor_meta_info_get_header_size()).
    1503              :  */
    1504              : gboolean
    1505          401 : gst_tensor_meta_info_update_header (GstTensorMetaInfo * meta, gpointer header)
    1506              : {
    1507              :   gsize hsize;
    1508              : 
    1509          401 :   g_return_val_if_fail (header != NULL, FALSE);
    1510          400 :   g_return_val_if_fail (gst_tensor_meta_info_validate (meta), FALSE);
    1511              : 
    1512          399 :   hsize = gst_tensor_meta_info_get_header_size (meta);
    1513              : 
    1514          399 :   memset (header, 0, hsize);
    1515              : 
    1516          399 :   memcpy (header, meta, sizeof (GstTensorMetaInfo));
    1517          399 :   return TRUE;
    1518              : }
    1519              : 
    1520              : /**
    1521              :  * @brief Parse header and fill the tensor meta.
    1522              :  * @param[out] meta tensor meta structure to be filled
    1523              :  * @param[in] header pointer to header to be parsed
    1524              :  * @return TRUE if successfully set the meta
    1525              :  */
    1526              : gboolean
    1527        52868 : gst_tensor_meta_info_parse_header (GstTensorMetaInfo * meta, gpointer header)
    1528              : {
    1529        52868 :   uint32_t *val = (uint32_t *) header;
    1530              : 
    1531        52868 :   g_return_val_if_fail (header != NULL, FALSE);
    1532        52867 :   g_return_val_if_fail (meta != NULL, FALSE);
    1533              : 
    1534        52866 :   gst_tensor_meta_info_init (meta);
    1535              : 
    1536        52866 :   meta->magic = val[0];
    1537        52866 :   meta->version = val[1];
    1538        52866 :   meta->type = val[2];
    1539        52866 :   memcpy (meta->dimension, &val[3], sizeof (uint32_t) * NNS_TENSOR_RANK_LIMIT);
    1540        52866 :   meta->format = val[19];
    1541        52866 :   meta->media_type = val[20];
    1542              : 
    1543        52866 :   switch ((tensor_format) meta->format) {
    1544          204 :     case _NNS_TENSOR_FORMAT_SPARSE:
    1545          204 :       meta->sparse_info.nnz = val[21];
    1546          204 :       break;
    1547        52662 :     default:
    1548        52662 :       break;
    1549              :   }
    1550              : 
    1551              :   /** @todo update meta info for each version */
    1552        52866 :   return gst_tensor_meta_info_validate (meta);
    1553              : }
    1554              : 
    1555              : /**
    1556              :  * @brief Convert GstTensorMetaInfo structure to GstTensorInfo.
    1557              :  * @param[in] meta tensor meta structure to be converted
    1558              :  * @param[out] info GstTensorInfo to be filled
    1559              :  * @return TRUE if successfully set the info
    1560              :  */
    1561              : gboolean
    1562          225 : gst_tensor_meta_info_convert (GstTensorMetaInfo * meta, GstTensorInfo * info)
    1563              : {
    1564              :   guint i;
    1565              : 
    1566          225 :   g_return_val_if_fail (info != NULL, FALSE);
    1567          224 :   g_return_val_if_fail (gst_tensor_meta_info_validate (meta), FALSE);
    1568              : 
    1569          223 :   gst_tensor_info_init (info);
    1570              : 
    1571          223 :   info->type = meta->type;
    1572              : 
    1573         3791 :   for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++)
    1574         3568 :     info->dimension[i] = meta->dimension[i];
    1575              : 
    1576          223 :   return TRUE;
    1577              : }
    1578              : 
    1579              : /**
    1580              :  * @brief Find the index value of the given key string array
    1581              :  * @return Corresponding index. Returns -1 if not found.
    1582              :  * @param strv Null terminated array of gchar *
    1583              :  * @param key The key string value
    1584              :  */
    1585              : gint
    1586        12658 : find_key_strv (const gchar ** strv, const gchar * key)
    1587              : {
    1588        12658 :   gint cursor = 0;
    1589              : 
    1590        12658 :   if (strv == NULL) {
    1591            0 :     ml_logf_stacktrace
    1592              :         ("find_key_strv is called with a null pointer. Possible internal logic errors.\n");
    1593            0 :     return -1;
    1594              :   }
    1595        15177 :   while (strv[cursor] && key) {
    1596        13685 :     if (g_ascii_strcasecmp (strv[cursor], key) == 0)
    1597        11166 :       return cursor;
    1598         2519 :     cursor++;
    1599              :   }
    1600              : 
    1601         1492 :   return -1;                    /* Not Found */
    1602              : }
    1603              : 
    1604              : /**
    1605              :  * @brief Get the version of NNStreamer (string).
    1606              :  * @return Newly allocated string. The returned string should be freed with g_free().
    1607              :  */
    1608              : gchar *
    1609            1 : nnstreamer_version_string (void)
    1610              : {
    1611              :   gchar *version;
    1612              : 
    1613            1 :   version = g_strdup_printf ("NNStreamer %s", VERSION);
    1614            1 :   return version;
    1615              : }
    1616              : 
    1617              : /**
    1618              :  * @brief Get the version of NNStreamer (int, divided).
    1619              :  * @param[out] major MAJOR.minor.micro, won't set if it's null.
    1620              :  * @param[out] minor major.MINOR.micro, won't set if it's null.
    1621              :  * @param[out] micro major.minor.MICRO, won't set if it's null.
    1622              :  */
    1623              : void
    1624            1 : nnstreamer_version_fetch (guint * major, guint * minor, guint * micro)
    1625              : {
    1626            1 :   if (major)
    1627            1 :     *major = (NNSTREAMER_VERSION_MAJOR);
    1628            1 :   if (minor)
    1629            1 :     *minor = (NNSTREAMER_VERSION_MINOR);
    1630            1 :   if (micro)
    1631            1 :     *micro = (NNSTREAMER_VERSION_MICRO);
    1632            1 : }
        

Generated by: LCOV version 2.0-1