--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-only */\r
+/**\r
+ * GStreamer/NNStreamer Tensor-Decoder\r
+ * Copyright (C) 2021 Gichan Jang <gichan2.jang@samsung.com>\r
+ */\r
+/**\r
+ * @file tensor_decoder_custom.h\r
+ * @date 22 Mar 2021\r
+ * @brief NNStreamer APIs for tensor_decoder custom condition\r
+ * @see https://github.com/nnstreamer/nnstreamer\r
+ * @author Gichan Jang <gichan2.jang@samsung.com>\r
+ * @bug No known bugs except for NYI items\r
+ *\r
+ */\r
+\r
+#ifndef __NNS_TENSOR_DECODER_CUSTOM_H__\r
+#define __NNS_TENSOR_DECODER_CUSTOM_H__\r
+\r
+#include <glib.h>\r
+#include <gst/gst.h>\r
+#include "tensor_typedef.h"\r
+\r
+G_BEGIN_DECLS\r
+/**\r
+ * @brief Decode from tensors to media as customized operation\r
+ * @param[in] input the input memory containg tensors\r
+ * @param[in] config input tensors config\r
+ * @param[in] data private data for the callback\r
+ * @param[out] output buffer filled by user\r
+ * @return 0 if success. -ERRNO if error.\r
+ */\r
+typedef int (* tensor_decoder_custom) (const GstTensorMemory *input,\r
+ const GstTensorsConfig *config, void *data, GstBuffer * out_buf);\r
+\r
+/**\r
+ * @brief Register the custom callback function.\r
+ * @param[in] name The name of tensor_decoder custom callback function.\r
+ * @param[in] func The custom condition function body\r
+ * @param[in/out] data The internal data for the function\r
+ * @return 0 if success. -ERRNO if error.\r
+ */\r
+extern int\r
+nnstreamer_decoder_custom_register (const gchar *name, tensor_decoder_custom func, void *data);\r
+\r
+/**\r
+ * @brief Unregister the custom callback function.\r
+ * @param[in] name The registered name of tensor_decoder custom callback function.\r
+ * @return 0 if success. -ERRNO if error.\r
+ */\r
+extern int\r
+nnstreamer_decoder_custom_unregister (const gchar *name);\r
+\r
+G_END_DECLS\r
+#endif /*__NNS_TENSOR_DECODER_CUSTOM_H__*/\r
g_return_val_if_fail (config != NULL, NULL);
if (self->decoder == NULL) {
+ if (self->is_custom) {
+ GstCaps *caps;
+ caps = gst_caps_from_string ("application/octet-stream");
+ if (config->rate_n >= 0 && config->rate_d > 0)
+ gst_caps_set_simple (caps, "framerate",
+ GST_TYPE_FRACTION, config->rate_n, config->rate_d, NULL);
+ return caps;
+ }
GST_ERROR_OBJECT (self, "Decoder plugin is not yet configured.");
return NULL;
}
self->negotiated = FALSE;
self->decoder = NULL;
self->plugin_data = NULL;
-
+ self->is_custom = FALSE;
+ self->custom.func = NULL;
+ self->custom.data = NULL;
for (i = 0; i < TensorDecMaxOpNum; i++)
self->option[i] = NULL;
guint i;
mode_string = g_value_get_string (value);
+ if (g_ascii_strcasecmp (mode_string, "custom-code") == 0) {
+ self->is_custom = TRUE;
+ break;
+ }
+
decoder = nnstreamer_decoder_find (mode_string);
/* See if we are using "plugin" */
gst_tensor_decoder_clean_plugin (self);
self->decoder = NULL;
}
-
break;
}
PROP_MODE_OPTION (1);
PROP_MODE_OPTION (7);
PROP_MODE_OPTION (8);
PROP_MODE_OPTION (9);
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_set_boolean (value, self->silent);
break;
case PROP_MODE:
- if (self->decoder)
+ if (self->is_custom)
+ g_value_set_string (value, "custom");
+ else if (self->decoder)
g_value_set_string (value, self->decoder->modename);
else
g_value_set_string (value, "");
for (i = 0; i < TensorDecMaxOpNum; ++i) {
g_free (self->option[i]);
}
+ self->custom.func = NULL;
+ self->custom.data = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
return FALSE;
}
- if (self->decoder == NULL) {
+ if (self->decoder == NULL && !self->is_custom) {
GST_ERROR_OBJECT (self, "Decoder plugin is not yet configured.");
return FALSE;
}
if (G_UNLIKELY (!self->configured))
goto unknown_format;
- if (self->decoder) {
+ if (self->decoder || self->is_custom) {
GstMemory *in_mem[NNS_TENSOR_SIZE_LIMIT];
GstMapInfo in_info[NNS_TENSOR_SIZE_LIMIT];
GstTensorMemory input[NNS_TENSOR_SIZE_LIMIT];
input[i].data = in_info[i].data;
input[i].size = in_info[i].size;
}
-
- res = self->decoder->decode (&self->plugin_data, &self->tensor_config,
- input, outbuf);
+ if (!self->is_custom) {
+ res = self->decoder->decode (&self->plugin_data, &self->tensor_config,
+ input, outbuf);
+ } else if (self->custom.func != NULL) {
+ res = self->custom.func (input, &self->tensor_config, self->custom.data,
+ outbuf);
+ } else {
+ GST_ERROR_OBJECT (self, "Custom decoder callback is not registered.");
+ res = GST_FLOW_ERROR;
+ }
for (i = 0; i < num_tensors; i++)
gst_memory_unmap (in_mem[i], &in_info[i]);
self = GST_TENSOR_DECODER_CAST (trans);
/* Not ready */
- if (self->decoder == NULL)
+ if (self->decoder == NULL && !self->is_custom)
return NULL;
+ if (self->is_custom) {
+ const decoder_custom_cb_s *ptr = NULL;
+ if (self->option[0] == NULL) {
+ nns_logw ("Tensor decoder custom option is not given.");
+ return NULL;
+ }
+ self->custom.func = NULL;
+ ptr = get_subplugin (NNS_CUSTOM_DECODER, self->option[0]);
+ if (!ptr) {
+ nns_logw ("Failed to find custom subplugin of the tensor_decoder");
+ return NULL;
+ }
+ self->custom.func = ptr->func;
+ self->custom.data = ptr->data;
+ }
+
silent_debug ("Direction = %d\n", direction);
silent_debug_caps (caps, "from");
silent_debug_caps (filter, "filter");
gst_tensordec_set_caps (GstBaseTransform * trans,
GstCaps * incaps, GstCaps * outcaps)
{
- GstTensorDec *self;
-
- self = GST_TENSOR_DECODER_CAST (trans);
+ GstTensorDec *self = GST_TENSOR_DECODER_CAST (trans);
silent_debug_caps (incaps, "from incaps");
silent_debug_caps (outcaps, "from outcaps");
self = GST_TENSOR_DECODER_CAST (trans);
g_assert (self->configured);
- g_assert (self->decoder);
- if (self->decoder->getTransformSize)
+ if (!self->is_custom && self->decoder->getTransformSize)
*othersize = self->decoder->getTransformSize (&self->plugin_data,
&self->tensor_config, caps, size, othercaps, direction);
else
return TRUE;
}
+
+/**
+ * @brief Registers a callback for tensor_decoder custom condition
+ * @return 0 if success. -ERRNO if error.
+ */
+int
+nnstreamer_decoder_custom_register (const gchar * name,
+ tensor_decoder_custom func, void *data)
+{
+ decoder_custom_cb_s *ptr;
+
+ g_return_val_if_fail (name && strlen (name), -EINVAL);
+ g_return_val_if_fail (func, -EINVAL);
+
+ if (!(ptr = g_try_new0 (decoder_custom_cb_s, 1)))
+ return -ENOMEM;
+
+ ptr->func = func;
+ ptr->data = data;
+
+ if (register_subplugin (NNS_CUSTOM_DECODER, name, ptr) == TRUE)
+ return 0;
+
+ g_free (ptr);
+ return -EINVAL;
+}
+
+/**
+ * @brief Unregisters a callback for tensor_decoder custom condition
+ * @return 0 if success. -ERRNO if error.
+ */
+int
+nnstreamer_decoder_custom_unregister (const gchar * name)
+{
+ decoder_custom_cb_s *ptr;
+
+ ptr = (decoder_custom_cb_s *) get_subplugin (NNS_CUSTOM_DECODER, name);
+ if (!unregister_subplugin (NNS_CUSTOM_DECODER, name)) {
+ ml_loge ("Failed to unregister custom callback %s.", name);
+ return -EINVAL;
+ }
+ g_free (ptr);
+
+ return 0;
+}