Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * Copyright (C) 2021 Samsung Electronics Co., Ltd.
4 : *
5 : * @file tensor_query_serversink.c
6 : * @date 09 Jul 2021
7 : * @brief GStreamer plugin to handle tensor query server sink
8 : * @author Junhwan Kim <jejudo.kim@samsung.com>
9 : * @see http://github.com/nnstreamer/nnstreamer
10 : * @bug No known bugs
11 : *
12 : */
13 : #ifdef HAVE_CONFIG_H
14 : #include <config.h>
15 : #endif
16 :
17 : #include <string.h>
18 : #include "tensor_query_serversink.h"
19 :
20 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_query_serversink_debug);
21 : #define GST_CAT_DEFAULT gst_tensor_query_serversink_debug
22 :
23 : #define DEFAULT_METALESS_FRAME_LIMIT 1
24 :
25 : /**
26 : * @brief the capabilities of the inputs.
27 : */
28 : static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
29 : GST_PAD_SINK,
30 : GST_PAD_ALWAYS,
31 : GST_STATIC_CAPS_ANY);
32 :
33 : enum
34 : {
35 : PROP_0,
36 : PROP_CONNECT_TYPE,
37 : PROP_ID,
38 : PROP_TIMEOUT,
39 : PROP_METALESS_FRAME_LIMIT
40 : };
41 :
42 : #define gst_tensor_query_serversink_parent_class parent_class
43 904 : G_DEFINE_TYPE (GstTensorQueryServerSink, gst_tensor_query_serversink,
44 : GST_TYPE_BASE_SINK);
45 : static GstStateChangeReturn gst_tensor_query_serversink_change_state (GstElement
46 : * element, GstStateChange transition);
47 : static void gst_tensor_query_serversink_set_property (GObject * object,
48 : guint prop_id, const GValue * value, GParamSpec * pspec);
49 : static void gst_tensor_query_serversink_get_property (GObject * object,
50 : guint prop_id, GValue * value, GParamSpec * pspec);
51 : static void gst_tensor_query_serversink_finalize (GObject * object);
52 :
53 : static GstFlowReturn gst_tensor_query_serversink_render (GstBaseSink * bsink,
54 : GstBuffer * buf);
55 : static gboolean gst_tensor_query_serversink_set_caps (GstBaseSink * basesink,
56 : GstCaps * caps);
57 :
58 : /**
59 : * @brief initialize the class
60 : */
61 : static void
62 1 : gst_tensor_query_serversink_class_init (GstTensorQueryServerSinkClass * klass)
63 : {
64 : GObjectClass *gobject_class;
65 : GstElementClass *gstelement_class;
66 : GstBaseSinkClass *gstbasesink_class;
67 :
68 1 : gstbasesink_class = (GstBaseSinkClass *) klass;
69 1 : gstelement_class = (GstElementClass *) gstbasesink_class;
70 1 : gobject_class = (GObjectClass *) gstelement_class;
71 :
72 1 : gstelement_class->change_state = gst_tensor_query_serversink_change_state;
73 1 : gobject_class->set_property = gst_tensor_query_serversink_set_property;
74 1 : gobject_class->get_property = gst_tensor_query_serversink_get_property;
75 1 : gobject_class->finalize = gst_tensor_query_serversink_finalize;
76 :
77 1 : g_object_class_install_property (gobject_class, PROP_CONNECT_TYPE,
78 : g_param_spec_enum ("connect-type", "Connect Type",
79 : "The connection type",
80 : GST_TYPE_QUERY_CONNECT_TYPE, DEFAULT_CONNECT_TYPE,
81 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
82 1 : g_object_class_install_property (gobject_class, PROP_TIMEOUT,
83 : g_param_spec_uint ("timeout", "Timeout",
84 : "The timeout as seconds to maintain connection", 0,
85 : 3600, QUERY_DEFAULT_TIMEOUT_SEC,
86 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
87 1 : g_object_class_install_property (gobject_class, PROP_ID,
88 : g_param_spec_uint ("id", "ID",
89 : "ID for distinguishing query servers.", 0,
90 : G_MAXUINT, DEFAULT_SERVER_ID,
91 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
92 1 : g_object_class_install_property (gobject_class, PROP_METALESS_FRAME_LIMIT,
93 : g_param_spec_int ("limit", "Limit",
94 : "Limits of the number of the buffers that the server cannot handle. "
95 : "e.g., If the received buffer does not have a GstMetaQuery, the server cannot handle the buffer.",
96 : 0, 65535, DEFAULT_METALESS_FRAME_LIMIT,
97 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
98 :
99 1 : gst_element_class_add_pad_template (gstelement_class,
100 : gst_static_pad_template_get (&sinktemplate));
101 :
102 1 : gst_element_class_set_static_metadata (gstelement_class,
103 : "TensorQueryServerSink", "Sink/Tensor/Query",
104 : "Send tensor data as a server over the network",
105 : "Samsung Electronics Co., Ltd.");
106 :
107 1 : gstbasesink_class->set_caps = gst_tensor_query_serversink_set_caps;
108 1 : gstbasesink_class->render = gst_tensor_query_serversink_render;
109 :
110 1 : GST_DEBUG_CATEGORY_INIT (gst_tensor_query_serversink_debug,
111 : "tensor_query_serversink", 0, "Tensor Query Server Sink");
112 1 : }
113 :
114 : /**
115 : * @brief initialize the new element
116 : */
117 : static void
118 3 : gst_tensor_query_serversink_init (GstTensorQueryServerSink * sink)
119 : {
120 3 : sink->connect_type = DEFAULT_CONNECT_TYPE;
121 3 : sink->timeout = QUERY_DEFAULT_TIMEOUT_SEC;
122 3 : sink->sink_id = DEFAULT_SERVER_ID;
123 3 : sink->metaless_frame_count = 0;
124 3 : }
125 :
126 : /**
127 : * @brief finalize the object
128 : */
129 : static void
130 2 : gst_tensor_query_serversink_finalize (GObject * object)
131 : {
132 2 : GstTensorQueryServerSink *sink = GST_TENSOR_QUERY_SERVERSINK (object);
133 2 : gst_tensor_query_server_remove_data (sink->sink_id);
134 2 : G_OBJECT_CLASS (parent_class)->finalize (object);
135 2 : }
136 :
137 : /**
138 : * @brief start processing of query_serversink
139 : */
140 : static gboolean
141 5 : _gst_tensor_query_serversink_start (GstTensorQueryServerSink * sink)
142 : {
143 : gboolean ret;
144 :
145 5 : ret = gst_tensor_query_server_add_data (sink->sink_id);
146 5 : if (ret)
147 5 : gst_tensor_query_server_set_configured (sink->sink_id);
148 :
149 5 : return ret;
150 : }
151 :
152 : /**
153 : * @brief start processing of query_serversink
154 : */
155 : static gboolean
156 4 : _gst_tensor_query_serversink_playing (GstTensorQueryServerSink * sink)
157 : {
158 : gboolean ret;
159 :
160 4 : ret = gst_tensor_query_server_prepare (sink->sink_id, sink->connect_type,
161 : NULL);
162 :
163 4 : return ret;
164 : }
165 :
166 : /**
167 : * @brief Change state of query server sink.
168 : */
169 : static GstStateChangeReturn
170 24 : gst_tensor_query_serversink_change_state (GstElement * element,
171 : GstStateChange transition)
172 : {
173 24 : GstTensorQueryServerSink *sink = GST_TENSOR_QUERY_SERVERSINK (element);
174 24 : GstBaseSink *bsink = GST_BASE_SINK (element);
175 24 : GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
176 : GstCaps *caps;
177 :
178 24 : switch (transition) {
179 4 : case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
180 4 : if (!_gst_tensor_query_serversink_playing (sink)) {
181 0 : nns_loge ("Failed to change state from PAUSED to PLAYING.");
182 0 : return GST_STATE_CHANGE_FAILURE;
183 : }
184 :
185 4 : caps = gst_pad_peer_query_caps (GST_BASE_SINK_PAD (bsink), NULL);
186 4 : gst_tensor_query_serversink_set_caps (bsink, caps);
187 4 : gst_caps_unref (caps);
188 4 : break;
189 5 : case GST_STATE_CHANGE_READY_TO_PAUSED:
190 5 : if (!_gst_tensor_query_serversink_start (sink)) {
191 0 : nns_loge ("Failed to change state from READY to PAUSED.");
192 0 : return GST_STATE_CHANGE_FAILURE;
193 : }
194 5 : break;
195 15 : default:
196 15 : break;
197 : }
198 :
199 24 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
200 24 : if (ret == GST_STATE_CHANGE_FAILURE) {
201 0 : nns_loge ("Failed to change state");
202 0 : return ret;
203 : }
204 :
205 24 : switch (transition) {
206 4 : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
207 4 : gst_tensor_query_server_release_edge_handle (sink->sink_id);
208 4 : break;
209 20 : default:
210 20 : break;
211 : }
212 :
213 24 : return ret;
214 : }
215 :
216 : /**
217 : * @brief set property
218 : */
219 : static void
220 4 : gst_tensor_query_serversink_set_property (GObject * object, guint prop_id,
221 : const GValue * value, GParamSpec * pspec)
222 : {
223 4 : GstTensorQueryServerSink *serversink = GST_TENSOR_QUERY_SERVERSINK (object);
224 :
225 4 : switch (prop_id) {
226 1 : case PROP_CONNECT_TYPE:
227 1 : serversink->connect_type = g_value_get_enum (value);
228 1 : break;
229 1 : case PROP_TIMEOUT:
230 1 : serversink->timeout = g_value_get_uint (value);
231 1 : break;
232 1 : case PROP_ID:
233 1 : serversink->sink_id = g_value_get_uint (value);
234 1 : break;
235 1 : case PROP_METALESS_FRAME_LIMIT:
236 1 : serversink->metaless_frame_limit = g_value_get_int (value);
237 1 : break;
238 0 : default:
239 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
240 0 : break;
241 : }
242 4 : }
243 :
244 : /**
245 : * @brief get property
246 : */
247 : static void
248 6 : gst_tensor_query_serversink_get_property (GObject * object, guint prop_id,
249 : GValue * value, GParamSpec * pspec)
250 : {
251 6 : GstTensorQueryServerSink *serversink = GST_TENSOR_QUERY_SERVERSINK (object);
252 :
253 6 : switch (prop_id) {
254 2 : case PROP_CONNECT_TYPE:
255 2 : g_value_set_enum (value, serversink->connect_type);
256 2 : break;
257 2 : case PROP_TIMEOUT:
258 2 : g_value_set_uint (value, serversink->timeout);
259 2 : break;
260 1 : case PROP_ID:
261 1 : g_value_set_uint (value, serversink->sink_id);
262 1 : break;
263 1 : case PROP_METALESS_FRAME_LIMIT:
264 1 : g_value_set_int (value, serversink->metaless_frame_limit);
265 1 : break;
266 0 : default:
267 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
268 0 : break;
269 : }
270 6 : }
271 :
272 : /**
273 : * @brief An implementation of the set_caps vmethod in GstBaseSinkClass
274 : */
275 : static gboolean
276 5 : gst_tensor_query_serversink_set_caps (GstBaseSink * bsink, GstCaps * caps)
277 : {
278 5 : GstTensorQueryServerSink *sink = GST_TENSOR_QUERY_SERVERSINK (bsink);
279 : gchar *caps_str, *new_caps_str;
280 :
281 5 : caps_str = gst_caps_to_string (caps);
282 :
283 5 : new_caps_str = g_strdup_printf ("@query_server_sink_caps@%s", caps_str);
284 5 : gst_tensor_query_server_set_caps (sink->sink_id, new_caps_str);
285 :
286 5 : g_free (new_caps_str);
287 5 : g_free (caps_str);
288 :
289 5 : return TRUE;
290 : }
291 :
292 : /**
293 : * @brief render buffer, send buffer to client
294 : */
295 : static GstFlowReturn
296 0 : gst_tensor_query_serversink_render (GstBaseSink * bsink, GstBuffer * buf)
297 : {
298 0 : GstTensorQueryServerSink *sink = GST_TENSOR_QUERY_SERVERSINK (bsink);
299 : GstMetaQuery *meta_query;
300 :
301 0 : meta_query = gst_buffer_get_meta_query (buf);
302 0 : if (meta_query) {
303 0 : sink->metaless_frame_count = 0;
304 :
305 0 : if (!gst_tensor_query_server_send_buffer (sink->sink_id, buf)) {
306 0 : nns_loge ("Failed to send buffer to edge device in server sink.");
307 0 : return GST_FLOW_ERROR;
308 : }
309 : } else {
310 0 : nns_logw ("Cannot get tensor query meta. Drop buffers!\n");
311 0 : sink->metaless_frame_count++;
312 :
313 0 : if (sink->metaless_frame_count >= sink->metaless_frame_limit) {
314 0 : nns_logw ("Cannot get tensor query meta. Stop the query server!\n"
315 : "There are elements that are not available on the query server.\n"
316 : "Please check available elements on the server."
317 : "See: https://github.com/nnstreamer/nnstreamer/wiki/Available-elements-on-query-server");
318 0 : return GST_FLOW_ERROR;
319 : }
320 : }
321 :
322 0 : return GST_FLOW_OK;
323 : }
|