57 #include "nnstreamer-orc.h"
64 #define DBG (!filter->silent)
68 #define GST_CAT_DEFAULT gst_tensor_transform_debug
69 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_MAKE ("{ static, flexible }")
70 #define REGEX_DIMCHG_OPTION "^([0-9]|1[0-5]):([0-9]|1[0-5])$"
71 #define REGEX_TYPECAST_OPTION "(^[u]?int(8|16|32|64)$|^float(16|32|64)$)"
72 #define REGEX_TRANSPOSE_OPTION "^(?:([0-2]):(?!.*\\1)){3}3$"
73 #define REGEX_STAND_OPTION "^(default|dc-average)(:([u]?int(8|16|32|64)|float(16|32|64)))?(,per-channel:(true|false))?$"
74 #define REGEX_CLAMP_OPTION "^((([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?))):"\
75 "((([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)))$"
76 #define REGEX_PADDING_OPTION "^((left|right|top|bottom|front|back):(\\d)(,)?)+(layout:(NCHW|NHWC))?$"
77 #define REGEX_ARITH_OPTION "^(typecast:([u]?int(8|16|32|64)|float(16|32|64)),)?"\
78 "(per-channel:(false|true@[0-9]+),)?"\
79 "(((add|mul|div)(:([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?))+(@[0-9]+)?)(,|))+$"
81 #define REGEX_ARITH_OPTION_TYPECAST "(typecast:([u]?int(8|16|32|64)|float(16|32|64)))"
87 #define NNS_TENSOR_TRANSPOSE_RANK_LIMIT (4)
93 #define NNS_TENSOR_PADDING_RANK_LIMIT (3)
113 #define DEFAULT_ACCELERATION TRUE
115 #define DEFAULT_ACCELERATION FALSE
135 static GstStaticPadTemplate
sink_factory = GST_STATIC_PAD_TEMPLATE (
"sink",
143 static GstStaticPadTemplate
src_factory = GST_STATIC_PAD_TEMPLATE (
"src",
148 #define gst_tensor_transform_parent_class parent_class
150 GST_TYPE_BASE_TRANSFORM);
154 const GValue * value, GParamSpec * pspec);
156 GValue * value, GParamSpec * pspec);
161 GstBuffer * inbuf, GstBuffer * outbuf);
163 GstPadDirection direction, GstCaps * caps, GstCaps * filter);
165 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
167 GstCaps * incaps, GstCaps * outcaps);
169 GstPadDirection direction, GstCaps * caps, gsize size,
170 GstCaps * othercaps, gsize * othersize);
173 filter, GstPadDirection direction, guint idx,
const GstTensorInfo * in_info,
176 #define GST_TYPE_TENSOR_TRANSFORM_MODE (gst_tensor_transform_mode_get_type ())
184 static GType mode_type = 0;
186 if (mode_type == 0) {
187 static GEnumValue mode_types[] = {
188 {
GTT_DIMCHG,
"Mode for changing tensor dimensions, "
190 ", where NNS_TENSOR_RANK_LIMIT is 16)",
195 "option=[typecast:TYPE,][per-channel:(false|true@DIM),]add|mul|div:NUMBER[@CH_IDX], ...",
198 "option=D1\':D2\':D3\':D4 (fixed to 3)",
200 {
GTT_STAND,
"Mode for statistical standardization of tensor, "
201 "option=(default|dc-average)[:TYPE][,per-channel:(false|true)]",
203 {
GTT_CLAMP,
"Mode for clamping all elements of tensor into the range, "
204 "option=CLAMP_MIN:CLAMP_MAX",
207 "option=left|right|top|bottom|front|back:NUMBER[,layout:(NCHW|NHWC)]",
209 {
GTT_UNKNOWN,
"Unknown or not-implemented-yet mode",
214 mode_type = g_enum_register_static (
"gtt_mode_type", mode_types);
226 GObjectClass *gobject_class;
227 GstElementClass *gstelement_class;
228 GstBaseTransformClass *trans_class;
230 GST_DEBUG_CATEGORY_INIT (gst_tensor_transform_debug,
"tensor_transform", 0,
231 "Element to transforms tensor dimension or type");
233 trans_class = (GstBaseTransformClass *) klass;
234 gstelement_class = (GstElementClass *) trans_class;
235 gobject_class = (GObjectClass *) gstelement_class;
241 g_object_class_install_property (gobject_class,
PROP_SILENT,
242 g_param_spec_boolean (
"silent",
"Silent",
"Produce verbose output ?",
243 FALSE, G_PARAM_READWRITE));
244 g_object_class_install_property (gobject_class,
PROP_MODE,
245 g_param_spec_enum (
"mode",
"Mode",
"Mode used for transforming tensor",
247 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
248 g_object_class_install_property (gobject_class,
PROP_OPTION,
249 g_param_spec_string (
"option",
"Option",
250 "Option for the tensor transform mode ?",
"", G_PARAM_READWRITE));
252 g_param_spec_boolean (
"acceleration",
"Acceleration",
"Orc acceleration",
254 g_object_class_install_property (gobject_class,
PROP_APPLY,
255 g_param_spec_string (
"apply",
"Apply",
"Select tensors to apply, "
256 "separated with ',' in case of multiple tensors. Default to apply all tensors.",
257 "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
259 g_param_spec_uint (
"transpose-rank-limit",
"Transpose rank limit",
260 "The rank limit of transpose, which varies per version of nnstreamer and may be lower than the global rank limit if it is over 4.",
262 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
264 gst_element_class_set_details_simple (gstelement_class,
267 "Transforms other/tensor dimensions for different models or frameworks",
268 "MyungJoo Ham <myungjoo.ham@samsung.com>");
270 gst_element_class_add_pad_template (gstelement_class,
272 gst_element_class_add_pad_template (gstelement_class,
275 trans_class->passthrough_on_same_caps =
FALSE;
281 trans_class->transform_caps =
283 trans_class->fixate_caps =
288 trans_class->transform_size =
307 filter->
apply = NULL;
343 #ifndef FLOAT16_SUPPORT
351 (
"Tensor_transform does not support float16 operators. Apply -Denable-float16=true for meson build option if your architecture support float16. Note that tensor-transform's float16 is adhoc and does NOT perform good (slow!).\n");
356 #ifdef FLOAT16_SUPPORT
362 refrain_from_heavy_op_on_float16 (gulong n)
364 static int warned = 0;
370 (
"Tensor_transform implementation for float16 does not support SIMD. Heavy tensor-transform operations of float16 is not recommended. Try to apply heavy ops with other types (e.g., float32) and convert it to float16 at the time when it's really needed.\n");
376 #define _conv_to_f16(intype, o, i, n) \
378 float16 *op = (gpointer) (o); \
379 intype *ip = (gpointer) (i); \
381 refrain_from_heavy_op_on_float16 (n); \
382 for (idx = 0; idx < n; idx++) \
383 *(op + idx) = (float16) *(ip + idx); \
387 #define _conv_from_f16_action(n, op, ip, otypename) \
390 for (idx = 0; idx < n; idx++) \
391 *(op + idx) = (otypename) *(ip + idx); \
395 #define _conv_from_f16(otype, o, i, n) \
397 float16 *ip = (gpointer) (i); \
398 refrain_from_heavy_op_on_float16 (n); \
401 int32_t *op = (gpointer) (o); \
402 _conv_from_f16_action (n, op, ip, int32_t); \
404 case _NNS_UINT32: { \
405 uint32_t *op = (gpointer) (o); \
406 _conv_from_f16_action (n, op, ip, uint32_t); \
409 int16_t *op = (gpointer) (o); \
410 _conv_from_f16_action (n, op, ip, int16_t); \
412 case _NNS_UINT16: { \
413 uint16_t *op = (gpointer) (o); \
414 _conv_from_f16_action (n, op, ip, uint16_t); \
417 int8_t *op = (gpointer) (o); \
418 _conv_from_f16_action (n, op, ip, int8_t); \
421 uint8_t *op = (gpointer) (o); \
422 _conv_from_f16_action (n, op, ip, uint8_t); \
424 case _NNS_FLOAT64: { \
425 double *op = (gpointer) (o); \
426 _conv_from_f16_action (n, op, ip, double); \
428 case _NNS_FLOAT32: { \
429 float *op = (gpointer) (o); \
430 _conv_from_f16_action (n, op, ip, float); \
432 case _NNS_FLOAT16: { \
433 float16 *op = (gpointer) (o); \
434 _conv_from_f16_action (n, op, ip, float16); \
436 default: GST_ERROR_OBJECT (filter, "Unsupported type %d", (otype)); g_assert (0); \
441 #define _op_float16(i, n, v, op) \
444 float16 *data_in = (float16 *) (i); \
445 refrain_from_heavy_op_on_float16 (n); \
448 for (idx = 0; idx < n; idx++) \
449 data_in[idx] = data_in[idx] + (v); \
452 for (idx = 0; idx < n; idx++) \
453 data_in[idx] = data_in[idx] * (v); \
456 for (idx = 0; idx < n; idx++) \
457 data_in[idx] = data_in[idx] / (v); \
459 default: GST_ERROR_OBJECT (filter, "Unknown operator for float16: %d", op); break; \
464 #define _conv_to_f16(intype, o, i, n) do { float16_not_supported (); } while (0)
465 #define _conv_from_f16(otype, o, i, n) do { float16_not_supported (); } while (0)
466 #define _op_float16(i, n, v, op) do { float16_not_supported (); } while (0)
471 #define orc_func_conv(intype,outtype) nns_orc_conv_
472 #define orc_func_add(intype) nns_orc_add_c_
473 #define orc_func_mul(intype) nns_orc_mul_c_
474 #define orc_func_div(intype) nns_orc_div_c_
476 #define orc_typecast_to(i,o,n,intype,otype,intypename) do { \
478 case _NNS_INT32: orc_func_conv (intype, s32) ((gpointer) o, (gpointer) i, n); break; \
479 case _NNS_UINT32: orc_func_conv (intype, u32) ((gpointer) o, (gpointer) i, n); break; \
480 case _NNS_INT16: orc_func_conv (intype, s16) ((gpointer) o, (gpointer) i, n); break; \
481 case _NNS_UINT16: orc_func_conv (intype, u16) ((gpointer) o, (gpointer) i, n); break; \
482 case _NNS_INT8: orc_func_conv (intype, s8) ((gpointer) o, (gpointer) i, n); break; \
483 case _NNS_UINT8: orc_func_conv (intype, u8) ((gpointer) o, (gpointer) i, n); break; \
484 case _NNS_FLOAT64: orc_func_conv (intype, f64) ((gpointer) o, (gpointer) i, n); break; \
485 case _NNS_FLOAT32: orc_func_conv (intype, f32) ((gpointer) o, (gpointer) i, n); break; \
486 case _NNS_INT64: orc_func_conv (intype, s64) ((gpointer) o, (gpointer) i, n); break; \
487 case _NNS_UINT64: orc_func_conv (intype, u64) ((gpointer) o, (gpointer) i, n); break; \
488 case _NNS_FLOAT16: _conv_to_f16 (intypename, o, i, n); break; \
489 default: GST_ERROR_OBJECT (filter, "Unsupported output type %d", otype); g_assert (0); break; \
493 #define orc_typecast(i,o,n,itype,otype) do { \
495 case _NNS_INT32: orc_typecast_to (i, o, n, s32, otype, int32_t); break; \
496 case _NNS_UINT32: orc_typecast_to (i, o, n, u32, otype, uint32_t); break; \
497 case _NNS_INT16: orc_typecast_to (i, o, n, s16, otype, int16_t); break; \
498 case _NNS_UINT16: orc_typecast_to (i, o, n, u16, otype, uint16_t); break; \
499 case _NNS_INT8: orc_typecast_to (i, o, n, s8, otype, int8_t); break; \
500 case _NNS_UINT8: orc_typecast_to (i, o, n, u8, otype, uint8_t); break; \
501 case _NNS_FLOAT64: orc_typecast_to (i, o, n, f64, otype, double); break; \
502 case _NNS_FLOAT32: orc_typecast_to (i, o, n, f32, otype, float); break; \
503 case _NNS_INT64: orc_typecast_to (i, o, n, s64, otype, int64_t); break; \
504 case _NNS_UINT64: orc_typecast_to (i, o, n, u64, otype, uint64_t); break; \
505 case _NNS_FLOAT16: _conv_from_f16 (otype, o, i, n); break; \
506 default: GST_ERROR_OBJECT (filter, "Unsupported input type %d", itype); g_assert (0); break; \
510 #define orc_typesize(size, type) do { \
512 case _NNS_INT32: size = sizeof(int32_t); break; \
513 case _NNS_UINT32: size = sizeof(uint32_t); break; \
514 case _NNS_INT16: size = sizeof(int16_t); break; \
515 case _NNS_UINT16: size = sizeof(uint16_t); break; \
516 case _NNS_INT8: size = sizeof(int8_t); break; \
517 case _NNS_UINT8: size = sizeof(uint8_t); break; \
518 case _NNS_FLOAT64: size = sizeof(double); break; \
519 case _NNS_FLOAT32: size = sizeof(float); break; \
520 case _NNS_INT64: size = sizeof(int64_t); break; \
521 case _NNS_UINT64: size = sizeof(uint64_t); break; \
522 default: GST_ERROR_OBJECT (filter, "Unsupported type %d", type); g_assert (0); break; \
526 #define orc_operator_func(i,n,v,opfunc,op) do { \
527 switch ((v)->type) { \
528 case _NNS_INT32: opfunc (s32) ((gpointer) i, (v)->data._int32_t, n); break; \
529 case _NNS_UINT32: opfunc (u32) ((gpointer) i, (v)->data._uint32_t, n); break; \
530 case _NNS_INT16: opfunc (s16) ((gpointer) i, (v)->data._int16_t, n); break; \
531 case _NNS_UINT16: opfunc (u16) ((gpointer) i, (v)->data._uint16_t, n); break; \
532 case _NNS_INT8: opfunc (s8) ((gpointer) i, (v)->data._int8_t, n); break; \
533 case _NNS_UINT8: opfunc (u8) ((gpointer) i, (v)->data._uint8_t, n); break; \
534 case _NNS_FLOAT64: opfunc (f64) ((gpointer) i, (v)->data._double, n); break; \
535 case _NNS_FLOAT32: opfunc (f32) ((gpointer) i, (v)->data._float, n); break; \
536 case _NNS_INT64: opfunc (s64) ((gpointer) i, (v)->data._int64_t, n); break; \
537 case _NNS_UINT64: opfunc (u64) ((gpointer) i, (v)->data._uint64_t, n); break; \
538 case _NNS_FLOAT16: _op_float16 (i, n, (v)->data._float16, op); break; \
539 default: GST_ERROR_OBJECT (filter, "Unsupported type %d", (v)->type); g_assert (0); break; \
543 #define orc_operator_div_loop(i,n,val,typename) do { \
545 typename *data_in = (typename *) (i); \
546 for (idx_div = 0; idx_div < (n); ++idx_div) { \
547 data_in[idx_div] = data_in[idx_div] / (val); \
551 #define orc_operator(i,n,v,op) do { \
553 case GTT_OP_ADD: orc_operator_func (i, n, v, orc_func_add, op); break; \
554 case GTT_OP_MUL: orc_operator_func (i, n, v, orc_func_mul, op); break; \
556 switch ((v)->type) { \
557 case _NNS_INT32: orc_operator_div_loop (i, n, (v)->data._int32_t, int32_t); break; \
558 case _NNS_UINT32: orc_operator_div_loop (i, n, (v)->data._uint32_t, uint32_t); break; \
559 case _NNS_INT16: orc_operator_div_loop (i, n, (v)->data._int16_t, int16_t); break; \
560 case _NNS_UINT16: orc_operator_div_loop (i, n, (v)->data._uint16_t, uint16_t); break; \
561 case _NNS_INT8: orc_operator_div_loop (i, n, (v)->data._int8_t, int8_t); break; \
562 case _NNS_UINT8: orc_operator_div_loop (i, n, (v)->data._uint8_t, uint8_t); break; \
563 case _NNS_FLOAT64: orc_func_div (f64) ((gpointer) i, (v)->data._double, n); break; \
564 case _NNS_FLOAT32: orc_func_div (f32) ((gpointer) i, (v)->data._float, n); break; \
565 case _NNS_INT64: orc_operator_div_loop (i, n, (v)->data._int64_t, int64_t); break; \
566 case _NNS_UINT64: orc_operator_div_loop (i, n, (v)->data._uint64_t, uint64_t); break; \
567 case _NNS_FLOAT16: _op_float16 (i, n, (v)->data._float16, op); break; \
568 default: GST_ERROR_OBJECT (filter, "Unsupported type %d", (v)->type); g_assert (0); break; \
571 default: GST_ERROR_OBJECT (filter, "Unknown operator %d", op); break; \
579 #define handle_operator(d,v,oper,vtype) do { \
589 GST_ERROR_OBJECT (filter, "Invalid state, denominator is 0."); \
595 GST_ERROR_OBJECT (filter, "Unknown operator %d", oper); \
613 g_return_val_if_fail (desc != NULL,
FALSE);
614 g_return_val_if_fail (val != NULL,
FALSE);
617 switch (desc->
type) {
643 #ifdef FLOAT16_SUPPORT
656 GST_ERROR_OBJECT (filter,
"Unknown tensor type %d", desc->
type);
672 gboolean ret =
FALSE;
677 filter_name = gst_object_get_name ((GstObject *) filter);
679 switch (filter->mode) {
685 G_REGEX_CASELESS, 0)) {
687 (
"%s: dimchg: \'%s\' is not valid option string: it should be in the form of IDX_DIM_FROM:IDX_DIM_TO: with a regex, "
692 strv = g_strsplit (filter->option,
":", 2);
694 filter->data_dimchg.from = (int) g_ascii_strtoll (strv[0], NULL, 10);
695 filter->data_dimchg.to = (int) g_ascii_strtoll (strv[1], NULL, 10);
696 ret = filter->loaded =
TRUE;
703 G_REGEX_CASELESS, 0)) {
705 ret = filter->loaded =
TRUE;
708 (
"%s: typecast: \'%s\' is not valid data type for tensor: data type of tensor should be one of %s\n",
716 gchar **str_operators;
719 guint i, num_operators, num_op;
720 GRegex *regex_option_tc;
722 filter->data_arithmetic.out_type =
_NNS_END;
723 filter->data_arithmetic.per_channel_arith =
FALSE;
725 if (filter->operators) {
726 GST_WARNING_OBJECT (filter,
727 "There exists pre-defined operators (total %d), now reset these.",
728 g_slist_length (filter->operators));
730 g_slist_free_full (filter->operators,
g_free);
731 filter->operators = NULL;
735 G_REGEX_CASELESS, 0, 0);
737 if (!regex_option_tc) {
738 GST_ERROR_OBJECT (filter,
739 "arithmetic: failed to create a GRegex structure for %s\n",
744 if (g_regex_match_full (regex_option_tc, filter->option, -1,
746 str_option = g_regex_replace (regex_option_tc, filter->option, -1, 1,
749 (
"%s: arithmetic: [typecast:TYPE,] should be located at the first to prevent memory re-allocation: typecast(s) in the middle of \'%s\' will be ignored\n",
750 filter_name, filter->option);
752 str_option = g_strdup (filter->option);
754 g_regex_unref (regex_option_tc);
757 G_REGEX_CASELESS, 0)) {
759 (
"%s: arithmetic: \'%s\' is not valid option string: it should be in the form of [typecast:TYPE,][per-channel:(false|true@DIM),]add|mul|div:NUMBER[@CH_IDX]..., ...\n",
760 filter_name, str_option);
764 str_operators = g_strsplit (str_option,
",", -1);
765 num_operators = g_strv_length (str_operators);
767 for (i = 0; i < num_operators; ++i) {
768 str_op = g_strsplit (str_operators[i],
":", -1);
769 num_op = g_strv_length (str_op);
772 gchar **values = g_strsplit (str_op[1],
"@", -1);
773 guint num_values = g_strv_length (values);
776 if (g_ascii_strcasecmp (str_op[0],
"per-channel") == 0) {
777 if (num_values > 1 && g_ascii_strcasecmp (values[0],
"true") == 0) {
779 (
"Set per-channel for arithmetic and assume that %s-th dim is the channel",
781 filter->data_arithmetic.per_channel_arith =
TRUE;
782 filter->data_arithmetic.ch_dim =
783 (guint) g_ascii_strtoull (values[1], NULL, 10);
798 if (num_op > 1 && str_op[1]) {
800 filter->data_arithmetic.out_type = op_s->
value.
type;
802 GST_WARNING_OBJECT (filter,
"Invalid option for typecast %s",
810 if (num_op > 1 && str_op[1]) {
812 if (strchr (values[0],
'.') || strchr (values[0],
'e') ||
813 strchr (values[0],
'E')) {
816 val = g_ascii_strtod (values[0], NULL);
821 val = g_ascii_strtoll (values[0], NULL, 10);
825 if (filter->data_arithmetic.per_channel_arith && num_values > 1) {
826 op_s->
applying_ch = g_ascii_strtoll (values[1], NULL, 10);
830 GST_WARNING_OBJECT (filter,
831 "Invalid option for arithmetic %s", str_operators[i]);
836 GST_WARNING_OBJECT (filter,
"Unknown operator %s", str_op[0]);
842 filter->operators = g_slist_append (filter->operators, op_s);
849 GST_WARNING_OBJECT (filter,
"Invalid option %s", str_operators[i]);
855 ret = filter->loaded = (filter->operators != NULL);
856 g_strfreev (str_operators);
866 G_REGEX_CASELESS, 0)) {
868 (
"%s: transpose: \'%s\' is not valid option string: it should be in the form of NEW_IDX_DIM0:NEW_IDX_DIM1:NEW_IDX_DIM2:3 (Now transpose mode's rank is fixed to 3. Note that the index of the last dim is always fixed to 3)\n",
869 filter_name, filter->option);
875 filter->data_transpose.trans_order[i] =
876 (uint8_t) g_ascii_strtoull (strv[i], NULL, 10);
879 ret = filter->loaded =
TRUE;
885 gchar **options = NULL;
886 guint i, num_options;
889 G_REGEX_CASELESS, 0)) {
891 (
"%s: stand: \'%s\' is not a valid option string: it should be in the form of (default|dc-average)[:TYPE][,per-channel:(false|true)]\n",
892 filter_name, filter->option);
896 filter->data_stand.out_type =
_NNS_END;
897 filter->data_stand.per_channel =
FALSE;
899 options = g_strsplit (filter->option,
",", -1);
900 num_options = g_strv_length (options);
902 for (i = 0; i < num_options; i++) {
903 gchar **strv = g_strsplit (options[i],
":", -1);
905 if (g_ascii_strcasecmp (strv[0],
"default") == 0 ||
906 g_ascii_strcasecmp (strv[0],
"dc-average") == 0) {
907 filter->data_stand.mode =
909 if (g_strv_length (strv) > 1)
911 }
else if (g_ascii_strcasecmp (strv[0],
"per-channel") == 0) {
912 if (g_strv_length (strv) > 1 &&
913 g_ascii_strcasecmp (strv[1],
"true") == 0)
914 filter->data_stand.per_channel =
TRUE;
917 ml_logw (
"Unknown option for stand mode: %s", strv[0]);
923 g_strfreev (options);
924 ret = filter->loaded =
TRUE;
932 G_REGEX_CASELESS, 0)) {
934 (
"%s: clamp: \'%s\' is not valid option string: it should be in the form of [CLAMP_MIN:CLAMP_MAX]\n",
935 filter_name, filter->option);
939 strv = g_strsplit (filter->option,
":", 2);
941 filter->data_clamp.min = g_ascii_strtod (strv[0], NULL);
942 if (errno == ERANGE) {
943 ml_loge (
"%s: clamp: CLAMP_MIN value has an invalid range\n",
948 filter->data_clamp.max = g_ascii_strtod (strv[1], NULL);
949 if (errno == ERANGE) {
950 ml_loge (
"%s: clamp: CLAMP_MAX value has an invalid range\n",
958 if (filter->data_clamp.min > filter->data_clamp.max) {
959 ml_loge (
"%s: clamp: CLAMP_MIN is larger than CLAMP_MAX\n",
964 ret = filter->loaded =
TRUE;
969 gchar **options = NULL;
970 guint i, num_options;
973 G_REGEX_CASELESS, 0)) {
975 (
"%s: padding: \'%s\' is not valid option string: it should be in the form of left|right|top|bottom|front|back:PADDING,[layout:(NCHW|NHWC)]\n",
976 filter_name, filter->option);
981 filter->data_padding.pad[i] = 0;
984 options = g_strsplit (filter->option,
",", -1);
985 num_options = g_strv_length (options);
987 for (i = 0; i < num_options; i++) {
988 gchar **strv = g_strsplit (options[i],
":", 2);
989 if (g_ascii_strcasecmp (strv[0],
"left") == 0) {
991 (guint) g_ascii_strtoull (strv[1], NULL, 10);
992 }
else if (g_ascii_strcasecmp (strv[0],
"right") == 0) {
994 (guint) g_ascii_strtoull (strv[1], NULL, 10);
995 }
else if (g_ascii_strcasecmp (strv[0],
"top") == 0) {
997 (guint) g_ascii_strtoull (strv[1], NULL, 10);
998 }
else if (g_ascii_strcasecmp (strv[0],
"bottom") == 0) {
1000 (guint) g_ascii_strtoull (strv[1], NULL, 10);
1001 }
else if (g_ascii_strcasecmp (strv[0],
"front") == 0) {
1003 (guint) g_ascii_strtoull (strv[1], NULL, 10);
1004 }
else if (g_ascii_strcasecmp (strv[0],
"back") == 0) {
1006 (guint) g_ascii_strtoull (strv[1], NULL, 10);
1007 }
else if (g_ascii_strcasecmp (strv[0],
"layout") == 0) {
1008 if (g_ascii_strcasecmp (strv[1],
"NHWC") == 0)
1013 ml_logw (
"Unknown option for padding mode: %s", strv[0]);
1017 g_strfreev (options);
1020 guint prev_left = filter->data_padding.pad[
PADDING_LEFT],
1030 ret = filter->loaded =
TRUE;
1034 GST_ERROR_OBJECT (filter,
"Cannot identify mode\n");
1047 const GValue * value, GParamSpec * pspec)
1053 filter->
silent = g_value_get_boolean (value);
1056 filter->
mode = g_value_get_enum (value);
1061 gchar *backup_option = filter->
option;
1062 filter->
option = g_value_dup_string (value);
1064 silent_debug (filter,
"Option = %s --> %s\n", backup_option,
1070 filter->
option = backup_option;
1080 GST_WARNING_OBJECT (filter,
"Orc acceleration is not supported");
1087 const gchar *param = g_value_get_string (value);
1088 gchar **strv = g_strsplit_set (param,
",", -1);
1089 guint i, num = g_strv_length (strv);
1090 gchar *endptr = NULL;
1092 for (i = 0; i < num; i++) {
1094 val = g_ascii_strtoll (strv[i], &endptr, 10);
1095 if (errno == ERANGE || errno == EINVAL || (endptr == strv[i])) {
1096 ml_loge (
"Cannot convert string %s to a gint64 value", strv[i]);
1098 filter->
apply = g_list_append (filter->
apply, GINT_TO_POINTER (val));
1104 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
1114 GValue * value, GParamSpec * pspec)
1120 g_value_set_boolean (value, filter->
silent);
1123 g_value_set_enum (value, filter->
mode);
1138 if (filter->
apply == NULL) {
1143 arr = g_ptr_array_new ();
1144 for (list = filter->
apply; list != NULL; list = list->next) {
1145 g_ptr_array_add (arr, g_strdup_printf (
"%i",
1146 GPOINTER_TO_INT (list->data)));
1148 g_ptr_array_add (arr, NULL);
1149 strings = (gchar **) g_ptr_array_free (arr,
FALSE);
1150 p = g_strjoinv (
",", strings);
1152 g_strfreev (strings);
1153 g_value_take_string (value, p);
1160 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
1185 if (filter->
apply) {
1186 g_list_free (filter->
apply);
1187 filter->
apply = NULL;
1190 G_OBJECT_CLASS (parent_class)->finalize (
object);
1202 static GstFlowReturn
1205 const uint8_t * inptr, uint8_t * outptr)
1211 unsigned int i, j, k;
1212 unsigned int loopLimit = 1;
1213 gsize loopBlockSize, copyblocksize, copyblocklimit;
1218 GST_WARNING_OBJECT (filter,
1219 "Calling tensor_transform with high memcpy overhead WITHOUT any effects! Check your stream whether you really need tensor_transform.\n");
1225 g_assert (fromDim[from] == toDim[to]);
1240 loopLimit *= toDim[i];
1243 for (i = 0; i < to; i++) {
1246 loopBlockSize *= toDim[i];
1249 for (i = 0; i < from; i++) {
1250 if (fromDim[i] == 0)
1252 copyblocksize *= fromDim[i];
1254 for (i = 0; i < to; i++) {
1257 copyblocklimit *= toDim[i];
1260 for (i = 0; i < loopLimit; i++) {
1262 uint8_t *destptr = outptr + loopBlockSize * toDim[to] * i;
1263 const uint8_t *srcptr = inptr + loopBlockSize * toDim[to] * i;
1265 for (j = 0; j < toDim[to]; j++) {
1266 uint8_t *j_destptr = destptr + loopBlockSize * j;
1267 for (k = 0; k < copyblocklimit; k++) {
1269 srcptr + k * copyblocksize * toDim[to] + j * copyblocksize,
1281 (
"tensor-transform/dimchg operation is not permitted if from >= to.\n");
1282 return GST_FLOW_ERROR;
1297 static GstFlowReturn
1300 const uint8_t * inptr, uint8_t * outptr)
1303 gsize in_element_size, out_element_size;
1309 orc_typecast (inptr, outptr, num, in_info->
type, out_info->
type);
1317 for (i = 0; i < num; ++i) {
1319 (gpointer) (inptr + in_element_size * i), in_info->
type,
1320 (gpointer) (outptr + out_element_size * i), out_info->
type);
1335 static GstFlowReturn
1338 const uint8_t * inptr, uint8_t * outptr)
1340 gulong i, num, j, ch;
1341 gsize in_element_size, out_element_size;
1356 orc_typecast (inptr, outptr, num, in_info->
type, out_info->
type);
1364 orc_operator (outptr, num, &op_s->
value, op_s->
op);
1367 walk = g_slist_next (walk);
1372 gsize ch_offset, ch_size = 1;
1373 uint8_t *tmp_outptr = NULL;
1375 for (i = 0; i < ch_dim; ++i) {
1378 ch_offset = ch_size * in_info->
dimension[ch_dim];
1379 orc_typesize (typesize, out_info->
type);
1384 walk = g_slist_next (walk);
1390 orc_operator (outptr, num, &op_s->
value, op_s->
op);
1392 for (i = 0; i < num / ch_offset; ++i) {
1395 ch_offset * i) * typesize;
1397 orc_operator (tmp_outptr, ch_size, &op_s->
value, op_s->
op);
1400 walk = g_slist_next (walk);
1413 gsize ch_offset, ch_size = 1;
1414 for (i = 0; i < ch_dim; ++i) {
1417 ch_offset = ch_size * in_info->
dimension[ch_dim];
1426 for (i = 0; i < num / ch_offset; ++i) {
1427 for (ch = 0; ch < in_info->
dimension[ch_dim]; ++ch) {
1428 for (j = 0; j < ch_size; ++j) {
1429 gulong data_idx = (i * ch_offset) + (ch * ch_size) + j;
1431 (gpointer) (inptr + in_element_size * data_idx));
1447 gst_tensor_transform_do_operator (filter, &value,
1454 return GST_FLOW_ERROR;
1457 walk = g_slist_next (walk);
1470 for (i = 0; i < num; ++i) {
1473 (gpointer) (inptr + in_element_size * i));
1490 gst_tensor_transform_do_operator (filter, &value, &op_s->
value,
1495 return GST_FLOW_ERROR;
1498 walk = g_slist_next (walk);
1512 #define transposeloop(cl,ck,cj,ci,sl,sk,sj,si,typesize) do { \
1513 size_t i, j, k, l; \
1514 int inidx = 0, outidx=0; \
1515 for(cl=0;cl<sl;cl++) \
1516 for(ci=0;ci<si;ci++) \
1517 for(cj=0;cj<sj;cj++) \
1518 for(ck=0;ck<sk;ck++){ \
1519 const uint8_t *_in; \
1521 outidx = si*sj*sk*cl + sj*sk*ci + sk*cj + ck; \
1522 inidx = SK*SJ*SI*l + SJ*SI*k + SI*j + i; \
1523 _in = inptr + inidx * typesize; \
1524 _out = outptr + outidx * typesize; \
1525 nns_memcpy(_out, _in, typesize); \
1538 static GstFlowReturn
1541 const uint8_t * inptr, uint8_t * outptr)
1544 gboolean checkdim =
FALSE;
1547 gsize indexI, indexJ, SL, SI, SJ, SK;
1561 GST_WARNING_OBJECT (filter,
1562 "Calling tensor_transform with high memcpy overhead WITHOUT any effects!");
1568 SL = fromDim[3] > 0 ? fromDim[3] : 1;
1569 SI = fromDim[0] > 0 ? fromDim[0] : 1;
1570 SJ = fromDim[1] > 0 ? fromDim[1] : 1;
1571 SK = fromDim[2] > 0 ? fromDim[2] : 1;
1610 static GstFlowReturn
1613 const uint8_t * inptr, uint8_t * outptr)
1615 GstFlowReturn ret = GST_FLOW_OK;
1616 gsize in_element_size, out_element_size, data_size, ch_size;
1617 gulong i, num, data_idx, ch;
1618 gdouble tmp, *average, *std;
1628 average = std = NULL;
1638 in_info->
type, &average);
1649 for (i = 0; i < num; i++) {
1650 data_idx = in_element_size * i;
1654 tmp = fabs ((tmp - *average) / *std);
1656 data_idx = out_element_size * i;
1658 (gpointer) (outptr + data_idx), out_info->
type);
1661 for (ch = 0; ch < ch_size; ++ch) {
1662 for (i = 0; i < num / ch_size; i++) {
1663 data_idx = in_element_size * ((i * ch_size) + ch);
1667 tmp = fabs ((tmp - average[ch]) / std[ch]);
1669 data_idx = out_element_size * ((i * ch_size) + ch);
1671 (gpointer) (outptr + data_idx), out_info->
type);
1680 for (i = 0; i < num; i++) {
1681 data_idx = in_element_size * i;
1687 data_idx = out_element_size * i;
1689 (gpointer) (outptr + data_idx), out_info->
type);
1692 for (ch = 0; ch < ch_size; ++ch) {
1693 for (i = 0; i < num / ch_size; i++) {
1694 data_idx = in_element_size * ((i * ch_size) + ch);
1700 data_idx = out_element_size * ((i * ch_size) + ch);
1702 (gpointer) (outptr + data_idx), out_info->
type);
1709 GST_ERROR_OBJECT (filter,
"Cannot identify mode\n");
1710 ret = GST_FLOW_ERROR;
1730 static GstFlowReturn
1733 const uint8_t * inptr, uint8_t * outptr)
1735 gsize in_element_size, out_element_size;
1736 gulong i, num, data_idx;
1743 for (i = 0; i < num; ++i) {
1744 data_idx = in_element_size * i;
1750 data_idx = out_element_size * i;
1767 static GstFlowReturn
1772 gsize element_size, in_loop_size, out_loop_size, copy_block_size;
1773 guint i, j, k, left, top, front, loop_limit = 1;
1779 * out_info->
dimension[0] * element_size;
1780 copy_block_size = in_info->
dimension[0] * element_size;
1793 memset (outptr, 0, out_loop_size * loop_limit);
1795 for (i = 0; i < loop_limit; i++)
1796 for (j = 0; j < in_info->
dimension[2]; j++)
1797 for (k = 0; k < in_info->
dimension[1]; k++) {
1803 out_idx += left + top * out_info->
dimension[0]
1806 memcpy (outptr + out_idx * element_size + out_loop_size * i,
1807 inptr + in_idx * element_size + in_loop_size * i, copy_block_size);
1820 static GstFlowReturn
1822 GstBuffer * inbuf, GstBuffer * outbuf)
1826 GstFlowReturn res = GST_FLOW_ERROR;
1831 uint8_t *inptr, *outptr;
1832 guint i, num_tensors, num_mems;
1833 gsize buf_size, hsize;
1836 gboolean in_flexible, out_flexible;
1840 g_return_val_if_fail (filter->
loaded, GST_FLOW_ERROR);
1850 num_tensors = num_mems;
1851 g_return_val_if_fail (out_flexible, GST_FLOW_ERROR);
1854 g_return_val_if_fail (num_mems == num_tensors, GST_FLOW_ERROR);
1857 for (i = 0; i < num_tensors; i++) {
1861 if (filter->
apply && !g_list_find (filter->
apply, GINT_TO_POINTER (i))) {
1864 if (!in_flexible && out_flexible) {
1865 GstMemory *old = mem;
1870 gst_memory_unref (old);
1879 if (!gst_memory_map (in_mem[i], &in_map[i], GST_MAP_READ)) {
1880 ml_loge (
"Cannot map input buffer to gst-buf at tensor-transform.\n");
1881 res = GST_FLOW_ERROR;
1884 inptr = in_map[i].data;
1887 in_info = &in_flex_info;
1888 out_info = &out_flex_info;
1893 res = GST_FLOW_ERROR;
1898 i, in_info, out_info);
1912 out_mem[i] = gst_allocator_alloc (NULL, buf_size, NULL);
1915 if (!gst_memory_map (out_mem[i], &out_map[i], GST_MAP_WRITE)) {
1916 ml_loge (
"Cannot map output buffer to gst-buf at tensor-transform.\n");
1917 res = GST_FLOW_ERROR;
1920 outptr = out_map[i].data;
1927 switch (filter->
mode) {
1957 ml_loge (
"Not supported tensor transform mode");
1958 res = GST_FLOW_NOT_SUPPORTED;
1964 for (i = 0; i < num_tensors; i++) {
1966 gst_memory_unmap (in_mem[i], &in_map[i]);
1967 gst_memory_unref (in_mem[i]);
1970 gst_memory_unmap (out_mem[i], &out_map[i]);
1987 GstStructure *structure;
1988 g_return_val_if_fail (config != NULL,
FALSE);
1990 structure = gst_caps_get_structure (caps, 0);
1993 GST_WARNING_OBJECT (filter,
"caps is not tensor %s\n",
1994 gst_structure_get_name (structure));
2012 GstPadDirection direction, guint idx,
const GstTensorInfo * in_info,
2020 if (filter->
apply && !g_list_find (filter->
apply, GINT_TO_POINTER (idx)))
2023 switch (filter->
mode) {
2029 if (direction == GST_PAD_SINK) {
2031 if ((i < from && i < to) || (i > from && i > to) || from == to) {
2033 }
else if (i == to) {
2035 }
else if (from > to) {
2045 if ((i < from && i < to) || (i > from && i > to) || from == to) {
2047 }
else if (i == from) {
2049 }
else if (from > to) {
2062 if (direction == GST_PAD_SINK) {
2074 if (direction == GST_PAD_SINK) {
2084 if (direction == GST_PAD_SINK) {
2101 if (direction == GST_PAD_SINK) {
2115 if (direction == GST_PAD_SINK) {
2146 GstPadDirection direction, GstCaps * caps, GstCaps * filtercap)
2150 GstStructure *structure;
2155 silent_debug (filter,
"Calling TransformCaps, direction = %d\n", direction);
2159 result = gst_caps_new_empty ();
2160 for (i = 0; i < gst_caps_get_size (caps); i++) {
2163 gboolean is_types_not_fixed =
FALSE;
2164 GstCaps *result_aux = gst_caps_new_empty ();
2168 structure = gst_caps_get_structure (caps, i);
2180 j, in_info, out_info);
2183 is_types_not_fixed =
TRUE;
2198 if (is_types_not_fixed) {
2199 GstStructure *s = gst_caps_get_structure (result_aux, 0);
2200 gst_structure_remove_field (s,
"types");
2204 gst_caps_append (
result, result_aux);
2210 if (filtercap && gst_caps_get_size (filtercap) > 0) {
2211 GstCaps *intersection;
2214 gst_caps_intersect_full (
result, filtercap, GST_CAPS_INTERSECT_FIRST);
2229 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
2236 silent_debug (filter,
"Calling FixateCaps, direction = %d\n", direction);
2242 gst_caps_unref (othercaps);
2256 GstCaps * incaps, GstCaps * outcaps)
2262 gboolean in_flexible, out_flexible;
2263 gboolean allowed =
FALSE;
2273 GST_ERROR_OBJECT (filter,
"Cannot read cap of incaps\n");
2278 GST_ERROR_OBJECT (filter,
"Cannot read cap of outcaps\n");
2299 i, in_info, out_info)) {
2300 GST_ERROR_OBJECT (filter,
2301 "Tensor info is not matched with given properties.");
2308 GST_INFO_OBJECT (filter,
"Output tensor is flexible.");
2312 out_config = config;
2314 GST_ERROR_OBJECT (filter,
2315 "Tensor info is not matched with given properties.\n");
2326 GST_ERROR_OBJECT (filter,
"Set Caps Failed!\n");
2336 GstPadDirection direction, GstCaps * caps, gsize size, GstCaps * othercaps,