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_reposrc
20 : *
21 : * Pop element to handle tensor repo
22 : *
23 : * @file gsttensor_reposrc.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 :
35 : #include <string.h>
36 : #include "gsttensor_repo.h"
37 : #include "gsttensor_reposrc.h"
38 :
39 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_reposrc_debug);
40 : #define GST_CAT_DEFAULT gst_tensor_reposrc_debug
41 : #define CAPS_STRING GST_TENSOR_CAP_DEFAULT "; " GST_TENSORS_CAP_DEFAULT
42 :
43 : /**
44 : * @brief tensor_reposrc properties
45 : */
46 : enum
47 : {
48 : PROP_0,
49 : PROP_CAPS,
50 : PROP_SLOT_ID,
51 : PROP_SILENT
52 : };
53 :
54 : #define DEFAULT_SILENT TRUE
55 : #define DEFAULT_INDEX 0
56 : #define INVALID_INDEX G_MAXUINT
57 :
58 : static void gst_tensor_reposrc_set_property (GObject * object, guint prop_id,
59 : const GValue * value, GParamSpec * pspec);
60 : static void gst_tensor_reposrc_get_property (GObject * object, guint prop_id,
61 : GValue * value, GParamSpec * pspec);
62 : static void gst_tensor_reposrc_dispose (GObject * object);
63 : static GstCaps *gst_tensor_reposrc_getcaps (GstBaseSrc * src, GstCaps * filter);
64 : static GstFlowReturn gst_tensor_reposrc_create (GstPushSrc * src,
65 : GstBuffer ** buffer);
66 :
67 : #define gst_tensor_reposrc_parent_class parent_class
68 1108 : G_DEFINE_TYPE (GstTensorRepoSrc, gst_tensor_reposrc, GST_TYPE_PUSH_SRC);
69 :
70 : /**
71 : * @brief class initialization of tensor_reposrc
72 : */
73 : static void
74 10 : gst_tensor_reposrc_class_init (GstTensorRepoSrcClass * klass)
75 : {
76 10 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
77 10 : GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
78 10 : GstPushSrcClass *pushsrc_class = GST_PUSH_SRC_CLASS (klass);
79 10 : GstBaseSrcClass *basesrc_class = GST_BASE_SRC_CLASS (klass);
80 : GstPadTemplate *pad_template;
81 : GstCaps *pad_caps;
82 :
83 10 : GST_DEBUG_CATEGORY_INIT (gst_tensor_reposrc_debug, "tensor_reposrc", 0,
84 : "Source element to handle tensor repository");
85 :
86 10 : gobject_class->set_property = gst_tensor_reposrc_set_property;
87 10 : gobject_class->get_property = gst_tensor_reposrc_get_property;
88 10 : gobject_class->dispose = gst_tensor_reposrc_dispose;
89 :
90 10 : g_object_class_install_property (gobject_class, PROP_CAPS,
91 : g_param_spec_boxed ("caps", "Caps",
92 : "Caps describing the format of the data.",
93 : GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
94 :
95 10 : g_object_class_install_property (gobject_class, PROP_SILENT,
96 : g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
97 : DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
98 :
99 10 : g_object_class_install_property (gobject_class, PROP_SLOT_ID,
100 : g_param_spec_uint ("slot-index", "Slot Index", "repository slot index",
101 : 0, INVALID_INDEX - 1, DEFAULT_INDEX,
102 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
103 :
104 10 : basesrc_class->get_caps = gst_tensor_reposrc_getcaps;
105 10 : pushsrc_class->create = gst_tensor_reposrc_create;
106 :
107 10 : gst_element_class_set_static_metadata (element_class,
108 : "TensorRepoSrc",
109 : "Source/Tensor/Repository",
110 : "Pop element to handle tensor repository",
111 : "Samsung Electronics Co., Ltd.");
112 :
113 : /* pad template */
114 10 : pad_caps = gst_caps_from_string (GST_TENSOR_CAP_DEFAULT "; "
115 : GST_TENSORS_CAP_DEFAULT);
116 10 : pad_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
117 : pad_caps);
118 10 : gst_element_class_add_pad_template (element_class, pad_template);
119 10 : gst_caps_unref (pad_caps);
120 10 : }
121 :
122 : /**
123 : * @brief object initialization of tensor_reposrc
124 : */
125 : static void
126 14 : gst_tensor_reposrc_init (GstTensorRepoSrc * self)
127 : {
128 14 : self->silent = TRUE;
129 14 : self->ini = FALSE;
130 14 : self->negotiation = FALSE;
131 14 : gst_tensors_config_init (&self->config);
132 14 : self->caps = NULL;
133 14 : self->set_startid = FALSE;
134 14 : self->myid = INVALID_INDEX;
135 14 : }
136 :
137 : /**
138 : * @brief object dispose of tensor_reposrc
139 : */
140 : static void
141 13 : gst_tensor_reposrc_dispose (GObject * object)
142 : {
143 13 : GstTensorRepoSrc *self = GST_TENSOR_REPOSRC (object);
144 :
145 13 : if (self->myid != INVALID_INDEX
146 13 : && !gst_tensor_repo_remove_repodata (self->myid))
147 0 : GST_ELEMENT_ERROR (self, RESOURCE, WRITE,
148 : ("Cannot remove [key: %d] in repo", self->myid), NULL);
149 :
150 13 : if (self->caps)
151 13 : gst_caps_unref (self->caps);
152 :
153 13 : G_OBJECT_CLASS (parent_class)->dispose (object);
154 13 : }
155 :
156 : /**
157 : * @brief get cap of tensor_reposrc
158 : */
159 : static GstCaps *
160 41 : gst_tensor_reposrc_getcaps (GstBaseSrc * src, GstCaps * filter)
161 : {
162 41 : GstTensorRepoSrc *self = GST_TENSOR_REPOSRC (src);
163 : GstCaps *cap, *check, *result;
164 41 : GstStructure *st = NULL;
165 :
166 41 : GST_DEBUG_OBJECT (self, "returning %" GST_PTR_FORMAT, self->caps);
167 :
168 41 : if (self->caps) {
169 41 : if (filter) {
170 0 : cap = gst_caps_intersect_full (filter, self->caps,
171 : GST_CAPS_INTERSECT_FIRST);
172 : } else
173 41 : cap = gst_caps_ref (self->caps);
174 : } else {
175 0 : if (filter) {
176 0 : cap = gst_caps_ref (filter);
177 : } else
178 0 : cap = gst_caps_new_any ();
179 : }
180 :
181 41 : check = gst_caps_from_string (CAPS_STRING);
182 41 : result = gst_caps_intersect_full (cap, check, GST_CAPS_INTERSECT_FIRST);
183 :
184 41 : if (!result) {
185 0 : GST_ELEMENT_ERROR (GST_ELEMENT (self), STREAM, WRONG_TYPE,
186 : ("Only Tensor/Tensors MIME are supported for now"), (NULL));
187 : }
188 41 : gst_caps_unref (check);
189 41 : gst_caps_unref (cap);
190 :
191 41 : st = gst_caps_get_structure (result, 0);
192 41 : gst_tensors_config_from_structure (&self->config, st);
193 :
194 41 : return result;
195 : }
196 :
197 : /**
198 : * @brief set property of tensor_reposrc
199 : */
200 : static void
201 42 : gst_tensor_reposrc_set_property (GObject * object, guint prop_id,
202 : const GValue * value, GParamSpec * pspec)
203 : {
204 42 : GstTensorRepoSrc *self = GST_TENSOR_REPOSRC (object);
205 :
206 42 : switch (prop_id) {
207 14 : case PROP_SILENT:
208 14 : self->silent = g_value_get_boolean (value);
209 14 : break;
210 14 : case PROP_SLOT_ID:
211 14 : self->o_myid = self->myid;
212 14 : self->myid = g_value_get_uint (value);
213 14 : self->negotiation = FALSE;
214 :
215 14 : gst_tensor_repo_add_repodata (self->myid, FALSE);
216 :
217 14 : if (!self->set_startid) {
218 14 : self->o_myid = self->myid;
219 14 : self->set_startid = TRUE;
220 : }
221 :
222 14 : if (self->o_myid != self->myid)
223 0 : gst_tensor_repo_set_changed (self->o_myid, self->myid, FALSE);
224 14 : break;
225 14 : case PROP_CAPS:
226 : {
227 14 : GstStructure *st = NULL;
228 14 : const GstCaps *caps = gst_value_get_caps (value);
229 : GstCaps *new_caps;
230 :
231 14 : if (caps == NULL) {
232 0 : new_caps = gst_caps_new_any ();
233 : } else {
234 14 : new_caps = gst_caps_copy (caps);
235 : }
236 14 : gst_caps_replace (&self->caps, new_caps);
237 14 : gst_pad_set_caps (GST_BASE_SRC_PAD (self), new_caps);
238 14 : st = gst_caps_get_structure (new_caps, 0);
239 :
240 14 : if (new_caps && gst_caps_get_size (new_caps) == 1 && st
241 14 : && gst_structure_get_fraction (st, "framerate", &self->fps_n,
242 : &self->fps_d)) {
243 14 : GST_INFO_OBJECT (self, "Setting framerate to %d/%d", self->fps_n,
244 : self->fps_d);
245 : } else {
246 0 : self->fps_n = -1;
247 0 : self->fps_d = -1;
248 : }
249 :
250 14 : if (new_caps)
251 14 : gst_caps_unref (new_caps);
252 14 : self->negotiation = FALSE;
253 14 : break;
254 : }
255 0 : default:
256 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
257 0 : break;
258 : }
259 42 : }
260 :
261 : /**
262 : * @brief get property of tensor_reposrc
263 : */
264 : static void
265 3 : gst_tensor_reposrc_get_property (GObject * object, guint prop_id,
266 : GValue * value, GParamSpec * pspec)
267 : {
268 3 : GstTensorRepoSrc *self = GST_TENSOR_REPOSRC (object);
269 :
270 3 : switch (prop_id) {
271 1 : case PROP_SILENT:
272 1 : g_value_set_boolean (value, self->silent);
273 1 : break;
274 1 : case PROP_SLOT_ID:
275 1 : g_value_set_uint (value, self->myid);
276 1 : break;
277 1 : case PROP_CAPS:
278 1 : gst_value_set_caps (value, self->caps);
279 1 : break;
280 0 : default:
281 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
282 0 : break;
283 : }
284 3 : }
285 :
286 : /**
287 : * @brief create dummy buffer for initialization
288 : */
289 : static GstBuffer *
290 14 : gst_tensor_reposrc_gen_dummy_buffer (GstTensorRepoSrc * self)
291 : {
292 14 : GstBuffer *buf = NULL;
293 : GstTensorInfo *_info;
294 : GstMemory *mem;
295 : GstMapInfo map;
296 : guint i, num_tensors;
297 14 : gsize size = 0;
298 :
299 14 : buf = gst_buffer_new ();
300 14 : num_tensors = self->config.info.num_tensors;
301 :
302 28 : for (i = 0; i < num_tensors; i++) {
303 14 : _info = gst_tensors_info_get_nth_info (&self->config.info, i);
304 14 : size = gst_tensor_info_get_size (_info);
305 14 : mem = gst_allocator_alloc (NULL, size, NULL);
306 14 : gst_tensor_buffer_append_memory (buf, mem, _info);
307 :
308 14 : if (!gst_memory_map (mem, &map, GST_MAP_WRITE)) {
309 0 : gst_buffer_unref (buf);
310 0 : ml_logf ("Cannot map gst memory (tensor-repo-src).");
311 14 : return NULL;
312 : }
313 :
314 14 : memset (map.data, 0, map.size);
315 14 : gst_memory_unmap (mem, &map);
316 : }
317 :
318 14 : return buf;
319 : }
320 :
321 : /**
322 : * @brief create func of tensor_reposrc
323 : */
324 : static GstFlowReturn
325 135 : gst_tensor_reposrc_create (GstPushSrc * src, GstBuffer ** buffer)
326 : {
327 : GstTensorRepoSrc *self;
328 135 : GstBuffer *buf = NULL;
329 135 : GstCaps *caps = NULL;
330 135 : gboolean eos = FALSE;
331 : guint newid;
332 :
333 135 : self = GST_TENSOR_REPOSRC (src);
334 135 : gst_tensor_repo_wait ();
335 :
336 135 : if (!self->ini) {
337 14 : buf = gst_tensor_reposrc_gen_dummy_buffer (self);
338 14 : self->ini = TRUE;
339 : } else {
340 242 : while (!buf && !eos) {
341 121 : buf = gst_tensor_repo_get_buffer (self->myid, &eos, &newid, &caps);
342 : }
343 :
344 121 : if (eos)
345 8 : goto handle_eos;
346 :
347 113 : if (!self->negotiation && buf != NULL) {
348 14 : if (!gst_tensor_caps_can_intersect (self->caps, caps)) {
349 3 : GST_ELEMENT_ERROR (GST_ELEMENT (self), CORE, NEGOTIATION,
350 : ("Negotiation Failed! : repo_sink & repos_src"), (NULL));
351 :
352 3 : gst_tensor_repo_set_eos (self->myid);
353 3 : goto handle_eos;
354 : }
355 :
356 11 : self->negotiation = TRUE;
357 : }
358 :
359 110 : if (caps)
360 110 : gst_caps_unref (caps);
361 : }
362 :
363 124 : *buffer = buf;
364 135 : return GST_FLOW_OK;
365 :
366 11 : handle_eos:
367 11 : if (buf)
368 3 : gst_buffer_unref (buf);
369 11 : if (caps)
370 3 : gst_caps_unref (caps);
371 11 : return GST_FLOW_EOS;
372 : }
|