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 GstStructure *structure;
685 structure = gst_caps_get_structure (caps, 0);
700 switch (GST_EVENT_TYPE (event)) {
704 gst_event_parse_caps (event, &caps);
706 GST_ERROR_OBJECT (tensor_if,
"Failed to parse caps.\n");
715 return gst_pad_event_default (pad, parent, event);
734 GstCaps *caps = NULL;
739 if (nth == pad->
nth) {
750 GST_DEBUG_OBJECT (tensor_if,
"creating pad: %d(%dth)",
753 name = g_strdup_printf (
"src_%d", nth);
754 pad = gst_pad_new_from_static_template (&
src_factory, name);
757 tensorpad->
pad = pad;
758 tensorpad->
nth = nth;
760 tensorpad->
last_ts = GST_CLOCK_TIME_NONE;
762 tensor_if->
srcpads = g_slist_append (tensor_if->
srcpads, tensorpad);
765 gst_pad_use_fixed_caps (pad);
766 gst_pad_set_active (pad,
TRUE);
767 gst_element_add_pad (GST_ELEMENT_CAST (tensor_if), pad);
772 gst_pad_set_caps (pad, caps);
774 gst_caps_unref (caps);
797 if (ret != GST_FLOW_NOT_LINKED)
800 for (walk = tensor_if->
srcpads; walk; walk = g_slist_next (walk)) {
803 if (ret != GST_FLOW_NOT_LINKED)
813 #define operator_func(cv,t,op,sv1,sv2,ret) do { \
815 case TIFOP_EQ: ret = (cv._
816 case TIFOP_NE: ret = (cv._
817 case TIFOP_GT: ret = (cv._
818 case TIFOP_GE: ret = (cv._
819 case TIFOP_LT: ret = (cv._
820 case TIFOP_LE: ret = (cv._
821 case TIFOP_RANGE_INCLUSIVE: \
823 case TIFOP_RANGE_EXCLUSIVE: \
825 case TIFOP_NOT_IN_RANGE_INCLUSIVE: \
827 case TIFOP_NOT_IN_RANGE_EXCLUSIVE: \
840 gboolean ret =
FALSE;
893 GST_ERROR_OBJECT (tensor_if,
"Unknown tensor type %d",
cv->
type);
914 if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
915 GST_WARNING_OBJECT (tensor_if,
"Failed to map the input buffer.");
916 gst_memory_unref (in_mem);
925 gst_memory_unmap (in_mem, &in_info);
926 gst_memory_unref (in_mem);
944 switch (tensor_if->
cv) {
950 uint32_t idx = 0, nth, i, offset = 1;
952 const uint32_t *in_dim;
956 GST_ERROR_OBJECT (tensor_if,
957 "Please specify a proper 'compared-value-option' property, e.g., 0:1:2:3,0");
960 for (list = tensor_if->
cv_option; list->next != NULL; list = list->next) {
961 target[idx++] = GPOINTER_TO_INT (list->data);
964 nth = GPOINTER_TO_INT (list->data);
966 GST_ERROR_OBJECT (tensor_if,
"Index should be lower than buffer size");
971 in_type = _info->
type;
975 if (!gst_memory_map (in_mem, &in_info, GST_MAP_READ)) {
976 GST_WARNING_OBJECT (tensor_if,
"Failed to map the input buffer.");
977 gst_memory_unref (in_mem);
984 offset *= in_dim[i - 1];
985 idx += (target[i]) * offset;
991 gst_memory_unmap (in_mem, &in_info);
992 gst_memory_unref (in_mem);
998 if (g_list_length (tensor_if->
cv_option) != 1) {
999 GST_ERROR_OBJECT (tensor_if,
1000 "Please specify a proper 'compared-value-option' property, For TENSOR_AVERAGE_VALUE, specify only one tensor. Tensors is not supported.");
1003 nth = GPOINTER_TO_INT (tensor_if->
cv_option->data);
1005 GST_ERROR_OBJECT (tensor_if,
"Index should be lower than buffer size");
1011 GST_ERROR_OBJECT (tensor_if,
1012 "Compared value is not supported yet or not defined");
1028 g_return_val_if_fail (name && strlen (name), -EINVAL);
1029 g_return_val_if_fail (func, -EINVAL);
1055 ml_loge (
"Failed to unregister custom callback %s.", name);
1073 gboolean ret =
FALSE;
1082 nns_loge (
"custom condition of the tensor_if is not configured.");
1088 if (!gst_memory_map (in_mem[i], &in_info[i], GST_MAP_READ)) {
1089 for (j = 0; j < i; j++) {
1090 gst_memory_unmap (in_mem[j], &in_info[j]);
1091 gst_memory_unref (in_mem[j]);
1093 gst_memory_unref (in_mem[i]);
1095 GST_WARNING_OBJECT (tensor_if,
"Cannot map input buffer(%d)\n", i);
1098 in_tensors[i].
data = in_info[i].data;
1099 in_tensors[i].
size = in_info[i].size;
1106 gst_memory_unmap (in_mem[i], &in_info[i]);
1107 gst_memory_unref (in_mem[i]);
1112 GST_ERROR_OBJECT (tensor_if,
" failed to calculate compared value");
1115 ret = gst_tensor_if_get_comparison_result (tensor_if, &
cv,
result);
1124 static GstFlowReturn
1127 guint num_tensors, i;
1128 GstFlowReturn res = GST_FLOW_OK;
1130 gboolean condition_result =
FALSE;
1133 GList *curr_act_option = NULL;
1136 GstBuffer *outbuf = NULL;
1137 GstMemory *mem = NULL;
1143 GST_DEBUG_OBJECT (tensor_if,
" Number of Tensors: %u", num_tensors);
1148 GST_ERROR_OBJECT (tensor_if,
" Failed to check condition");
1149 return GST_FLOW_ERROR;
1152 if (condition_result) {
1162 config = &tensor_if->
out_config[which_srcpad];
1174 outbuf = gst_buffer_ref (buf);
1183 outbuf = gst_buffer_new ();
1184 for (list = curr_act_option; list != NULL; list = list->next) {
1185 i = GPOINTER_TO_INT (list->data);
1204 GST_DEBUG_OBJECT (tensor_if,
" Not defined behavior");
1213 gst_segment_init (&segment, GST_FORMAT_TIME);
1214 gst_pad_push_event (srcpad->
pad, gst_event_new_segment (&segment));
1217 outbuf = gst_buffer_make_writable (outbuf);
1220 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1222 ts = GST_BUFFER_TIMESTAMP (buf);
1223 if (srcpad->
last_ts == GST_CLOCK_TIME_NONE || srcpad->
last_ts != ts) {
1226 GST_DEBUG_OBJECT (tensor_if,
"invalid timestamp %" GST_TIME_FORMAT,
1227 GST_TIME_ARGS (ts));
1230 res = gst_pad_push (srcpad->
pad, outbuf);
1234 gst_buffer_unref (buf);