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