Add your filter into filter system of sensor framework
Many sensors are noisy, such as accelerometer,gyro and so fourth. Sensor framework introduces a filter system which intends to construct reusable filter and easy filter API in sensor API library. The system leverages pipeline of GStreamer in order to save effort of scheduling each filter, which means, you are able to construct a pipeline that has several same/different filters, GStreamer will be responsible for flowing data from the first to the last.
Note: Filter system is disabled by default. To enable it, do below:
./autogen.sh --enable-filter=yesPic1 show an overview of how data passes through.

As you see, #SFSensor (see sensor-object.h) is both source and sink of data. When new data arrives from sensor daemon, it inputs data into pipeline and output to application while data is filtered. Two member functions in #SFSensor are designed for this purpose, they are:
typedef void (*SFSensorReceive) (SFSensor* self, sf_packet_data_t* packet);
SFSensorReceive receive_to_filter;
typedef gboolean (*SFIOEventFunc) (gint fd, GIOCondition flag, gpointer userdata);
SFIOEventFunc receive_from_filter;Both are pure virtual functions, which means, derived object such as #SFAccel should implement them optionally if it wants to support filter system.
Receive_to_filter() is a callback connects to #SFSensor just like what does in sf_sensor_connect_receive_func(). So it will be called periodically when new data arrives from sensor daemon, you should do preparation(eg. arrange data in the format requested by filter) and write data to filter in this function. Below is a snap from accel-object.c
memcpy (f.buf, data, packet->head.datalen);
if ( write ( sf_fd_get_writefd (sf_sensor_get_filter_src_fd (self)), &f, sizeof(f)) != sizeof (f) )
g_warning ("%s, write to source of filter failed\n", strerror (errno));sf_sensor_get_filter_src_fd () returns a pipe links to #GstFdSrc whilst sf_fd_get_writefd() returns its writable pin.
Once data flows over whole pipeline and gets ready in #GstFdSink, receive_from_filter() is invoked. This is an IO callback function which actually driven by #GMainLoop and #GSource. Parameter “fd” is the file descriptor where you will read filtered data. Because receive_from_filter() is implemented as peer with receive_to_filter(), you know quite well about how many bytes should be read and what’s format of the data. The rest work is to dispatch data to application, it is same as what does in member function receive() of #SFSensor.
Accel-object.c implements receive_to_filter() and receive_from_filter() as a reference.
Green parts showed in Pic1 are components you have to prepare for GStreamer, they are cores in our pipeline. #GstFdSrc and #GstFdSink have been implemented by GStreamer itself, so your responsibility is to write #GstElement. The HowTo of writing a GStreamer pulgin could be found at:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/index....
I don’t think it is necessary to know all details, my suggestion is reading chapter 2 “Building a Plugin”, it will teach you how to generate a pulgin template through a smart tool. Once you get the template, with some small codes, you will get the pulgin run (My assumption is you have basic knowledge of GObject which is an OO library written in C).
I did a sample for kalman filter, it is located at src/libsensor/filters/gstsfkalman.c, feel free to reference.
It is quite simple, the main works are done in gst_sfkalman_chain() that is the core function of Gst plugin. Please keep in mind we just leverage Gst to drive data from last level to next level, there is no filtering work involves in Gst pulgin, they should be done in filter object written by yourself. These filter objects showed in Pic1 as #SFKalman, #SFLowPass, #SFWiener, only #SFKalman has been done.
Sensor Framework has a parent object for all child filters named #SFFilter (see filter-object.c/h). The #SFFilter is quite simple, it only contains four members:
gfloat* in_buffer;
guint in_size;
gfloat* out_buffer;
guint out_size;from the name you will clearly understand the meanings, they are input/output buffer and length (in bytes) of each buffer. All filter objects should be derived from #SFFilter, kalman-object.c is a good reference. How to implement a filter object is up to you, there are a few rules should be followed:
- _sf_filter_get_in_buffer(),_sf_filter_get_out_buffer(),_sf_filter_get_in_size(),_sf_filter_get_out_buffer() could help you fetch data from parent’s input buffer and fill result into parent’s output buffer.
- provide a run() function to trigger the object do filtering. This function will be called in Gst pulgin’s gst_xxx_chain() after data is pushed into filter’s in buffer.
- data arranged in what format is decided in derived object of #SFSensor, for example, #SFAccel has below format for filtering:
struct _AccelFilterData {
gfloat x, y, z;
guint8 buf[FILTER_BLOCK_SIZE - sizeof (gfloat)*3];
} __attribute__ ((packed));The filter object should only touch what’s really needed be touched, for instance first 12 bytes (in 32bit machine) above, and know the format of data if necessary (for example, to accelerometer you should know first 4 bytes is value of X axis, the next 4 bytes is Y axis, and the last is Z axis). Anyway, make all possible to construct a common filter for different sensors. In the sample kalman I did, with different parameters and matrixes, it can work with different data formats.
- Provide a helper function in order to add your filter into pipeline of filter system. See what I did in sf_filter_add_kalman(). Generally speaking, you need do below steps:
Create filter object:
kalman = sf_kalman_new (n_d, n_m, n_c, sizeof(gfloat), &err);
if ( !kalman ) {
g_warning ("%s, can not add kalman filter to sensor (ID=%#x)\n",
err->message, _sf_sensor_get_id (sensor));
g_clear_error (&err);
return NULL;
}Then create the Gst pulgin related to your filter:
pad = gst_element_factory_make ("sfkalman", "gstsfkalman");
if ( !pad ) {
g_warning ("Cannot create kalman pad in GStreamer\n");
sf_kalman_destroy (kalman);
return NULL;
}The next, bind filter to Gst pulgin:
g_object_set (pad, "actor", kalman, NULL);
Bear in mind, you have to add a property “actor” in gst pulgin. This is a pointer which points to filter object (#SFKalman in our example), thanks it, you can reference your filter object in gst_xxx_chain(). See gstsfkalman.c that how I added “actor” to # GstSFKalman.
At this point, filter object has been created and bound to related Gst pulgin. It’s time to add it in target sensor’s filter list, do below:
sf_sensor_add_filter (sensor, pad);
Ok, all things are done. The filter will be invoked by filter system when data get ready.
You should have been understood how to build your own filter and integrate it into sensor framework. Now let’s take a look at inside of sf_kalman_chain() before the end, this helps you get clear how data stream from Gst plugin to filter object and reverse.
static GstFlowReturn
gst_sfkalman_chain (GstPad * pad, GstBuffer * buf)
{
GstSFKalman *filter;
SFKalman* kalman;
filter = GST_SFKALMAN (GST_OBJECT_PARENT (pad));
/*filter->kalman is the “actor” set by g_object_set (pad, "actor", kalman, NULL);*/
if ( filter->kalman ) {
kalman = filter->kalman;
/*here we fetch data from GST_BUFFER and push into filter object. Note that sf_filter_push_data() will only copy data in length of #SFFilter->in_size*/
sf_filter_push_data (SF_FILTER (kalman), GST_BUFFER_DATA (buf));
/*now we trigger kalman filter to run. At last of this function, post-processed data are going to be filled into #SFFilter->out_buffer in length of #SFFilter->out_size*/
sf_kalman_run (kalman);
/* output result to GST_BUFFER and stream to next level*/
memcpy (GST_BUFFER_DATA (buf), _sf_filter_get_out_buffer (SF_FILTER (kalman)), _sf_filter_get_out_size (SF_FILTER (kalman)));
g_print ("%f\n", *(gfloat*)GST_BUFFER_DATA (buf));
}
/* just push out the incoming buffer without touching it */
return gst_pad_push (filter->srcpad, buf);
}Aha, we are at end. This simple doc doesn’t detail all things, read code is always the best way to get understood. Filter related codes are located at src/libsensor/filters, feel free to send you comments to me. Thanks.
The kalman is only a reference to show how the filter system runs. The object itself doesn’t work well because my bad skill on signal processing. I will refine it when I have time.
For filter API to application programmer please refer to API doc. here is a snap:
SFAccel* acc = sf_accel_new ();
sf_filter_add_kalman_to_accel (SF_SENSOR (acc));
sf_sensor_connect_receive_func (SF_SENSOR (acc), your_callback, NULL);
sf_sensor_flow_with_filter (SF_SENSOR (acc), TRUE);
..................
sf_sensor_set_active (SF_SENSOR (acc), FALSE);
sf_accel_destroy (acc);- Printer-friendly version
- Login or register to post comments