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 Samsung Electronics Co., Ltd.
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 : * SECTION: element-tensor_reposink
20 : *
21 : * Set element to handle tensor repo
22 : *
23 : * @file gsttensor_reposink.c
24 : * @date 19 Nov 2018
25 : * @brief GStreamer plugin to handle tensor repository
26 : * @see https://github.com/nnstreamer/nnstreamer
27 : * @author Jijoong Moon <jijoong.moon@samsung.com>
28 : * @bug No known bugs except for NYI items
29 : */
30 :
31 : #ifdef HAVE_CONFIG_H
32 : #include <config.h>
33 : #endif
34 : #include <nnstreamer_util.h>
35 :
36 : #include "gsttensor_repo.h"
37 : #include "gsttensor_reposink.h"
38 :
39 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_reposink_debug);
40 : #define GST_CAT_DEFAULT gst_tensor_reposink_debug
41 :
42 : /**
43 : * @brief tensor_reposink properties
44 : */
45 : enum
46 : {
47 : PROP_0,
48 : PROP_SIGNAL_RATE,
49 : PROP_SLOT,
50 : PROP_SILENT
51 : };
52 :
53 : #define DEFAULT_SIGNAL_RATE 0
54 : #define DEFAULT_SILENT TRUE
55 : #define DEFAULT_QOS TRUE
56 : #define DEFAULT_INDEX 0
57 :
58 : static void gst_tensor_reposink_set_property (GObject * object, guint prop_id,
59 : const GValue * value, GParamSpec * pspec);
60 : static void gst_tensor_reposink_get_property (GObject * object, guint prop_id,
61 : GValue * value, GParamSpec * pspec);
62 : static void gst_tensor_reposink_dispose (GObject * object);
63 :
64 : static gboolean gst_tensor_reposink_start (GstBaseSink * sink);
65 : static gboolean gst_tensor_reposink_stop (GstBaseSink * sink);
66 : static gboolean gst_tensor_reposink_event (GstBaseSink * sink,
67 : GstEvent * event);
68 : static gboolean gst_tensor_reposink_query (GstBaseSink * sink,
69 : GstQuery * query);
70 : static GstFlowReturn gst_tensor_reposink_render (GstBaseSink * sink,
71 : GstBuffer * buffer);
72 : static GstFlowReturn gst_tensor_reposink_render_list (GstBaseSink * sink,
73 : GstBufferList * buffer_list);
74 : static gboolean gst_tensor_reposink_set_caps (GstBaseSink * sink,
75 : GstCaps * caps);
76 : static GstCaps *gst_tensor_reposink_get_caps (GstBaseSink * sink,
77 : GstCaps * filter);
78 :
79 : #define gst_tensor_reposink_parent_class parent_class
80 1417 : G_DEFINE_TYPE (GstTensorRepoSink, gst_tensor_reposink, GST_TYPE_BASE_SINK);
81 :
82 : /**
83 : * @brief class initialization of tensor_reposink
84 : */
85 : static void
86 10 : gst_tensor_reposink_class_init (GstTensorRepoSinkClass * klass)
87 : {
88 : GObjectClass *gobject_class;
89 : GstElementClass *element_class;
90 : GstBaseSinkClass *basesink_class;
91 : GstPadTemplate *pad_template;
92 : GstCaps *pad_caps;
93 :
94 10 : GST_DEBUG_CATEGORY_INIT (gst_tensor_reposink_debug, "tensor_reposink", 0,
95 : "Sink element to handle tensor repository");
96 :
97 10 : gobject_class = G_OBJECT_CLASS (klass);
98 10 : element_class = GST_ELEMENT_CLASS (klass);
99 10 : basesink_class = GST_BASE_SINK_CLASS (klass);
100 :
101 10 : gobject_class->set_property = gst_tensor_reposink_set_property;
102 10 : gobject_class->get_property = gst_tensor_reposink_get_property;
103 10 : gobject_class->dispose = gst_tensor_reposink_dispose;
104 :
105 10 : g_object_class_install_property (gobject_class, PROP_SIGNAL_RATE,
106 : g_param_spec_uint ("signal-rate", "Signal rate",
107 : "New data signals per second (0 for unlimited, max 500)", 0, 500,
108 : DEFAULT_SIGNAL_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
109 :
110 10 : g_object_class_install_property (gobject_class, PROP_SLOT,
111 : g_param_spec_uint ("slot-index", "Slot Index", "repository slot index",
112 : 0, UINT_MAX, DEFAULT_INDEX,
113 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114 :
115 10 : g_object_class_install_property (gobject_class, PROP_SILENT,
116 : g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
117 : DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
118 :
119 10 : gst_element_class_set_static_metadata (element_class,
120 : "TensorRepoSink",
121 : "Sink/Tensor/Repository",
122 : "Set element to handle tensor repository",
123 : "Samsung Electronics Co., Ltd.");
124 :
125 : /* pad template */
126 10 : pad_caps = gst_caps_from_string (GST_TENSOR_CAP_DEFAULT "; "
127 : GST_TENSORS_CAP_DEFAULT);
128 10 : pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
129 : pad_caps);
130 10 : gst_element_class_add_pad_template (element_class, pad_template);
131 10 : gst_caps_unref (pad_caps);
132 :
133 10 : basesink_class->start = GST_DEBUG_FUNCPTR (gst_tensor_reposink_start);
134 10 : basesink_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_reposink_stop);
135 10 : basesink_class->event = GST_DEBUG_FUNCPTR (gst_tensor_reposink_event);
136 10 : basesink_class->query = GST_DEBUG_FUNCPTR (gst_tensor_reposink_query);
137 10 : basesink_class->render = GST_DEBUG_FUNCPTR (gst_tensor_reposink_render);
138 10 : basesink_class->render_list =
139 10 : GST_DEBUG_FUNCPTR (gst_tensor_reposink_render_list);
140 10 : basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_tensor_reposink_set_caps);
141 10 : basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_tensor_reposink_get_caps);
142 10 : }
143 :
144 : /**
145 : * @brief initialization of tensor_reposink
146 : */
147 : static void
148 14 : gst_tensor_reposink_init (GstTensorRepoSink * self)
149 : {
150 : GstBaseSink *basesink;
151 :
152 14 : basesink = GST_BASE_SINK (self);
153 :
154 14 : gst_tensor_repo_init ();
155 :
156 14 : GST_DEBUG_OBJECT (self, "GstTensorRepo is successfully initialized");
157 :
158 14 : self->silent = DEFAULT_SILENT;
159 14 : self->signal_rate = DEFAULT_SIGNAL_RATE;
160 14 : self->last_render_time = GST_CLOCK_TIME_NONE;
161 14 : self->set_startid = FALSE;
162 14 : self->in_caps = NULL;
163 :
164 14 : gst_base_sink_set_qos_enabled (basesink, DEFAULT_QOS);
165 :
166 : /* ignore sync and preroll in repo */
167 14 : gst_base_sink_set_sync (basesink, FALSE);
168 14 : gst_base_sink_set_async_enabled (basesink, FALSE);
169 14 : }
170 :
171 : /**
172 : * @brief set property vmethod
173 : */
174 : static void
175 29 : gst_tensor_reposink_set_property (GObject * object, guint prop_id,
176 : const GValue * value, GParamSpec * pspec)
177 : {
178 : GstTensorRepoSink *self;
179 :
180 29 : self = GST_TENSOR_REPOSINK (object);
181 :
182 29 : switch (prop_id) {
183 1 : case PROP_SIGNAL_RATE:
184 1 : self->signal_rate = g_value_get_uint (value);
185 1 : break;
186 14 : case PROP_SILENT:
187 14 : self->silent = g_value_get_boolean (value);
188 14 : break;
189 14 : case PROP_SLOT:
190 14 : self->o_myid = self->myid;
191 14 : self->myid = g_value_get_uint (value);
192 :
193 14 : gst_tensor_repo_add_repodata (self->myid, TRUE);
194 :
195 14 : if (!self->set_startid) {
196 14 : self->o_myid = self->myid;
197 14 : self->set_startid = TRUE;
198 : }
199 :
200 14 : if (self->o_myid != self->myid)
201 0 : gst_tensor_repo_set_changed (self->o_myid, self->myid, TRUE);
202 14 : break;
203 0 : default:
204 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
205 0 : break;
206 : }
207 29 : }
208 :
209 : /**
210 : * @brief get property vmethod
211 : */
212 : static void
213 3 : gst_tensor_reposink_get_property (GObject * object, guint prop_id,
214 : GValue * value, GParamSpec * pspec)
215 : {
216 : GstTensorRepoSink *self;
217 :
218 3 : self = GST_TENSOR_REPOSINK (object);
219 :
220 3 : switch (prop_id) {
221 1 : case PROP_SIGNAL_RATE:
222 1 : g_value_set_uint (value, self->signal_rate);
223 1 : break;
224 1 : case PROP_SILENT:
225 1 : g_value_set_boolean (value, self->silent);
226 1 : break;
227 1 : case PROP_SLOT:
228 1 : g_value_set_uint (value, self->myid);
229 1 : break;
230 0 : default:
231 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
232 0 : break;
233 : }
234 3 : }
235 :
236 : /**
237 : * @brief dispose vmethod implementation
238 : */
239 : static void
240 13 : gst_tensor_reposink_dispose (GObject * object)
241 : {
242 : GstTensorRepoSink *self;
243 :
244 13 : self = GST_TENSOR_REPOSINK (object);
245 :
246 13 : if (self->in_caps)
247 13 : gst_caps_unref (self->in_caps);
248 :
249 13 : G_OBJECT_CLASS (parent_class)->dispose (object);
250 13 : }
251 :
252 : /**
253 : * @brief start vmethod implementation
254 : */
255 : static gboolean
256 14 : gst_tensor_reposink_start (GstBaseSink * sink)
257 : {
258 : UNUSED (sink);
259 14 : return TRUE;
260 : }
261 :
262 : /**
263 : * @brief stop vmethod implementation
264 : */
265 : static gboolean
266 13 : gst_tensor_reposink_stop (GstBaseSink * sink)
267 : {
268 : UNUSED (sink);
269 13 : return TRUE;
270 : }
271 :
272 : /**
273 : * @brief Handle events.
274 : *
275 : * GstBaseSink method implementation.
276 : */
277 : static gboolean
278 53 : gst_tensor_reposink_event (GstBaseSink * sink, GstEvent * event)
279 : {
280 : GstTensorRepoSink *self;
281 : GstEventType type;
282 :
283 53 : self = GST_TENSOR_REPOSINK (sink);
284 53 : type = GST_EVENT_TYPE (event);
285 :
286 53 : GST_DEBUG_OBJECT (self, "received event %s", GST_EVENT_TYPE_NAME (event));
287 :
288 53 : switch (type) {
289 11 : case GST_EVENT_EOS:
290 11 : gst_tensor_repo_set_eos (self->myid);
291 11 : break;
292 42 : default:
293 42 : break;
294 : }
295 :
296 53 : return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
297 : }
298 :
299 : /**
300 : * @brief query vmethod implementation
301 : */
302 : static gboolean
303 97 : gst_tensor_reposink_query (GstBaseSink * sink, GstQuery * query)
304 : {
305 : GstTensorRepoSink *self;
306 : GstQueryType type;
307 : GstFormat format;
308 :
309 97 : self = GST_TENSOR_REPOSINK (sink);
310 97 : type = GST_QUERY_TYPE (query);
311 :
312 97 : GST_DEBUG_OBJECT (self, "received query %s", GST_QUERY_TYPE_NAME (query));
313 :
314 97 : switch (type) {
315 0 : case GST_QUERY_SEEKING:
316 0 : gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
317 0 : gst_query_set_seeking (query, format, FALSE, 0, -1);
318 97 : return TRUE;
319 97 : default:
320 97 : break;
321 : }
322 :
323 97 : return GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
324 : }
325 :
326 : /**
327 : * @brief Push GstBuffer
328 : */
329 : static gboolean
330 119 : gst_tensor_reposink_render_buffer (GstTensorRepoSink * self, GstBuffer * buffer)
331 : {
332 119 : GstClockTime now = GST_CLOCK_TIME_NONE;
333 : guint signal_rate;
334 119 : gboolean notify = FALSE;
335 119 : g_return_val_if_fail (GST_IS_TENSOR_REPOSINK (self), FALSE);
336 :
337 119 : signal_rate = self->signal_rate;
338 :
339 119 : if (signal_rate) {
340 : GstClock *clock;
341 : GstClockTime render_time;
342 :
343 0 : clock = gst_element_get_clock (GST_ELEMENT (self));
344 :
345 0 : if (clock) {
346 0 : now = gst_clock_get_time (clock);
347 0 : render_time = (1000 / signal_rate) * GST_MSECOND + self->last_render_time;
348 :
349 0 : if (!GST_CLOCK_TIME_IS_VALID (self->last_render_time) ||
350 0 : GST_CLOCK_DIFF (now, render_time) <= 0) {
351 0 : notify = TRUE;
352 : }
353 :
354 0 : gst_object_unref (clock);
355 : }
356 : } else {
357 119 : notify = TRUE;
358 : }
359 :
360 119 : if (notify) {
361 119 : self->last_render_time = now;
362 :
363 119 : if (!gst_tensor_repo_set_buffer (self->myid, buffer, self->in_caps)) {
364 3 : GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
365 : ("Cannot Set buffer into repo [key: %d]", self->myid), NULL);
366 3 : return FALSE;
367 : }
368 : }
369 :
370 116 : return TRUE;
371 : }
372 :
373 : /**
374 : * @brief render vmethod implementation
375 : */
376 : static GstFlowReturn
377 119 : gst_tensor_reposink_render (GstBaseSink * sink, GstBuffer * buffer)
378 : {
379 : GstTensorRepoSink *self;
380 :
381 119 : self = GST_TENSOR_REPOSINK (sink);
382 :
383 119 : if (!gst_tensor_reposink_render_buffer (self, buffer))
384 3 : return GST_FLOW_ERROR;
385 116 : return GST_FLOW_OK;
386 : }
387 :
388 : /**
389 : * @brief render list vmethod implementation
390 : */
391 : static GstFlowReturn
392 0 : gst_tensor_reposink_render_list (GstBaseSink * sink,
393 : GstBufferList * buffer_list)
394 : {
395 : GstTensorRepoSink *self;
396 : GstBuffer *buffer;
397 : guint i;
398 : guint num_buffers;
399 :
400 0 : self = GST_TENSOR_REPOSINK (sink);
401 0 : num_buffers = gst_buffer_list_length (buffer_list);
402 :
403 0 : for (i = 0; i < num_buffers; i++) {
404 0 : buffer = gst_buffer_list_get (buffer_list, i);
405 0 : if (!gst_tensor_reposink_render_buffer (self, buffer))
406 0 : return GST_FLOW_ERROR;
407 : }
408 :
409 0 : return GST_FLOW_OK;
410 : }
411 :
412 : /**
413 : * @brief set_caps vmethod implementation
414 : */
415 : static gboolean
416 14 : gst_tensor_reposink_set_caps (GstBaseSink * sink, GstCaps * caps)
417 : {
418 : GstTensorRepoSink *self;
419 :
420 14 : self = GST_TENSOR_REPOSINK (sink);
421 14 : gst_caps_replace (&self->in_caps, caps);
422 :
423 : /* debug print caps */
424 14 : if (!self->silent) {
425 : GstStructure *structure;
426 : gchar *str;
427 : guint caps_size, i;
428 :
429 14 : caps_size = gst_caps_get_size (caps);
430 14 : GST_DEBUG_OBJECT (self, "set caps, size is %d", caps_size);
431 :
432 28 : for (i = 0; i < caps_size; i++) {
433 14 : structure = gst_caps_get_structure (caps, i);
434 14 : str = gst_structure_to_string (structure);
435 :
436 14 : GST_DEBUG_OBJECT (self, "[%d] %s", i, str);
437 14 : g_free (str);
438 : }
439 : }
440 :
441 14 : return TRUE;
442 : }
443 :
444 : /**
445 : * @brief get_caps vmethod implementation
446 : */
447 : static GstCaps *
448 96 : gst_tensor_reposink_get_caps (GstBaseSink * sink, GstCaps * filter)
449 : {
450 : GstTensorRepoSink *self;
451 : GstCaps *caps;
452 :
453 96 : self = GST_TENSOR_REPOSINK (sink);
454 :
455 96 : caps = self->in_caps;
456 :
457 96 : if (caps) {
458 0 : if (filter) {
459 0 : caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
460 : } else {
461 0 : gst_caps_ref (caps);
462 : }
463 : }
464 :
465 96 : return caps;
466 : }
|