82 #define DBG (!tensor_if->silent)
103 #define GST_CAT_DEFAULT gst_tensor_if_debug
105 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT "; " GST_TENSORS_CAP_DEFAULT
109 static GstStaticPadTemplate
sink_factory = GST_STATIC_PAD_TEMPLATE (
"sink",
117 static GstStaticPadTemplate
src_factory = GST_STATIC_PAD_TEMPLATE (
"src",
122 #define gst_tensor_if_parent_class parent_class
127 const GValue * value, GParamSpec * pspec);
129 GValue * value, GParamSpec * pspec);
139 #define GST_TYPE_TENSOR_IF_CV (gst_tensor_if_cv_get_type ())
147 static GType mode_type = 0;
149 if (mode_type == 0) {
150 static GEnumValue mode_types[] = {
151 {
TIFCV_A_VALUE,
"A_VALUE",
"Decide based on a single scalar value"},
153 "Decide based on a average value of a specific tensor"},
154 {
TIFCV_CUSTOM,
"CUSTOM",
"Decide based on a user defined callback"},
157 mode_type = g_enum_register_static (
"tensor_if_compared_value", mode_types);
163 #define GST_TYPE_TENSOR_IF_OP (gst_tensor_if_op_get_type ())
171 static GType mode_type = 0;
173 if (mode_type == 0) {
174 static GEnumValue mode_types[] = {
178 {
TIFOP_GE,
"GE",
"greater_or_equal"},
184 "not in range inclusive"},
186 "not in range exclusive"},
189 mode_type = g_enum_register_static (
"tensor_if_operator", mode_types);
195 #define GST_TYPE_TENSOR_IF_ACT (gst_tensor_if_act_get_type ())
203 static GType mode_type = 0;
205 if (mode_type == 0) {
206 static GEnumValue mode_types[] = {
212 mode_type = g_enum_register_static (
"tensor_if_behavior", mode_types);
224 GObjectClass *gobject_class;
225 GstElementClass *gstelement_class;
227 GST_DEBUG_CATEGORY_INIT (gst_tensor_if_debug,
"tensor_if", 0,
228 "Tensor if to control streams based on tensor(s) values");
230 gobject_class = (GObjectClass *) klass;
231 gstelement_class = (GstElementClass *) klass;
233 parent_class = g_type_class_peek_parent (klass);
241 gst_element_class_set_details_simple (gstelement_class,
244 "Controls streams based on the tensor(s) values",
245 "MyungJoo Ham <myungjoo.ham@samsung.com>");
247 gst_element_class_add_pad_template (gstelement_class,
249 gst_element_class_add_pad_template (gstelement_class,
268 gst_element_add_pad (GST_ELEMENT_CAST (tensor_if), tensor_if->
sinkpad);
269 gst_pad_set_chain_function (tensor_if->
sinkpad,
271 gst_pad_set_event_function (tensor_if->
sinkpad,
283 g_mutex_init (&tensor_if->
lock);
292 while (tensor_if->
srcpads != NULL) {
294 gst_element_remove_pad (GST_ELEMENT (tensor_if), tensor_pad->
pad);
310 g_mutex_clear (&tensor_if->
lock);
321 G_OBJECT_CLASS (parent_class)->dispose (
object);
329 const gchar * delimiters)
332 const gchar *param = g_value_get_string (value);
333 gchar **strv = g_strsplit_set (param, delimiters, -1);
334 gint i, num = g_strv_length (strv);
336 g_list_free (*prop_list);
339 for (i = 0; i < num; i++) {
340 val = g_ascii_strtoll (strv[i], NULL, 10);
341 if (errno == ERANGE) {
342 ml_loge (
"Overflow occurred during converting %s to a gint64 value",
345 *prop_list = g_list_append (*prop_list, GINT_TO_POINTER (val));
358 const gchar *param = g_value_get_string (value);
359 gchar **strv = g_strsplit_set (param,
",", -1);
360 GValue tmp = G_VALUE_INIT;
362 length = g_strv_length (strv);
366 (
"Invalid compared value option. It should be in the form of 'IDX_DIM0: ... :INDEX_DIM_LAST,nth-tensor'(A_VALUE) or 'nth-tensor' (TENSOR_AVERAGE_VALUE)");
371 g_value_init (&tmp, G_TYPE_STRING);
378 length = g_list_length (*prop_list);
382 *prop_list = g_list_append (*prop_list, GINT_TO_POINTER (0));
385 val = g_ascii_strtoll (strv[1], NULL, 10);
386 if (errno == ERANGE) {
387 ml_loge (
"Overflow occurred during converting %s to a gint64 value",
390 *prop_list = g_list_append (*prop_list, GINT_TO_POINTER (val));
393 g_value_reset (&tmp);
404 gboolean is_float =
FALSE;
405 const gchar *param = g_value_get_string (value);
406 gchar **strv = g_strsplit_set (param, delimiters, -1);
407 gint num = g_strv_length (strv);
410 ml_loge (
"Invalid supplied value. The value is NULL.");
414 if (strchr (param,
'.') || strchr (param,
'E') || strchr (param,
'e')) {
419 for (i = 0; i < num; i++) {
422 sv->
data[i].
_double = g_ascii_strtod (strv[i], NULL);
425 sv->
data[i].
_int64_t = g_ascii_strtoll (strv[i], NULL, 10);
437 if (!self->custom.name)
443 nns_logw (
"Failed to find custom subplugin of the tensor_if");
446 self->custom_configured =
TRUE;
447 self->custom.func = (*ptr).func;
448 self->custom.data = (*ptr).data;
457 const GValue * value, GParamSpec * pspec)
463 self->cv = g_value_get_enum (value);
467 g_free (self->custom.name);
468 self->custom.name = g_value_dup_string (value);
473 self->op = g_value_get_enum (value);
479 self->act_then = g_value_get_enum (value);
485 self->act_else = g_value_get_enum (value);
491 self->silent = g_value_get_boolean (value);
494 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
512 if (prop_list == NULL) {
517 arr = g_ptr_array_new ();
518 for (list = prop_list; list != NULL; list = list->next) {
519 g_ptr_array_add (arr, g_strdup_printf (
"%i", GPOINTER_TO_INT (list->data)));
521 g_ptr_array_add (arr, NULL);
527 gchar *tensor = (gchar *) g_ptr_array_index (arr, len - 2);
528 g_ptr_array_remove_index (arr, len - 2);
529 strings = (gchar **) g_ptr_array_free (arr,
FALSE);
530 dim = g_strjoinv (
":", strings);
531 p = g_strjoin (
",", dim, tensor, NULL);
535 strings = (gchar **) g_ptr_array_free (arr,
FALSE);
536 p = g_strjoinv (
",", strings);
539 g_strfreev (strings);
540 g_value_take_string (value, p);
554 if (sv == NULL || sv->
num == 0) {
559 arr = g_ptr_array_new ();
560 for (i = 0; i < sv->
num; i++) {
562 g_ptr_array_add (arr, g_strdup_printf (
"%lf", sv->
data[i].
_double));
564 g_ptr_array_add (arr, g_strdup_printf (
"%ld",
568 g_ptr_array_add (arr, NULL);
569 strings = (gchar **) g_ptr_array_free (arr,
FALSE);
570 p = g_strjoinv (
",", strings);
571 g_strfreev (strings);
572 g_value_take_string (value, p);
580 GValue * value, GParamSpec * pspec)
586 g_value_set_enum (value, self->cv);
596 g_value_set_enum (value, self->op);
602 g_value_set_enum (value, self->act_then);
608 g_value_set_enum (value, self->act_else);
614 g_value_set_boolean (value, self->silent);
617 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
629 g_object_class_install_property (gobject_class,
PROP_SILENT,
630 g_param_spec_boolean (
"silent",
"Silent",
"Produce verbose output",
631 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
633 g_object_class_install_property (gobject_class,
PROP_CV,
634 g_param_spec_enum (
"compared-value",
"CV",
639 g_param_spec_string (
"compared-value-option",
"CV_OPTION",
640 "Specify an element of the nth tensor or pick tensor ",
"",
641 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
643 g_object_class_install_property (gobject_class,
PROP_SV,
644 g_param_spec_string (
"supplied-value",
"SV",
645 " Supplied Value by user ",
"",
646 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
648 g_object_class_install_property (gobject_class,
PROP_OP,
649 g_param_spec_enum (
"operator",
"OP",
"Comparison Operator",
651 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
653 g_object_class_install_property (gobject_class,
PROP_THEN,
654 g_param_spec_enum (
"then",
"THEN",
"Action if it is TRUE",
656 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
659 g_param_spec_string (
"then-option",
"THEN_OPTION",
660 "Pick tensor ",
"", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
662 g_object_class_install_property (gobject_class,
PROP_ELSE,
663 g_param_spec_enum (
"else",
"ELSE",
"Action if it is FALSE",
665 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
668 g_param_spec_string (
"else-option",
"ELSE_OPTION",
669 "Pick tensor ",
"", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
681 switch (GST_EVENT_TYPE (event)) {
685 gst_event_parse_caps (event, &caps);
687 GST_ERROR_OBJECT (tensor_if,
"Failed to parse caps.\n");
688 gst_event_unref (event);
697 return gst_pad_event_default (pad, parent, event);
716 GstCaps *caps = NULL;
721 if (nth == pad->
nth) {
732 GST_DEBUG_OBJECT (tensor_if,
"creating pad: %d(%dth)",
735 name = g_strdup_printf (
"src_%d", nth);
736 pad = gst_pad_new_from_static_template (&
src_factory, name);
739 tensorpad->
pad = pad;
740 tensorpad->
nth = nth;
742 tensorpad->
last_ts = GST_CLOCK_TIME_NONE;
744 tensor_if->
srcpads = g_slist_append (tensor_if->
srcpads, tensorpad);
747 gst_pad_use_fixed_caps (pad);
748 gst_pad_set_active (pad,
TRUE);
749 gst_element_add_pad (GST_ELEMENT_CAST (tensor_if), pad);
754 gst_pad_set_caps (pad, caps);
756 gst_caps_unref (caps);
779 if (ret != GST_FLOW_NOT_LINKED)
782 for (walk = tensor_if->
srcpads; walk; walk = g_slist_next (walk)) {
785 if (ret != GST_FLOW_NOT_LINKED)
795 #define operator_func(cv,t,op,sv1,sv2,ret) do { \
797 case TIFOP_EQ: ret = (cv._
798 case TIFOP_NE: ret = (cv._
799 case TIFOP_GT: ret = (cv._
800 case TIFOP_GE: ret = (cv._
801 case TIFOP_LT: ret = (cv._
802 case TIFOP_LE: ret = (cv._
803 case TIFOP_RANGE_INCLUSIVE: \
805 case TIFOP_RANGE_EXCLUSIVE: \
807 case TIFOP_NOT_IN_RANGE_INCLUSIVE: \
809 case TIFOP_NOT_IN_RANGE_EXCLUSIVE: \
822 gboolean ret =
FALSE;
875 GST_ERROR_OBJECT (tensor_if,
"Unknown tensor type %d",
cv->
type);
896 if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
897 GST_WARNING_OBJECT (tensor_if,
"Failed to map the input buffer.");
898 gst_memory_unref (in_mem);
907 gst_memory_unmap (in_mem, &in_info);
908 gst_memory_unref (in_mem);
926 switch (tensor_if->
cv) {
932 uint32_t idx = 0, nth, i, offset = 1;
934 const uint32_t *in_dim;
938 GST_ERROR_OBJECT (tensor_if,
939 "Please specify a proper 'compared-value-option' property, e.g., 0:1:2:3,0");
942 for (list = tensor_if->
cv_option; list->next != NULL; list = list->next) {
943 target[idx++] = GPOINTER_TO_INT (list->data);
946 nth = GPOINTER_TO_INT (list->data);
948 GST_ERROR_OBJECT (tensor_if,
"Index should be lower than buffer size");
953 in_type = _info->
type;
957 if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
958 GST_WARNING_OBJECT (tensor_if,
"Failed to map the input buffer.");
959 gst_memory_unref (in_mem);
966 offset *= in_dim[i - 1];
967 idx += (target[i]) * offset;
973 gst_memory_unmap (in_mem, &in_info);
974 gst_memory_unref (in_mem);
980 if (g_list_length (tensor_if->
cv_option) != 1) {
981 GST_ERROR_OBJECT (tensor_if,
982 "Please specify a proper 'compared-value-option' property, For TENSOR_AVERAGE_VALUE, specify only one tensor. Tensors is not supported.");
985 nth = GPOINTER_TO_INT (tensor_if->
cv_option->data);
987 GST_ERROR_OBJECT (tensor_if,
"Index should be lower than buffer size");
993 GST_ERROR_OBJECT (tensor_if,
994 "Compared value is not supported yet or not defined");
1010 g_return_val_if_fail (name && strlen (name), -EINVAL);
1011 g_return_val_if_fail (func, -EINVAL);
1037 ml_loge (
"Failed to unregister custom callback %s.", name);
1055 gboolean ret =
FALSE;
1064 nns_loge (
"custom condition of the tensor_if is not configured.");
1070 if (!gst_memory_map (in_mem[i], &in_info[i], GST_MAP_READ)) {
1071 for (j = 0; j < i; j++) {
1072 gst_memory_unmap (in_mem[j], &in_info[j]);
1073 gst_memory_unref (in_mem[j]);
1075 gst_memory_unref (in_mem[i]);
1077 GST_WARNING_OBJECT (tensor_if,
"Cannot map input buffer(%d)\n", i);
1080 in_tensors[i].
data = in_info[i].data;
1081 in_tensors[i].
size = in_info[i].size;
1088 gst_memory_unmap (in_mem[i], &in_info[i]);
1089 gst_memory_unref (in_mem[i]);
1094 GST_ERROR_OBJECT (tensor_if,
" failed to calculate compared value");
1097 ret = gst_tensor_if_get_comparison_result (tensor_if, &
cv,
result);
1106 static GstFlowReturn
1109 guint num_tensors, i;
1110 GstFlowReturn res = GST_FLOW_OK;
1112 gboolean condition_result =
FALSE;
1115 GList *curr_act_option = NULL;
1118 GstBuffer *outbuf = NULL;
1119 GstMemory *mem = NULL;
1125 GST_DEBUG_OBJECT (tensor_if,
" Number of Tensors: %u", num_tensors);
1130 GST_ERROR_OBJECT (tensor_if,
" Failed to check condition");
1131 return GST_FLOW_ERROR;
1134 if (condition_result) {
1144 config = &tensor_if->
out_config[which_srcpad];
1156 outbuf = gst_buffer_ref (buf);
1165 outbuf = gst_buffer_new ();
1166 for (list = curr_act_option; list != NULL; list = list->next) {
1167 i = GPOINTER_TO_INT (list->data);
1186 GST_DEBUG_OBJECT (tensor_if,
" Not defined behavior");
1195 gst_segment_init (&segment, GST_FORMAT_TIME);
1196 gst_pad_push_event (srcpad->
pad, gst_event_new_segment (&segment));
1199 outbuf = gst_buffer_make_writable (outbuf);
1202 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1204 ts = GST_BUFFER_TIMESTAMP (buf);
1205 if (srcpad->
last_ts == GST_CLOCK_TIME_NONE || srcpad->
last_ts != ts) {
1208 GST_DEBUG_OBJECT (tensor_if,
"invalid timestamp %" GST_TIME_FORMAT,
1209 GST_TIME_ARGS (ts));
1212 res = gst_pad_push (srcpad->
pad, outbuf);
1216 gst_buffer_unref (buf);