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