Line data Source code
1 : /**
2 : * GStreamer Tensor_Src_TizenSensor
3 : * Copyright (C) 2019 MyungJoo Ham <myungjoo.ham@samsung.com>
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation;
8 : * version 2.1 of the License.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : */
16 : /**
17 : * @file tensor_src_tizensensor.c
18 : * @date 07 Nov 2019
19 : * @brief GStreamer plugin to support Tizen sensor framework (sensord)
20 : * @see http://github.com/nnstreamer/nnstreamer
21 : * @author MyungJoo Ham <myungjoo.ham@samsung.com>
22 : * @bug No known bugs except for NYI items
23 : */
24 :
25 : /**
26 : * SECTION:element-tensor_src_tizensensor
27 : *
28 : * #tensor_src_tizensensor extends #gstbasesrc source element to handle Tizen
29 : * Sensor-Framework (sensord) as input.
30 : *
31 : * <refsect2>
32 : * <title>Example launch line</title>
33 : * |[
34 : * gst-launch -v -m tensor_src_tizensensor type=ACCELEROMETER sequence=0 mode=POLLING ! fakesink
35 : * ]|
36 : * </refsect2>
37 : *
38 : * Available types can be retrieved with Tizen System/Sensor APIs:
39 : * https://docs.tizen.org/application/native/api/wearable/latest/group__CAPI__SYSTEM__SENSOR__MODULE.html#ga92804cd50337aef93d0e3a3807a9cf33 (Tizen 5.5 Mobile API)
40 : *
41 : * In case there are multiple sensors for a given sensor type,
42 : * you may designate the sequence to choose non-0 sensor instance.
43 : * which is equivalent to choosing list[sequence] from
44 : * Tizen-API / sensor_get_sensor_list(ACCELEROMETER, list, count);
45 : * When the sequence is not specified, the first (.0) is chosen.
46 : * You may specify the enum value of the sensor (sensor_type_e) defined
47 : * in sensor.h of Tizen with type.
48 : *
49 : * If sequence = -1 (default), we use "default sensor".
50 : *
51 : * @todo More manual entries coming.
52 : *
53 : * @todo Allow to use sensor URIs to designate a sensor
54 : * https://docs.tizen.org/application/native/api/mobile/latest/group__CAPI__SYSTEM__SENSOR__LISTENER__MODULE.html#CAPI_SYSTEM_SENSOR_LISTENER_MODULE_URI
55 : *
56 : * @todo Add "Listener" mode (creates data only if there are updates)
57 : *
58 : * @todo Every mode should handle timestamp/duration properly!
59 : *
60 : * @todo Add "power management" options (Tizen sensor f/w accepts such)
61 : *
62 : * @todo Some sensor types are privileged. We need privilege control.
63 : * Some sensor types are privileged. An application should have the privilege http://tizen.org/privilege/healthinfo to get handles for the following sensors: SENSOR_HRM, SENSOR_HRM_LED_GREEN, SENSOR_HRM_LED_IR, SENSOR_HRM_LED_RED, SENSOR_HUMAN_PEDOMETER, SENSOR_HUMAN_SLEEP_MONITOR, SENSOR_HUMAN_SLEEP_DETECTOR, and SENSOR_HUMAN_STRESS_MONITOR.
64 : *
65 : * @todo Some sensor types appear to have mixed types (float32 & int32).
66 : * @todo Add a property to set output tensor type (float32/int32/...) along
67 : * with a few simple multiplications (e.g., x1000) and casting options.
68 : */
69 :
70 : #ifdef HAVE_CONFIG_H
71 : #include <config.h>
72 : #endif
73 :
74 : #include <string.h>
75 : #include <errno.h>
76 :
77 : #include <gst/gst.h>
78 : #include <glib.h>
79 :
80 : /** @todo VALIDATE: Tizen's System/Sensor Public C-API */
81 : #include <sensor.h>
82 :
83 : #include <tensor_typedef.h>
84 : #include <nnstreamer_plugin_api.h>
85 : #include <nnstreamer_log.h>
86 : #include <nnstreamer_util.h>
87 :
88 : #include "tensor_src_tizensensor.h"
89 :
90 : /**
91 : * @brief Macro for debug mode.
92 : */
93 : #ifndef DBG
94 : #define DBG (!self->silent)
95 : #endif
96 :
97 : /**
98 : * @brief Macro for debug message.
99 : */
100 : #define silent_debug(...) do { \
101 : if (DBG) { \
102 : GST_DEBUG_OBJECT (self, __VA_ARGS__); \
103 : } \
104 : } while (0)
105 :
106 : GST_DEBUG_CATEGORY_STATIC (gst_tensor_src_tizensensor_debug);
107 : #define GST_CAT_DEFAULT gst_tensor_src_tizensensor_debug
108 :
109 : /**
110 : * @brief tensor_src_tizensensor properties.
111 : */
112 : enum
113 : {
114 : PROP_0,
115 : PROP_SILENT,
116 : PROP_TYPE,
117 : PROP_SEQUENCE,
118 : PROP_MODE,
119 : PROP_FREQ,
120 : };
121 :
122 : /**
123 : * @brief Flag to print minimized log.
124 : */
125 : #define DEFAULT_PROP_SILENT TRUE
126 :
127 : /**
128 : * @brief Default Tizen sensor type
129 : */
130 : #define DEFAULT_PROP_TYPE -1 /* Denotes "ALL" (any) */
131 :
132 : /**
133 : * @brief Default sensor value retrieving mode
134 : */
135 : #define DEFAULT_PROP_MODE "polling"
136 :
137 : /**
138 : * @brief Default sensor retrieving frequency
139 : */
140 : #define DEFAULT_PROP_FREQ_N 10
141 : #define DEFAULT_PROP_FREQ_D 1
142 :
143 : /**
144 : * @brief Default sequence number
145 : */
146 : #define DEFAULT_PROP_SEQUENCE -1
147 :
148 : #define _LOCK(obj) g_mutex_lock (&(obj)->lock)
149 : #define _UNLOCK(obj) g_mutex_unlock (&(obj)->lock)
150 :
151 : /** GObject method implementation */
152 : static void gst_tensor_src_tizensensor_set_property (GObject * object,
153 : guint prop_id, const GValue * value, GParamSpec * pspec);
154 : static void gst_tensor_src_tizensensor_get_property (GObject * object,
155 : guint prop_id, GValue * value, GParamSpec * pspec);
156 : static void gst_tensor_src_tizensensor_finalize (GObject * object);
157 :
158 : /** GstBaseSrc method implementation */
159 : static gboolean gst_tensor_src_tizensensor_start (GstBaseSrc * src);
160 : static gboolean gst_tensor_src_tizensensor_stop (GstBaseSrc * src);
161 : static gboolean gst_tensor_src_tizensensor_event (GstBaseSrc * src,
162 : GstEvent * event);
163 : static gboolean gst_tensor_src_tizensensor_set_caps (GstBaseSrc * src,
164 : GstCaps * caps);
165 : static GstCaps *gst_tensor_src_tizensensor_get_caps (GstBaseSrc * src,
166 : GstCaps * filter);
167 : static GstCaps *gst_tensor_src_tizensensor_fixate (GstBaseSrc * src,
168 : GstCaps * caps);
169 : static gboolean gst_tensor_src_tizensensor_is_seekable (GstBaseSrc * src);
170 : static gboolean gst_tensor_src_tizensensor_query (GstBaseSrc * src, GstQuery * query);
171 : static GstFlowReturn gst_tensor_src_tizensensor_create (GstBaseSrc * src,
172 : guint64 offset, guint size, GstBuffer ** buf);
173 : static GstFlowReturn gst_tensor_src_tizensensor_fill (GstBaseSrc * src,
174 : guint64 offset, guint size, GstBuffer * buf);
175 :
176 : #define gst_tensor_src_tizensensor_parent_class parent_class
177 78 : G_DEFINE_TYPE (GstTensorSrcTIZENSENSOR, gst_tensor_src_tizensensor,
178 : GST_TYPE_BASE_SRC);
179 :
180 : #define GST_TYPE_TIZEN_SENSOR_TYPE (tizen_sensor_get_type ())
181 : /**
182 : * @brief Support GEnumValue array for Tizen sensor framework's sensor_type_e (sensor.h)
183 : * @todo We need an automated maintenance system for sensor.h's sensor_type_e, which makes a build error if it has been changed.
184 : */
185 : static GType
186 11 : tizen_sensor_get_type (void)
187 : {
188 : static GType etype = 0;
189 11 : if (etype == 0) {
190 : static const GEnumValue values[] = {
191 : {SENSOR_ALL, "SENSOR_ALL", "all"},
192 : {SENSOR_ACCELEROMETER, "SENSOR_ACCELEROMETER", "accelerometer"},
193 : {SENSOR_GRAVITY, "SENSOR_GRAVITY", "gravity"},
194 : {SENSOR_LINEAR_ACCELERATION, "SENSOR_LINEAR_ACCELERATION",
195 : "linear_acceleration"},
196 : {SENSOR_MAGNETIC, "SENSOR_MAGNETIC", "magnetic"},
197 : {SENSOR_ROTATION_VECTOR, "SENSOR_ROTATION_VECTOR", "rotation_vector"},
198 : {SENSOR_ORIENTATION, "SENSOR_ORIENTATION", "orientation"},
199 : {SENSOR_GYROSCOPE, "SENSOR_GYROSCOPE", "gyroscope"},
200 : {SENSOR_LIGHT, "SENSOR_LIGHT", "light"},
201 : {SENSOR_PROXIMITY, "SENSOR_PROXIMITY", "proximity"},
202 : {SENSOR_PRESSURE, "SENSOR_PRESSURE", "pressure"},
203 : {SENSOR_ULTRAVIOLET, "SENSOR_ULTRAVIOLET", "ultraviolet"},
204 : {SENSOR_TEMPERATURE, "SENSOR_TEMPERATURE", "temperature"},
205 : {SENSOR_HUMIDITY, "SENSOR_HUMIDITY", "humidity"},
206 : {SENSOR_HRM, "SENSOR_HRM", "hrm"},
207 : {SENSOR_HRM_LED_GREEN, "SENSOR_HRM_LED_GREEN", "hrm_led_green"},
208 : {SENSOR_HRM_LED_IR, "SENSOR_HRM_LED_IR", "hrm_led_ir"},
209 : {SENSOR_HRM_LED_RED, "SENSOR_HRM_LED_RED", "hrm_led_red"},
210 : {SENSOR_GYROSCOPE_UNCALIBRATED, "SENSOR_GYROSCOPE_UNCALIBRATED",
211 : "gyroscope_uncalibrated"},
212 : {SENSOR_GEOMAGNETIC_UNCALIBRATED, "SENSOR_GEOMAGNETIC_UNCALIBRATED",
213 : "geomagnetic_uncalibrated"},
214 : {SENSOR_GYROSCOPE_ROTATION_VECTOR, "SENSOR_GYROSCOPE_ROTATION_VECTOR",
215 : "gyroscope_rotation_vector"},
216 : {SENSOR_GEOMAGNETIC_ROTATION_VECTOR, "SENSOR_GEOMAGNETIC_ROTATION_VECTOR",
217 : "geomagnetic_rotation_vector"},
218 : {SENSOR_SIGNIFICANT_MOTION, "SENSOR_SIGNIFICANT_MOTION",
219 : "significant_motion"},
220 : {SENSOR_HUMAN_PEDOMETER, "SENSOR_HUMAN_PEDOMETER", "human_pedometer"},
221 : {SENSOR_HUMAN_SLEEP_MONITOR, "SENSOR_HUMAN_SLEEP_MONITOR",
222 : "human_sleep_monitor"},
223 : {SENSOR_HUMAN_SLEEP_DETECTOR, "SENSOR_HUMAN_SLEEP_DETECTOR",
224 : "human_sleep_detector"},
225 : {SENSOR_HUMAN_STRESS_MONITOR, "SENSOR_HUMAN_STRESS_MONITOR",
226 : "human_stress_monitor"},
227 : {SENSOR_LAST, "SENSOR_LAST", "last"},
228 : {SENSOR_CUSTOM, "SENSOR_CUSTOM", "custom"},
229 : {0, NULL, NULL},
230 : };
231 11 : etype = g_enum_register_static ("sensor_type_e", values);
232 : }
233 11 : return etype;
234 : }
235 :
236 : static GHashTable *tizensensors = NULL;
237 :
238 : /**
239 : * @brief Specification for each Tizen Sensor Type
240 : */
241 : typedef struct
242 : {
243 : sensor_type_e type;
244 : int value_count;
245 : GstTensorInfo tinfo;
246 : } TizenSensorSpec;
247 :
248 : /**
249 : * @brief Tizen sensor type specification
250 : * @details According to Tizen document,
251 : * https://developer.tizen.org/development/guides/native-application/location-and-sensors/device-sensors
252 : * Each sensor type has predetermined dimensions and types
253 : */
254 : static TizenSensorSpec tizensensorspecs[] = {
255 : {.type = SENSOR_ACCELEROMETER,.value_count = 3,
256 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
257 : .dimension = {3, 1, 0, }}},
258 : {.type = SENSOR_GRAVITY,.value_count = 3,
259 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
260 : .dimension = {3, 1, 0, }}},
261 : {.type = SENSOR_LINEAR_ACCELERATION,.value_count = 3,
262 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
263 : .dimension = {3, 1, 0, }}},
264 : {.type = SENSOR_MAGNETIC,.value_count = 3,
265 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
266 : .dimension = {3, 1, 0, }}},
267 : {.type = SENSOR_ROTATION_VECTOR,.value_count = 4,
268 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
269 : .dimension = {4, 1, 0, }}},
270 : {.type = SENSOR_ORIENTATION,.value_count = 3,
271 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
272 : .dimension = {3, 1, 0, }}},
273 : {.type = SENSOR_GYROSCOPE,.value_count = 3,
274 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
275 : .dimension = {3, 1, 0, }}},
276 : {.type = SENSOR_LIGHT,.value_count = 1,
277 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
278 : .dimension = {1, 1, 0, }}},
279 : {.type = SENSOR_PROXIMITY,.value_count = 1,
280 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
281 : .dimension = {1, 1, 0, }}},
282 : {.type = SENSOR_PRESSURE,.value_count = 1,
283 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
284 : .dimension = {1, 1, 0, }}},
285 : {.type = SENSOR_ULTRAVIOLET,.value_count = 1,
286 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
287 : .dimension = {1, 1, 0, }}},
288 : {.type = SENSOR_TEMPERATURE,.value_count = 1,
289 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
290 : .dimension = {1, 1, 0, }}},
291 : {.type = SENSOR_HUMIDITY,.value_count = 1,
292 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
293 : .dimension = {1, 1, 0, }}},
294 : {.type = SENSOR_HRM,.value_count = 1,
295 : .tinfo = {.name = NULL,.type = _NNS_INT32,
296 : .dimension = {1, 1, 0, }}},
297 : {.type = SENSOR_HRM_LED_GREEN,.value_count = 1,
298 : .tinfo = {.name = NULL,.type = _NNS_INT32,
299 : .dimension = {1, 1, 0, }}},
300 : {.type = SENSOR_HRM_LED_IR,.value_count = 1,
301 : .tinfo = {.name = NULL,.type = _NNS_INT32,
302 : .dimension = {1, 1, 0, }}},
303 : {.type = SENSOR_HRM_LED_RED,.value_count = 1,
304 : .tinfo = {.name = NULL,.type = _NNS_INT32,
305 : .dimension = {1, 1, 0, }}},
306 : {.type = SENSOR_GYROSCOPE_UNCALIBRATED,.value_count = 6,
307 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
308 : .dimension = {6, 1, 0, }}},
309 : {.type = SENSOR_GEOMAGNETIC_UNCALIBRATED,.value_count = 6,
310 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
311 : .dimension = {6, 1, 0, }}},
312 : {.type = SENSOR_GYROSCOPE_ROTATION_VECTOR,.value_count = 4,
313 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
314 : .dimension = {4, 1, 0, }}},
315 : {.type = SENSOR_GEOMAGNETIC_ROTATION_VECTOR,.value_count = 4,
316 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
317 : .dimension = {4, 1, 0, }}},
318 : {.type = SENSOR_SIGNIFICANT_MOTION,.value_count = 1,
319 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
320 : .dimension = {1, 1, 0, }}},
321 : {.type = SENSOR_HUMAN_PEDOMETER,.value_count = 8, /* Last 5 values might be flost32..? */
322 : .tinfo = {.name = NULL,.type = _NNS_INT32,
323 : .dimension = {8, 1, 0, }}},
324 : {.type = SENSOR_HUMAN_SLEEP_MONITOR,.value_count = 1, /* STATE */
325 : .tinfo = {.name = NULL,.type = _NNS_INT32,
326 : .dimension = {1, 1, 0, }}},
327 : {.type = SENSOR_HUMAN_SLEEP_DETECTOR,.value_count = 1, /** @todo check! */
328 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
329 : .dimension = {1, 1, 0, }}},
330 : {.type = SENSOR_HUMAN_STRESS_MONITOR,.value_count = 1, /** @todo check! */
331 : .tinfo = {.name = NULL,.type = _NNS_FLOAT32,
332 : .dimension = {1, 1, 0, }}},
333 : {.type = SENSOR_LAST,.value_count = 0,.tinfo = {0,}},
334 : };
335 :
336 : #define GST_TYPE_TIZEN_SENSOR_MODE (tizen_sensor_get_mode ())
337 : /**
338 : * @brief Provide options of sensor operations
339 : */
340 : static GType
341 11 : tizen_sensor_get_mode (void)
342 : {
343 : static GType etype = 0;
344 11 : if (etype == 0) {
345 : static const GEnumValue values[] = {
346 : {TZN_SENSOR_MODE_POLLING, "POLLING", "polling"},
347 : {0, NULL, NULL},
348 : };
349 11 : etype = g_enum_register_static ("sensor_op_modes", values);
350 : }
351 11 : return etype;
352 : }
353 :
354 : /**
355 : * @brief initialize the tensor_src_tizensensor class.
356 : */
357 : static void
358 11 : gst_tensor_src_tizensensor_class_init (GstTensorSrcTIZENSENSORClass * klass)
359 : {
360 11 : GObjectClass *gobject_class = (GObjectClass *) klass;
361 11 : GstElementClass *gstelement_class = (GstElementClass *) klass;
362 11 : GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
363 : GstPadTemplate *pad_template;
364 : GstCaps *pad_caps;
365 :
366 11 : GST_DEBUG_CATEGORY_INIT (gst_tensor_src_tizensensor_debug,
367 : "tensor_src_tizensensor", 0,
368 : "src element to support Tizen sensor framework");
369 :
370 11 : gobject_class->set_property = gst_tensor_src_tizensensor_set_property;
371 11 : gobject_class->get_property = gst_tensor_src_tizensensor_get_property;
372 11 : gobject_class->finalize = gst_tensor_src_tizensensor_finalize;
373 :
374 11 : g_object_class_install_property (gobject_class, PROP_SILENT,
375 : g_param_spec_boolean ("silent", "Silent",
376 : "Produce verbose output", DEFAULT_PROP_SILENT,
377 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
378 11 : g_object_class_install_property (gobject_class, PROP_TYPE,
379 : g_param_spec_enum ("type", "Tizen Sensor Type (enum)",
380 : "Tizen sensor type as a enum-name, defined in sensor.h of Tizen",
381 : GST_TYPE_TIZEN_SENSOR_TYPE, SENSOR_ALL,
382 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
383 11 : g_object_class_install_property (gobject_class, PROP_SEQUENCE,
384 : g_param_spec_int ("sequence", "Sequence number of a sensor type",
385 : "Select a sensor if there are multiple sensors of a type",
386 : -1, G_MAXINT, DEFAULT_PROP_SEQUENCE, G_PARAM_READWRITE));
387 11 : g_object_class_install_property (gobject_class, PROP_MODE,
388 : g_param_spec_enum ("mode", "Sensor data retrieval mode (enum)",
389 : "Determine how sensor data are retrieved (e.g. polling)",
390 : GST_TYPE_TIZEN_SENSOR_MODE, TZN_SENSOR_MODE_POLLING,
391 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
392 11 : g_object_class_install_property (gobject_class, PROP_FREQ,
393 : gst_param_spec_fraction ("framerate", "Framerate",
394 : "Rate of data retrievals from a sensor. Effective only when "
395 : "mode is ACTIVE_POLLING",
396 : 0, 1, G_MAXINT, 1,
397 : DEFAULT_PROP_FREQ_N, DEFAULT_PROP_FREQ_D,
398 : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
399 :
400 : /* pad template */
401 : /** @todo Narrow down allowed tensors/tensor. */
402 11 : pad_caps = gst_caps_from_string (GST_TENSOR_CAP_DEFAULT "; "
403 : GST_TENSORS_CAP_WITH_NUM ("1"));
404 11 : pad_template = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
405 : pad_caps);
406 11 : gst_element_class_add_pad_template (gstelement_class, pad_template);
407 11 : gst_caps_unref (pad_caps);
408 :
409 11 : gst_element_class_set_static_metadata (gstelement_class,
410 : "TensorSrcTizenSensor", "Source/Tensor/Device",
411 : "Creates tensor(s) stream from a given Tizen sensor framework node",
412 : "MyungJoo Ham <myungjoo.ham@samsung.com>");
413 :
414 11 : gstbasesrc_class->set_caps =
415 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_set_caps);
416 11 : gstbasesrc_class->get_caps =
417 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_get_caps);
418 11 : gstbasesrc_class->fixate =
419 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_fixate);
420 11 : gstbasesrc_class->is_seekable =
421 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_is_seekable);
422 11 : gstbasesrc_class->start =
423 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_start);
424 11 : gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_stop);
425 11 : gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_query);
426 11 : gstbasesrc_class->create =
427 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_create);
428 11 : gstbasesrc_class->fill = GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_fill);
429 11 : gstbasesrc_class->event =
430 11 : GST_DEBUG_FUNCPTR (gst_tensor_src_tizensensor_event);
431 11 : }
432 :
433 : /**
434 : * @brief initialize tensor_src_tizensensor element.
435 : */
436 : static void
437 9 : gst_tensor_src_tizensensor_init (GstTensorSrcTIZENSENSOR * self)
438 : {
439 : /** init properties */
440 9 : self->configured = FALSE;
441 9 : self->silent = DEFAULT_PROP_SILENT;
442 9 : self->running = FALSE;
443 9 : self->freq_n = DEFAULT_PROP_FREQ_N;
444 9 : self->freq_d = DEFAULT_PROP_FREQ_D;
445 9 : self->type = SENSOR_ALL;
446 :
447 9 : g_mutex_init (&self->lock);
448 :
449 : /**
450 : * @todo TBD. Update This!
451 : * format of the source since IIO device as a source is live and operates
452 : * at a fixed frequency, GST_FORMAT_TIME is used
453 : */
454 9 : gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
455 : /** set the source to be a live source */
456 9 : gst_base_src_set_live (GST_BASE_SRC (self), TRUE);
457 : /** set base_src to automatically timestamp outgoing buffers
458 : * based on the current running_time of the pipeline.
459 : */
460 9 : gst_base_src_set_do_timestamp (GST_BASE_SRC (self), TRUE);
461 : /**
462 : * set async is necessary to make state change async
463 : * sync state changes does not need calling _start_complete() from _start()
464 : */
465 9 : gst_base_src_set_async (GST_BASE_SRC (self), TRUE);
466 :
467 : /** @todo TBD. Let's assume each frame has a fixed size */
468 9 : gst_base_src_set_dynamic_size (GST_BASE_SRC (self), FALSE);
469 :
470 9 : if (NULL == tizensensors) {
471 : int i, sensor_dim;
472 1 : tizensensors = g_hash_table_new (g_direct_hash, g_direct_equal);
473 :
474 27 : for (i = 0; tizensensorspecs[i].type != SENSOR_LAST; i++) {
475 26 : g_assert (g_hash_table_insert (tizensensors,
476 : GINT_TO_POINTER (tizensensorspecs[i].type),
477 : &tizensensorspecs[i].tinfo));
478 26 : sensor_dim = tizensensorspecs[i].tinfo.dimension[0];
479 26 : g_assert (tizensensorspecs[i].value_count == sensor_dim);
480 : }
481 : }
482 9 : }
483 :
484 : /**
485 : * @brief This cleans up.
486 : * @details This cleans up the Tizen sensor handle/context,
487 : * ready for a new handle/context or exit.
488 : * This does not alter saved properties.
489 : * @returns it returns -1 if there is an error.
490 : */
491 : static int
492 11 : _ts_clean_up_handle (GstTensorSrcTIZENSENSOR * self)
493 : {
494 11 : if (self->running) {
495 3 : sensor_listener_stop (self->listener);
496 3 : if (!self->configured)
497 0 : return -1;
498 : }
499 :
500 11 : self->running = FALSE;
501 :
502 11 : if (self->configured) {
503 3 : sensor_destroy_listener (self->listener);
504 : }
505 :
506 11 : self->src_spec = NULL;
507 11 : self->listener = NULL;
508 11 : self->sensor = NULL;
509 :
510 11 : self->configured = FALSE;
511 11 : return 0;
512 : }
513 :
514 : /**
515 : * @brief Sensor event (data retrieval) handler
516 : * @details This is for TZN_SENSOR_MODE_ACTIVE_POLLING
517 : */
518 : static void __attribute__((unused))
519 0 : _ts_tizen_sensor_callback (sensor_h sensor, sensor_event_s events[],
520 : int events_count, void *user_data)
521 : {
522 0 : GstTensorSrcTIZENSENSOR *self = (GstTensorSrcTIZENSENSOR *) user_data;
523 : sensor_event_s *event;
524 : sensor_type_e type;
525 0 : int n_tensor_size = gst_tensor_get_element_count (self->src_spec->dimension);
526 :
527 0 : g_assert (self->configured);
528 0 : g_assert (self->running);
529 0 : g_assert (events_count > 0);
530 :
531 : /** @todo last or first sensor data? */
532 0 : event = &events[events_count - 1];
533 :
534 0 : sensor_get_type (sensor, &type);
535 :
536 0 : g_assert (type == self->type);
537 0 : g_assert (n_tensor_size == event->value_count);
538 :
539 : /** @todo Call some GST/BASESRC callback to fill things in from event */
540 :
541 : /** @todo Get proper timestamp from Tizen API, record it to metadata */
542 :
543 0 : g_assert (1 == 0);/** @todo NYI. Needed if we add more modes */
544 : }
545 :
546 : /**
547 : * @brief Calculate interval in ms from framerate
548 : * @details This is effective only for TZN_SENSOR_MODE_ACTIVE_POLLING.
549 : */
550 : static unsigned int
551 3 : _ts_get_interval_ms (GstTensorSrcTIZENSENSOR * self)
552 : {
553 3 : if (self->freq_n == 0)
554 0 : return 100; /* If it's 0Hz, assume 100ms interval */
555 :
556 3 : g_assert (self->freq_d > 0 && self->freq_n > 0);
557 :
558 3 : return gst_util_uint64_scale_int ((guint64) self->freq_d, 1000, self->freq_n);
559 : }
560 :
561 : /**
562 : * @brief Get handle, setup context, make it ready!
563 : */
564 : static int
565 4 : _ts_configure_handle (GstTensorSrcTIZENSENSOR * self)
566 : {
567 4 : int ret = 0;
568 8 : const GstTensorInfo *val = g_hash_table_lookup (tizensensors,
569 4 : GINT_TO_POINTER (self->type));
570 4 : bool supported = false;
571 :
572 4 : if (NULL == val) {
573 0 : nns_loge ("The given sensor type (%d) is not supported.\n", self->type);
574 4 : return -ENODEV;
575 : }
576 4 : self->src_spec = val;
577 :
578 : /* Based on Tizen Native App (Sensor) Guide */
579 : /* 1. Check if the sensor supported */
580 4 : ret = sensor_is_supported (self->type, &supported);
581 4 : if (ret != SENSOR_ERROR_NONE) {
582 0 : nns_loge ("Tizen sensor framework is not working (sensor_is_supported).\n");
583 0 : return -ENODEV;
584 : }
585 :
586 4 : if (false == supported) {
587 1 : GST_ERROR_OBJECT (self,
588 : "Tizen sensor framework API, sensor_is_supported(), says the sensor %d is not supported",
589 : self->type);
590 1 : return -EINVAL;
591 : }
592 :
593 : /* 2. Get sensor listener */
594 3 : if (self->sequence == -1) {
595 : /* Get the default sensor */
596 1 : ret = sensor_get_default_sensor (self->type, &self->sensor);
597 1 : if (ret != SENSOR_ERROR_NONE) {
598 0 : nns_loge ("Cannot get default sensor");
599 0 : return ret;
600 : }
601 : } else {
602 : sensor_h *list;
603 : int count;
604 :
605 : /* Use the sequence number to choose one */
606 2 : ret = sensor_get_sensor_list (self->type, &list, &count);
607 2 : if (ret != SENSOR_ERROR_NONE) {
608 0 : nns_loge ("Cannot get sensor list");
609 0 : return ret;
610 : }
611 :
612 2 : if (count <= self->sequence) {
613 0 : GST_ERROR_OBJECT (self,
614 : "The requested sensor sequence %d for sensor %d is not available. The max-sequence is used instead",
615 : self->sequence, self->type);
616 0 : self->sequence = 0;
617 0 : g_free (list);
618 0 : return -EINVAL;
619 : }
620 :
621 2 : self->sensor = list[self->sequence];
622 2 : g_free (list);
623 : }
624 :
625 3 : ret = sensor_create_listener (self->sensor, &self->listener);
626 3 : if (ret != SENSOR_ERROR_NONE) {
627 0 : nns_loge ("Cannot create sensor listener");
628 0 : return ret;
629 : }
630 :
631 : /* 3. Configure interval_ms */
632 3 : self->interval_ms = _ts_get_interval_ms (self);
633 :
634 3 : ret = sensor_listener_set_interval (self->listener, self->interval_ms);
635 3 : if (ret != SENSOR_ERROR_NONE) {
636 0 : nns_loge ("Cannot set the sensor interval");
637 0 : return ret;
638 : }
639 :
640 3 : nns_logi ("Set sensor_listener interval: %ums", self->interval_ms);
641 :
642 : /* 4. Register sensor event handler */
643 3 : switch (self->mode) {
644 3 : case TZN_SENSOR_MODE_POLLING:
645 : /* Nothing to do. Let Gst poll data */
646 3 : break;
647 : #if 0 /** Use this if TZN_SENSOR_MODE_ACTIVE_POLLING is implemented */
648 : case TZN_SENSOR_MODE_ACTIVE_POLLING:
649 : ret = sensor_listener_set_events_cb (listener,
650 : _ts_tizen_sensor_callback, self);
651 : if (ret != SENSOR_ERROR_NONE)
652 : return ret;
653 : break;
654 : #endif
655 0 : default:
656 0 : GST_ERROR_OBJECT (self,
657 : "The requested mode (%d) is invalid, use values defined in sensor_op_modes only.",
658 : self->mode);
659 : }
660 :
661 3 : self->configured = TRUE;
662 3 : return 0;
663 : }
664 :
665 : /**
666 : * @brief Keeping the handle/context, reconfigure a few parameters
667 : */
668 : static int
669 0 : _ts_reconfigure (GstTensorSrcTIZENSENSOR * self)
670 : {
671 0 : _ts_clean_up_handle (self);
672 0 : return _ts_configure_handle (self);
673 : }
674 :
675 : /**
676 : * @brief set tensor_src_tizensensor properties
677 : */
678 : static void
679 25 : gst_tensor_src_tizensensor_set_property (GObject * object,
680 : guint prop_id, const GValue * value, GParamSpec * pspec)
681 : {
682 25 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR (object);
683 25 : int ret = 0;
684 :
685 25 : switch (prop_id) {
686 1 : case PROP_SILENT:
687 1 : self->silent = g_value_get_boolean (value);
688 1 : silent_debug ("Set silent = %d", self->silent);
689 1 : break;
690 9 : case PROP_TYPE:
691 : {
692 9 : sensor_type_e new_type = g_value_get_enum (value);
693 :
694 9 : _LOCK (self);
695 :
696 9 : if (new_type != self->type) {
697 : /* Different sensor is being used. Clean it up! */
698 9 : if (self->configured)
699 0 : ret = _ts_clean_up_handle (self);
700 :
701 9 : if (ret) {
702 0 : GST_ERROR_OBJECT (self, "_ts_clean_up_handle() returns %d", ret);
703 : }
704 :
705 9 : silent_debug ("Set type from %d --> %d.", self->type, new_type);
706 9 : self->type = new_type;
707 : } else {
708 0 : silent_debug ("Set type ignored (%d --> %d).", self->type, new_type);
709 : }
710 :
711 9 : _UNLOCK (self);
712 : }
713 9 : break;
714 6 : case PROP_SEQUENCE:
715 : {
716 6 : gint new_sequence = g_value_get_int (value);
717 :
718 6 : _LOCK (self);
719 :
720 6 : if (self->sequence != new_sequence) {
721 : /* Different sensor is being used. Clean it up! */
722 4 : if (self->configured)
723 0 : ret = _ts_clean_up_handle (self);
724 :
725 4 : if (ret) {
726 0 : GST_ERROR_OBJECT (self, "_ts_clean_up_handle() returns %d", ret);
727 : }
728 :
729 4 : silent_debug ("Set sequence from %d --> %d.", self->sequence,
730 : new_sequence);
731 4 : self->sequence = new_sequence;
732 : } else {
733 2 : silent_debug ("Set sequence ignored (%d --> %d).", self->sequence,
734 : new_sequence);
735 : }
736 :
737 6 : _UNLOCK (self);
738 : }
739 6 : break;
740 2 : case PROP_MODE:
741 : {
742 2 : sensor_op_modes new_mode = g_value_get_enum (value);
743 2 : sensor_op_modes old_mode = self->mode;
744 :
745 2 : _LOCK (self);
746 :
747 2 : if (new_mode != self->mode) {
748 0 : silent_debug ("Set mode from %d --> %d.", self->mode, new_mode);
749 0 : self->mode = new_mode;
750 :
751 : /* Same sensor is kept. Only mode is changed */
752 0 : if (self->configured)
753 0 : ret = _ts_reconfigure (self);
754 :
755 0 : if (ret) {
756 0 : self->mode = old_mode;
757 0 : GST_ERROR_OBJECT (self, "_ts_reconfigure () returns %d", ret);
758 : }
759 :
760 : } else {
761 2 : silent_debug ("Set mode ignored (%d --> %d).", self->mode, new_mode);
762 : }
763 :
764 2 : _UNLOCK (self);
765 : }
766 2 : break;
767 7 : case PROP_FREQ:
768 : {
769 7 : gint n = self->freq_n;
770 7 : gint d = self->freq_d;
771 :
772 7 : _LOCK (self);
773 :
774 7 : self->freq_n = gst_value_get_fraction_numerator (value);
775 7 : self->freq_d = gst_value_get_fraction_denominator (value);
776 :
777 7 : if (self->freq_n < 0)
778 0 : self->freq_n = 0;
779 7 : if (self->freq_d < 1)
780 0 : self->freq_d = 1;
781 :
782 7 : silent_debug ("Set operating frequency %d/%d --> %d/%d",
783 : n, d, self->freq_n, self->freq_d);
784 :
785 7 : if (n != self->freq_n || d != self->freq_d) {
786 : /* Same sensor is kept. Only frequency is changed */
787 6 : if (self->configured)
788 0 : ret = _ts_reconfigure (self);
789 :
790 6 : if (ret) {
791 0 : self->freq_n = n;
792 0 : self->freq_d = d;
793 0 : GST_ERROR_OBJECT (self,
794 : "Calling _ts_reconfigure at set PROP_FREQ has failed. _ts_reconfigure () returns %d",
795 : ret);
796 : }
797 : }
798 7 : _UNLOCK (self);
799 : }
800 7 : break;
801 0 : default:
802 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
803 0 : break;
804 : }
805 25 : }
806 :
807 : /**
808 : * @brief get tensor_src_tizensensor properties
809 : */
810 : static void
811 12 : gst_tensor_src_tizensensor_get_property (GObject * object,
812 : guint prop_id, GValue * value, GParamSpec * pspec)
813 : {
814 12 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR (object);
815 :
816 12 : switch (prop_id) {
817 1 : case PROP_SILENT:
818 1 : g_value_set_boolean (value, self->silent);
819 1 : break;
820 3 : case PROP_TYPE:
821 3 : g_value_set_enum (value, self->type);
822 3 : break;
823 1 : case PROP_SEQUENCE:
824 1 : g_value_set_int (value, self->sequence);
825 1 : break;
826 3 : case PROP_MODE:
827 3 : g_value_set_enum (value, self->mode);
828 3 : break;
829 4 : case PROP_FREQ:
830 4 : gst_value_set_fraction (value, self->freq_n, self->freq_d);
831 4 : break;
832 0 : default:
833 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
834 0 : break;
835 : }
836 12 : }
837 :
838 : /**
839 : * @brief finalize the instance
840 : */
841 : static void
842 8 : gst_tensor_src_tizensensor_finalize (GObject * object)
843 : {
844 8 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR (object);
845 :
846 8 : _LOCK (self);
847 :
848 8 : _ts_clean_up_handle (self);
849 :
850 8 : _UNLOCK (self);
851 8 : g_mutex_clear (&self->lock);
852 :
853 8 : G_OBJECT_CLASS (parent_class)->finalize (object);
854 8 : }
855 :
856 : /**
857 : * @brief start function
858 : * @details This is called when state changed null to ready.
859 : * load the device and init the device resources
860 : * We won't configure before start is called.
861 : * Postcondition: configured = TRUE. src = RUNNING.
862 : */
863 : static gboolean
864 4 : gst_tensor_src_tizensensor_start (GstBaseSrc * src)
865 : {
866 4 : int ret = 0;
867 4 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
868 4 : gboolean retval = TRUE;
869 : guint blocksize;
870 :
871 4 : _LOCK (self);
872 :
873 : /* 1. Clean it up if there is a previous session */
874 4 : if (self->configured) {
875 0 : ret = _ts_clean_up_handle (self);
876 0 : if (ret) {
877 0 : GST_ERROR_OBJECT (self,
878 : "Start method failed, cleaning up previous context failed. _ts_clean_up_handle () returns %d",
879 : ret);
880 0 : retval = FALSE; /* FAIL! */
881 0 : goto exit;
882 : }
883 : }
884 :
885 : /* 2. Configure handle / context */
886 4 : ret = _ts_configure_handle (self);
887 4 : if (ret) {
888 1 : retval = FALSE;
889 1 : goto exit;
890 : }
891 3 : g_assert (self->configured);
892 :
893 : /* 3. Fire it up! */
894 3 : if (sensor_listener_start (self->listener) != 0) {
895 : /* Failed to start listener. Clean this up */
896 0 : ret = _ts_clean_up_handle (self);
897 0 : if (ret) {
898 0 : GST_ERROR_OBJECT (self, "_ts_clean_up_handle () returns %d", ret);
899 : }
900 0 : retval = FALSE;
901 0 : goto exit;
902 : }
903 :
904 : /* set data size */
905 3 : blocksize = (guint) gst_tensor_info_get_size (self->src_spec);
906 3 : gst_base_src_set_blocksize (src, blocksize);
907 :
908 3 : self->running = TRUE;
909 :
910 : /** complete the start of the base src */
911 3 : gst_base_src_start_complete (src, GST_FLOW_OK);
912 :
913 4 : exit:
914 4 : _UNLOCK (self);
915 4 : return retval;
916 : }
917 :
918 : /**
919 : * @brief stop function.
920 : * @details This is called when state changed ready to null.
921 : * Postcondition: configured = FALSE. src = STOPPED.
922 : */
923 : static gboolean
924 3 : gst_tensor_src_tizensensor_stop (GstBaseSrc * src)
925 : {
926 3 : int ret = 0;
927 3 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
928 3 : gboolean retval = TRUE;
929 :
930 3 : _LOCK (self);
931 :
932 3 : ret = _ts_clean_up_handle (self);
933 3 : if (ret) {
934 0 : GST_ERROR_OBJECT (self,
935 : "Stop method failed, cleaning up previous context failed. _ts_clean_up_handle () returns %d",
936 : ret);
937 0 : retval = FALSE; /* FAIL! */
938 0 : goto exit;
939 : }
940 :
941 3 : g_assert (!self->configured);
942 :
943 3 : exit:
944 3 : _UNLOCK (self);
945 3 : return retval;
946 : }
947 :
948 : /**
949 : * @brief handle events
950 : */
951 : static gboolean
952 130 : gst_tensor_src_tizensensor_event (GstBaseSrc * src, GstEvent * event)
953 : {
954 : /** No events to be handled yet */
955 130 : return GST_BASE_SRC_CLASS (parent_class)->event (src, event);
956 : }
957 :
958 : /**
959 : * @brief Get possible GstCap from the configuration of self.
960 : */
961 : static GstCaps *
962 6 : _ts_get_gstcaps_from_conf (GstTensorSrcTIZENSENSOR * self)
963 : {
964 : const GstTensorInfo *spec;
965 : GstCaps *retval;
966 :
967 6 : spec = self->src_spec;
968 :
969 6 : if (!self->configured || SENSOR_ALL == self->type || NULL == spec) {
970 0 : retval = gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (self));
971 : } else {
972 : GstTensorsConfig tensors_config;
973 :
974 6 : gst_tensors_config_init (&tensors_config);
975 6 : tensors_config.info.num_tensors = 1;
976 :
977 6 : gst_tensor_info_copy (&tensors_config.info.info[0], spec);
978 6 : tensors_config.rate_n = self->freq_n;
979 6 : tensors_config.rate_d = self->freq_d;
980 :
981 6 : retval = gst_tensor_caps_from_config (&tensors_config);
982 6 : gst_caps_append (retval, gst_tensors_caps_from_config (&tensors_config));
983 : }
984 :
985 6 : return retval;
986 : }
987 :
988 : /**
989 : * @brief set new caps
990 : * @retval TRUE if it's acceptable. FALSE if it's not acceptable.
991 : */
992 : static gboolean
993 3 : gst_tensor_src_tizensensor_set_caps (GstBaseSrc * src, GstCaps * caps)
994 : {
995 3 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
996 : GstCaps *cap_tensor;
997 3 : gboolean retval = FALSE;
998 :
999 3 : _LOCK (self);
1000 :
1001 3 : cap_tensor = _ts_get_gstcaps_from_conf (self);
1002 :
1003 : /* Check if it's compatible with either tensor or tensors */
1004 3 : retval = gst_caps_can_intersect (caps, cap_tensor);
1005 3 : gst_caps_unref (cap_tensor);
1006 :
1007 3 : _UNLOCK (self);
1008 3 : return retval;
1009 : }
1010 :
1011 : /**
1012 : * @brief get caps of subclass
1013 : * @note basesrc _get_caps returns the caps from the pad_template
1014 : * however, we set the caps manually and needs to returned here
1015 : */
1016 : static GstCaps *
1017 21 : gst_tensor_src_tizensensor_get_caps (GstBaseSrc * src, GstCaps * filter)
1018 : {
1019 : GstCaps *caps;
1020 : GstPad *pad;
1021 :
1022 21 : pad = src->srcpad;
1023 21 : caps = gst_pad_get_current_caps (pad);
1024 :
1025 21 : if (caps == NULL)
1026 21 : caps = gst_pad_get_pad_template_caps (pad);
1027 :
1028 21 : if (filter) {
1029 : GstCaps *intersection =
1030 0 : gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1031 0 : gst_caps_unref (caps);
1032 0 : caps = intersection;
1033 : }
1034 :
1035 21 : return caps;
1036 : }
1037 :
1038 : /**
1039 : * @brief fixate the caps when needed during negotiation
1040 : */
1041 : static GstCaps *
1042 3 : gst_tensor_src_tizensensor_fixate (GstBaseSrc * src, GstCaps * caps)
1043 : {
1044 3 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
1045 : GstCaps *cap_tensor;
1046 3 : GstCaps *retval = NULL;
1047 :
1048 3 : _LOCK (self);
1049 :
1050 3 : cap_tensor = _ts_get_gstcaps_from_conf (self);
1051 :
1052 3 : if (gst_caps_can_intersect (caps, cap_tensor))
1053 3 : retval = gst_caps_intersect (caps, cap_tensor);
1054 3 : gst_caps_unref (cap_tensor);
1055 :
1056 3 : _UNLOCK (self);
1057 3 : return gst_caps_fixate (retval);
1058 : }
1059 :
1060 : /**
1061 : * @brief Sensor nodes are not seekable.
1062 : */
1063 : static gboolean
1064 3 : gst_tensor_src_tizensensor_is_seekable (GstBaseSrc * src)
1065 : {
1066 : UNUSED (src);
1067 3 : nns_logd ("tensor_src_tizensensor is not seekable");
1068 3 : return FALSE;
1069 : }
1070 :
1071 : /**
1072 : * @brief Handle queries.
1073 : *
1074 : * GstBaseSrc method implementation.
1075 : */
1076 : static gboolean
1077 27 : gst_tensor_src_tizensensor_query (GstBaseSrc * src, GstQuery * query)
1078 : {
1079 27 : gboolean res = FALSE;
1080 27 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
1081 :
1082 27 : switch (GST_QUERY_TYPE (query)) {
1083 3 : case GST_QUERY_LATENCY:
1084 : {
1085 3 : GstClockTime min_latency, max_latency = -1;
1086 : gint freq_d, freq_n;
1087 :
1088 3 : freq_d = self->freq_d;
1089 3 : freq_n = self->freq_n;
1090 :
1091 : /* we must have a framerate */
1092 3 : if (freq_n <= 0 || freq_d <= 0) {
1093 0 : GST_WARNING_OBJECT (self,
1094 : "Can't give latency since framerate isn't fixated");
1095 0 : goto done;
1096 : }
1097 :
1098 : /* min latency is the time to capture one frame/field */
1099 3 : min_latency = gst_util_uint64_scale_int (GST_SECOND, freq_d, freq_n);
1100 :
1101 3 : GST_DEBUG_OBJECT (self,
1102 : "Reporting latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
1103 : GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
1104 :
1105 3 : gst_query_set_latency (query, TRUE, min_latency, max_latency);
1106 :
1107 3 : res = TRUE;
1108 3 : break;
1109 : }
1110 24 : default:
1111 24 : res = GST_BASE_SRC_CLASS (parent_class)->query (src, query);
1112 24 : break;
1113 : }
1114 :
1115 27 : done:
1116 27 : return res;
1117 : }
1118 :
1119 : /**
1120 : * @brief create a buffer with requested size and offset
1121 : * @note offset, size ignored as the tensor src tizensensor does not support pull mode
1122 : */
1123 : static GstFlowReturn
1124 130 : gst_tensor_src_tizensensor_create (GstBaseSrc * src, guint64 offset,
1125 : guint size, GstBuffer ** buffer)
1126 : {
1127 130 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
1128 130 : GstBuffer *buf = gst_buffer_new ();
1129 : GstMemory *mem;
1130 : guint buffer_size;
1131 130 : GstFlowReturn retval = GST_FLOW_OK;
1132 : UNUSED (size);
1133 130 : _LOCK (self);
1134 :
1135 130 : if (!self->configured) {
1136 0 : GST_ERROR_OBJECT (self,
1137 : "Buffer creation requested while the element is not configured. gst_tensor_src_tizensensor_create() cannot proceed if it is not configured.");
1138 0 : retval = GST_FLOW_ERROR;
1139 0 : goto exit;
1140 : }
1141 :
1142 130 : g_assert (self->src_spec); /* It should be valid if configured */
1143 :
1144 : /* We don't have multi-tensor (tensors with num-tensors > 1) */
1145 130 : buffer_size = (guint) gst_tensor_info_get_size (self->src_spec);
1146 130 : mem = gst_allocator_alloc (NULL, buffer_size, NULL);
1147 130 : if (mem == NULL) {
1148 0 : GST_ERROR_OBJECT (self,
1149 : "Cannot allocate memory for gst buffer of %u bytes", buffer_size);
1150 0 : retval = GST_FLOW_ERROR;
1151 0 : goto exit;
1152 : }
1153 130 : gst_buffer_append_memory (buf, mem);
1154 :
1155 130 : _UNLOCK (self);
1156 130 : retval = gst_tensor_src_tizensensor_fill (src, offset, buffer_size, buf);
1157 130 : _LOCK (self);
1158 130 : if (retval != GST_FLOW_OK)
1159 0 : goto exit;
1160 :
1161 130 : *buffer = buf;
1162 :
1163 130 : exit:
1164 130 : _UNLOCK (self);
1165 130 : if (retval != GST_FLOW_OK)
1166 0 : gst_buffer_unref (buf);
1167 130 : return retval;
1168 : }
1169 :
1170 : #define cast_loop(values, count, dest, desttype) \
1171 : do { \
1172 : int i; \
1173 : char *destptr = (char *) (dest); \
1174 : for (i = 0; i < (count); i++) \
1175 : *(destptr + (sizeof (desttype) * i)) = (desttype) (values)[i]; \
1176 : } while (0)
1177 :
1178 : #define case_cast_loop(values, count, dest, desttype, desttypeenum) \
1179 : case desttypeenum: \
1180 : cast_loop (values, count, dest, desttype); \
1181 : break;
1182 :
1183 : /**
1184 : * @brief Copy sensor's values[] to Gst memory map.
1185 : */
1186 : static void
1187 130 : _ts_assign_values (float values[], int count, GstMapInfo * map,
1188 : const GstTensorInfo * spec)
1189 : {
1190 130 : switch (spec->type) {
1191 130 : case _NNS_FLOAT32:
1192 130 : memcpy (map->data, values, sizeof (float) * count);
1193 130 : break;
1194 0 : case_cast_loop (values, count, map->data, int64_t, _NNS_INT64);
1195 0 : case_cast_loop (values, count, map->data, int32_t, _NNS_INT32);
1196 0 : case_cast_loop (values, count, map->data, int16_t, _NNS_INT16);
1197 0 : case_cast_loop (values, count, map->data, int8_t, _NNS_INT8);
1198 0 : case_cast_loop (values, count, map->data, uint64_t, _NNS_UINT64);
1199 0 : case_cast_loop (values, count, map->data, uint32_t, _NNS_UINT32);
1200 0 : case_cast_loop (values, count, map->data, uint16_t, _NNS_UINT16);
1201 0 : case_cast_loop (values, count, map->data, uint8_t, _NNS_UINT8);
1202 0 : case_cast_loop (values, count, map->data, double, _NNS_FLOAT64);
1203 0 : default:
1204 0 : g_assert (0); /** Other types are not implemented! */
1205 : }
1206 130 : }
1207 :
1208 : /**
1209 : * @brief fill the buffer with data
1210 : * @note ignore offset,size as there is pull mode
1211 : * @note buffer timestamp is already handled by gstreamer with gst clock
1212 : * @note Get data from Tizen Sensor F/W. Get the timestamp as well!
1213 : */
1214 : static GstFlowReturn
1215 130 : gst_tensor_src_tizensensor_fill (GstBaseSrc * src, guint64 offset,
1216 : guint size, GstBuffer * buffer)
1217 : {
1218 130 : GstTensorSrcTIZENSENSOR *self = GST_TENSOR_SRC_TIZENSENSOR_CAST (src);
1219 130 : sensor_event_s *events = NULL;
1220 130 : GstFlowReturn retval = GST_FLOW_OK;
1221 : GstMemory *mem;
1222 : GstMapInfo map;
1223 : int src_dim;
1224 : guint data_size;
1225 : UNUSED (offset);
1226 130 : _LOCK (self);
1227 :
1228 130 : if (!self->configured) {
1229 0 : GST_ERROR_OBJECT (self,
1230 : "gst_tensor_src_tizensensor_fill() cannot proceed if it is not configured.");
1231 0 : retval = GST_FLOW_ERROR;
1232 0 : goto exit;
1233 : }
1234 :
1235 130 : data_size = (guint) gst_tensor_info_get_size (self->src_spec);
1236 130 : if (size != data_size) {
1237 0 : GST_ERROR_OBJECT (self,
1238 : "gst_tensor_src_tizensensor_fill() requires size value (%u) to be matched with the configurations of sensors (%u).",
1239 : size, data_size);
1240 0 : retval = GST_FLOW_ERROR;
1241 0 : goto exit;
1242 : }
1243 :
1244 130 : mem = gst_buffer_peek_memory (buffer, 0);
1245 130 : if (!gst_memory_map (mem, &map, GST_MAP_WRITE)) {
1246 0 : GST_ERROR_OBJECT (self,
1247 : "gst_tensor_src_tizensensor_fill() cannot map the given buffer for writing data.");
1248 0 : retval = GST_FLOW_ERROR;
1249 0 : goto exit;
1250 : }
1251 :
1252 130 : if (self->mode == TZN_SENSOR_MODE_POLLING) {
1253 : sensor_event_s *event;
1254 130 : int count = 0;
1255 : gint64 duration;
1256 : int ret;
1257 :
1258 : /* 1. Read sensor data directly from Tizen API */
1259 130 : ret = sensor_listener_read_data_list (self->listener, &events, &count);
1260 130 : if (ret != SENSOR_ERROR_NONE || count == 0) {
1261 0 : GST_ERROR_OBJECT (self,
1262 : "Tizen sensor read failed: sensor_listener_read_data returned %d, count %d",
1263 : ret, count);
1264 0 : retval = GST_FLOW_ERROR;
1265 0 : goto exit_unmap;
1266 : }
1267 :
1268 130 : event = &events[count - 1];
1269 130 : src_dim = self->src_spec->dimension[0];
1270 130 : if (event->value_count != src_dim) {
1271 0 : GST_ERROR_OBJECT (self,
1272 : "The number of values (%d) mismatches the metadata (%d).",
1273 : event->value_count, src_dim);
1274 0 : retval = GST_FLOW_ERROR;
1275 0 : goto exit_unmap;
1276 : }
1277 :
1278 : /* 2. Do not timestamp. Let BaseSrc timestamp */
1279 130 : nns_logd ("read sensor_data at %" GST_TIME_FORMAT,
1280 : GST_TIME_ARGS (event->timestamp * 1000));
1281 :
1282 : /* 3. Set duration so that BaseSrc handles the frequency */
1283 130 : if (self->freq_n == 0)
1284 : /* 100ms */
1285 0 : duration = 100 * 1000 * 1000;
1286 : else
1287 130 : duration = gst_util_uint64_scale_int (GST_SECOND,
1288 : self->freq_d, self->freq_n);
1289 :
1290 130 : GST_BUFFER_DURATION (buffer) = duration;
1291 :
1292 : /* 4. Write values to buffer. Be careful on type casting */
1293 130 : _ts_assign_values (event->values, event->value_count, &map, self->src_spec);
1294 : } else {
1295 : /** NYI! */
1296 0 : GST_ERROR_OBJECT (self,
1297 : "gst_tensor_src_tizensensor_fill reached unimplemented code.");
1298 0 : retval = GST_FLOW_ERROR;
1299 0 : goto exit_unmap;
1300 : }
1301 :
1302 130 : exit_unmap:
1303 130 : g_free (events);
1304 130 : gst_memory_unmap (mem, &map);
1305 130 : exit:
1306 130 : _UNLOCK (self);
1307 130 : return retval;
1308 : }
|