69 #define TEXT_CAPS_STR "text/x-raw, format = (string) utf8"
71 #define append_text_caps_template(caps) \
72 gst_caps_append (caps, gst_caps_from_string (TEXT_CAPS_STR))
77 #define OCTET_CAPS_STR "application/octet-stream"
79 #define append_octet_caps_template(caps) \
80 gst_caps_append (caps, gst_caps_from_string (OCTET_CAPS_STR))
85 #define append_flex_tensor_caps_template(caps) \
86 gst_caps_append (caps, gst_caps_from_string (GST_TENSORS_FLEX_CAP_DEFAULT))
92 #define DBG (!self->silent)
95 #define silent_debug_timestamp(self, buf) do { \
97 GST_DEBUG_OBJECT (self, "pts = %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (buf))); \
98 GST_DEBUG_OBJECT (self, "dts = %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_DTS (buf))); \
99 GST_DEBUG_OBJECT (self, "duration = %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (GST_BUFFER_DURATION (buf))); \
104 #define GST_CAT_DEFAULT gst_tensor_converter_debug
106 #define STRING_CUSTOM_MODE(self) \
107 (((self)->mode == _CONVERTER_MODE_CUSTOM_CODE) ? \
108 "custom_code (function)" : \
109 (((self)->mode == _CONVERTER_MODE_CUSTOM_SCRIPT) ? \
110 "custom_script (py)" : \
111 "unknown custom mode (internal error!)"))
132 #define DEFAULT_SET_TIMESTAMP TRUE
137 #define DEFAULT_SILENT TRUE
142 #define DEFAULT_FRAMES_PER_TENSOR 1
144 #define gst_tensor_converter_parent_class parent_class
149 guint prop_id,
const GValue * value, GParamSpec * pspec);
151 guint prop_id, GValue * value, GParamSpec * pspec);
154 GstObject * parent, GstEvent * event);
156 GstObject * parent, GstQuery * query);
158 GstObject * parent, GstQuery * query);
160 GstObject * parent, GstBuffer * buf);
161 static GstStateChangeReturn
163 GstStateChange transition);
167 GstPad * pad, GstCaps * filter);
169 const GstCaps * caps);
180 GObjectClass *object_class;
181 GstElementClass *element_class;
182 GstPadTemplate *pad_template;
188 GST_DEBUG_CATEGORY_INIT (gst_tensor_converter_debug,
"tensor_converter", 0,
189 "Element to convert media stream to tensor stream");
191 object_class = (GObjectClass *) klass;
192 element_class = (GstElementClass *) klass;
208 g_param_spec_string (
"input-dim",
"Input tensor dimension",
209 "Input tensor dimension from inner array",
"",
210 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
221 g_param_spec_string (
"input-type",
"Input tensor type",
222 "Type of each element of the input tensor",
"",
223 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
232 g_param_spec_uint (
"frames-per-tensor",
"Frames per tensor",
233 "The number of frames in output tensor", 1, G_MAXUINT,
235 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
243 g_param_spec_boolean (
"set-timestamp",
"Set timestamp",
244 "The flag to set timestamp when received a buffer with invalid timestamp",
253 g_param_spec_string (
"sub-plugins",
"Sub-plugins",
254 "Registrable sub-plugins list",
"",
255 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
262 g_object_class_install_property (object_class,
PROP_SILENT,
263 g_param_spec_boolean (
"silent",
"Silent",
"Produce verbose output",
271 g_object_class_install_property (object_class,
PROP_MODE,
272 g_param_spec_string (
"mode",
"Mode",
273 "Converter mode. e.g., mode=custom-code:<registered callback name>. For detail, refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter",
274 "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
281 pad_template = gst_pad_template_new (
"src", GST_PAD_SRC, GST_PAD_ALWAYS,
283 gst_element_class_add_pad_template (element_class, pad_template);
285 gst_caps_unref (pad_caps);
288 pad_caps = gst_caps_new_empty ();
300 total = g_strv_length (str_array);
302 for (i = 0; i < total; i++) {
305 gst_caps_append (pad_caps, ex->
query_caps (NULL));
308 g_strfreev (str_array);
311 pad_template = gst_pad_template_new (
"sink", GST_PAD_SINK, GST_PAD_ALWAYS,
313 gst_element_class_add_pad_template (element_class, pad_template);
315 gst_caps_unref (pad_caps);
317 gst_element_class_set_static_metadata (element_class,
320 "Converts an audio, video, text, or arbitrary stream to a tensor stream of C-Array for neural network framework filters",
321 "MyungJoo Ham <myungjoo.ham@samsung.com>");
335 gst_pad_new_from_template (gst_element_class_get_pad_template
336 (GST_ELEMENT_GET_CLASS (
self),
"sink"),
"sink");
337 gst_pad_set_event_function (self->sinkpad,
339 gst_pad_set_query_function (self->sinkpad,
341 gst_pad_set_chain_function (self->sinkpad,
343 GST_PAD_SET_PROXY_CAPS (self->sinkpad);
344 gst_element_add_pad (GST_ELEMENT (
self), self->sinkpad);
348 gst_pad_new_from_template (gst_element_class_get_pad_template
349 (GST_ELEMENT_GET_CLASS (
self),
"src"),
"src");
350 gst_pad_set_query_function (self->srcpad,
352 GST_PAD_SET_PROXY_CAPS (self->srcpad);
353 gst_element_add_pad (GST_ELEMENT (
self), self->srcpad);
360 self->frame_size = 0;
361 self->remove_padding =
FALSE;
362 self->externalConverter = NULL;
363 self->priv_data = NULL;
365 self->mode_option = NULL;
366 self->custom.func = NULL;
367 self->custom.data = NULL;
368 self->do_not_append_header =
FALSE;
371 self->tensors_configured =
FALSE;
391 g_hash_table_destroy (self->adapter_table);
393 g_free (self->mode_option);
395 self->custom.func = NULL;
396 self->custom.data = NULL;
397 if (self->externalConverter && self->externalConverter->close)
398 self->externalConverter->close (&self->priv_data);
399 G_OBJECT_CLASS (parent_class)->finalize (
object);
407 const GValue * value, GParamSpec * pspec)
413 const gchar *value_str;
416 info = &
self->tensors_info;
420 value_str = g_value_get_string (value);
424 GST_WARNING (
"%s is invalid dimension string.", value_str);
426 GST_WARNING (
"%s, the number of tensor is %u.", value_str, num);
440 value_str = g_value_get_string (value);
444 GST_WARNING (
"%s is invalid type string.", value_str);
446 GST_WARNING (
"%s, the number of tensor is %u.", value_str, num);
458 self->frames_per_tensor = g_value_get_uint (value);
459 silent_debug (
self,
"Set frames in output = %d", self->frames_per_tensor);
462 self->set_timestamp = g_value_get_boolean (value);
463 silent_debug (
self,
"Set timestamp = %d", self->set_timestamp);
466 self->silent = g_value_get_boolean (value);
471 const gchar *param = g_value_get_string (value);
473 gchar **strv = g_strsplit_set (param,
":", -1);
474 self->custom.func = NULL;
476 if (g_strv_length (strv) < 2) {
478 (
"Tensor converter mode option is incorrect. Please specify mode option as <MODE>:<MODE_OPTION>. Refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter for detail.");
483 self->mode_option = g_strdup (strv[1]);
484 if (g_ascii_strcasecmp (strv[0],
"custom-code") == 0) {
489 (
"Failed to find custom subplugin of the tensor_converter. The custom-code for tensor_converter, \"%s\" is not registered by nnstreamer_converter_custom_register() function. Refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter for detail.",
493 self->custom.func = ptr->
func;
494 self->custom.data = ptr->
data;
495 }
else if (g_ascii_strcasecmp (strv[0],
"custom-script") == 0) {
498 self->ext_fw = g_strdup (
"python3");
505 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
515 GValue * value, GParamSpec * pspec)
521 info = &
self->tensors_info;
526 g_value_take_string (value,
540 g_value_set_uint (value, self->frames_per_tensor);
543 g_value_set_boolean (value, self->set_timestamp);
550 g_value_take_string (value, g_strjoinv (
",", str_array));
551 g_strfreev (str_array);
558 g_value_set_boolean (value, self->silent);
562 gchar *mode_str = NULL;
563 if (self->mode_option == NULL)
564 mode_str = g_strdup (
"");
568 g_strdup_printf (
"%s:%s",
"custom-code", self->mode_option);
571 g_strdup_printf (
"%s:%s",
"custom-script", self->mode_option);
573 g_value_take_string (value, mode_str);
577 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
593 GST_DEBUG_OBJECT (
self,
"Received %s event: %" GST_PTR_FORMAT,
594 GST_EVENT_TYPE_NAME (event), event);
596 switch (GST_EVENT_TYPE (event)) {
601 gst_event_parse_caps (event, &in_caps);
606 gst_event_unref (event);
609 gst_event_unref (event);
614 case GST_EVENT_FLUSH_STOP:
617 case GST_EVENT_SEGMENT:
621 gst_event_copy_segment (event, &seg);
622 silent_debug (
self,
"received seg %s", gst_format_get_name (seg.format));
625 self->have_segment =
TRUE;
627 if (seg.format == GST_FORMAT_TIME) {
628 return gst_pad_push_event (self->srcpad, event);
631 if (seg.format == GST_FORMAT_BYTES) {
633 self->need_segment =
TRUE;
634 gst_event_unref (event);
638 GST_ERROR_OBJECT (
self,
"Unsupported format = %s\n",
639 gst_format_get_name (seg.format));
640 gst_event_unref (event);
647 return gst_pad_event_default (pad, parent, event);
660 GST_DEBUG_OBJECT (
self,
"Received %s query: %" GST_PTR_FORMAT,
661 GST_QUERY_TYPE_NAME (query), query);
663 switch (GST_QUERY_TYPE (query)) {
669 gst_query_parse_caps (query, &filter);
672 gst_query_set_caps_result (query, caps);
673 gst_caps_unref (caps);
676 case GST_QUERY_ACCEPT_CAPS:
679 GstCaps *template_caps;
680 gboolean res =
FALSE;
682 gst_query_parse_accept_caps (query, &caps);
685 if (gst_caps_is_fixed (caps)) {
686 template_caps = gst_pad_get_pad_template_caps (pad);
688 res = gst_caps_can_intersect (template_caps, caps);
689 gst_caps_unref (template_caps);
692 gst_query_set_accept_caps_result (query, res);
699 return gst_pad_query_default (pad, parent, query);
729 GST_DEBUG_OBJECT (
self,
"Received %s query: %" GST_PTR_FORMAT,
730 GST_QUERY_TYPE_NAME (query), query);
732 switch (GST_QUERY_TYPE (query)) {
738 gst_query_parse_caps (query, &filter);
741 gst_query_set_caps_result (query, caps);
742 gst_caps_unref (caps);
749 return gst_pad_query_default (pad, parent, query);
757 if (self->need_segment) {
761 gboolean have_framerate;
763 config = &
self->tensors_config;
764 have_framerate = (config->
rate_n > 0 && config->
rate_d > 0);
768 start =
self->segment.start;
770 gst_segment_init (&seg, GST_FORMAT_TIME);
772 if (have_framerate && start > 0) {
773 start = gst_util_uint64_scale_int (start * config->
rate_d, GST_SECOND,
774 frame_size * config->
rate_n);
775 seg.start = seg.time = start;
779 self->need_segment =
FALSE;
781 gst_pad_push_event (self->srcpad, gst_event_new_segment (&seg));
788 GstBuffer * inbuf, guint frames_in)
790 if (self->set_timestamp) {
792 GstClockTime pts, duration;
793 gboolean have_framerate;
795 config = &
self->tensors_config;
796 have_framerate = (config->
rate_n > 0 && config->
rate_d > 0);
799 duration = GST_BUFFER_DURATION (inbuf);
801 if (!GST_CLOCK_TIME_IS_VALID (duration)) {
802 if (have_framerate) {
804 gst_util_uint64_scale_int ((guint64) frames_in * config->
rate_d,
805 GST_SECOND, config->
rate_n);
807 GST_BUFFER_DURATION (inbuf) = duration;
812 pts = GST_BUFFER_TIMESTAMP (inbuf);
814 if (!GST_CLOCK_TIME_IS_VALID (pts)) {
815 pts =
self->segment.start;
817 if (have_framerate) {
818 if (GST_CLOCK_TIME_IS_VALID (self->old_timestamp)) {
819 pts =
self->old_timestamp + duration;
824 clock = gst_element_get_clock (GST_ELEMENT (
self));
827 GstClockTime now, base;
829 base = gst_element_get_base_time (GST_ELEMENT (
self));
830 now = gst_clock_get_time (clock);
832 pts = (base < now) ? (now - base) : 0;
833 gst_object_unref (clock);
837 GST_BUFFER_TIMESTAMP (inbuf) = pts;
842 self->old_timestamp = GST_BUFFER_TIMESTAMP (inbuf);
849 GstBuffer *buffer = buf;
854 if (multi || gst_buffer_n_memory (buf) > 1) {
856 GstMemory *mem, *new_mem;
860 g_assert (self->frames_per_tensor == 1);
863 buffer = gst_buffer_new ();
864 mem = gst_buffer_get_all_memory (buf);
871 new_mem = gst_memory_share (mem, offset, size);
877 gst_memory_unref (mem);
884 gst_buffer_copy_into (buffer, buf, GST_BUFFER_COPY_METADATA, 0, -1);
885 gst_buffer_unref (buf);
897 GstMemory *mem, *new_mem;
903 info = &
self->tensors_config.
info;
904 buffer = gst_buffer_new ();
911 switch (self->in_media_type) {
926 gst_memory_unref (mem);
931 gst_buffer_copy_into (buffer, buf, GST_BUFFER_COPY_METADATA, 0, -1);
932 gst_buffer_unref (buf);
940 GstBuffer *buffer = buf;
948 if (!self->do_not_append_header
954 return gst_pad_push (self->srcpad, buffer);
960 GstBuffer * inbuf, guint frames_in, guint frames_out, gsize frame_size)
964 GstFlowReturn ret = GST_FLOW_OK;
965 GstClockTime pts, dts, duration;
966 gsize avail, out_size;
967 gboolean have_framerate;
969 config = &
self->tensors_config;
973 have_framerate = (config->
rate_n > 0 && config->
rate_d > 0);
975 duration = GST_BUFFER_DURATION (inbuf);
976 if (GST_CLOCK_TIME_IS_VALID (duration)) {
978 duration = gst_util_uint64_scale_int (duration, frames_out, frames_in);
981 gst_adapter_push (adapter, inbuf);
983 out_size = frames_out * frame_size;
984 while ((avail = gst_adapter_available (adapter)) >= out_size &&
985 ret == GST_FLOW_OK) {
987 guint64 pts_dist, dts_dist;
989 pts = gst_adapter_prev_pts (adapter, &pts_dist);
990 dts = gst_adapter_prev_dts (adapter, &dts_dist);
996 if (frames_in > 1 && have_framerate) {
997 if (GST_CLOCK_TIME_IS_VALID (pts)) {
999 gst_util_uint64_scale_int (pts_dist * config->
rate_d, GST_SECOND,
1000 config->
rate_n * frame_size);
1003 if (GST_CLOCK_TIME_IS_VALID (dts)) {
1005 gst_util_uint64_scale_int (dts_dist * config->
rate_d, GST_SECOND,
1006 config->
rate_n * frame_size);
1010 outbuf = gst_adapter_take_buffer (adapter, out_size);
1011 outbuf = gst_buffer_make_writable (outbuf);
1014 GST_BUFFER_PTS (outbuf) = pts;
1015 GST_BUFFER_DTS (outbuf) = dts;
1016 GST_BUFFER_DURATION (outbuf) = duration;
1027 static GstFlowReturn
1035 gsize buf_size, frame_size;
1036 guint frames_in, frames_out;
1039 buf_size = gst_buffer_get_size (buf);
1040 g_return_val_if_fail (buf_size > 0, GST_FLOW_ERROR);
1045 g_assert (self->tensors_configured);
1046 config = &
self->tensors_config;
1049 frames_out =
self->frames_per_tensor;
1056 frame_size =
self->frame_size;
1059 switch (self->in_media_type) {
1062 guint color, width, height;
1071 frame_size =
type * color * width * height;
1074 g_assert ((buf_size / self->frame_size) == 1);
1076 if (self->remove_padding) {
1077 GstMapInfo src_info, dest_info;
1079 unsigned int src_idx = 0, dest_idx = 0;
1080 size_t size, offset;
1082 if (!gst_buffer_map (buf, &src_info, GST_MAP_READ)) {
1084 (
"tensor_converter: Cannot map src buffer at tensor_converter/video. The incoming buffer (GstBuffer) for the sinkpad of tensor_converter cannot be mapped for reading.\n");
1088 inbuf = gst_buffer_new_and_alloc (frame_size);
1089 gst_buffer_memset (inbuf, 0, 0, frame_size);
1090 if (!gst_buffer_map (inbuf, &dest_info, GST_MAP_WRITE)) {
1092 (
"tensor_converter: Cannot map dest buffer at tensor_converter/video. The outgoing buffer (GstBuffer) for the srcpad of tensor_converter cannot be mapped for writing.\n");
1093 gst_buffer_unmap (buf, &src_info);
1094 gst_buffer_unref (inbuf);
1101 size = offset =
type * color * width;
1105 offset += 4 - (offset % 4);
1108 for (d0 = 0; d0 < frames_in; d0++) {
1109 for (d1 = 0; d1 < height; d1++) {
1110 memcpy (dest_info.data + dest_idx, src_info.data + src_idx, size);
1116 gst_buffer_unmap (buf, &src_info);
1117 gst_buffer_unmap (inbuf, &dest_info);
1120 gst_buffer_copy_into (inbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1126 frames_in = buf_size / frame_size;
1129 if (buf_size != frame_size) {
1130 GstMapInfo src_info, dest_info;
1131 gsize block_size = MIN (buf_size, frame_size);
1133 if (!gst_buffer_map (buf, &src_info, GST_MAP_READ)) {
1135 (
"tensor_converter: Cannot map src buffer at tensor_converter/text. The incoming buffer (GstBuffer) for the sinkpad of tensor_converter cannot be mapped for reading.\n");
1139 inbuf = gst_buffer_new_and_alloc (frame_size);
1140 gst_buffer_memset (inbuf, 0, 0, frame_size);
1141 if (!gst_buffer_map (inbuf, &dest_info, GST_MAP_WRITE)) {
1143 (
"tensor_converter: Cannot map dest buffer at tensor_converter/text. The outgoing buffer (GstBuffer) for the srcpad of tensor_converter cannot be mapped for writing.\n");
1144 gst_buffer_unmap (buf, &src_info);
1145 gst_buffer_unref (inbuf);
1149 memcpy (dest_info.data, src_info.data, block_size);
1151 gst_buffer_unmap (buf, &src_info);
1152 gst_buffer_unmap (inbuf, &dest_info);
1155 gst_buffer_copy_into (inbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1162 frame_size = buf_size;
1165 g_assert ((buf_size % frame_size) == 0);
1166 frames_in = buf_size / frame_size;
1173 GstMemory *mem, *new_mem;
1174 gsize s1, s2, hsize;
1189 inbuf = gst_buffer_new ();
1194 s1 = gst_memory_get_sizes (mem, NULL, NULL);
1210 (
"Cannot process an incoming buffer frame for tensor_converter (chain function). It appears that it is trying to convert other/tensors,format=flexible to other/tensors,format=static. Incoming buffer has invalid data size %zd, expected size is %zd (%u/%u).",
1212 gst_memory_unref (mem);
1213 gst_buffer_unref (inbuf);
1217 new_mem = gst_memory_share (mem, hsize, s1);
1218 gst_memory_unref (mem);
1222 gst_buffer_copy_into (inbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
1227 (
"Incoming buffer does not match with given tensors info. It appears that it is trying to convert other/tensors,format=flexible to other/tensors,format=static. The converted output appears not compatible with the given configuration.");
1228 gst_buffer_unref (inbuf);
1241 if (self->custom.func == NULL) {
1243 (
"Tensor converter is in custom/code mode (mode=custom-code:${funcname}), where a user code as a callback function is required. However, the required information to configure the tensor converter is not given or incorrectly given. For detail, please refer to https://github.com/nnstreamer/nnstreamer/blob/main/gst/nnstreamer/elements/gsttensor_converter.md#custom-converter. The given ${funcname} is \"%s\", which is an invalid/unregistered name.",
1247 inbuf =
self->custom.func (buf, self->custom.data, &new_config);
1249 if (inbuf == NULL) {
1251 (
"Failed to convert input streams to tensors: the converted result of the incoming buffer is NULL. The converter is custom-func with %s function, which is available and loaded, but has returned NULL buffer after the conversion.",
1255 }
else if (self->externalConverter && self->externalConverter->convert) {
1257 self->externalConverter->convert (buf, &new_config,
1260 if (inbuf == NULL) {
1262 (
"Failed to convert input streams to tensors: the converted result of the incoming buffer is NULL. The converter is using external tensor_converter subplugin (%s), which is available and loaded, but has returned NULL buffer after the conversion.",
1263 self->externalConverter->name);
1268 GST_ERROR_OBJECT (
self,
1269 "Tensor converter is in custom/script mode (mode=custom-script:${scriptpath}), where a path to a script file is required. However, it is not properly configured. The given ${scriptpath} is \"%s\".",
1274 GST_ERROR_OBJECT (
self,
1275 "Tensor converter has an undefined behavior with type _NNS_MEDIA_ANY. It should've been custom-code or custom-script mode or a corresponding external converter should've been registered (tensor_converter subplugin). However, nothing is available for the given input stream.");
1278 self->do_not_append_header =
1282 frame_size = gst_buffer_get_size (inbuf);
1286 *config = new_config;
1296 GST_ERROR_OBJECT (
self,
1297 "The incoming tensor to be converted has no type defined (INVALID). This is an internal unknown error. Please report the case to https://github.com/nnstreamer/issues with the pipeline description reproducing the error.");
1301 GST_ERROR_OBJECT (
self,
1302 "The incoming tensor to be converted has unknown type (type value not recognized: %d). This is an internal unknown error. Please report the case to https://github.com/nnstreamer/issues with the pipeline description reproducing the error.",
1303 self->in_media_type);
1308 gst_buffer_unref (buf);
1317 if (frames_in == frames_out) {
1324 frames_out, frame_size);
1327 gst_buffer_unref (buf);
1329 return GST_FLOW_ERROR;
1335 static GstStateChangeReturn
1337 GstStateChange transition)
1340 GstStateChangeReturn ret;
1344 switch (transition) {
1345 case GST_STATE_CHANGE_READY_TO_PAUSED:
1352 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1354 switch (transition) {
1355 case GST_STATE_CHANGE_PAUSED_TO_READY:
1374 self->have_segment =
FALSE;
1375 self->need_segment =
FALSE;
1376 gst_segment_init (&self->segment, GST_FORMAT_TIME);
1378 self->old_timestamp = GST_CLOCK_TIME_NONE;
1387 GValue item = G_VALUE_INIT;
1391 g_value_init (list, GST_TYPE_LIST);
1393 va_start (args, list);
1394 while ((str = va_arg (args, gchar *))) {
1395 g_value_init (&item, G_TYPE_STRING);
1398 gst_value_list_append_value (list, &item);
1399 g_value_unset (&item);
1420 #if GST_CHECK_VERSION(1, 20, 0)
1421 case GST_VIDEO_FORMAT_RGBP:
1422 case GST_VIDEO_FORMAT_BGRP:
1454 gint width, height, views;
1457 g_return_val_if_fail (config != NULL,
FALSE);
1463 char *capstr = gst_caps_to_string (caps);
1464 GST_ERROR_OBJECT (
self,
1465 "Failed to get video info from caps; gst_video_info_from_caps (&info, \"%s\") has returned FALSE, which means the given caps cannot be parsed as a video.",
1474 views = GST_VIDEO_INFO_VIEWS (&vinfo);
1477 GST_WARNING_OBJECT (
self,
1478 "Incoming video caps should have 'views=(int)1 but has views=(int)%d - ignoring all but view #0. \n",
1519 #if GST_CHECK_VERSION(1, 20, 0)
1520 case GST_VIDEO_FORMAT_RGBP:
1521 case GST_VIDEO_FORMAT_BGRP:
1529 GST_WARNING_OBJECT (
self,
1530 "The given video caps with format \"%s\" is not supported. Please use " NNS_VIDEO_FORMAT,
1548 self->remove_padding =
TRUE;
1549 silent_debug (
self,
"Set flag to remove padding, width = %d", width);
1551 #if GST_CHECK_VERSION(1, 20, 0)
1552 if (format == GST_VIDEO_FORMAT_RGBP || format == GST_VIDEO_FORMAT_BGRP) {
1553 if (self->remove_padding) {
1554 GST_ERROR_OBJECT (
self,
1555 "Padding removal is not supported for RGBP and BGRP formats. Please use width as multiple of 4. Given width: %d",
1563 GST_WARNING_OBJECT (
self,
1564 "\nYOUR STREAM CONFIGURATION INCURS PERFORMANCE DETERIORATION!\n"
1565 "Please use 4 x n as image width for inputs; the width of your input is %d.\n",
1595 g_return_val_if_fail (config != NULL,
FALSE);
1601 char *capstr = gst_caps_to_string (caps);
1602 GST_ERROR_OBJECT (
self,
1603 "Failed to get audio info from caps; gst_audio_info_from_caps(&info, \"%s\") has returned FALSE.\n",
1641 GST_WARNING_OBJECT (
self,
1642 "Audio format \"%s\" is not supported. Please use S8, U8, S16, U16, S32, U32, F32, or F64.\n",
1677 const gchar *format_string;
1680 g_return_val_if_fail (config != NULL,
FALSE);
1681 g_return_val_if_fail (structure != NULL,
FALSE);
1686 text_size =
self->tensors_info.info[0].dimension[0];
1687 if (text_size == 0) {
1688 GST_ERROR_OBJECT (
self,
1689 "Failed to get tensor info, need to update string size.");
1692 (
"tensor_converter: Please set the property input-dim to convert stream manually for text streams unlike video streams. For example, input-dim=30 to handle up to 30 bytes of string per frame.");
1696 format_string = gst_structure_get_string (structure,
"format");
1697 if (format_string) {
1698 if (g_ascii_strcasecmp (format_string,
"utf8") == 0) {
1701 GST_WARNING_OBJECT (
self,
1702 "For text streams, only utf8 streams are supported; format = \"%s\" is not supported.\n",
1719 if (gst_structure_has_field (structure,
"framerate")) {
1720 gst_structure_get_fraction (structure,
"framerate", &config->
rate_n,
1746 gboolean flexible, configured;
1749 g_return_val_if_fail (config != NULL,
FALSE);
1750 g_return_val_if_fail (structure != NULL,
FALSE);
1753 flexible = configured =
FALSE;
1765 if (!flexible && !configured) {
1766 GST_ERROR_OBJECT (
self,
1767 "Failed to get tensor info, need to update dimension and type.");
1770 (
"tensor_converter: Please set the properties input-dim and input-type to convert application/stream to non-flexible other/tensors. Use other/tensors,format=flexible if you want flexible dimensions. For static (non-flexible) tensors, you may, for example, use input-dim=30,input-type=uint8 to handle 30 bytes of bin data as a single frame.");
1775 if (self->frames_per_tensor > 1) {
1781 (
"tensor_converter: Cannot configure multiple tensors (num_tensors = %u) from an application/octet stream with frames_per_tensor (= %u)> 1. Please set the property frames-per-tensor 1 to convert stream to multiple-tensors (num_tensors > 1).",
1787 (
"tensor_converter: Cannot configure flexible tensors from an application/octet stream with frames_per_tensor (%u) > 1. Please set the property frames-per-tensor 1 to convert stream to flexible tensors.",
1788 self->frames_per_tensor);
1793 if (gst_structure_has_field (structure,
"framerate")) {
1794 gst_structure_get_fraction (structure,
"framerate", &config->
rate_n,
1840 g_return_val_if_fail (config != NULL,
FALSE);
1841 g_return_val_if_fail (structure != NULL,
FALSE);
1845 if (self->frames_per_tensor > 1) {
1847 (
"tensor_converter: Cannot configure multiple tensors. Please set the property frames-per-tensor (%u != 1) 1 to convert stream into tensor stream with num_tensor > 1.",
1848 self->frames_per_tensor);
1869 if (gst_structure_has_field (structure,
"framerate")) {
1870 gst_structure_get_fraction (structure,
"framerate", &config->
rate_n,
1892 GstStructure *structure;
1893 const gchar *mimetype;
1894 gboolean is_fixed =
FALSE;
1896 g_return_val_if_fail (config != NULL,
FALSE);
1897 g_return_val_if_fail (gst_caps_is_fixed (caps),
FALSE);
1901 structure = gst_caps_get_structure (caps, 0);
1902 mimetype = gst_structure_get_name (structure);
1912 if (gst_structure_has_field (structure,
"framerate")) {
1913 gst_structure_get_fraction (structure,
"framerate", &config->
rate_n,
1921 }
else if (!self->externalConverter) {
1924 mimetype =
self->ext_fw;
1928 (
"tensor_converter: Failed to get external converter for %s. Cannot find a corresponding external converter for the given type. The custom converter mode is %s with \"%s\"",
1936 (
"tensor_converter: Failed to get tensors info from %s (%s:%s). Its corresponding external converter is found. but its mandatory callback, get_out_config is not available.",
1941 char *capstr = gst_caps_to_string (caps);
1943 (
"tensor_converter: Failed to get tensors info from %s (%s:%s). Its corresponding external converter is found. but its mandatory callback, get_out_config(\"%s\", config) has returned FALSE (cannot get config from the caps).",
1950 self->externalConverter = ex;
1953 if (self->externalConverter->open &&
1954 (ret = self->externalConverter->open (self->mode_option,
1955 &self->priv_data)) < 0) {
1957 (
"tensor_converter: Failed to open tensor converter custom subplugin: custom-script mode with \"%s\" for \"%s\" (%s) has 'open' callback; however, it has returned %d error.\n",
1958 self->mode_option, mimetype, self->externalConverter->name, ret);
1959 self->externalConverter = NULL;
1974 GstCaps *media_caps = NULL;
1984 media_caps = gst_pad_get_pad_template_caps (self->sinkpad);
1985 media_caps = gst_caps_make_writable (media_caps);
1987 caps_len = gst_caps_get_size (media_caps);
1989 for (i = 0; i < caps_len; ++i) {
1990 st = gst_caps_get_structure (media_caps, i);
1997 GValue supported_formats = G_VALUE_INIT;
1998 gint colorspace, width, height;
2004 switch (colorspace) {
2007 "GRAY8",
"GRAY16_BE",
"GRAY16_LE", NULL);
2011 "RGB",
"BGR", NULL);
2015 "RGBx",
"BGRx",
"xRGB",
"xBGR",
"RGBA",
"BGRA",
"ARGB",
2023 if (G_VALUE_TYPE (&supported_formats) == GST_TYPE_LIST &&
2024 gst_value_list_get_size (&supported_formats) > 0) {
2025 gst_structure_set_value (st,
"format", &supported_formats);
2027 g_value_unset (&supported_formats);
2030 gst_structure_set (st,
"width", G_TYPE_INT, width, NULL);
2034 gst_structure_set (st,
"height", G_TYPE_INT, height, NULL);
2038 gst_structure_set (st,
"framerate", GST_TYPE_FRACTION,
2043 #if GST_CHECK_VERSION(1, 20, 0)
2048 if (colorspace == 3) {
2049 GValue nchw_format = G_VALUE_INIT;
2050 GstStructure *nchw_st = gst_structure_copy (st);
2053 "RGBP",
"BGRP", NULL);
2055 if (G_VALUE_TYPE (&nchw_format) == GST_TYPE_LIST &&
2056 gst_value_list_get_size (&nchw_format) > 0) {
2057 gst_structure_set_value (nchw_st,
"format", &nchw_format);
2059 g_value_unset (&nchw_format);
2062 gst_structure_set (nchw_st,
"width", G_TYPE_INT, width, NULL);
2066 gst_structure_set (nchw_st,
"height", G_TYPE_INT, height, NULL);
2068 gst_caps_append_structure (media_caps, nchw_st);
2102 (
"tensor_converter: Audio stream cannot be converted to float16 stream directly because GStreamer's standard audio streams do not support float16. Try Float32 or Float64 instead and 'transform' it to Float16 later.\n");
2117 gst_structure_set (st,
"format", G_TYPE_STRING,
2121 gst_structure_set (st,
"channels", G_TYPE_INT, ch, NULL);
2124 if ((rate = config.
rate_n) > 0) {
2125 gst_structure_set (st,
"rate", G_TYPE_INT, rate, NULL);
2149 caps = gst_pad_get_current_caps (pad);
2151 caps = gst_pad_get_pad_template_caps (pad);
2154 if (pad == self->sinkpad) {
2155 GstCaps *media_caps;
2160 GstCaps *tmp = gst_caps_intersect_full (media_caps, caps,
2161 GST_CAPS_INTERSECT_FIRST);
2162 gst_caps_unref (caps);
2165 gst_caps_unref (media_caps);
2173 GstCaps *intersection;
2176 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
2178 gst_caps_unref (caps);
2179 caps = intersection;
2191 const GstCaps * caps)
2193 GstStructure *structure;
2196 gint frames_dim = -1;
2198 g_return_val_if_fail (caps != NULL,
FALSE);
2199 g_return_val_if_fail (gst_caps_is_fixed (caps),
FALSE);
2201 structure = gst_caps_get_structure (caps, 0);
2212 char *capstr = gst_caps_to_string (caps);
2213 GST_ERROR_OBJECT (
self,
2214 "Failed to configure tensor from gst cap \"%s\" for video streams.",
2223 (
"tensor_converter: This binary does not support video type. Please build NNStreamer with -Dvideo-support=enabled (default). You have configured -Dvideo-support=disabled when you build this binary.\n");
2230 char *capstr = gst_caps_to_string (caps);
2231 GST_ERROR_OBJECT (
self,
2232 "Failed to configure tensor from gst cap \"%s\" for audio streams.",
2241 (
"tensor_converter: This binary does not support audio type. Please build NNStreamer with -Daudio-support=enabled (default). You have configured -Daudio-support=disabled when you build this binary.\n");
2247 char *capstr = gst_caps_to_string (caps);
2248 GST_ERROR_OBJECT (
self,
2249 "Failed to configure tensor from gst cap \"%s\" for text streams.",
2259 char *capstr = gst_caps_to_string (caps);
2260 GST_ERROR_OBJECT (
self,
2261 "Failed to configure tensors from gst cap \"%s\" for octet streams.",
2270 char *capstr = gst_caps_to_string (caps);
2271 GST_ERROR_OBJECT (
self,
2272 "Failed to configure tensor from flexible tensor (%s); trying to convert to static tensor.",
2280 char *capstr = gst_caps_to_string (caps);
2281 GST_ERROR_OBJECT (
self,
2282 "Failed to configure tensors with custom mode from streams of gst cap (%s) with custom converter subplugins.",
2292 if (frames_dim >= 0) {
2298 char *capstr = gst_caps_to_string (caps);
2300 GST_ERROR_OBJECT (
self,
2301 "Failed to configure tensors info with gst cap (%s). Cannot validate tensor configuration acquired from the given gst cap. The resulting invalid tensor config is: %s\n",
2313 GST_ERROR_OBJECT (
self,
2314 "Failed, mismatched tensor info. The two tensor configuration should match: \"configured by properties and tensor output\": %s and \"configured by input stream\": %s\n",
2322 self->in_media_type = in_type;
2323 self->tensors_configured =
TRUE;
2324 self->tensors_config = config;
2336 GstCaps *curr_caps, *out_caps;
2338 config = &
self->tensors_config;
2342 curr_caps = gst_pad_get_current_caps (self->srcpad);
2343 if (curr_caps == NULL || !gst_caps_is_equal (curr_caps, out_caps)) {
2345 gst_pad_set_caps (self->srcpad, out_caps);
2349 gst_caps_unref (curr_caps);
2351 gst_caps_unref (out_caps);
2371 if (!converter || !converter->
name) {
2411 guint total, i, j, caps_size;
2413 const gchar *caps_name;
2418 total = g_strv_length (str_array);
2420 for (i = 0; i < total; i++) {
2423 if (g_strcmp0 (
media_type, str_array[i]) == 0) {
2425 g_strfreev (str_array);
2431 caps_size = gst_caps_get_size (caps);
2433 for (j = 0; j < caps_size; j++) {
2434 caps_name = gst_structure_get_name (gst_caps_get_structure (caps, j));
2435 if (g_strcmp0 (
media_type, caps_name) == 0) {
2437 gst_caps_unref (caps);
2438 g_strfreev (str_array);
2443 gst_caps_unref (caps);
2447 g_strfreev (str_array);
2458 const char *
prop, ...)
2462 va_start (varargs,
prop);
2478 g_return_val_if_fail (name && strlen (name), -EINVAL);
2479 g_return_val_if_fail (func, -EINVAL);
2490 (
"tensor_converter: cannot register a converter subplugin, \"%s\" function. register_subplugin () has failed to register \"%s\".",
2506 ml_loge (
"tensor_converter: Failed to unregister custom callback %s.",