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_demux.c
20 : * @date 03 July 2018
21 : * @brief GStreamer plugin to demux tensors (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_demux
30 : *
31 : * A Demuxer that demux tensors stream to tensor(s) stream for NN frameworks.
32 : * The output is always in the format of other/tensor or other/tensors.
33 : *
34 : * <refsect2>
35 : * <title>Example launch line</title>
36 : * |[
37 : * gst-launch-1.0 tensor_mux name=mux ! tensor_demux name=demux \
38 : * filesrc location=testcase01_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter ! mux.sink_0 \
39 : * filesrc location=testcase01_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter ! mux.sink_1 \
40 : * filesrc location=testcase01_RGB_100x100.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter ! mux.sink_2 \
41 : * demux.src_0 ! queue ! filesink location=demux00.log \
42 : * demux.src_1 ! queue ! filesink location=demux01.log \
43 : * demux.src_2 ! queue ! filesink location=demux02.log
44 : * ]|
45 : *
46 : * |[
47 : * gst-launch-1.0 tensor_mux name=mux ! tensor_demux name=demux tensorpick=0,1:2,2+0 \
48 : * ... (tensor 0) ! mux.sink_0 \
49 : * ... (tensor 1) ! mux.sink_1 \
50 : * ... (tensor 2) ! mux.sink_2 \
51 : * demux.src_0 ! (tensor 0) ...
52 : * demux.src_1 ! (tensor 1,2) ...
53 : * demux.src_2 ! (tensor 2,0) ...
54 : * ]|
55 : *
56 : * </refsect2>
57 : *
58 : */
59 :
60 :
61 : #ifdef HAVE_CONFIG_H
62 : #include <config.h>
63 : #endif
64 :
65 : #include <string.h>
66 : #include <gst/gst.h>
67 : #include <glib.h>
68 : #include <nnstreamer_util.h>
69 :
70 : #include "gsttensor_demux.h"
71 :
72 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_demux_debug);
73 : #define GST_CAT_DEFAULT gst_tensor_demux_debug
74 :
75 : /**
76 : * @brief Default caps string for sink pad.
77 : */
78 : #define CAPS_STRING_SINK GST_TENSORS_CAP_MAKE ("{ static, flexible }")
79 :
80 : /**
81 : * @brief Default caps string for src pad.
82 : */
83 : #define CAPS_STRING_SRC GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_MAKE ("{ static, flexible }")
84 :
85 : enum
86 : {
87 : PROP_0,
88 : PROP_SILENT,
89 : PROP_TENSORPICK
90 : };
91 :
92 : /**
93 : * @brief the capabilities of the inputs and outputs.
94 : * describe the real formats here.
95 : */
96 : static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src_%u",
97 : GST_PAD_SRC,
98 : GST_PAD_SOMETIMES,
99 : GST_STATIC_CAPS (CAPS_STRING_SRC)
100 : );
101 :
102 : static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
103 : GST_PAD_SINK,
104 : GST_PAD_ALWAYS,
105 : GST_STATIC_CAPS (CAPS_STRING_SINK)
106 : );
107 :
108 : static GstFlowReturn gst_tensor_demux_chain (GstPad * pad, GstObject * parent,
109 : GstBuffer * buf);
110 : static gboolean gst_tensor_demux_event (GstPad * pad, GstObject * parent,
111 : GstEvent * event);
112 : static GstStateChangeReturn gst_tensor_demux_change_state (GstElement * element,
113 : GstStateChange transition);
114 : static void gst_tensor_demux_set_property (GObject * object, guint prop_id,
115 : const GValue * value, GParamSpec * pspec);
116 : static void gst_tensor_demux_get_property (GObject * object, guint prop_id,
117 : GValue * value, GParamSpec * pspec);
118 : static void gst_tensor_demux_dispose (GObject * object);
119 : #define gst_tensor_demux_parent_class parent_class
120 1403 : G_DEFINE_TYPE (GstTensorDemux, gst_tensor_demux, GST_TYPE_ELEMENT);
121 :
122 :
123 : /**
124 : * @brief initialize the tensor_demux's class
125 : */
126 : static void
127 24 : gst_tensor_demux_class_init (GstTensorDemuxClass * klass)
128 : {
129 : GObjectClass *gobject_class;
130 : GstElementClass *gstelement_class;
131 :
132 24 : GST_DEBUG_CATEGORY_INIT (gst_tensor_demux_debug, "tensor_demux", 0,
133 : "Element to demux tensors to tensor stream");
134 :
135 24 : gobject_class = (GObjectClass *) klass;
136 24 : gstelement_class = (GstElementClass *) klass;
137 :
138 24 : parent_class = g_type_class_peek_parent (klass);
139 :
140 24 : gobject_class->dispose = gst_tensor_demux_dispose;
141 24 : gobject_class->get_property = gst_tensor_demux_get_property;
142 24 : gobject_class->set_property = gst_tensor_demux_set_property;
143 :
144 24 : g_object_class_install_property (gobject_class, PROP_SILENT,
145 : g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
146 : TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
147 :
148 24 : g_object_class_install_property (gobject_class, PROP_TENSORPICK,
149 : g_param_spec_string ("tensorpick", "TensorPick",
150 : "Choose nth tensor among tensors ?", "",
151 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 :
153 24 : gstelement_class->change_state =
154 24 : GST_DEBUG_FUNCPTR (gst_tensor_demux_change_state);
155 :
156 24 : gst_element_class_add_pad_template (gstelement_class,
157 : gst_static_pad_template_get (&sink_templ));
158 24 : gst_element_class_add_pad_template (gstelement_class,
159 : gst_static_pad_template_get (&src_templ));
160 :
161 24 : gst_element_class_set_details_simple (gstelement_class,
162 : "TensorDemux",
163 : "Demuxer/Tensor",
164 : "Demux tensors stream to other/tensor stream",
165 : "Jijoong Moon <jijoong.moon@samsung.com>");
166 24 : }
167 :
168 : /**
169 : * @brief initialize the new element
170 : * instantiate pads and add them to element
171 : * set pad callback functions
172 : * initialize instance structure
173 : */
174 : static void
175 33 : gst_tensor_demux_init (GstTensorDemux * tensor_demux)
176 : {
177 33 : tensor_demux->sinkpad =
178 33 : gst_pad_new_from_static_template (&sink_templ, "sink");
179 33 : gst_element_add_pad (GST_ELEMENT_CAST (tensor_demux), tensor_demux->sinkpad);
180 33 : gst_pad_set_chain_function (tensor_demux->sinkpad,
181 : GST_DEBUG_FUNCPTR (gst_tensor_demux_chain));
182 33 : gst_pad_set_event_function (tensor_demux->sinkpad,
183 : GST_DEBUG_FUNCPTR (gst_tensor_demux_event));
184 :
185 33 : tensor_demux->num_srcpads = 0;
186 33 : tensor_demux->silent = TRUE;
187 33 : tensor_demux->tensorpick = NULL;
188 33 : tensor_demux->have_group_id = FALSE;
189 33 : tensor_demux->group_id = G_MAXUINT;
190 33 : tensor_demux->srcpads = NULL;
191 :
192 33 : gst_tensors_config_init (&tensor_demux->tensors_config);
193 33 : }
194 :
195 : /**
196 : * @brief function to remove srcpad list
197 : */
198 : static void
199 63 : gst_tensor_demux_remove_src_pads (GstTensorDemux * tensor_demux)
200 : {
201 149 : while (tensor_demux->srcpads != NULL) {
202 86 : GstTensorPad *tensor_pad = tensor_demux->srcpads->data;
203 86 : gst_element_remove_pad (GST_ELEMENT (tensor_demux), tensor_pad->pad);
204 86 : g_free (tensor_pad);
205 86 : tensor_demux->srcpads =
206 86 : g_slist_delete_link (tensor_demux->srcpads, tensor_demux->srcpads);
207 : }
208 63 : tensor_demux->srcpads = NULL;
209 63 : tensor_demux->num_srcpads = 0;
210 :
211 63 : gst_tensors_config_free (&tensor_demux->tensors_config);
212 63 : gst_tensors_config_init (&tensor_demux->tensors_config);
213 63 : }
214 :
215 : /**
216 : * @brief dispose function for tensor demux (gst element vmethod)
217 : */
218 : static void
219 32 : gst_tensor_demux_dispose (GObject * object)
220 : {
221 32 : GstTensorDemux *tensor_demux = GST_TENSOR_DEMUX (object);
222 :
223 32 : gst_tensor_demux_remove_src_pads (tensor_demux);
224 32 : g_list_free_full (tensor_demux->tensorpick, g_free);
225 32 : G_OBJECT_CLASS (parent_class)->dispose (object);
226 32 : }
227 :
228 : /**
229 : * @brief event function for sink (gst element vmethod)
230 : */
231 : static gboolean
232 128 : gst_tensor_demux_event (GstPad * pad, GstObject * parent, GstEvent * event)
233 : {
234 : GstTensorDemux *tensor_demux;
235 128 : tensor_demux = GST_TENSOR_DEMUX (parent);
236 :
237 128 : switch (GST_EVENT_TYPE (event)) {
238 31 : case GST_EVENT_CAPS:
239 : {
240 : GstCaps *caps;
241 31 : gst_event_parse_caps (event, &caps);
242 31 : gst_tensors_config_from_cap (&tensor_demux->tensors_config, caps);
243 31 : break;
244 : }
245 31 : case GST_EVENT_EOS:
246 31 : if (!tensor_demux->srcpads) {
247 1 : GST_ELEMENT_ERROR (tensor_demux, STREAM, WRONG_TYPE,
248 : ("This stream contains no valid stremas."),
249 : ("Got EOS before adding any pads"));
250 1 : gst_event_unref (event);
251 1 : return FALSE;
252 : }
253 30 : break;
254 66 : default:
255 66 : break;
256 : }
257 :
258 127 : return gst_pad_event_default (pad, parent, event);
259 : }
260 :
261 : /**
262 : * @brief Get tensor config info from configured tensors
263 : * @param tensor_demux "this" pointer
264 : * @param config tensor config to be filled
265 : * @param nth source ordering
266 : * @param total number of tensors
267 : * @return TRUE if successfully configured
268 : */
269 : static gboolean
270 86 : gst_tensor_demux_get_tensor_config (GstTensorDemux * tensor_demux,
271 : GstTensorsConfig * config, const guint nth, const guint total)
272 : {
273 86 : gst_tensors_config_init (config);
274 :
275 86 : if (tensor_demux->tensorpick != NULL) {
276 : gchar *selected_tensor;
277 : gchar **strv;
278 : guint i, num, idx;
279 :
280 15 : g_assert (g_list_length (tensor_demux->tensorpick) >= nth);
281 :
282 15 : selected_tensor = (gchar *) g_list_nth_data (tensor_demux->tensorpick, nth);
283 15 : strv = g_strsplit_set (selected_tensor, ":+", -1);
284 15 : num = g_strv_length (strv);
285 :
286 32 : for (i = 0; i < num; i++) {
287 17 : idx = (guint) g_ascii_strtoll (strv[i], NULL, 10);
288 :
289 : /* Internal error, handle invalid index. */
290 17 : if (idx >= total) {
291 0 : g_strfreev (strv);
292 0 : return FALSE;
293 : }
294 :
295 17 : gst_tensor_info_copy (gst_tensors_info_get_nth_info (&config->info, i),
296 17 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
297 : idx));
298 : }
299 :
300 15 : config->info.num_tensors = num;
301 15 : g_strfreev (strv);
302 : } else {
303 : /* Internal error, handle invalid index. */
304 71 : if (nth >= total)
305 0 : return FALSE;
306 :
307 71 : config->info.num_tensors = 1;
308 71 : gst_tensor_info_copy (&config->info.info[0],
309 71 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
310 : nth));
311 : }
312 :
313 86 : config->info.format = tensor_demux->tensors_config.info.format;
314 86 : config->rate_n = tensor_demux->tensors_config.rate_n;
315 86 : config->rate_d = tensor_demux->tensors_config.rate_d;
316 86 : return TRUE;
317 : }
318 :
319 : /**
320 : * @brief Checking if the source pad is created and if not, create TensorPad
321 : * @param tensor_demux TensorDemux Object
322 : * @param[out] created will be updated in this function
323 : * @param nth source ordering
324 : * @param total number of tensors
325 : * @return TensorPad if pad is already created, then return created pad.
326 : * If not return new pad after creation.
327 : */
328 : static GstTensorPad *
329 429 : gst_tensor_demux_get_tensor_pad (GstTensorDemux * tensor_demux,
330 : gboolean * created, const guint nth, const guint total)
331 : {
332 429 : GstElement *element = GST_ELEMENT_CAST (tensor_demux);
333 429 : g_autofree gchar *element_name = gst_element_get_name (element);
334 : GSList *walk;
335 : GstPad *pad;
336 : GstTensorPad *tensorpad;
337 : gchar *name;
338 : GstEvent *event;
339 : gchar *stream_id;
340 429 : GstCaps *caps = NULL;
341 : GstTensorsConfig config;
342 :
343 429 : walk = tensor_demux->srcpads;
344 1642 : while (walk) {
345 1556 : GstTensorPad *pad = (GstTensorPad *) walk->data;
346 1556 : if (nth == pad->nth) {
347 343 : if (created) {
348 343 : *created = FALSE;
349 : }
350 343 : return pad;
351 : }
352 1213 : walk = walk->next;
353 : }
354 :
355 86 : tensorpad = g_new0 (GstTensorPad, 1);
356 86 : g_assert (tensorpad != NULL);
357 86 : GST_DEBUG_OBJECT (tensor_demux, "creating pad: %d(%dth)",
358 : tensor_demux->num_srcpads, nth);
359 :
360 86 : name = g_strdup_printf ("src_%u", tensor_demux->num_srcpads);
361 86 : pad = gst_pad_new_from_static_template (&src_templ, name);
362 86 : stream_id = gst_pad_create_stream_id_printf (pad, element,
363 : "%s-nnsdemux-%s-%08x", element_name, name, g_random_int ());
364 86 : g_free (name);
365 :
366 86 : tensorpad->pad = pad;
367 86 : tensorpad->nth = nth;
368 86 : tensorpad->last_ret = GST_FLOW_OK;
369 86 : tensorpad->last_ts = GST_CLOCK_TIME_NONE;
370 :
371 86 : tensor_demux->srcpads = g_slist_append (tensor_demux->srcpads, tensorpad);
372 86 : tensor_demux->num_srcpads++;
373 :
374 86 : gst_pad_use_fixed_caps (pad);
375 86 : gst_pad_set_active (pad, TRUE);
376 86 : gst_element_add_pad (GST_ELEMENT_CAST (tensor_demux), pad);
377 :
378 86 : if (!tensor_demux->have_group_id) {
379 : event =
380 86 : gst_pad_get_sticky_event (tensor_demux->sinkpad, GST_EVENT_STREAM_START,
381 : 0);
382 86 : if (event) {
383 86 : tensor_demux->have_group_id =
384 86 : gst_event_parse_group_id (event, &tensor_demux->group_id);
385 86 : gst_event_unref (event);
386 0 : } else if (!tensor_demux->have_group_id) {
387 0 : tensor_demux->have_group_id = TRUE;
388 0 : tensor_demux->group_id = gst_util_group_id_next ();
389 : }
390 : }
391 :
392 86 : event = gst_event_new_stream_start (stream_id);
393 86 : if (tensor_demux->have_group_id)
394 0 : gst_event_set_group_id (event, tensor_demux->group_id);
395 :
396 86 : gst_pad_store_sticky_event (pad, event);
397 86 : g_free (stream_id);
398 86 : gst_event_unref (event);
399 :
400 : /* configure nth pad caps */
401 86 : if (gst_tensor_demux_get_tensor_config (tensor_demux, &config, nth, total)) {
402 86 : caps = gst_tensor_pad_caps_from_config (pad, &config);
403 :
404 86 : gst_pad_set_caps (pad, caps);
405 86 : gst_caps_unref (caps);
406 : } else {
407 0 : GST_WARNING_OBJECT (tensor_demux, "Unable to set pad caps");
408 : }
409 :
410 86 : if (created) {
411 86 : *created = TRUE;
412 : }
413 :
414 86 : if (tensor_demux->tensorpick != NULL) {
415 15 : GST_DEBUG_OBJECT (tensor_demux, "TensorPick is set! : %dth tensor\n", nth);
416 15 : if (g_list_length (tensor_demux->tensorpick) == tensor_demux->num_srcpads) {
417 9 : gst_element_no_more_pads (GST_ELEMENT_CAST (tensor_demux));
418 : }
419 : }
420 :
421 86 : gst_tensors_config_free (&config);
422 86 : return tensorpad;
423 : }
424 :
425 : /**
426 : * @brief Check the status among sources in demux
427 : * @param tensor_demux TensorDemux Object
428 : * @param TensorPad Tensorpad
429 : * @param ret return status of current pad
430 : * @return return status after check sources
431 : */
432 : static GstFlowReturn
433 429 : gst_tensor_demux_combine_flows (GstTensorDemux * tensor_demux,
434 : GstTensorPad * pad, GstFlowReturn ret)
435 : {
436 : GSList *walk;
437 429 : pad->last_ret = ret;
438 :
439 429 : if (ret != GST_FLOW_NOT_LINKED)
440 344 : goto done;
441 :
442 85 : for (walk = tensor_demux->srcpads; walk; walk = g_slist_next (walk)) {
443 85 : GstTensorPad *opad = (GstTensorPad *) walk->data;
444 85 : ret = opad->last_ret;
445 85 : if (ret != GST_FLOW_NOT_LINKED)
446 85 : goto done;
447 : }
448 0 : done:
449 429 : return ret;
450 : }
451 :
452 : /**
453 : * @brief chain function for sink (gst element vmethod)
454 : */
455 : static GstFlowReturn
456 151 : gst_tensor_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
457 : {
458 : guint num_tensors, num_srcs, i, idx;
459 151 : GstFlowReturn res = GST_FLOW_OK;
460 : GstTensorDemux *tensor_demux;
461 151 : GList *list = NULL;
462 : GstTensorInfo *_info;
463 :
464 : UNUSED (pad);
465 151 : tensor_demux = GST_TENSOR_DEMUX (parent);
466 :
467 151 : buf = gst_tensor_buffer_from_config (buf, &tensor_demux->tensors_config);
468 :
469 : /**
470 : * The number of tensors in the buffer:
471 : * The number of tensors from caps and gst-buffer should be same when incoming buffer is static tensor.
472 : * If given buffer is flexible tensor, we cannot get exact number of tensors from config.
473 : */
474 151 : num_tensors = gst_tensor_buffer_get_count (buf);
475 151 : if (gst_tensors_config_is_static (&tensor_demux->tensors_config))
476 144 : g_assert (tensor_demux->tensors_config.info.num_tensors == num_tensors);
477 :
478 151 : GST_DEBUG_OBJECT (tensor_demux, " Number of Tensors: %d", num_tensors);
479 :
480 151 : num_srcs = num_tensors;
481 151 : if (tensor_demux->tensorpick != NULL) {
482 44 : num_srcs = g_list_length (tensor_demux->tensorpick);
483 44 : list = tensor_demux->tensorpick;
484 : }
485 :
486 577 : for (i = 0; i < num_srcs; i++) {
487 : GstTensorPad *srcpad;
488 : GstBuffer *outbuf;
489 : GstMemory *mem;
490 : gboolean created;
491 : GstClockTime ts;
492 :
493 429 : srcpad = gst_tensor_demux_get_tensor_pad (tensor_demux, &created, i,
494 : num_tensors);
495 429 : outbuf = gst_buffer_new ();
496 :
497 429 : if (tensor_demux->tensorpick != NULL) {
498 : guint num, j;
499 67 : gchar **strv = g_strsplit_set ((gchar *) list->data, ":+", -1);
500 :
501 67 : num = g_strv_length (strv);
502 136 : for (j = 0; j < num; j++) {
503 69 : idx = (guint) g_ascii_strtoll (strv[j], NULL, 10);
504 : _info =
505 69 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
506 : idx);
507 69 : mem = gst_tensor_buffer_get_nth_memory (buf, idx);
508 69 : if (!gst_tensor_buffer_append_memory (outbuf, mem, _info)) {
509 0 : gst_buffer_unref (outbuf);
510 0 : res = GST_FLOW_ERROR;
511 0 : goto error;
512 : }
513 : }
514 67 : g_strfreev (strv);
515 67 : list = list->next;
516 : } else {
517 : _info =
518 362 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info, i);
519 362 : mem = gst_tensor_buffer_get_nth_memory (buf, i);
520 362 : if (!gst_tensor_buffer_append_memory (outbuf, mem, _info)) {
521 0 : gst_buffer_unref (outbuf);
522 0 : res = GST_FLOW_ERROR;
523 0 : goto error;
524 : }
525 : }
526 :
527 429 : ts = GST_BUFFER_TIMESTAMP (buf);
528 :
529 429 : if (created) {
530 : GstSegment segment;
531 86 : gst_segment_init (&segment, GST_FORMAT_TIME);
532 86 : gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
533 : }
534 :
535 429 : outbuf = gst_buffer_make_writable (outbuf);
536 :
537 : /* metadata from incoming buffer */
538 429 : gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
539 :
540 429 : if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
541 429 : srcpad->last_ts = ts;
542 : } else {
543 0 : GST_DEBUG_OBJECT (tensor_demux, "invalid timestamp %" GST_TIME_FORMAT,
544 : GST_TIME_ARGS (ts));
545 : }
546 :
547 429 : GST_DEBUG_OBJECT (tensor_demux,
548 : "pushing buffer with timestamp %" GST_TIME_FORMAT,
549 : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
550 429 : res = gst_pad_push (srcpad->pad, outbuf);
551 429 : res = gst_tensor_demux_combine_flows (tensor_demux, srcpad, res);
552 :
553 429 : if (res != GST_FLOW_OK)
554 3 : break;
555 : }
556 :
557 148 : error:
558 151 : gst_buffer_unref (buf);
559 151 : return res;
560 : }
561 :
562 : /**
563 : * @brief change state (gst element vmethod)
564 : */
565 : static GstStateChangeReturn
566 186 : gst_tensor_demux_change_state (GstElement * element, GstStateChange transition)
567 : {
568 : GstTensorDemux *tensor_demux;
569 : GstStateChangeReturn ret;
570 186 : tensor_demux = GST_TENSOR_DEMUX (element);
571 186 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
572 186 : if (ret == GST_STATE_CHANGE_FAILURE)
573 0 : return ret;
574 186 : switch (transition) {
575 30 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
576 30 : break;
577 31 : case GST_STATE_CHANGE_PAUSED_TO_READY:
578 31 : tensor_demux->group_id = G_MAXUINT;
579 31 : tensor_demux->have_group_id = FALSE;
580 31 : gst_tensor_demux_remove_src_pads (tensor_demux);
581 31 : break;
582 31 : case GST_STATE_CHANGE_READY_TO_NULL:
583 31 : break;
584 94 : default:
585 94 : break;
586 : }
587 :
588 186 : return ret;
589 : }
590 :
591 : /**
592 : * @brief Get property (gst element vmethod)
593 : */
594 : static void
595 12 : gst_tensor_demux_set_property (GObject * object, guint prop_id,
596 : const GValue * value, GParamSpec * pspec)
597 : {
598 12 : GstTensorDemux *filter = GST_TENSOR_DEMUX (object);
599 12 : switch (prop_id) {
600 2 : case PROP_SILENT:
601 2 : filter->silent = g_value_get_boolean (value);
602 2 : break;
603 10 : case PROP_TENSORPICK:
604 : {
605 : guint i;
606 10 : const gchar *param = g_value_get_string (value);
607 10 : gchar **strv = g_strsplit_set (param, ",.;/", -1);
608 10 : guint num = g_strv_length (strv);
609 :
610 : /* Before setting the new Tensor Pick data, the existing one should be removed. */
611 10 : if (filter->tensorpick) {
612 0 : g_list_free_full (filter->tensorpick, g_free);
613 0 : filter->tensorpick = NULL;
614 : }
615 27 : for (i = 0; i < num; i++) {
616 17 : gchar *tmp = g_strdup (strv[i]);
617 17 : filter->tensorpick = g_list_append (filter->tensorpick, tmp);
618 : }
619 10 : g_strfreev (strv);
620 10 : break;
621 : }
622 0 : default:
623 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
624 0 : break;
625 : }
626 12 : }
627 :
628 : /**
629 : * @brief Get property (gst element vmethod)
630 : */
631 : static void
632 6 : gst_tensor_demux_get_property (GObject * object, guint prop_id,
633 : GValue * value, GParamSpec * pspec)
634 : {
635 6 : GstTensorDemux *filter = GST_TENSOR_DEMUX (object);
636 6 : switch (prop_id) {
637 4 : case PROP_SILENT:
638 4 : g_value_set_boolean (value, filter->silent);
639 4 : break;
640 2 : case PROP_TENSORPICK:
641 : {
642 : GList *list;
643 : char *p;
644 2 : GPtrArray *arr = g_ptr_array_new ();
645 : gchar **strings;
646 :
647 6 : for (list = filter->tensorpick; list != NULL; list = list->next) {
648 4 : g_ptr_array_add (arr, g_strdup_printf ("%s", (gchar *) list->data));
649 : }
650 2 : g_ptr_array_add (arr, NULL);
651 2 : strings = (gchar **) g_ptr_array_free (arr, FALSE);
652 2 : p = g_strjoinv (",", strings);
653 2 : g_strfreev (strings);
654 2 : g_value_take_string (value, p);
655 2 : break;
656 : }
657 0 : default:
658 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
659 0 : break;
660 : }
661 6 : }
|