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 1122 : 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 12 : gst_tensor_split_class_init (GstTensorSplitClass * klass)
110 : {
111 : GObjectClass *gobject_class;
112 : GstElementClass *gstelement_class;
113 :
114 12 : GST_DEBUG_CATEGORY_INIT (gst_tensor_split_debug, "tensor_split", 0,
115 : "Element to split tensors stream to tensor stream");
116 :
117 12 : gobject_class = (GObjectClass *) klass;
118 12 : gstelement_class = (GstElementClass *) klass;
119 :
120 12 : parent_class = g_type_class_peek_parent (klass);
121 :
122 12 : gobject_class->finalize = gst_tensor_split_finalize;
123 12 : gobject_class->get_property = gst_tensor_split_get_property;
124 12 : gobject_class->set_property = gst_tensor_split_set_property;
125 :
126 12 : 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 12 : 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 12 : 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 12 : gstelement_class->change_state =
139 12 : GST_DEBUG_FUNCPTR (gst_tensor_split_change_state);
140 :
141 12 : gst_element_class_add_pad_template (gstelement_class,
142 : gst_static_pad_template_get (&sink_templ));
143 12 : gst_element_class_add_pad_template (gstelement_class,
144 : gst_static_pad_template_get (&src_templ));
145 :
146 12 : 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 12 : }
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->sink_tensor_conf);
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->sink_tensor_conf);
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 12 : gst_event_parse_caps (event, &caps);
228 12 : if (!gst_tensors_config_from_cap (&split->sink_tensor_conf, caps)) {
229 0 : GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
230 : ("This stream contains no valid type."), NULL);
231 : }
232 12 : break;
233 : }
234 12 : case GST_EVENT_EOS:
235 12 : if (!split->srcpads) {
236 0 : GST_ELEMENT_ERROR (split, STREAM, WRONG_TYPE,
237 : ("This stream contains no valid stremas."),
238 : ("Got EOS before adding any pads"));
239 0 : gst_event_unref (event);
240 0 : return FALSE;
241 : }
242 12 : break;
243 24 : default:
244 24 : break;
245 : }
246 :
247 48 : return gst_pad_event_default (pad, parent, event);
248 : }
249 :
250 : /**
251 : * @brief Checking if the source pad is created and if not, create TensorPad
252 : * @param split TensorSplit Object
253 : * @param inbuf inputbuf GstBuffer Object including GstMeta
254 : * @param[out] created will be updated in this function
255 : * @param nth source ordering
256 : * @return TensorPad if pad is already created, then return created pad.
257 : * If not return new pad after creation.
258 : */
259 : static GstTensorPad *
260 191 : gst_tensor_split_get_tensor_pad (GstTensorSplit * split, GstBuffer * inbuf,
261 : gboolean * created, guint nth)
262 : {
263 191 : GstElement *element = GST_ELEMENT_CAST (split);
264 191 : g_autofree gchar *element_name = gst_element_get_name (element);
265 : GSList *walk;
266 : GstPad *pad;
267 : GstTensorPad *tensorpad;
268 : gchar *name;
269 : GstEvent *event;
270 : gchar *stream_id;
271 : GstCaps *caps;
272 : GstTensorsConfig pad_config;
273 : tensor_dim *dim;
274 : guint i;
275 : UNUSED (inbuf);
276 :
277 191 : walk = split->srcpads;
278 304 : while (walk) {
279 280 : GstTensorPad *pad = (GstTensorPad *) walk->data;
280 280 : if (nth == pad->nth) {
281 167 : if (created) {
282 167 : *created = FALSE;
283 : }
284 167 : return pad;
285 : }
286 113 : walk = g_slist_next (walk);
287 : }
288 :
289 24 : tensorpad = g_new0 (GstTensorPad, 1);
290 24 : g_assert (tensorpad != NULL);
291 24 : GST_DEBUG_OBJECT (split, "creating pad: %d(%dth)", split->num_srcpads, nth);
292 :
293 24 : name = g_strdup_printf ("src_%u", split->num_srcpads);
294 24 : pad = gst_pad_new_from_static_template (&src_templ, name);
295 24 : stream_id = gst_pad_create_stream_id_printf (pad, element,
296 : "%s-nnssplit-%s-%08x", element_name, name, g_random_int ());
297 24 : g_free (name);
298 :
299 24 : tensorpad->pad = pad;
300 24 : tensorpad->nth = nth;
301 24 : tensorpad->last_ret = GST_FLOW_OK;
302 24 : tensorpad->last_ts = GST_CLOCK_TIME_NONE;
303 :
304 24 : split->srcpads = g_slist_append (split->srcpads, tensorpad);
305 24 : dim = g_array_index (split->tensorseg, tensor_dim *, split->num_srcpads);
306 :
307 24 : split->num_srcpads++;
308 :
309 24 : gst_pad_use_fixed_caps (pad);
310 24 : gst_pad_set_active (pad, TRUE);
311 :
312 24 : if (!split->have_group_id) {
313 : event =
314 12 : gst_pad_get_sticky_event (split->sinkpad, GST_EVENT_STREAM_START, 0);
315 12 : if (event) {
316 12 : split->have_group_id = gst_event_parse_group_id (event, &split->group_id);
317 12 : gst_event_unref (event);
318 0 : } else if (!split->have_group_id) {
319 0 : split->have_group_id = TRUE;
320 0 : split->group_id = gst_util_group_id_next ();
321 : }
322 : }
323 :
324 24 : event = gst_event_new_stream_start (stream_id);
325 24 : if (split->have_group_id)
326 24 : gst_event_set_group_id (event, split->group_id);
327 :
328 24 : gst_pad_store_sticky_event (pad, event);
329 24 : g_free (stream_id);
330 24 : gst_event_unref (event);
331 :
332 : /* tensor config to set caps */
333 24 : gst_tensors_config_init (&pad_config);
334 24 : pad_config.info.num_tensors = 1;
335 408 : for (i = 0; i < NNS_TENSOR_RANK_LIMIT; i++) {
336 384 : pad_config.info.info[0].dimension[i] = (*dim)[i];
337 : }
338 24 : pad_config.info.info[0].type = split->sink_tensor_conf.info.info[0].type;
339 24 : pad_config.rate_n = split->sink_tensor_conf.rate_n;
340 24 : pad_config.rate_d = split->sink_tensor_conf.rate_d;
341 :
342 24 : caps = gst_tensor_pad_caps_from_config (pad, &pad_config);
343 :
344 24 : gst_pad_set_caps (pad, caps);
345 24 : gst_element_add_pad (GST_ELEMENT_CAST (split), pad);
346 :
347 24 : gst_caps_unref (caps);
348 :
349 24 : if (created) {
350 24 : *created = TRUE;
351 : }
352 :
353 24 : if (split->tensorpick != NULL) {
354 5 : GST_DEBUG_OBJECT (split, "TensorPick is set! : %dth tensor\n", nth);
355 5 : if (g_list_length (split->tensorpick) == split->num_srcpads) {
356 2 : gst_element_no_more_pads (GST_ELEMENT_CAST (split));
357 : }
358 : }
359 :
360 24 : return tensorpad;
361 : }
362 :
363 : /**
364 : * @brief Check the status among sources in split
365 : * @param split TensorSplit Object
366 : * @param TensorPad Tensorpad
367 : * @param ret return status of current pad
368 : * @return return status after check sources
369 : */
370 : static GstFlowReturn
371 191 : gst_tensor_split_combine_flows (GstTensorSplit * split,
372 : GstTensorPad * pad, GstFlowReturn ret)
373 : {
374 : GSList *walk;
375 : GstTensorPad *opad;
376 :
377 191 : pad->last_ret = ret;
378 191 : if (ret != GST_FLOW_NOT_LINKED)
379 147 : goto done;
380 :
381 44 : for (walk = split->srcpads; walk; walk = g_slist_next (walk)) {
382 44 : opad = (GstTensorPad *) walk->data;
383 44 : ret = opad->last_ret;
384 44 : if (ret != GST_FLOW_NOT_LINKED)
385 44 : goto done;
386 : }
387 0 : done:
388 191 : return ret;
389 : }
390 :
391 : /**
392 : * @brief Make splitted tensor
393 : * @param split TensorSplit object
394 : * @param buffer gstbuffer form src
395 : * @param nth orther of tensor
396 : * @return return GstMemory for splitted tensor
397 : */
398 : static GstMemory *
399 191 : gst_tensor_split_get_splitted (GstTensorSplit * split, GstBuffer * buffer,
400 : gint nth)
401 : {
402 : GstMemory *mem;
403 : tensor_dim *dim;
404 : int i;
405 : gsize size, offset;
406 : GstMapInfo src_info, dest_info;
407 :
408 191 : dim = g_array_index (split->tensorseg, tensor_dim *, nth);
409 191 : size = gst_tensor_get_element_count (*dim) *
410 191 : gst_tensor_get_element_size (split->sink_tensor_conf.info.info[0].type);
411 :
412 191 : mem = gst_allocator_alloc (NULL, size, NULL);
413 191 : if (!gst_memory_map (mem, &dest_info, GST_MAP_WRITE)) {
414 0 : ml_logf ("Cannot map memory for destination buffer.\n");
415 0 : gst_memory_unref (mem);
416 191 : return NULL;
417 : }
418 191 : if (!gst_buffer_map (buffer, &src_info, GST_MAP_READ)) {
419 0 : ml_logf ("Cannot map src-memory to gst buffer at tensor-split.\n");
420 0 : gst_memory_unmap (mem, &dest_info);
421 0 : gst_memory_unref (mem);
422 0 : return NULL;
423 : }
424 :
425 191 : offset = 0;
426 304 : for (i = 0; i < nth; i++) {
427 113 : dim = g_array_index (split->tensorseg, tensor_dim *, i);
428 113 : offset += gst_tensor_get_element_count (*dim) *
429 113 : gst_tensor_get_element_size (split->sink_tensor_conf.info.info[0].type);
430 : }
431 :
432 191 : nns_memcpy (dest_info.data, src_info.data + offset, size);
433 191 : gst_buffer_unmap (buffer, &src_info);
434 191 : gst_memory_unmap (mem, &dest_info);
435 :
436 191 : return mem;
437 : }
438 :
439 : /**
440 : * @brief chain function for sink (gst element vmethod)
441 : */
442 : static GstFlowReturn
443 94 : gst_tensor_split_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
444 : {
445 : GstTensorSplit *split;
446 : guint num_tensors, i;
447 94 : GstFlowReturn res = GST_FLOW_OK;
448 : UNUSED (pad);
449 :
450 94 : split = GST_TENSOR_SPLIT (parent);
451 :
452 94 : num_tensors = split->num_tensors;
453 94 : GST_DEBUG_OBJECT (split, " Number of Tensors: %d", num_tensors);
454 :
455 94 : if (split->tensorseg == NULL) {
456 0 : GST_ERROR_OBJECT (split, "No rule to split incoming buffers.");
457 0 : return GST_FLOW_ERROR;
458 : }
459 :
460 293 : for (i = 0; i < num_tensors; i++) {
461 : GstTensorPad *srcpad;
462 : GstBuffer *outbuf;
463 : GstMemory *mem;
464 : gboolean created;
465 : GstClockTime ts;
466 :
467 201 : if (split->tensorpick != NULL) {
468 45 : gboolean found = FALSE;
469 : GList *list;
470 90 : for (list = split->tensorpick; list != NULL; list = list->next) {
471 80 : if (i == GPOINTER_TO_UINT (list->data)) {
472 35 : found = TRUE;
473 35 : break;
474 : }
475 : }
476 45 : if (!found)
477 10 : continue;
478 : }
479 :
480 191 : srcpad = gst_tensor_split_get_tensor_pad (split, buf, &created, i);
481 :
482 191 : outbuf = gst_buffer_new ();
483 191 : mem = gst_tensor_split_get_splitted (split, buf, i);
484 191 : gst_buffer_append_memory (outbuf, mem);
485 191 : ts = GST_BUFFER_TIMESTAMP (buf);
486 :
487 191 : if (created) {
488 : GstSegment segment;
489 24 : gst_segment_init (&segment, GST_FORMAT_TIME);
490 24 : gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
491 : }
492 :
493 191 : outbuf = gst_buffer_make_writable (outbuf);
494 :
495 : /* metadata from incoming buffer */
496 191 : gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
497 :
498 191 : if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
499 191 : srcpad->last_ts = ts;
500 : } else {
501 0 : GST_DEBUG_OBJECT (split, "invalid timestamp %" GST_TIME_FORMAT,
502 : GST_TIME_ARGS (ts));
503 : }
504 :
505 191 : GST_DEBUG_OBJECT (split, "pushing buffer with timestamp %" GST_TIME_FORMAT,
506 : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
507 191 : res = gst_pad_push (srcpad->pad, outbuf);
508 191 : res = gst_tensor_split_combine_flows (split, srcpad, res);
509 191 : if (res != GST_FLOW_OK)
510 2 : break;
511 : }
512 :
513 94 : gst_buffer_unref (buf);
514 94 : return res;
515 : }
516 :
517 : /**
518 : * @brief change state (gst element vmethod)
519 : */
520 : static GstStateChangeReturn
521 70 : gst_tensor_split_change_state (GstElement * element, GstStateChange transition)
522 : {
523 : GstTensorSplit *split;
524 : GstStateChangeReturn ret;
525 :
526 70 : split = GST_TENSOR_SPLIT (element);
527 :
528 70 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
529 70 : if (ret == GST_STATE_CHANGE_FAILURE)
530 0 : return ret;
531 :
532 70 : switch (transition) {
533 11 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
534 11 : break;
535 12 : case GST_STATE_CHANGE_PAUSED_TO_READY:
536 12 : split->group_id = G_MAXUINT;
537 12 : split->have_group_id = FALSE;
538 12 : gst_tensor_split_remove_src_pads (split);
539 12 : break;
540 12 : case GST_STATE_CHANGE_READY_TO_NULL:
541 12 : break;
542 35 : default:
543 35 : break;
544 : }
545 :
546 70 : return ret;
547 : }
548 :
549 : /**
550 : * @brief Glib Array Clear Function
551 : */
552 : static void
553 29 : _clear_tensorseg (tensor_dim ** element)
554 : {
555 29 : g_free (*element);
556 29 : }
557 :
558 : /**
559 : * @brief Get property (gst element vmethod)
560 : */
561 : static void
562 18 : gst_tensor_split_set_property (GObject * object, guint prop_id,
563 : const GValue * value, GParamSpec * pspec)
564 : {
565 : GstTensorSplit *split;
566 :
567 18 : split = GST_TENSOR_SPLIT (object);
568 :
569 18 : switch (prop_id) {
570 2 : case PROP_SILENT:
571 2 : split->silent = g_value_get_boolean (value);
572 2 : break;
573 3 : case PROP_TENSORPICK:
574 : {
575 : gint i;
576 : gint64 val;
577 3 : const gchar *param = g_value_get_string (value);
578 3 : gchar **strv = g_strsplit_set (param, ",.;/", -1);
579 3 : gint num = g_strv_length (strv);
580 11 : for (i = 0; i < num; i++) {
581 8 : val = g_ascii_strtoll (strv[i], NULL, 10);
582 8 : split->tensorpick =
583 8 : g_list_append (split->tensorpick, GINT_TO_POINTER (val));
584 : }
585 3 : g_strfreev (strv);
586 3 : break;
587 : }
588 13 : case PROP_TENSORSEG:
589 : {
590 : guint i;
591 13 : const gchar *param = g_value_get_string (value);
592 13 : gchar **strv = g_strsplit_set (param, ",.;/", -1);
593 13 : GArray *tensorseg = split->tensorseg;
594 :
595 13 : split->num_tensors = g_strv_length (strv);
596 13 : if (NULL == tensorseg) {
597 13 : split->tensorseg =
598 13 : g_array_sized_new (FALSE, FALSE, sizeof (tensor_dim *),
599 : split->num_tensors);
600 13 : g_array_set_clear_func (split->tensorseg,
601 : (GDestroyNotify) _clear_tensorseg);
602 :
603 42 : for (i = 0; i < split->num_tensors; i++) {
604 29 : tensor_dim *d = g_new0 (tensor_dim, 1);
605 29 : g_array_append_val (split->tensorseg, d);
606 : }
607 13 : tensorseg = split->tensorseg;
608 : }
609 42 : for (i = 0; i < split->num_tensors; i++) {
610 : gchar **p;
611 : gint num, k;
612 : tensor_dim *d;
613 29 : p = g_strsplit_set (strv[i], ":", -1);
614 29 : num = g_strv_length (p);
615 :
616 29 : d = g_array_index (tensorseg, tensor_dim *, i);
617 :
618 130 : for (k = 0; k < num; k++) {
619 101 : (*d)[k] = g_ascii_strtod (p[k], NULL);
620 : }
621 :
622 29 : g_strfreev (p);
623 : }
624 13 : g_strfreev (strv);
625 13 : break;
626 : }
627 0 : default:
628 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
629 0 : break;
630 : }
631 18 : }
632 :
633 : /**
634 : * @brief Get property (gst element vmethod)
635 : */
636 : static void
637 3 : gst_tensor_split_get_property (GObject * object, guint prop_id,
638 : GValue * value, GParamSpec * pspec)
639 : {
640 : GstTensorSplit *split;
641 :
642 3 : split = GST_TENSOR_SPLIT (object);
643 :
644 3 : switch (prop_id) {
645 1 : case PROP_SILENT:
646 1 : g_value_set_boolean (value, split->silent);
647 1 : break;
648 1 : case PROP_TENSORPICK:
649 : {
650 : GList *list;
651 : char *p;
652 1 : GPtrArray *arr = g_ptr_array_new ();
653 : gchar **strings;
654 :
655 4 : for (list = split->tensorpick; list != NULL; list = list->next) {
656 3 : g_ptr_array_add (arr, g_strdup_printf ("%i",
657 3 : GPOINTER_TO_INT (list->data)));
658 : }
659 1 : g_ptr_array_add (arr, NULL);
660 1 : strings = (gchar **) g_ptr_array_free (arr, FALSE);
661 1 : p = g_strjoinv (",", strings);
662 1 : g_strfreev (strings);
663 1 : g_value_take_string (value, p);
664 1 : break;
665 : }
666 1 : case PROP_TENSORSEG:
667 : {
668 2 : if ((split->tensorseg) && (split->tensorseg->len > 0)) {
669 1 : tensor_dim *dim = NULL;
670 1 : gchar *strv = NULL;
671 : guint i, j;
672 :
673 :
674 4 : for (i = 0; i < split->tensorseg->len; i++) {
675 3 : GPtrArray *arr = g_ptr_array_new ();
676 3 : gchar *p = NULL;
677 : gchar **strings;
678 :
679 3 : dim = g_array_index (split->tensorseg, tensor_dim *, i);
680 51 : for (j = 0; j < NNS_TENSOR_RANK_LIMIT; j++) {
681 48 : g_ptr_array_add (arr, g_strdup_printf ("%i", (*dim)[j]));
682 : }
683 3 : g_ptr_array_add (arr, NULL);
684 3 : strings = (gchar **) g_ptr_array_free (arr, FALSE);
685 3 : p = g_strjoinv (":", strings);
686 3 : g_strfreev (strings);
687 3 : if (i > 0) {
688 : /**
689 : * If i = 1, this is previous p.
690 : * Otherwise, it's previous g_strjoin result.
691 : */
692 2 : gchar *oldstrv = strv;
693 :
694 2 : strv = g_strjoin (",", strv, p, NULL);
695 2 : g_free (oldstrv);
696 2 : g_free (p);
697 : } else {
698 1 : strv = p;
699 : }
700 : }
701 : /* the second parameter, strv (i.e., gchar *v_string), is nullable */
702 1 : g_value_take_string (value, strv ? strv : g_strdup (""));
703 : } else {
704 0 : g_value_set_string (value, "");
705 : }
706 1 : break;
707 : }
708 0 : default:
709 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
710 0 : break;
711 : }
712 3 : }
|