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 1433 : 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 34 : gst_tensor_demux_class_init (GstTensorDemuxClass * klass)
128 : {
129 : GObjectClass *gobject_class;
130 : GstElementClass *gstelement_class;
131 :
132 34 : GST_DEBUG_CATEGORY_INIT (gst_tensor_demux_debug, "tensor_demux", 0,
133 : "Element to demux tensors to tensor stream");
134 :
135 34 : gobject_class = (GObjectClass *) klass;
136 34 : gstelement_class = (GstElementClass *) klass;
137 :
138 34 : parent_class = g_type_class_peek_parent (klass);
139 :
140 34 : gobject_class->dispose = gst_tensor_demux_dispose;
141 34 : gobject_class->get_property = gst_tensor_demux_get_property;
142 34 : gobject_class->set_property = gst_tensor_demux_set_property;
143 :
144 34 : 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 34 : 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 34 : gstelement_class->change_state =
154 34 : GST_DEBUG_FUNCPTR (gst_tensor_demux_change_state);
155 :
156 34 : gst_element_class_add_pad_template (gstelement_class,
157 : gst_static_pad_template_get (&sink_templ));
158 34 : gst_element_class_add_pad_template (gstelement_class,
159 : gst_static_pad_template_get (&src_templ));
160 :
161 34 : 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 34 : }
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 :
242 31 : gst_event_parse_caps (event, &caps);
243 31 : gst_tensors_config_from_caps (&tensor_demux->tensors_config, caps, TRUE);
244 31 : break;
245 : }
246 31 : case GST_EVENT_EOS:
247 31 : if (!tensor_demux->srcpads) {
248 1 : GST_ELEMENT_ERROR (tensor_demux, STREAM, WRONG_TYPE,
249 : ("This stream contains no valid stremas."),
250 : ("Got EOS before adding any pads"));
251 1 : gst_event_unref (event);
252 1 : return FALSE;
253 : }
254 30 : break;
255 66 : default:
256 66 : break;
257 : }
258 :
259 127 : return gst_pad_event_default (pad, parent, event);
260 : }
261 :
262 : /**
263 : * @brief Get tensor config info from configured tensors
264 : * @param tensor_demux "this" pointer
265 : * @param config tensor config to be filled
266 : * @param nth source ordering
267 : * @param total number of tensors
268 : * @return TRUE if successfully configured
269 : */
270 : static gboolean
271 86 : gst_tensor_demux_get_tensor_config (GstTensorDemux * tensor_demux,
272 : GstTensorsConfig * config, const guint nth, const guint total)
273 : {
274 86 : gst_tensors_config_init (config);
275 :
276 86 : if (tensor_demux->tensorpick != NULL) {
277 : gchar *selected_tensor;
278 : gchar **strv;
279 : guint i, num, idx;
280 :
281 15 : g_assert (g_list_length (tensor_demux->tensorpick) >= nth);
282 :
283 15 : selected_tensor = (gchar *) g_list_nth_data (tensor_demux->tensorpick, nth);
284 15 : strv = g_strsplit_set (selected_tensor, ":+", -1);
285 15 : num = g_strv_length (strv);
286 :
287 32 : for (i = 0; i < num; i++) {
288 17 : idx = (guint) g_ascii_strtoll (strv[i], NULL, 10);
289 :
290 : /* Internal error, handle invalid index. */
291 17 : if (idx >= total) {
292 0 : g_strfreev (strv);
293 0 : return FALSE;
294 : }
295 :
296 17 : gst_tensor_info_copy (gst_tensors_info_get_nth_info (&config->info, i),
297 17 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
298 : idx));
299 : }
300 :
301 15 : config->info.num_tensors = num;
302 15 : g_strfreev (strv);
303 : } else {
304 : /* Internal error, handle invalid index. */
305 71 : if (nth >= total)
306 0 : return FALSE;
307 :
308 71 : config->info.num_tensors = 1;
309 71 : gst_tensor_info_copy (&config->info.info[0],
310 71 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
311 : nth));
312 : }
313 :
314 86 : config->info.format = tensor_demux->tensors_config.info.format;
315 86 : config->rate_n = tensor_demux->tensors_config.rate_n;
316 86 : config->rate_d = tensor_demux->tensors_config.rate_d;
317 86 : return TRUE;
318 : }
319 :
320 : /**
321 : * @brief Checking if the source pad is created and if not, create TensorPad
322 : * @param tensor_demux TensorDemux Object
323 : * @param[out] created will be updated in this function
324 : * @param nth source ordering
325 : * @param total number of tensors
326 : * @return TensorPad if pad is already created, then return created pad.
327 : * If not return new pad after creation.
328 : */
329 : static GstTensorPad *
330 429 : gst_tensor_demux_get_tensor_pad (GstTensorDemux * tensor_demux,
331 : gboolean * created, const guint nth, const guint total)
332 : {
333 429 : GstElement *element = GST_ELEMENT_CAST (tensor_demux);
334 429 : g_autofree gchar *element_name = gst_element_get_name (element);
335 : GSList *walk;
336 : GstPad *pad;
337 : GstTensorPad *tensorpad;
338 : gchar *name;
339 : GstEvent *event;
340 : gchar *stream_id;
341 429 : GstCaps *caps = NULL;
342 : GstTensorsConfig config;
343 :
344 429 : walk = tensor_demux->srcpads;
345 1642 : while (walk) {
346 1556 : GstTensorPad *pad = (GstTensorPad *) walk->data;
347 1556 : if (nth == pad->nth) {
348 343 : if (created) {
349 343 : *created = FALSE;
350 : }
351 343 : return pad;
352 : }
353 1213 : walk = walk->next;
354 : }
355 :
356 86 : tensorpad = g_new0 (GstTensorPad, 1);
357 86 : g_assert (tensorpad != NULL);
358 86 : GST_DEBUG_OBJECT (tensor_demux, "creating pad: %d(%dth)",
359 : tensor_demux->num_srcpads, nth);
360 :
361 86 : name = g_strdup_printf ("src_%u", tensor_demux->num_srcpads);
362 86 : pad = gst_pad_new_from_static_template (&src_templ, name);
363 86 : stream_id = gst_pad_create_stream_id_printf (pad, element,
364 : "%s-nnsdemux-%s-%08x", element_name, name, g_random_int ());
365 86 : g_free (name);
366 :
367 86 : tensorpad->pad = pad;
368 86 : tensorpad->nth = nth;
369 86 : tensorpad->last_ret = GST_FLOW_OK;
370 86 : tensorpad->last_ts = GST_CLOCK_TIME_NONE;
371 :
372 86 : tensor_demux->srcpads = g_slist_append (tensor_demux->srcpads, tensorpad);
373 86 : tensor_demux->num_srcpads++;
374 :
375 86 : gst_pad_use_fixed_caps (pad);
376 86 : gst_pad_set_active (pad, TRUE);
377 86 : gst_element_add_pad (GST_ELEMENT_CAST (tensor_demux), pad);
378 :
379 86 : if (!tensor_demux->have_group_id) {
380 : event =
381 86 : gst_pad_get_sticky_event (tensor_demux->sinkpad, GST_EVENT_STREAM_START,
382 : 0);
383 86 : if (event) {
384 86 : tensor_demux->have_group_id =
385 86 : gst_event_parse_group_id (event, &tensor_demux->group_id);
386 86 : gst_event_unref (event);
387 0 : } else if (!tensor_demux->have_group_id) {
388 0 : tensor_demux->have_group_id = TRUE;
389 0 : tensor_demux->group_id = gst_util_group_id_next ();
390 : }
391 : }
392 :
393 86 : event = gst_event_new_stream_start (stream_id);
394 86 : if (tensor_demux->have_group_id)
395 0 : gst_event_set_group_id (event, tensor_demux->group_id);
396 :
397 86 : gst_pad_store_sticky_event (pad, event);
398 86 : g_free (stream_id);
399 86 : gst_event_unref (event);
400 :
401 : /* configure nth pad caps */
402 86 : if (gst_tensor_demux_get_tensor_config (tensor_demux, &config, nth, total)) {
403 86 : caps = gst_tensor_pad_caps_from_config (pad, &config);
404 :
405 86 : gst_pad_set_caps (pad, caps);
406 86 : gst_caps_unref (caps);
407 : } else {
408 0 : GST_WARNING_OBJECT (tensor_demux, "Unable to set pad caps");
409 : }
410 :
411 86 : if (created) {
412 86 : *created = TRUE;
413 : }
414 :
415 86 : if (tensor_demux->tensorpick != NULL) {
416 15 : GST_DEBUG_OBJECT (tensor_demux, "TensorPick is set! : %dth tensor\n", nth);
417 15 : if (g_list_length (tensor_demux->tensorpick) == tensor_demux->num_srcpads) {
418 9 : gst_element_no_more_pads (GST_ELEMENT_CAST (tensor_demux));
419 : }
420 : }
421 :
422 86 : gst_tensors_config_free (&config);
423 86 : return tensorpad;
424 : }
425 :
426 : /**
427 : * @brief Check the status among sources in demux
428 : * @param tensor_demux TensorDemux Object
429 : * @param TensorPad Tensorpad
430 : * @param ret return status of current pad
431 : * @return return status after check sources
432 : */
433 : static GstFlowReturn
434 429 : gst_tensor_demux_combine_flows (GstTensorDemux * tensor_demux,
435 : GstTensorPad * pad, GstFlowReturn ret)
436 : {
437 : GSList *walk;
438 429 : pad->last_ret = ret;
439 :
440 429 : if (ret != GST_FLOW_NOT_LINKED)
441 344 : goto done;
442 :
443 85 : for (walk = tensor_demux->srcpads; walk; walk = g_slist_next (walk)) {
444 85 : GstTensorPad *opad = (GstTensorPad *) walk->data;
445 85 : ret = opad->last_ret;
446 85 : if (ret != GST_FLOW_NOT_LINKED)
447 85 : goto done;
448 : }
449 0 : done:
450 429 : return ret;
451 : }
452 :
453 : /**
454 : * @brief chain function for sink (gst element vmethod)
455 : */
456 : static GstFlowReturn
457 151 : gst_tensor_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
458 : {
459 : guint num_tensors, num_srcs, i, idx;
460 151 : GstFlowReturn res = GST_FLOW_OK;
461 : GstTensorDemux *tensor_demux;
462 151 : GList *list = NULL;
463 : GstTensorInfo *_info;
464 :
465 : UNUSED (pad);
466 151 : tensor_demux = GST_TENSOR_DEMUX (parent);
467 :
468 151 : buf = gst_tensor_buffer_from_config (buf, &tensor_demux->tensors_config);
469 :
470 : /**
471 : * The number of tensors in the buffer:
472 : * The number of tensors from caps and gst-buffer should be same when incoming buffer is static tensor.
473 : * If given buffer is flexible tensor, we cannot get exact number of tensors from config.
474 : */
475 151 : num_tensors = gst_tensor_buffer_get_count (buf);
476 151 : if (gst_tensors_config_is_static (&tensor_demux->tensors_config))
477 144 : g_assert (tensor_demux->tensors_config.info.num_tensors == num_tensors);
478 :
479 151 : GST_DEBUG_OBJECT (tensor_demux, " Number of Tensors: %d", num_tensors);
480 :
481 151 : num_srcs = num_tensors;
482 151 : if (tensor_demux->tensorpick != NULL) {
483 44 : num_srcs = g_list_length (tensor_demux->tensorpick);
484 44 : list = tensor_demux->tensorpick;
485 : }
486 :
487 577 : for (i = 0; i < num_srcs; i++) {
488 : GstTensorPad *srcpad;
489 : GstBuffer *outbuf;
490 : GstMemory *mem;
491 : gboolean created;
492 : GstClockTime ts;
493 :
494 429 : srcpad = gst_tensor_demux_get_tensor_pad (tensor_demux, &created, i,
495 : num_tensors);
496 429 : outbuf = gst_buffer_new ();
497 :
498 429 : if (tensor_demux->tensorpick != NULL) {
499 : guint num, j;
500 67 : gchar **strv = g_strsplit_set ((gchar *) list->data, ":+", -1);
501 :
502 67 : num = g_strv_length (strv);
503 136 : for (j = 0; j < num; j++) {
504 69 : idx = (guint) g_ascii_strtoll (strv[j], NULL, 10);
505 : _info =
506 69 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info,
507 : idx);
508 69 : mem = gst_tensor_buffer_get_nth_memory (buf, idx);
509 69 : if (!gst_tensor_buffer_append_memory (outbuf, mem, _info)) {
510 0 : gst_buffer_unref (outbuf);
511 0 : res = GST_FLOW_ERROR;
512 0 : goto error;
513 : }
514 : }
515 67 : g_strfreev (strv);
516 67 : list = list->next;
517 : } else {
518 : _info =
519 362 : gst_tensors_info_get_nth_info (&tensor_demux->tensors_config.info, i);
520 362 : mem = gst_tensor_buffer_get_nth_memory (buf, i);
521 362 : if (!gst_tensor_buffer_append_memory (outbuf, mem, _info)) {
522 0 : gst_buffer_unref (outbuf);
523 0 : res = GST_FLOW_ERROR;
524 0 : goto error;
525 : }
526 : }
527 :
528 429 : ts = GST_BUFFER_TIMESTAMP (buf);
529 :
530 429 : if (created) {
531 : GstSegment segment;
532 86 : gst_segment_init (&segment, GST_FORMAT_TIME);
533 86 : gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment));
534 : }
535 :
536 429 : outbuf = gst_buffer_make_writable (outbuf);
537 :
538 : /* metadata from incoming buffer */
539 429 : gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
540 :
541 429 : if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) {
542 429 : srcpad->last_ts = ts;
543 : } else {
544 0 : GST_DEBUG_OBJECT (tensor_demux, "invalid timestamp %" GST_TIME_FORMAT,
545 : GST_TIME_ARGS (ts));
546 : }
547 :
548 429 : GST_DEBUG_OBJECT (tensor_demux,
549 : "pushing buffer with timestamp %" GST_TIME_FORMAT,
550 : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
551 429 : res = gst_pad_push (srcpad->pad, outbuf);
552 429 : res = gst_tensor_demux_combine_flows (tensor_demux, srcpad, res);
553 :
554 429 : if (res != GST_FLOW_OK)
555 3 : break;
556 : }
557 :
558 148 : error:
559 151 : gst_buffer_unref (buf);
560 151 : return res;
561 : }
562 :
563 : /**
564 : * @brief change state (gst element vmethod)
565 : */
566 : static GstStateChangeReturn
567 186 : gst_tensor_demux_change_state (GstElement * element, GstStateChange transition)
568 : {
569 : GstTensorDemux *tensor_demux;
570 : GstStateChangeReturn ret;
571 186 : tensor_demux = GST_TENSOR_DEMUX (element);
572 186 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
573 186 : if (ret == GST_STATE_CHANGE_FAILURE)
574 0 : return ret;
575 186 : switch (transition) {
576 30 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
577 30 : break;
578 31 : case GST_STATE_CHANGE_PAUSED_TO_READY:
579 31 : tensor_demux->group_id = G_MAXUINT;
580 31 : tensor_demux->have_group_id = FALSE;
581 31 : gst_tensor_demux_remove_src_pads (tensor_demux);
582 31 : break;
583 31 : case GST_STATE_CHANGE_READY_TO_NULL:
584 31 : break;
585 94 : default:
586 94 : break;
587 : }
588 :
589 186 : return ret;
590 : }
591 :
592 : /**
593 : * @brief Get property (gst element vmethod)
594 : */
595 : static void
596 12 : gst_tensor_demux_set_property (GObject * object, guint prop_id,
597 : const GValue * value, GParamSpec * pspec)
598 : {
599 12 : GstTensorDemux *filter = GST_TENSOR_DEMUX (object);
600 12 : switch (prop_id) {
601 2 : case PROP_SILENT:
602 2 : filter->silent = g_value_get_boolean (value);
603 2 : break;
604 10 : case PROP_TENSORPICK:
605 : {
606 : guint i;
607 10 : const gchar *param = g_value_get_string (value);
608 10 : gchar **strv = g_strsplit_set (param, ",.;/", -1);
609 10 : guint num = g_strv_length (strv);
610 :
611 : /* Before setting the new Tensor Pick data, the existing one should be removed. */
612 10 : if (filter->tensorpick) {
613 0 : g_list_free_full (filter->tensorpick, g_free);
614 0 : filter->tensorpick = NULL;
615 : }
616 27 : for (i = 0; i < num; i++) {
617 17 : gchar *tmp = g_strdup (strv[i]);
618 17 : filter->tensorpick = g_list_append (filter->tensorpick, tmp);
619 : }
620 10 : g_strfreev (strv);
621 10 : break;
622 : }
623 0 : default:
624 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
625 0 : break;
626 : }
627 12 : }
628 :
629 : /**
630 : * @brief Get property (gst element vmethod)
631 : */
632 : static void
633 6 : gst_tensor_demux_get_property (GObject * object, guint prop_id,
634 : GValue * value, GParamSpec * pspec)
635 : {
636 6 : GstTensorDemux *filter = GST_TENSOR_DEMUX (object);
637 6 : switch (prop_id) {
638 4 : case PROP_SILENT:
639 4 : g_value_set_boolean (value, filter->silent);
640 4 : break;
641 2 : case PROP_TENSORPICK:
642 : {
643 : GList *list;
644 : char *p;
645 2 : GPtrArray *arr = g_ptr_array_new ();
646 : gchar **strings;
647 :
648 6 : for (list = filter->tensorpick; list != NULL; list = list->next) {
649 4 : g_ptr_array_add (arr, g_strdup_printf ("%s", (gchar *) list->data));
650 : }
651 2 : g_ptr_array_add (arr, NULL);
652 2 : strings = (gchar **) g_ptr_array_free (arr, FALSE);
653 2 : p = g_strjoinv (",", strings);
654 2 : g_strfreev (strings);
655 2 : g_value_take_string (value, p);
656 2 : break;
657 : }
658 0 : default:
659 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
660 0 : break;
661 : }
662 6 : }
|