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 : *
8 : * This library is free software; you can redistribute it and/or
9 : * modify it under the terms of the GNU Library General Public
10 : * License as published by the Free Software Foundation;
11 : * version 2.1 of the License.
12 : *
13 : * This library is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : * Library General Public License for more details.
17 : *
18 : */
19 : /**
20 : * @file gsttensor_mux.c
21 : * @date 03 July 2018
22 : * @brief GStreamer plugin to mux tensors (as a filter for other general neural network filters)
23 : * @see https://github.com/nnstreamer/nnstreamer
24 : * @author Jijoong Moon <jijoong.moon@samsung.com>
25 : * @bug No known bugs except for NYI items
26 : *
27 : */
28 :
29 : /**
30 : * SECTION:element-tensormux
31 : *
32 : * A Muxer that merge tensor stream to tensors stream for NN frameworks.
33 : * The output is always in the format of other/tensors
34 : *
35 : * <refsect2>
36 : * <title>Example launch line</title>
37 : * |[
38 : * gst-launch -v -m \
39 : * filesrc location=b.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter ! mux.sink_0 \
40 : * filesrc location=b.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter ! mux.sink_1 \
41 : * filesrc location=b.png ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=RGB,width=100,height=100,framerate=0/1 ! tensor_converter ! mux.sink_2 \
42 : * tensor_mux name=mux ! fakesink
43 : * ]|
44 : *
45 : * |[
46 : * gst-launch -v -m \
47 : * multifilesrc location="testsequence_%1d.png" index=0 caps="image/png, framerate=(fraction)30/1" ! pngdec ! tensor_converter ! mux.sink_0 \
48 : * multifilesrc location="testsequence_%1d.png" index=0 caps="image/png, framerate=(fraction)30/1" ! pngdec ! tensor_converter ! mux.sink_1 \
49 : * multifilesrc location="testsequence_%1d.png" index=0 caps="image/png, framerate=(fraction)30/1" ! pngdec ! tensor_converter ! mux.sink_2 \
50 : * tensor_mux name=mux ! filesink location=mux.log
51 : * ]|
52 : * </refsect2 >
53 : *
54 : */
55 :
56 :
57 : #ifdef HAVE_CONFIG_H
58 : #include <config.h>
59 : #endif
60 :
61 : #include <string.h>
62 : #include <gst/gst.h>
63 : #include <glib.h>
64 : #include <nnstreamer_util.h>
65 :
66 : #include "gsttensor_mux.h"
67 :
68 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_mux_debug);
69 : #define GST_CAT_DEFAULT gst_tensor_mux_debug
70 :
71 : /**
72 : * @brief Macro for debug mode.
73 : */
74 : #ifndef DBG
75 : #define DBG (!tensor_mux->silent)
76 : #endif
77 :
78 : enum
79 : {
80 : PROP_0,
81 : PROP_SILENT,
82 : PROP_SYNC_MODE,
83 : PROP_SYNC_OPTION,
84 : };
85 :
86 : /**
87 : * @brief Default caps string for sink pad.
88 : */
89 : #define CAPS_STRING_SINK GST_TENSOR_CAP_DEFAULT ";" GST_TENSORS_CAP_MAKE ("{ static, flexible }")
90 :
91 : /**
92 : * @brief Default caps string for src pad.
93 : */
94 : #define CAPS_STRING_SRC GST_TENSORS_CAP_MAKE ("{ static, flexible }")
95 :
96 : /**
97 : * @brief the capabilities of the inputs and outputs.
98 : * describe the real formats here.
99 : */
100 : static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
101 : GST_PAD_SRC,
102 : GST_PAD_ALWAYS,
103 : GST_STATIC_CAPS (CAPS_STRING_SRC)
104 : );
105 :
106 : static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink_%u",
107 : GST_PAD_SINK,
108 : GST_PAD_REQUEST,
109 : GST_STATIC_CAPS (CAPS_STRING_SINK)
110 : );
111 :
112 : static gboolean gst_tensor_mux_src_event (GstPad * pad, GstObject * parent,
113 : GstEvent * event);
114 : static GstPad *gst_tensor_mux_request_new_pad (GstElement * element,
115 : GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
116 : static GstStateChangeReturn gst_tensor_mux_change_state (GstElement * element,
117 : GstStateChange transition);
118 : static gboolean gst_tensor_mux_sink_event (GstCollectPads * pads,
119 : GstCollectData * data, GstEvent * event, GstTensorMux * tensor_mux);
120 : static GstFlowReturn gst_tensor_mux_collected (GstCollectPads * pads,
121 : GstTensorMux * tensor_mux);
122 : static GstFlowReturn gst_tensor_mux_do_clip (GstCollectPads * pads,
123 : GstCollectData * data, GstBuffer * buffer, GstBuffer ** out,
124 : GstTensorMux * tensor_mux);
125 :
126 : static void gst_tensor_mux_set_property (GObject * object, guint prop_id,
127 : const GValue * value, GParamSpec * pspec);
128 : static void gst_tensor_mux_get_property (GObject * object, guint prop_id,
129 : GValue * value, GParamSpec * pspec);
130 : static void gst_tensor_mux_finalize (GObject * object);
131 :
132 : #define gst_tensor_mux_parent_class parent_class
133 2689 : G_DEFINE_TYPE (GstTensorMux, gst_tensor_mux, GST_TYPE_ELEMENT);
134 :
135 : /**
136 : * @brief initialize the tensor_mux's class
137 : */
138 : static void
139 76 : gst_tensor_mux_class_init (GstTensorMuxClass * klass)
140 : {
141 : GObjectClass *gobject_class;
142 : GstElementClass *gstelement_class;
143 :
144 76 : GST_DEBUG_CATEGORY_INIT (gst_tensor_mux_debug, "tensor_mux", 0,
145 : "Element to merge tensor stream to tensors stream");
146 :
147 76 : gobject_class = (GObjectClass *) klass;
148 76 : gstelement_class = (GstElementClass *) klass;
149 :
150 76 : parent_class = g_type_class_peek_parent (klass);
151 :
152 76 : gobject_class->finalize = gst_tensor_mux_finalize;
153 76 : gobject_class->get_property = gst_tensor_mux_get_property;
154 76 : gobject_class->set_property = gst_tensor_mux_set_property;
155 :
156 76 : g_object_class_install_property (gobject_class, PROP_SILENT,
157 : g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
158 : TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
159 :
160 76 : g_object_class_install_property (gobject_class, PROP_SYNC_MODE,
161 : g_param_spec_string ("sync-mode", "Sync Mode",
162 : "Time synchronization mode?", "", G_PARAM_READWRITE));
163 :
164 76 : g_object_class_install_property (gobject_class, PROP_SYNC_OPTION,
165 : g_param_spec_string ("sync-option", "Sync Option",
166 : "Option for the time synchronization mode ?", "", G_PARAM_READWRITE));
167 :
168 76 : gstelement_class->request_new_pad =
169 76 : GST_DEBUG_FUNCPTR (gst_tensor_mux_request_new_pad);
170 76 : gstelement_class->change_state =
171 76 : GST_DEBUG_FUNCPTR (gst_tensor_mux_change_state);
172 :
173 76 : gst_element_class_add_pad_template (gstelement_class,
174 : gst_static_pad_template_get (&sink_templ));
175 76 : gst_element_class_add_pad_template (gstelement_class,
176 : gst_static_pad_template_get (&src_templ));
177 :
178 76 : gst_element_class_set_details_simple (gstelement_class,
179 : "TensorMux",
180 : "Muxer/Tensor",
181 : "Merge multiple tensor stream to tensors stream",
182 : "Jijoong Moon <jijoong.moon@samsung.com>");
183 :
184 76 : }
185 :
186 : /**
187 : * @brief initialize the new element
188 : * instantiate pads and add them to element
189 : * set pad callback functions
190 : * initialize instance structure
191 : */
192 : static void
193 127 : gst_tensor_mux_init (GstTensorMux * tensor_mux)
194 : {
195 127 : GstElementClass *klass = GST_ELEMENT_GET_CLASS (tensor_mux);
196 :
197 127 : tensor_mux->srcpad =
198 127 : gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
199 : "src"), "src");
200 127 : gst_pad_set_event_function (tensor_mux->srcpad, gst_tensor_mux_src_event);
201 :
202 127 : gst_element_add_pad (GST_ELEMENT (tensor_mux), tensor_mux->srcpad);
203 :
204 127 : tensor_mux->collect = gst_collect_pads_new ();
205 127 : gst_collect_pads_set_event_function (tensor_mux->collect,
206 : (GstCollectPadsEventFunction)
207 127 : GST_DEBUG_FUNCPTR (gst_tensor_mux_sink_event), tensor_mux);
208 127 : gst_collect_pads_set_function (tensor_mux->collect,
209 127 : (GstCollectPadsFunction) GST_DEBUG_FUNCPTR (gst_tensor_mux_collected),
210 : tensor_mux);
211 127 : gst_collect_pads_set_clip_function (tensor_mux->collect,
212 127 : (GstCollectPadsClipFunction) GST_DEBUG_FUNCPTR (gst_tensor_mux_do_clip),
213 : tensor_mux);
214 :
215 127 : tensor_mux->silent = TRUE;
216 127 : tensor_mux->sync.mode = SYNC_SLOWEST;
217 127 : tensor_mux->sync.option = NULL;
218 127 : tensor_mux->current_time = 0;
219 127 : tensor_mux->need_set_time = TRUE;
220 127 : gst_tensors_config_init (&tensor_mux->tensors_config);
221 127 : }
222 :
223 : /**
224 : * @brief finalize vmethod
225 : */
226 : static void
227 125 : gst_tensor_mux_finalize (GObject * object)
228 : {
229 : GstTensorMux *tensor_mux;
230 :
231 125 : tensor_mux = GST_TENSOR_MUX (object);
232 :
233 125 : if (tensor_mux->collect) {
234 125 : gst_tensor_time_sync_flush (tensor_mux->collect);
235 125 : gst_object_unref (tensor_mux->collect);
236 125 : tensor_mux->collect = NULL;
237 : }
238 :
239 125 : if (tensor_mux->sync.option) {
240 17 : g_free (tensor_mux->sync.option);
241 17 : tensor_mux->sync.option = NULL;
242 : }
243 :
244 125 : gst_tensors_config_free (&tensor_mux->tensors_config);
245 :
246 125 : G_OBJECT_CLASS (parent_class)->finalize (object);
247 125 : }
248 :
249 : /**
250 : * @brief making new request pad (gst element vmethod)
251 : */
252 : static GstPad *
253 409 : gst_tensor_mux_request_new_pad (GstElement * element, GstPadTemplate * templ,
254 : const gchar * req_name, const GstCaps * caps)
255 : {
256 : GstPad *newpad;
257 409 : GSList *walk = NULL;
258 : GstTensorMux *tensor_mux;
259 : gchar *name;
260 : UNUSED (req_name);
261 : UNUSED (caps);
262 :
263 409 : g_return_val_if_fail (templ != NULL, NULL);
264 409 : g_return_val_if_fail (GST_IS_TENSOR_MUX (element), NULL);
265 :
266 409 : tensor_mux = GST_TENSOR_MUX (element);
267 409 : walk = tensor_mux->collect->data;
268 :
269 409 : name = g_strdup_printf ("sink_%u", g_slist_length (walk));
270 409 : newpad = gst_pad_new_from_template (templ, name);
271 409 : g_free (name);
272 :
273 409 : if (newpad) {
274 : GstTensorCollectPadData *tensormuxpad;
275 : gboolean locked, waiting;
276 :
277 409 : locked = waiting = TRUE;
278 :
279 409 : if (tensor_mux->sync.mode == SYNC_REFRESH) {
280 2 : locked = waiting = FALSE;
281 : }
282 :
283 : tensormuxpad = (GstTensorCollectPadData *)
284 409 : gst_collect_pads_add_pad (tensor_mux->collect, newpad,
285 : sizeof (GstTensorCollectPadData), NULL, locked);
286 :
287 : /* NOTE: if locked is TRUE, waiting flag is not effective */
288 409 : gst_collect_pads_set_waiting (tensor_mux->collect,
289 : (GstCollectData *) tensormuxpad, waiting);
290 :
291 409 : gst_pad_set_element_private (newpad, tensormuxpad);
292 409 : gst_element_add_pad (element, newpad);
293 : } else {
294 0 : GST_WARNING_OBJECT (tensor_mux, "failed to create request pad");
295 : }
296 409 : return newpad;
297 : }
298 :
299 : /**
300 : * @brief src event vmethod
301 : */
302 : static gboolean
303 5418 : gst_tensor_mux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
304 : {
305 5418 : g_return_val_if_fail (event != NULL, FALSE);
306 :
307 5418 : switch (GST_EVENT_TYPE (event)) {
308 0 : case GST_EVENT_SEEK:
309 0 : gst_event_unref (event);
310 0 : return FALSE;
311 5418 : default:
312 5418 : break;
313 : }
314 :
315 5418 : return gst_pad_event_default (pad, parent, event);
316 : }
317 :
318 : /**
319 : * @brief set pads waiting property
320 : */
321 : static void
322 14333 : gst_tensor_mux_set_waiting (GstTensorMux * tensor_mux, gboolean waiting)
323 : {
324 14333 : if (tensor_mux->sync.mode == SYNC_REFRESH) {
325 9546 : GstCollectPads *pads = tensor_mux->collect;
326 9546 : GSList *walk = pads->data;
327 :
328 28638 : while (walk) {
329 19092 : gst_collect_pads_set_waiting (pads, walk->data, waiting);
330 19092 : walk = g_slist_next (walk);
331 : }
332 : }
333 14333 : }
334 :
335 : /**
336 : * @brief sink event vmethod
337 : */
338 : static gboolean
339 1606 : gst_tensor_mux_sink_event (GstCollectPads * pads, GstCollectData * data,
340 : GstEvent * event, GstTensorMux * tensor_mux)
341 : {
342 1606 : g_return_val_if_fail (event != NULL, FALSE);
343 :
344 1606 : switch (GST_EVENT_TYPE (event)) {
345 0 : case GST_EVENT_FLUSH_STOP:
346 0 : tensor_mux->need_segment = TRUE;
347 0 : tensor_mux->need_set_time = TRUE;
348 0 : gst_tensor_time_sync_flush (tensor_mux->collect);
349 0 : break;
350 389 : case GST_EVENT_EOS:
351 389 : gst_tensor_mux_set_waiting (tensor_mux, FALSE);
352 389 : break;
353 1217 : default:
354 1217 : break;
355 : }
356 :
357 1606 : return gst_collect_pads_event_default (pads, data, event, FALSE);
358 : }
359 :
360 : /**
361 : * @brief Looping to generete output buffer for srcpad
362 : * @param tensor_mux tensor muxer
363 : * @param tensors_buf output buffer for srcpad
364 : * @param is_eos boolean EOS ( End of Stream )
365 : * @return TRUE to push buffer to src pad
366 : */
367 : static gboolean
368 6123 : gst_tensor_mux_collect_buffer (GstTensorMux * tensor_mux,
369 : GstBuffer * tensors_buf, gboolean * is_eos)
370 : {
371 6123 : if (tensor_mux->need_set_time) {
372 5589 : if (gst_tensor_time_sync_get_current_time (tensor_mux->collect,
373 : &tensor_mux->sync, &tensor_mux->current_time, tensors_buf)) {
374 : /* end-of-stream */
375 174 : *is_eos = TRUE;
376 174 : return FALSE;
377 : }
378 :
379 5415 : tensor_mux->need_set_time = FALSE;
380 5415 : silent_debug (tensor_mux, "Current Time : %" GST_TIME_FORMAT,
381 : GST_TIME_ARGS (tensor_mux->current_time));
382 : }
383 :
384 5949 : return gst_tensor_time_sync_buffer_from_collectpad (tensor_mux->collect,
385 : &tensor_mux->sync, tensor_mux->current_time, tensors_buf,
386 : &tensor_mux->tensors_config, is_eos);
387 : }
388 :
389 : /**
390 : * @brief Set src pad caps if src pad is not negotiated.
391 : */
392 : static gboolean
393 5415 : gst_tensor_mux_set_src_caps (GstTensorMux * tensor_mux)
394 : {
395 5415 : if (!tensor_mux->negotiated) {
396 : GstCaps *caps;
397 :
398 124 : if (gst_tensors_config_validate (&tensor_mux->tensors_config)) {
399 248 : caps = gst_tensor_pad_caps_from_config (tensor_mux->srcpad,
400 124 : &tensor_mux->tensors_config);
401 :
402 124 : if (gst_pad_set_caps (tensor_mux->srcpad, caps)) {
403 124 : tensor_mux->negotiated = TRUE;
404 : }
405 :
406 124 : gst_caps_unref (caps);
407 : }
408 : }
409 :
410 5415 : if (!tensor_mux->negotiated) {
411 0 : GST_WARNING_OBJECT (tensor_mux, "failed to set caps");
412 0 : GST_ELEMENT_ERROR (tensor_mux, CORE, NEGOTIATION, (NULL), (NULL));
413 : }
414 :
415 5415 : return tensor_mux->negotiated;
416 : }
417 :
418 : /**
419 : * @brief Create a new segment event if necessary.
420 : */
421 : static void
422 5415 : gst_tensor_mux_send_segment_event (GstTensorMux * tensor_mux,
423 : GstClockTime pts, GstClockTime dts)
424 : {
425 5415 : if (tensor_mux->need_segment) {
426 : GstSegment segment;
427 124 : GstClockTime time = 0;
428 :
429 124 : if (GST_CLOCK_TIME_IS_VALID (dts)) {
430 2 : time = dts;
431 122 : } else if (GST_CLOCK_TIME_IS_VALID (pts)) {
432 122 : time = pts;
433 : }
434 :
435 124 : gst_segment_init (&segment, GST_FORMAT_TIME);
436 124 : segment.start = time;
437 124 : gst_pad_push_event (tensor_mux->srcpad, gst_event_new_segment (&segment));
438 124 : tensor_mux->need_segment = FALSE;
439 : }
440 5415 : }
441 :
442 : /**
443 : * @brief Process flex tensor.
444 : */
445 : static GstBuffer *
446 25 : gst_tensor_mux_chain_flex_tensor (GstTensorMux * tensor_mux, GstBuffer * buf)
447 : {
448 : GstBuffer *buffer;
449 : GstMemory *mem, *new_mem;
450 : GstTensorsInfo *info;
451 : GstTensorInfo *_info;
452 : GstTensorMetaInfo meta;
453 : guint i;
454 :
455 : /* If input is flexible, do nothing. It is already flexible tensor. */
456 25 : if (gst_tensors_config_is_flexible (&tensor_mux->tensors_config))
457 25 : return buf;
458 :
459 2 : info = &tensor_mux->tensors_config.info;
460 2 : buffer = gst_buffer_new ();
461 :
462 6 : for (i = 0; i < info->num_tensors; i++) {
463 4 : mem = gst_tensor_buffer_get_nth_memory (buf, i);
464 :
465 : /* append header */
466 4 : _info = gst_tensors_info_get_nth_info (info, i);
467 4 : gst_tensor_info_convert_to_meta (_info, &meta);
468 4 : new_mem = gst_tensor_meta_info_append_header (&meta, mem);
469 4 : gst_memory_unref (mem);
470 :
471 4 : gst_tensor_buffer_append_memory (buffer, new_mem, _info);
472 : }
473 :
474 2 : gst_buffer_copy_into (buffer, buf, GST_BUFFER_COPY_METADATA, 0, -1);
475 2 : gst_buffer_unref (buf);
476 2 : return buffer;
477 : }
478 :
479 : /**
480 : * @brief Gst Collect Pads Function which is called once collect pads done.
481 : * @param pads GstCollectPads
482 : * @param tensor_mux Muxer
483 : * @return GstFlowReturn
484 : */
485 : static GstFlowReturn
486 6123 : gst_tensor_mux_collected (GstCollectPads * pads, GstTensorMux * tensor_mux)
487 : {
488 6123 : GstFlowReturn ret = GST_FLOW_OK;
489 : GstBuffer *tensors_buf;
490 6123 : gboolean isEOS = FALSE;
491 6123 : gboolean buf_collected = FALSE;
492 :
493 6123 : GST_DEBUG_OBJECT (tensor_mux, " all pads are collected ");
494 :
495 6123 : if (tensor_mux->need_stream_start) {
496 : /**
497 : * Cannot use gst-pad util to get stream ID (multiple sink pads).
498 : * Create stream ID using first sink pad.
499 : */
500 124 : GstCollectData *data = (GstCollectData *) pads->data->data;
501 124 : g_autofree gchar *sink_stream_id = gst_pad_get_stream_id (data->pad);
502 124 : g_autofree gchar *element_name = gst_element_get_name (tensor_mux);
503 124 : g_autofree gchar *pad_name = gst_pad_get_name (tensor_mux->srcpad);
504 248 : g_autofree gchar *stream_id = g_strdup_printf ("%s-%s-nnsmux-%s-%08x",
505 124 : GST_STR_NULL (sink_stream_id), element_name, pad_name, g_random_int ());
506 :
507 124 : gst_pad_push_event (tensor_mux->srcpad, gst_event_new_stream_start (stream_id));
508 124 : tensor_mux->need_stream_start = FALSE;
509 : }
510 :
511 6123 : if ((tensors_buf = gst_buffer_new ()) == NULL) {
512 0 : ml_logf ("gst_buffer_new() returns NULL. Out of memory?\n");
513 6123 : return GST_FLOW_ERROR;
514 : }
515 :
516 : buf_collected =
517 6123 : gst_tensor_mux_collect_buffer (tensor_mux, tensors_buf, &isEOS);
518 :
519 6123 : gst_tensor_mux_set_waiting (tensor_mux, TRUE);
520 :
521 6123 : if (!buf_collected) {
522 708 : if (isEOS) {
523 174 : gst_pad_push_event (tensor_mux->srcpad, gst_event_new_eos ());
524 174 : ret = GST_FLOW_EOS;
525 : }
526 :
527 708 : gst_buffer_unref (tensors_buf);
528 708 : return ret;
529 : }
530 :
531 5415 : if (!gst_tensor_mux_set_src_caps (tensor_mux)) {
532 0 : gst_buffer_unref (tensors_buf);
533 0 : return GST_FLOW_NOT_NEGOTIATED;
534 : }
535 :
536 5415 : gst_tensor_mux_send_segment_event (tensor_mux, GST_BUFFER_PTS (tensors_buf),
537 : GST_BUFFER_DTS (tensors_buf));
538 :
539 : /* add header if output is flexible */
540 5415 : if (gst_tensor_pad_caps_is_flexible (tensor_mux->srcpad))
541 25 : tensors_buf = gst_tensor_mux_chain_flex_tensor (tensor_mux, tensors_buf);
542 :
543 5415 : ret = gst_pad_push (tensor_mux->srcpad, tensors_buf);
544 5415 : tensor_mux->need_set_time = TRUE;
545 :
546 5415 : if (ret != GST_FLOW_OK) {
547 17 : GST_WARNING_OBJECT (tensor_mux, "pushed outbuf, result = %s",
548 : gst_flow_get_name (ret));
549 : }
550 :
551 5415 : return ret;
552 : }
553 :
554 : /**
555 : * @brief Gst Clip Pads Function which is called right after a buffer is received for each pad.
556 : */
557 : static GstFlowReturn
558 7821 : gst_tensor_mux_do_clip (GstCollectPads * pads, GstCollectData * data,
559 : GstBuffer * buffer, GstBuffer ** out, GstTensorMux * tensor_mux)
560 : {
561 : UNUSED (pads);
562 : UNUSED (data);
563 7821 : gst_tensor_mux_set_waiting (tensor_mux, FALSE);
564 7821 : *out = buffer;
565 7821 : return GST_FLOW_OK;
566 : }
567 :
568 : /**
569 : * @brief Ready --> Pasuse State Change
570 : */
571 : static void
572 124 : gst_tensor_mux_ready_to_paused (GstTensorMux * tensor_mux)
573 : {
574 124 : tensor_mux->need_stream_start = TRUE;
575 124 : tensor_mux->need_segment = TRUE;
576 124 : tensor_mux->negotiated = FALSE;
577 124 : gst_collect_pads_start (tensor_mux->collect);
578 124 : }
579 :
580 : /**
581 : * @brief change state (gst element vmethod)
582 : */
583 : static GstStateChangeReturn
584 732 : gst_tensor_mux_change_state (GstElement * element, GstStateChange transition)
585 : {
586 : GstTensorMux *tensor_mux;
587 : GstStateChangeReturn ret;
588 732 : tensor_mux = GST_TENSOR_MUX (element);
589 732 : switch (transition) {
590 124 : case GST_STATE_CHANGE_READY_TO_PAUSED:
591 124 : gst_tensor_mux_ready_to_paused (tensor_mux);
592 124 : break;
593 122 : case GST_STATE_CHANGE_PAUSED_TO_READY:
594 122 : gst_collect_pads_stop (tensor_mux->collect);
595 122 : break;
596 486 : default:
597 486 : break;
598 : }
599 :
600 732 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
601 732 : if (ret == GST_STATE_CHANGE_FAILURE)
602 0 : return ret;
603 732 : switch (transition) {
604 122 : case GST_STATE_CHANGE_PAUSED_TO_READY:
605 122 : break;
606 610 : default:
607 610 : break;
608 : }
609 :
610 732 : return ret;
611 : }
612 :
613 : /**
614 : * @brief Get property (gst element vmethod)
615 : */
616 : static void
617 70 : gst_tensor_mux_set_property (GObject * object, guint prop_id,
618 : const GValue * value, GParamSpec * pspec)
619 : {
620 70 : GstTensorMux *tensor_mux = GST_TENSOR_MUX (object);
621 70 : switch (prop_id) {
622 4 : case PROP_SILENT:
623 4 : tensor_mux->silent = g_value_get_boolean (value);
624 4 : break;
625 49 : case PROP_SYNC_MODE:
626 49 : tensor_mux->sync.mode =
627 49 : gst_tensor_time_sync_get_mode (g_value_get_string (value));
628 49 : if (tensor_mux->sync.mode == SYNC_END) {
629 0 : tensor_mux->sync.mode = SYNC_SLOWEST;
630 : }
631 49 : silent_debug (tensor_mux, "Mode = %d(%s)\n", tensor_mux->sync.mode,
632 : gst_tensor_time_sync_get_mode_string (tensor_mux->sync.mode));
633 49 : gst_tensor_time_sync_set_option_data (&tensor_mux->sync);
634 49 : break;
635 17 : case PROP_SYNC_OPTION:
636 17 : tensor_mux->sync.option = g_value_dup_string (value);
637 17 : silent_debug (tensor_mux, "Option = %s\n", tensor_mux->sync.option);
638 17 : gst_tensor_time_sync_set_option_data (&tensor_mux->sync);
639 17 : break;
640 0 : default:
641 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
642 0 : break;
643 : }
644 70 : }
645 :
646 : /**
647 : * @brief Get property (gst element vmethod)
648 : */
649 : static void
650 4 : gst_tensor_mux_get_property (GObject * object, guint prop_id,
651 : GValue * value, GParamSpec * pspec)
652 : {
653 4 : GstTensorMux *tensor_mux = GST_TENSOR_MUX (object);
654 4 : switch (prop_id) {
655 2 : case PROP_SILENT:
656 2 : g_value_set_boolean (value, tensor_mux->silent);
657 2 : break;
658 1 : case PROP_SYNC_MODE:
659 1 : g_value_set_string (value,
660 : gst_tensor_time_sync_get_mode_string (tensor_mux->sync.mode));
661 1 : break;
662 1 : case PROP_SYNC_OPTION:
663 1 : g_value_set_string (value, tensor_mux->sync.option);
664 1 : break;
665 0 : default:
666 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
667 0 : break;
668 : }
669 4 : }
|