Line data Source code
1 : /**
2 : * GStreamer
3 : * Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
4 : * Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
5 : * Copyright (C) 2018 Jijoong Moon <jijoong.moon@samsung.com>
6 : *
7 : * This library is free software; you can redistribute it and/or
8 : * modify it under the terms of the GNU Library General Public
9 : * License as published by the Free Software Foundation;
10 : * version 2.1 of the License.
11 : *
12 : * This library is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * Library General Public License for more details.
16 : *
17 : */
18 : /**
19 : * @file gsttensor_split.c
20 : * @date 27 Aug 2018
21 : * @brief GStreamer plugin to split tensor (as a filter for other general neural network filters)
22 : * @see https://github.com/nnstreamer/nnstreamer
23 : * @author Jijoong Moon <jijoong.moon@samsung.com>
24 : * @bug No known bugs except for NYI items
25 : *
26 : */
27 :
28 : /**
29 : * SECTION:element-tensor_split
30 : *
31 : * A Deuxer that split tensors stream to tensor stream for NN frameworks.
32 : * The outputs are always in the format of other/tensor.
33 : *
34 : * <refsect2>
35 : * <title>Example launch line</title>
36 : * |[
37 : * gst-launch -v -m filesrc location=testcase_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter
38 : * ! tensor_split name=split tensorseg=2:100:100,1:100:100 split.src_0 ! queue ! filesink location=src0.log
39 : * split.src_1 ! queue ! filesink location=src1.log
40 : * ]|
41 : *
42 : * </refsect2>
43 : *
44 : */
45 :
46 :
47 : #ifdef HAVE_CONFIG_H
48 : #include <config.h>
49 : #endif
50 :
51 : #include <string.h>
52 : #include <gst/gst.h>
53 : #include <glib.h>
54 :
55 : #include "gsttensor_split.h"
56 : #include <tensor_common.h>
57 : #include <nnstreamer_util.h>
58 :
59 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_split_debug);
60 : #define GST_CAT_DEFAULT gst_tensor_split_debug
61 :
62 : enum
63 : {
64 : PROP_0,
65 : PROP_SILENT,
66 : PROP_TENSORPICK,
67 : PROP_TENSORSEG
68 : };
69 :
70 : /**
71 : * @brief Template caps string.
72 : */
73 : #define CAPS_STRING GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_WITH_NUM ("1")
74 :
75 : /**
76 : * @brief the capabilities of the inputs and outputs.
77 : * describe the real formats here.
78 : */
79 : static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src_%u",
80 : GST_PAD_SRC,
81 : GST_PAD_SOMETIMES,
82 : GST_STATIC_CAPS (CAPS_STRING));
83 :
84 : static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
85 : GST_PAD_SINK,
86 : GST_PAD_ALWAYS,
87 : GST_STATIC_CAPS (CAPS_STRING));
88 :
89 : static GstFlowReturn gst_tensor_split_chain (GstPad * pad, GstObject * parent,
90 : GstBuffer * buf);
91 : static gboolean gst_tensor_split_event (GstPad * pad, GstObject * parent,
92 : GstEvent * event);
93 : static GstStateChangeReturn gst_tensor_split_change_state (GstElement * element,
94 : GstStateChange transition);
95 : static void gst_tensor_split_set_property (GObject * object, guint prop_id,
96 : const GValue * value, GParamSpec * pspec);
97 : static void gst_tensor_split_get_property (GObject * object, guint prop_id,
98 : GValue * value, GParamSpec * pspec);
99 : static void gst_tensor_split_finalize (GObject * object);
100 :
101 : #define gst_tensor_split_parent_class parent_class
102 1152 : G_DEFINE_TYPE (GstTensorSplit, gst_tensor_split, GST_TYPE_ELEMENT);
103 :
104 :
105 : /**
106 : * @brief initialize the tensor_split's class
107 : */
108 : static void
109 22 : gst_tensor_split_class_init (GstTensorSplitClass * klass)
110 : {
111 : GObjectClass *gobject_class;
112 : GstElementClass *gstelement_class;
113 :
114 22 : GST_DEBUG_CATEGORY_INIT (gst_tensor_split_debug, "tensor_split", 0,
115 : "Element to split tensors stream to tensor stream");
116 :
117 22 : gobject_class = (GObjectClass *) klass;
118 22 : gstelement_class = (GstElementClass *) klass;
119 :
120 22 : parent_class = g_type_class_peek_parent (klass);
121 :
122 22 : gobject_class->finalize = gst_tensor_split_finalize;
123 22 : gobject_class->get_property = gst_tensor_split_get_property;
124 22 : gobject_class->set_property = gst_tensor_split_set_property;
125 :
126 22 : g_object_class_install_property (gobject_class, PROP_SILENT,
127 : g_param_spec_boolean ("silent", "Silent",
128 : "Do not produce verbose output ?", TRUE, G_PARAM_READWRITE));
129 :
130 22 : g_object_class_install_property (gobject_class, PROP_TENSORPICK,
131 : g_param_spec_string ("tensorpick", "TensorPick",
132 : "Choose nth tensor among tensors ?", "", G_PARAM_READWRITE));
133 :
134 22 : g_object_class_install_property (gobject_class, PROP_TENSORSEG,
135 : g_param_spec_string ("tensorseg", "TensorSeg",
136 : "How to split tensor ?", "", G_PARAM_READWRITE));
137 :
138 22 : gstelement_class->change_state =
139 22 : GST_DEBUG_FUNCPTR (gst_tensor_split_change_state);
140 :
141 22 : gst_element_class_add_pad_template (gstelement_class,
142 : gst_static_pad_template_get (&sink_templ));
143 22 : gst_element_class_add_pad_template (gstelement_class,
144 : gst_static_pad_template_get (&src_templ));
145 :
146 22 : gst_element_class_set_details_simple (gstelement_class,
147 : "TensorSplit",
148 : "Demuxer/Tensor",
149 : "Split tensor stream to other/tensor stream",
150 : "Jijoong Moon <jijoong.moon@samsung.com>");
151 22 : }
152 :
153 : /**
154 : * @brief initialize the new element
155 : * instantiate pads and add them to element
156 : * set pad callback functions
157 : * initialize instance structure
158 : */
159 : static void
160 13 : gst_tensor_split_init (GstTensorSplit * split)
161 : {
162 13 : split->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
163 13 : gst_element_add_pad (GST_ELEMENT_CAST (split), split->sinkpad);
164 13 : gst_pad_set_chain_function (split->sinkpad,
165 : GST_DEBUG_FUNCPTR (gst_tensor_split_chain));
166 13 : gst_pad_set_event_function (split->sinkpad,
167 : GST_DEBUG_FUNCPTR (gst_tensor_split_event));
168 :
169 13 : split->num_tensors = 0;
170 13 : split->num_srcpads = 0;
171 13 : split->silent = TRUE;
172 13 : split->tensorpick = NULL;
173 13 : split->tensorseg = NULL;
174 13 : split->have_group_id = FALSE;
175 13 : split->group_id = G_MAXUINT;
176 13 : split->srcpads = NULL;
177 13 : gst_tensors_config_init (&split->in_config);
178 13 : }
179 :
180 : /**
181 : * @brief function to remove srcpad list
182 : */
183 : static void
184 25 : gst_tensor_split_remove_src_pads (GstTensorSplit * split)
185 : {
186 49 : while (split->srcpads != NULL) {
187 24 : GstTensorPad *tensor_pad = split->srcpads->data;
188 24 : gst_element_remove_pad (GST_ELEMENT (split), tensor_pad->pad);
189 24 : g_free (tensor_pad);
190 24 : split->srcpads = g_slist_delete_link (split->srcpads, split->srcpads);
191 : }
192 25 : split->srcpads = NULL;
193 25 : split->num_tensors = 0;
194 25 : split->num_srcpads = 0;
195 25 : gst_tensors_config_free (&split->in_config);
196 25 : }
197 :
198 : /**
199 : * @brief finalize function for tensor split (gst element vmethod)
200 : */
201 : static void
202 13 : gst_tensor_split_finalize (GObject * object)
203 : {
204 : GstTensorSplit *split;
205 :
206 13 : split = GST_TENSOR_SPLIT (object);
207 13 : gst_tensor_split_remove_src_pads (split);
208 13 : g_list_free (split->tensorpick);
209 13 : g_array_free (split->tensorseg, TRUE);
210 13 : G_OBJECT_CLASS (parent_class)->finalize (object);
211 13 : }
212 :
213 : /**
214 : * @brief event function for sink (gst element vmethod)
215 : */
216 : static gboolean
217 48 : gst_tensor_split_event (GstPad * pad, GstObject * parent, GstEvent * event)
218 : {
219 : GstTensorSplit *split;
220 :
221 48 : split = GST_TENSOR_SPLIT (parent);
222 :
223 48 : switch (GST_EVENT_TYPE (event)) {
224 12 : case GST_EVENT_CAPS:
225 : {
226 : GstCaps *caps;
227 :
228 12 : gst_event_parse_caps (event, &caps);
229 12 : if (!gst_tensors_config_from_caps (&split->in_config, caps, TRUE)) {
230 0 : GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
231 : ("This stream contains no valid type."), NULL);
232 : }
233 12 : break;
234 : }
235 12 : case GST_EVENT_EOS:
236 12 : if (!split->srcpads) {
237 0 : GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
238 : ("This stream contains no valid stremas."),
239 : ("Got EOS before adding any pads"));
240 0 : gst_event_unref (event);
241 0 : return FALSE;
242 : }
243 12 : break;
244 24 : default:
245 24 : break;
246 : }
247 :
248 48 : return gst_pad_event_default (pad, parent, event);
249 : }
250 :
251 : /**
252 : * @brief Checking if the source pad is created and if not, create TensorPad
253 : * @param split TensorSplit Object
254 : * @param inbuf inputbuf GstBuffer Object including GstMeta
255 : * @param[out] created will be updated in this function
256 : * @param nth source ordering
257 : * @return TensorPad if pad is already created, then return created pad.
258 : * If not return new pad after creation.
259 : */
260 : static GstTensorPad *
261 191 : gst_tensor_split_get_tensor_pad (GstTensorSplit * split, GstBuffer * inbuf,
262 : gboolean * created, guint nth)
263 : {
264 191 : GstElement *element = GST_ELEMENT_CAST (split);
265 191 : g_autofree gchar *element_name = gst_element_get_name (element);
266 : GSList *walk;
267 : GstPad *pad;
268 : GstTensorPad *tensorpad;
269 : gchar *name;
270 : GstEvent *event;
271 : gchar *stream_id;
272 : GstCaps *caps;
273 : GstTensorsConfig pad_config;
274 : tensor_dim *dim;
275 : guint i;
276 : UNUSED (inbuf);
277 :
278 191 : walk = split->srcpads;
279 304 : while (walk) {
280 280 : GstTensorPad *pad = (GstTensorPad *) walk->data;
281 280 : if (nth == pad->nth) {
282 167 : if (created) {
283 167 : *created = FALSE;
284 : }
285 167 : return pad;
286 : }
287 113 : walk = g_slist_next (walk);
288 : }
289 :
290 24 : tensorpad = g_new0 (GstTensorPad, 1);
291 24 : g_assert (tensorpad != NULL);
292 24 : GST_DEBUG_OBJECT (split, "creating pad: %d(%dth)", split->num_srcpads, nth);
293 :
294 24 : name = g_strdup_printf ("src_%u", split->num_srcpads);
295 24 : pad = gst_pad_new_from_static_template (&src_templ, name);
296 24 : stream_id = gst_pad_create_stream_id_printf (pad, element,
297 : "%s-nnssplit-%s-%08x", element_name, name, g_random_int ());
298 24 : g_free (name);
299 :
300 24 : tensorpad->pad = pad;
301 24 : tensorpad->nth = nth;
302 24 : tensorpad->last_ret = GST_FLOW_OK;
303 24 : tensorpad->last_ts = GST_CLOCK_TIME_NONE;
304 :
305 24 : split->srcpads = g_slist_append (split->srcpads, tensorpad);
306 24 : dim = g_array_index (split->tensorseg, tensor_dim *, split->num_srcpads);
307 :
308 24 : split->num_srcpads++;
309 :
310 24 : gst_pad_use_fixed_caps (pad);
311 24 : gst_pad_set_active (pad, TRUE);
312 :
313 24 : if (!split->have_group_id) {
314 : event =
315 12 : gst_pad_get_sticky_event (split->sinkpad, GST_EVENT_STREAM_START, 0);
316 12 : if (event) {
317 12 : split->have_group_id = gst_event_parse_group_id (event, &split->group_id);
318 12 : gst_event_unref (event);
319 0 : } else if (!split->have_group_id) {
320 0 : split->have_group_id = TRUE;
321 0 : split->group_id = gst_util_group_id_next ();
322 : }
323 : }
324 :
325 24 : event = gst_event_new_stream_start (stream_id);
326 24 : if (split->have_group_id)
327 24 : gst_event_set_group_id (event, split->group_id);
328 :
329 24 : gst_pad_store_sticky_event (pad, event);
330 24 : g_free (stream_id);
331 24 : gst_event_unref (event);
332 :
333 : /* tensor config to set caps */
334 24 : gst_tensors_config_init (&pad_config);
335 24 : pad_config.info.num_tensors = 1;
336 408 : for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
337 384 : pad_config.info.info[0].dimension[i] = (*dim)[i];
338 : }
339 24 : pad_config.info.info[0].type = split->in_config.info.info[0].type;
340 24 : pad_config.rate_n = split->in_config.rate_n;
341 24 : pad_config.rate_d = split->in_config.rate_d;
342 :
343 24 : caps = gst_tensor_pad_caps_from_config (pad, &pad_config);
344 :
345 24 : gst_pad_set_caps (pad, caps);
346 24 : gst_element_add_pad (GST_ELEMENT_CAST (split), pad);
347 :
348 24 : gst_caps_unref (caps);
349 :
350 24 : if (created) {
351 24 : *created = TRUE;
352 : }
353 :
354 24 : if (split->tensorpick != NULL) {
355 5 : GST_DEBUG_OBJECT (split, "TensorPick is set! : %dth tensor\n", nth);
356 5 : if (g_list_length (split->tensorpick) == split->num_srcpads) {
357 2 : gst_element_no_more_pads (GST_ELEMENT_CAST (split));
358 : }
359 : }
360 :
361 24 : return tensorpad;
362 : }
363 :
364 : /**
365 : * @brief Check the status among sources in split
366 : * @param split TensorSplit Object
367 : * @param TensorPad Tensorpad
368 : * @param ret return status of current pad
369 : * @return return status after check sources
370 : */
371 : static GstFlowReturn
372 191 : gst_tensor_split_combine_flows (GstTensorSplit * split,
373 : GstTensorPad * pad, GstFlowReturn ret)
374 : {
375 : GSList *walk;
376 : GstTensorPad *opad;
377 :
378 191 : pad->last_ret = ret;
379 191 : if (ret != GST_FLOW_NOT_LINKED)
380 147 : goto done;
381 :
382 44 : for (walk = split->srcpads; walk; walk = g_slist_next (walk)) {
383 44 : opad = (GstTensorPad *) walk->data;
384 44 : ret = opad->last_ret;
385 44 : if (ret != GST_FLOW_NOT_LINKED)
386 44 : goto done;
387 : }
388 0 : done:
389 191 : return ret;
390 : }
391 :
392 : /**
393 : * @brief Make splitted tensor
394 : * @param split TensorSplit object
395 : * @param buffer gstbuffer form src
396 : * @param nth orther of tensor
397 : * @return return GstMemory for splitted tensor
398 : */
399 : static GstMemory *
400 191 : gst_tensor_split_get_splitted (GstTensorSplit * split, GstBuffer * buffer,
401 : gint nth)
402 : {
403 : GstMemory *mem;
404 : tensor_dim *dim;
405 : int i;
406 : gsize size, offset;
407 : GstMapInfo src_info, dest_info;
408 :
409 191 : dim = g_array_index (split->tensorseg, tensor_dim *, nth);
410 191 : size = gst_tensor_get_element_count (*dim) *
411 191 : gst_tensor_get_element_size (split->in_config.info.info[0].type);
412 :
413 191 : mem = gst_allocator_alloc (NULL, size, NULL);
414 191 : if (!gst_memory_map (mem, &dest_info, GST_MAP_WRITE)) {
415 0 : ml_logf ("Cannot map memory for destination buffer.\n");
416 0 : gst_memory_unref (mem);
417 191 : return NULL;
418 : }
419 191 : if (!gst_buffer_map (buffer, &src_info, GST_MAP_READ)) {
420 0 : ml_logf ("Cannot map src-memory to gst buffer at tensor-split.\n");
421 0 : gst_memory_unmap (mem, &dest_info);
422 0 : gst_memory_unref (mem);
423 0 : return NULL;
424 : }
425 :
426 191 : offset = 0;
427 304 : for (i = 0; i < nth; i++) {
428 113 : dim = g_array_index (split->tensorseg, tensor_dim *, i);
429 113 : offset += gst_tensor_get_element_count (*dim) *
430 113 : gst_tensor_get_element_size (split->in_config.info.info[0].type);
431 : }
432 :
433 191 : nns_memcpy (dest_info.data, src_info.data + offset, size);
434 191 : gst_buffer_unmap (buffer, &src_info);
435 191 : gst_memory_unmap (mem, &dest_info);
436 :
437 191 : return mem;
438 : }
439 :
440 : /**
441 : * @brief chain function for sink (gst element vmethod)
442 : */
443 : static GstFlowReturn
444 94 : gst_tensor_split_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
445 : {
446 : GstTensorSplit *split;
447 : guint num_tensors, i;
448 94 : GstFlowReturn res = GST_FLOW_OK;
449 : UNUSED (pad);
450 :
451 94 : split = GST_TENSOR_SPLIT (parent);
452 :
453 94 : num_tensors = split->num_tensors;
454 94 : GST_DEBUG_OBJECT (split, " Number of Tensors: %d", num_tensors);
455 :
456 94 : if (split->tensorseg == NULL) {
457 0 : GST_ERROR_OBJECT (split, "No rule to split incoming buffers.");
458 0 : return GST_FLOW_ERROR;
459 : }
460 :
461 293 : for (i = 0; i < num_tensors; i++) {
462 : GstTensorPad *srcpad;
463 : GstBuffer *outbuf;
464 : GstMemory *mem;
465 : gboolean created;
466 : GstClockTime ts;
467 :
468 201 : if (split->tensorpick != NULL) {
469 45 : gboolean found = FALSE;
470 : GList *list;
471 90 : for (list = split->tensorpick; list != NULL; list = list->next) {
472 80 : if (i == GPOINTER_TO_UINT (list->data)) {
473 35 : found = TRUE;
474 35 : break;
475 : }
476 : }
477 45 : if (!found)
478 10 : continue;
479 : }
480 :
481 191 : srcpad = gst_tensor_split_get_tensor_pad (split, buf, &created, i);
482 :
483 191 : outbuf = gst_buffer_new ();
484 191 : mem = gst_tensor_split_get_splitted (split, buf, i);
485 191 : gst_buffer_append_memory (outbuf, mem);
486 191 : ts = GST_BUFFER_TIMESTAMP (buf);
487 :
488 191 : if (created) {
489 : GstSegment segment;
490 24 : gst_segment_init (&segment, GST_FORMAT_TIME);
491 24 : gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
492 : }
493 :
494 191 : outbuf = gst_buffer_make_writable (outbuf);
495 :
496 : /* metadata from incoming buffer */
497 191 : gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
498 :
499 191 : if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
500 191 : srcpad->last_ts = ts;
501 : } else {
502 0 : GST_DEBUG_OBJECT (split, "invalid timestamp %" GST_TIME_FORMAT,
503 : GST_TIME_ARGS (ts));
504 : }
505 :
506 191 : GST_DEBUG_OBJECT (split, "pushing buffer with timestamp %" GST_TIME_FORMAT,
507 : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
508 191 : res = gst_pad_push (srcpad->pad, outbuf);
509 191 : res = gst_tensor_split_combine_flows (split, srcpad, res);
510 191 : if (res != GST_FLOW_OK)
511 2 : break;
512 : }
513 :
514 94 : gst_buffer_unref (buf);
515 94 : return res;
516 : }
517 :
518 : /**
519 : * @brief change state (gst element vmethod)
520 : */
521 : static GstStateChangeReturn
522 70 : gst_tensor_split_change_state (GstElement * element, GstStateChange transition)
523 : {
524 : GstTensorSplit *split;
525 : GstStateChangeReturn ret;
526 :
527 70 : split = GST_TENSOR_SPLIT (element);
528 :
529 70 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
530 70 : if (ret == GST_STATE_CHANGE_FAILURE)
531 0 : return ret;
532 :
533 70 : switch (transition) {
534 11 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
535 11 : break;
536 12 : case GST_STATE_CHANGE_PAUSED_TO_READY:
537 12 : split->group_id = G_MAXUINT;
538 12 : split->have_group_id = FALSE;
539 12 : gst_tensor_split_remove_src_pads (split);
540 12 : break;
541 12 : case GST_STATE_CHANGE_READY_TO_NULL:
542 12 : break;
543 35 : default:
544 35 : break;
545 : }
546 :
547 70 : return ret;
548 : }
549 :
550 : /**
551 : * @brief Glib Array Clear Function
552 : */
553 : static void
554 29 : _clear_tensorseg (tensor_dim ** element)
555 : {
556 29 : g_free (*element);
557 29 : }
558 :
559 : /**
560 : * @brief Get property (gst element vmethod)
561 : */
562 : static void
563 18 : gst_tensor_split_set_property (GObject * object, guint prop_id,
564 : const GValue * value, GParamSpec * pspec)
565 : {
566 : GstTensorSplit *split;
567 :
568 18 : split = GST_TENSOR_SPLIT (object);
569 :
570 18 : switch (prop_id) {
571 2 : case PROP_SILENT:
572 2 : split->silent = g_value_get_boolean (value);
573 2 : break;
574 3 : case PROP_TENSORPICK:
575 : {
576 : gint i;
577 : gint64 val;
578 3 : const gchar *param = g_value_get_string (value);
579 3 : gchar **strv = g_strsplit_set (param, ",.;/", -1);
580 3 : gint num = g_strv_length (strv);
581 11 : for (i = 0; i < num; i++) {
582 8 : val = g_ascii_strtoll (strv[i], NULL, 10);
583 8 : split->tensorpick =
584 8 : g_list_append (split->tensorpick, GINT_TO_POINTER (val));
585 : }
586 3 : g_strfreev (strv);
587 3 : break;
588 : }
589 13 : case PROP_TENSORSEG:
590 : {
591 : guint i;
592 13 : const gchar *param = g_value_get_string (value);
593 13 : gchar **strv = g_strsplit_set (param, ",.;/", -1);
594 13 : GArray *tensorseg = split->tensorseg;
595 :
596 13 : split->num_tensors = g_strv_length (strv);
597 13 : if (NULL == tensorseg) {
598 13 : split->tensorseg =
599 13 : g_array_sized_new (FALSE, FALSE, sizeof (tensor_dim *),
600 : split->num_tensors);
601 13 : g_array_set_clear_func (split->tensorseg,
602 : (GDestroyNotify) _clear_tensorseg);
603 :
604 42 : for (i = 0; i < split->num_tensors; i++) {
605 29 : tensor_dim *d = g_new0 (tensor_dim, 1);
606 29 : g_array_append_val (split->tensorseg, d);
607 : }
608 13 : tensorseg = split->tensorseg;
609 : }
610 42 : for (i = 0; i < split->num_tensors; i++) {
611 : gchar **p;
612 : gint num, k;
613 : tensor_dim *d;
614 29 : p = g_strsplit_set (strv[i], ":", -1);
615 29 : num = g_strv_length (p);
616 :
617 29 : d = g_array_index (tensorseg, tensor_dim *, i);
618 :
619 130 : for (k = 0; k < num; k++) {
620 101 : (*d)[k] = g_ascii_strtod (p[k], NULL);
621 : }
622 :
623 29 : g_strfreev (p);
624 : }
625 13 : g_strfreev (strv);
626 13 : break;
627 : }
628 0 : default:
629 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
630 0 : break;
631 : }
632 18 : }
633 :
634 : /**
635 : * @brief Get property (gst element vmethod)
636 : */
637 : static void
638 3 : gst_tensor_split_get_property (GObject * object, guint prop_id,
639 : GValue * value, GParamSpec * pspec)
640 : {
641 : GstTensorSplit *split;
642 :
643 3 : split = GST_TENSOR_SPLIT (object);
644 :
645 3 : switch (prop_id) {
646 1 : case PROP_SILENT:
647 1 : g_value_set_boolean (value, split->silent);
648 1 : break;
649 1 : case PROP_TENSORPICK:
650 : {
651 : GList *list;
652 : char *p;
653 1 : GPtrArray *arr = g_ptr_array_new ();
654 : gchar **strings;
655 :
656 4 : for (list = split->tensorpick; list != NULL; list = list->next) {
657 3 : g_ptr_array_add (arr, g_strdup_printf ("%i",
658 3 : GPOINTER_TO_INT (list->data)));
659 : }
660 1 : g_ptr_array_add (arr, NULL);
661 1 : strings = (gchar **) g_ptr_array_free (arr, FALSE);
662 1 : p = g_strjoinv (",", strings);
663 1 : g_strfreev (strings);
664 1 : g_value_take_string (value, p);
665 1 : break;
666 : }
667 1 : case PROP_TENSORSEG:
668 : {
669 2 : if ((split->tensorseg) && (split->tensorseg->len > 0)) {
670 1 : tensor_dim *dim = NULL;
671 1 : gchar *strv = NULL;
672 : guint i, j;
673 :
674 :
675 4 : for (i = 0; i < split->tensorseg->len; i++) {
676 3 : GPtrArray *arr = g_ptr_array_new ();
677 3 : gchar *p = NULL;
678 : gchar **strings;
679 :
680 3 : dim = g_array_index (split->tensorseg, tensor_dim *, i);
681 51 : for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++) {
682 48 : g_ptr_array_add (arr, g_strdup_printf ("%i", (*dim)[j]));
683 : }
684 3 : g_ptr_array_add (arr, NULL);
685 3 : strings = (gchar **) g_ptr_array_free (arr, FALSE);
686 3 : p = g_strjoinv (":", strings);
687 3 : g_strfreev (strings);
688 3 : if (i > 0) {
689 : /**
690 : * If i = 1, this is previous p.
691 : * Otherwise, it's previous g_strjoin result.
692 : */
693 2 : gchar *oldstrv = strv;
694 :
695 2 : strv = g_strjoin (",", strv, p, NULL);
696 2 : g_free (oldstrv);
697 2 : g_free (p);
698 : } else {
699 1 : strv = p;
700 : }
701 : }
702 : /* the second parameter, strv (i.e., gchar *v_string), is nullable */
703 1 : g_value_take_string (value, strv ? strv : g_strdup (""));
704 : } else {
705 0 : g_value_set_string (value, "");
706 : }
707 1 : break;
708 : }
709 0 : default:
710 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
711 0 : break;
712 : }
713 3 : }
|