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 : }
|