67 #define GST_CAT_DEFAULT gst_tensor_merge_debug
73 #define DBG (!tensor_merge->silent)
102 #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_WITH_NUM ("1")
108 static GstStaticPadTemplate
src_templ = GST_STATIC_PAD_TEMPLATE (
"src",
113 static GstStaticPadTemplate
sink_templ = GST_STATIC_PAD_TEMPLATE (
"sink_%u",
121 GstPadTemplate * templ,
const gchar * name,
const GstCaps * caps);
123 GstStateChange transition);
130 const GValue * value, GParamSpec * pspec);
132 GValue * value, GParamSpec * pspec);
135 #define gst_tensor_merge_parent_class parent_class
144 GObjectClass *gobject_class;
145 GstElementClass *gstelement_class;
147 GST_DEBUG_CATEGORY_INIT (gst_tensor_merge_debug,
"tensor_merge", 0,
148 "Element to merge multiple tensor stream to tensor stream");
150 gobject_class = (GObjectClass *) klass;
151 gstelement_class = (GstElementClass *) klass;
153 parent_class = g_type_class_peek_parent (klass);
159 g_object_class_install_property (gobject_class,
PROP_SILENT,
160 g_param_spec_boolean (
"silent",
"Silent",
"Produce verbose output",
161 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
163 g_object_class_install_property (gobject_class,
PROP_MODE,
164 g_param_spec_string (
"mode",
"Mode",
165 "Tensor Merge mode. Currently, `linear` is available only.",
167 g_object_class_install_property (gobject_class,
PROP_OPTION,
168 g_param_spec_string (
"option",
"Option",
169 "Option for the tensor Merge mode.\n"
170 "\t\t\t 1) linear mode: it will become the index of the rank.\n"
171 "\t\t\t (e.g. want to merge 3:640:480 & 3:640:480 to 3:1280:480, option=1)\n"
172 "\t\t\t 2) TBU",
"", G_PARAM_READWRITE));
175 g_param_spec_string (
"sync-mode",
"Sync Mode",
176 "Time synchronization mode\n"
177 "\t\t\tSee also: https://github.com/nnstreamer/nnstreamer/blob/main/Documentation/synchronization-policies-at-mux-merge.md",
178 "", G_PARAM_READWRITE));
181 g_param_spec_string (
"sync-option",
"Sync Option",
182 "Option for the time synchronization mode",
"", G_PARAM_READWRITE));
184 gstelement_class->request_new_pad =
186 gstelement_class->change_state =
189 gst_element_class_add_pad_template (gstelement_class,
191 gst_element_class_add_pad_template (gstelement_class,
192 gst_static_pad_template_get (&
src_templ));
194 gst_element_class_set_details_simple (gstelement_class,
197 "Merge multiple tensor stream to tensor stream",
198 "Jijoong Moon <jijoong.moon@samsung.com>");
211 GstElementClass *klass = GST_ELEMENT_GET_CLASS (tensor_merge);
214 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
218 gst_element_add_pad (GST_ELEMENT (tensor_merge), tensor_merge->
srcpad);
220 tensor_merge->
collect = gst_collect_pads_new ();
221 gst_collect_pads_set_event_function (tensor_merge->
collect,
222 (GstCollectPadsEventFunction)
224 gst_collect_pads_set_function (tensor_merge->
collect,
247 for (i = 0; i <
GTT_END; i++) {
266 gst_object_unref (tensor_merge->
collect);
270 if (tensor_merge->
option) {
272 tensor_merge->
option = NULL;
280 G_OBJECT_CLASS (parent_class)->finalize (
object);
288 const gchar * req_name,
const GstCaps * caps)
298 g_return_val_if_fail (templ != NULL, NULL);
302 walk = tensor_merge->
collect->data;
303 length = g_slist_length (walk);
306 GST_ERROR_OBJECT (tensor_merge,
311 name = g_strdup_printf (
"sink_%u", length);
312 newpad = gst_pad_new_from_template (templ, name);
319 gst_collect_pads_add_pad (tensor_merge->
collect, newpad,
322 gst_pad_set_element_private (newpad, tensormergepad);
323 gst_element_add_pad (element, newpad);
325 GST_WARNING_OBJECT (tensor_merge,
"failed to create request pad");
336 g_return_val_if_fail (event != NULL,
FALSE);
338 switch (GST_EVENT_TYPE (event)) {
340 gst_event_unref (event);
346 return gst_pad_event_default (pad, parent, event);
356 g_return_val_if_fail (event != NULL,
FALSE);
358 switch (GST_EVENT_TYPE (event)) {
359 case GST_EVENT_FLUSH_STOP:
368 return gst_collect_pads_event_default (pads,
data, event,
FALSE);
384 gboolean ret =
FALSE;
402 GST_ELEMENT_ERROR (tensor_merge, CORE, NEGOTIATION, (NULL), (NULL));
405 switch (tensor_merge->
mode) {
413 if (j == targetIdx) {
417 GST_ELEMENT_ERROR (tensor_merge, CORE, NEGOTIATION, (NULL),
449 GstBuffer * tensors_buf, gboolean * is_eos)
476 GstBuffer * tensors_buf, GstBuffer * tensor_buf)
478 GstFlowReturn ret = GST_FLOW_OK;
483 uint8_t *inptr, *outptr;
501 for (i = 0; i < num_mem; i++) {
503 if (!gst_memory_map (mem[i], &mInfo[i], GST_MAP_READ)) {
504 ml_logf (
"Cannot map input memory buffers (%d)\n", i);
505 gst_memory_unref (mem[i]);
507 ret = GST_FLOW_ERROR;
510 outSize += mInfo[i].size;
513 outMem = gst_allocator_alloc (NULL, outSize, NULL);
514 if (!gst_memory_map (outMem, &outInfo, GST_MAP_WRITE)) {
515 gst_memory_unref (outMem);
516 ml_logf (
"Cannot map output memory buffer\n");
517 ret = GST_FLOW_ERROR;
520 outptr = outInfo.data;
522 switch (tensor_merge->
mode) {
528 for (l = 0; l < dim[3]; l++) {
529 for (i = 0; i < dim[2]; i++) {
530 for (j = 0; j < dim[1]; j++) {
531 for (k = 0; k < num_mem; k++) {
535 s = element_size * c;
537 mInfo[k].data + (l * dim[2] * dim[1] + i * dim[1] +
539 memcpy (outptr, inptr, s);
549 for (l = 0; l < dim[3]; l++) {
550 for (i = 0; i < dim[2]; i++) {
551 for (k = 0; k < num_mem; k++) {
558 s = element_size * c;
560 inptr = mInfo[k].data + (l * dim[2] + i) * s;
562 memcpy (outptr, inptr, s);
571 for (l = 0; l < dim[3]; l++) {
572 for (k = 0; k < num_mem; k++) {
579 s = element_size * c;
581 inptr = mInfo[k].data + l * s;
583 memcpy (outptr, inptr, s);
591 for (k = 0; k < num_mem; k++) {
598 s = element_size * c;
600 inptr = mInfo[k].data;
601 memcpy (outptr, inptr, s);
607 ret = GST_FLOW_ERROR;
612 ret = GST_FLOW_ERROR;
615 gst_memory_unmap (outMem, &outInfo);
616 gst_buffer_append_memory (tensor_buf, outMem);
617 gst_buffer_copy_into (tensor_buf, tensors_buf, GST_BUFFER_COPY_TIMESTAMPS, 0,
621 for (i = 0; i < num_mem; i++) {
622 gst_memory_unmap (mem[i], &mInfo[i]);
623 gst_memory_unref (mem[i]);
647 if (gst_pad_set_caps (tensor_merge->
srcpad, newcaps)) {
651 gst_caps_unref (newcaps);
656 GST_WARNING_OBJECT (tensor_merge,
"failed to set caps");
657 GST_ELEMENT_ERROR (tensor_merge, CORE, NEGOTIATION, (NULL), (NULL));
667 GstClockTime pts, GstClockTime dts)
671 GstClockTime time = 0;
673 if (GST_CLOCK_TIME_IS_VALID (dts)) {
675 }
else if (GST_CLOCK_TIME_IS_VALID (pts)) {
679 gst_segment_init (&segment, GST_FORMAT_TIME);
680 segment.start = time;
681 gst_pad_push_event (tensor_merge->
srcpad, gst_event_new_segment (&segment));
696 GstFlowReturn ret = GST_FLOW_OK;
697 GstBuffer *tensors_buf, *tensor_buf;
698 gboolean isEOS =
FALSE;
700 GST_DEBUG_OBJECT (tensor_merge,
" all pads are collected ");
707 GstCollectData *
data = (GstCollectData *) pads->data->data;
708 g_autofree gchar *sink_stream_id = gst_pad_get_stream_id (
data->pad);
709 g_autofree gchar *element_name = gst_element_get_name (tensor_merge);
710 g_autofree gchar *pad_name = gst_pad_get_name (tensor_merge->
srcpad);
711 g_autofree gchar *stream_id = g_strdup_printf (
"%s-%s-nnsmerge-%s-%08x",
712 GST_STR_NULL (sink_stream_id), element_name, pad_name, g_random_int ());
714 gst_pad_push_event (tensor_merge->
srcpad, gst_event_new_stream_start (stream_id));
718 if ((tensors_buf = gst_buffer_new ()) == NULL) {
719 ml_logf (
"gst_buffer_new() returns NULL. Out of memory?\n");
720 return GST_FLOW_ERROR;
725 gst_pad_push_event (tensor_merge->
srcpad, gst_event_new_eos ());
733 ret = GST_FLOW_NOT_NEGOTIATED;
738 GST_BUFFER_PTS (tensors_buf), GST_BUFFER_DTS (tensors_buf));
740 if ((tensor_buf = gst_buffer_new ()) == NULL) {
741 ml_logf (
"gst_buffer_new() returns NULL. Out of memory?\n");
742 ret = GST_FLOW_ERROR;
748 ret = gst_pad_push (tensor_merge->
srcpad, tensor_buf);
751 if (ret != GST_FLOW_OK) {
752 GST_WARNING_OBJECT (tensor_merge,
"pushed outbuf, result = %s",
753 gst_flow_get_name (ret));
756 gst_buffer_unref (tensors_buf);
769 gst_collect_pads_start (tensor_merge->
collect);
775 static GstStateChangeReturn
779 GstStateChangeReturn ret;
781 switch (transition) {
782 case GST_STATE_CHANGE_READY_TO_PAUSED:
785 case GST_STATE_CHANGE_PAUSED_TO_READY:
786 gst_collect_pads_stop (tensor_merge->
collect);
792 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
793 if (ret == GST_STATE_CHANGE_FAILURE)
795 switch (transition) {
796 case GST_STATE_CHANGE_PAUSED_TO_READY:
816 switch (tensor_merge->
mode) {
831 GST_ERROR_OBJECT (tensor_merge,
"Cannot identify mode\n");
842 const GValue * value, GParamSpec * pspec)
847 tensor_merge->
silent = g_value_get_boolean (value);
853 ml_logw (
"Given mode property is not recognized: %s\n",
854 g_value_get_string (value));
859 ml_logw (
"Given mode property is not consistent with its options.\n");
863 tensor_merge->
option = g_value_dup_string (value);
866 ml_logw (
"Given option property is not consistent with its mode.\n");
880 tensor_merge->
sync.
option = g_value_dup_string (value);
885 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
895 GValue * value, GParamSpec * pspec)
900 g_value_set_boolean (value, tensor_merge->
silent);
917 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);